|
@@ -1,5 +1,5 @@
|
|
/*
|
|
/*
|
|
- * Copyright (c) 2009-2012 jMonkeyEngine
|
|
|
|
|
|
+ * Copyright (c) 2009-2025 jMonkeyEngine
|
|
* All rights reserved.
|
|
* All rights reserved.
|
|
*
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* Redistribution and use in source and binary forms, with or without
|
|
@@ -32,74 +32,160 @@
|
|
package com.jme3.scene.debug;
|
|
package com.jme3.scene.debug;
|
|
|
|
|
|
import com.jme3.math.Vector3f;
|
|
import com.jme3.math.Vector3f;
|
|
|
|
+import com.jme3.renderer.Camera;
|
|
|
|
+import com.jme3.scene.Geometry;
|
|
import com.jme3.scene.Mesh;
|
|
import com.jme3.scene.Mesh;
|
|
import com.jme3.scene.VertexBuffer;
|
|
import com.jme3.scene.VertexBuffer;
|
|
import com.jme3.scene.VertexBuffer.Type;
|
|
import com.jme3.scene.VertexBuffer.Type;
|
|
import com.jme3.scene.VertexBuffer.Usage;
|
|
import com.jme3.scene.VertexBuffer.Usage;
|
|
|
|
+import com.jme3.shadow.ShadowUtil;
|
|
import com.jme3.util.BufferUtils;
|
|
import com.jme3.util.BufferUtils;
|
|
import java.nio.FloatBuffer;
|
|
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 {
|
|
public class WireFrustum extends Mesh {
|
|
|
|
|
|
/**
|
|
/**
|
|
- * This constructor is for serialization only. Do not use.
|
|
|
|
|
|
+ * For Serialization only. Do not use.
|
|
*/
|
|
*/
|
|
protected WireFrustum() {
|
|
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[]{
|
|
new short[]{
|
|
|
|
+ // Near plane
|
|
0, 1,
|
|
0, 1,
|
|
1, 2,
|
|
1, 2,
|
|
2, 3,
|
|
2, 3,
|
|
3, 0,
|
|
3, 0,
|
|
|
|
|
|
|
|
+ // Far plane
|
|
4, 5,
|
|
4, 5,
|
|
5, 6,
|
|
5, 6,
|
|
6, 7,
|
|
6, 7,
|
|
7, 4,
|
|
7, 4,
|
|
|
|
|
|
|
|
+ // Connecting lines (near to far)
|
|
0, 4,
|
|
0, 4,
|
|
1, 5,
|
|
1, 5,
|
|
2, 6,
|
|
2, 6,
|
|
3, 7,
|
|
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);
|
|
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;
|
|
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();
|
|
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);
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|