Bladeren bron

Merge pull request #2480 from capdevon/capdevon-WireFrustum

WireFrustum: javadoc + add makeGeometry(Camera) method
Ryan McDonough 2 maanden geleden
bovenliggende
commit
ac7ee47361
1 gewijzigde bestanden met toevoegingen van 113 en 27 verwijderingen
  1. 113 27
      jme3-core/src/main/java/com/jme3/scene/debug/WireFrustum.java

+ 113 - 27
jme3-core/src/main/java/com/jme3/scene/debug/WireFrustum.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2025 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,74 +32,160 @@
 package com.jme3.scene.debug;
 
 import com.jme3.math.Vector3f;
+import com.jme3.renderer.Camera;
+import com.jme3.scene.Geometry;
 import com.jme3.scene.Mesh;
 import com.jme3.scene.VertexBuffer;
 import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.scene.VertexBuffer.Usage;
+import com.jme3.shadow.ShadowUtil;
 import com.jme3.util.BufferUtils;
 import java.nio.FloatBuffer;
 
+/**
+ * A specialized Mesh that renders a camera frustum as a wireframe.
+ * This class extends jME3's Mesh and is designed to visually represent
+ * the viewing volume of a camera, which can be useful for debugging
+ * or visualization purposes.
+ * <p>
+ * The frustum is defined by eight points: four for the near plane
+ * and four for the far plane. These points are connected by lines
+ * to form a wireframe cube-like structure.
+ */
 public class WireFrustum extends Mesh {
 
     /**
-     * This constructor is for serialization only. Do not use.
+     * For Serialization only. Do not use.
      */
     protected WireFrustum() {
     }
 
-    public WireFrustum(Vector3f[] points){
-        initGeom(this, points);
-    }
-
-    public static Mesh makeFrustum(Vector3f[] points){
-        Mesh m = new Mesh();
-        initGeom(m, points);
-        return m;
+    /**
+     * Constructs a new `WireFrustum` mesh using the specified frustum corner points.
+     * The points should represent the 8 corners of the frustum.
+     * The expected order of points is typically:
+     * 0-3: Near plane (e.g., bottom-left, bottom-right, top-right, top-left)
+     * 4-7: Far plane (e.g., bottom-left, bottom-right, top-right, top-left)
+     *
+     * @param points An array of 8 `Vector3f` objects representing the frustum's corners.
+     * If the array is null or does not contain 8 points, an
+     * `IllegalArgumentException` will be thrown.
+     */
+    public WireFrustum(Vector3f[] points) {
+        if (points == null || points.length != 8) {
+            throw new IllegalArgumentException("Frustum points array must not be null and must contain 8 points.");
+        }
+        setGeometryData(points);
     }
 
-    private static void initGeom(Mesh m, Vector3f[] points) {
-        if (points != null)
-            m.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(points));
+    /**
+     * Initializes the mesh's geometric data, setting up the vertex positions and indices.
+     * This method is called during the construction of the `WireFrustum`.
+     *
+     * @param points The 8 `Vector3f` points defining the frustum's corners.
+     */
+    private void setGeometryData(Vector3f[] points) {
+        // Set vertex positions
+        setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(points));
 
-        m.setBuffer(Type.Index, 2,
+        // Set indices to draw lines connecting the frustum corners
+        // The indices define 12 lines: 4 for near plane, 4 for far plane, and 4 connecting near to far.
+        setBuffer(Type.Index, 2,
                 new short[]{
+                        // Near plane
                         0, 1,
                         1, 2,
                         2, 3,
                         3, 0,
 
+                        // Far plane
                         4, 5,
                         5, 6,
                         6, 7,
                         7, 4,
 
+                        // Connecting lines (near to far)
                         0, 4,
                         1, 5,
                         2, 6,
                         3, 7,
                 }
         );
-        m.getBuffer(Type.Index).setUsage(Usage.Static);
-        m.setMode(Mode.Lines);
+        getBuffer(Type.Index).setUsage(Usage.Static);
+        setMode(Mode.Lines);
+        updateBound();
     }
 
-    public void update(Vector3f[] points){
+    /**
+     * Updates the vertex positions of the existing `WireFrustum` mesh.
+     * This is more efficient than creating a new `WireFrustum` instance
+     * if only the frustum's position or orientation changes.
+     *
+     * @param points An array of 8 `Vector3f` objects representing the new frustum's corners.
+     * If the array is null or does not contain 8 points, an
+     * `IllegalArgumentException` will be thrown.
+     */
+    public void update(Vector3f[] points) {
+        if (points == null || points.length != 8) {
+            throw new IllegalArgumentException("Frustum points array must not be null and must contain 8 points.");
+        }
+
         VertexBuffer vb = getBuffer(Type.Position);
-        if (vb == null){
-            setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(points));
+        if (vb == null) {
+            // If for some reason the position buffer is missing, re-create it.
+            // This case should ideally not happen if the object is constructed properly.
+            setGeometryData(points);
             return;
         }
 
-        FloatBuffer b = BufferUtils.createFloatBuffer(points);
-        FloatBuffer a = (FloatBuffer) vb.getData();
-        b.rewind();
-        a.rewind();
-        a.put(b);
-        a.rewind();
+        // Create a new FloatBuffer from the updated points
+        FloatBuffer newBuff = BufferUtils.createFloatBuffer(points);
+        // Get the existing FloatBuffer from the VertexBuffer
+        FloatBuffer currBuff = (FloatBuffer) vb.getData();
 
-        vb.updateData(a);
-        
+        currBuff.clear();       // Clear
+        currBuff.put(newBuff);  // Copy
+        currBuff.rewind();      // Rewind
+
+        // Update the VertexBuffer with the modified FloatBuffer data
+        vb.updateData(currBuff);
+
+        // Update the mesh's bounding volume to reflect the new vertex positions
         updateBound();
     }
 
+    /**
+     * A static factory method to create a new `WireFrustum` mesh.
+     * This method provides a cleaner way to instantiate a `WireFrustum`.
+     *
+     * @param points An array of 8 `Vector3f` objects representing the frustum's corners.
+     * @return A new `WireFrustum` instance.
+     */
+    public static Mesh makeFrustum(Vector3f[] points) {
+        return new WireFrustum(points);
+    }
+
+    /**
+     * Creates a `Geometry` object representing the wireframe frustum of a given camera.
+     * The frustum points are calculated based on the camera's current view settings.
+     * The returned `Geometry` can be directly attached to a scene graph.
+     *
+     * @param camera The `Camera` whose frustum is to be visualized.
+     * @return A `Geometry` object containing the `WireFrustum` mesh.
+     */
+    public static Geometry makeGeometry(Camera camera) {
+        Vector3f[] frustumCorners = new Vector3f[8];
+        for (int i = 0; i < 8; i++) {
+            frustumCorners[i] = new Vector3f();
+        }
+
+        Camera tempCam = camera.clone();
+        tempCam.setLocation(new Vector3f(0, 0, 0));
+        tempCam.lookAt(Vector3f.UNIT_Z, Vector3f.UNIT_Y);
+        ShadowUtil.updateFrustumPoints2(tempCam, frustumCorners);
+
+        WireFrustum mesh = new WireFrustum(frustumCorners);
+        return new Geometry("Viewing Frustum", mesh);
+    }
+
 }