Skip to content

Commit ac7ee47

Browse files
authored
Merge pull request jMonkeyEngine#2480 from capdevon/capdevon-WireFrustum
WireFrustum: javadoc + add makeGeometry(Camera) method
2 parents 097f391 + 875f846 commit ac7ee47

1 file changed

Lines changed: 113 additions & 27 deletions

File tree

Lines changed: 113 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2009-2012 jMonkeyEngine
2+
* Copyright (c) 2009-2025 jMonkeyEngine
33
* All rights reserved.
44
*
55
* Redistribution and use in source and binary forms, with or without
@@ -32,74 +32,160 @@
3232
package com.jme3.scene.debug;
3333

3434
import com.jme3.math.Vector3f;
35+
import com.jme3.renderer.Camera;
36+
import com.jme3.scene.Geometry;
3537
import com.jme3.scene.Mesh;
3638
import com.jme3.scene.VertexBuffer;
3739
import com.jme3.scene.VertexBuffer.Type;
3840
import com.jme3.scene.VertexBuffer.Usage;
41+
import com.jme3.shadow.ShadowUtil;
3942
import com.jme3.util.BufferUtils;
4043
import java.nio.FloatBuffer;
4144

45+
/**
46+
* A specialized Mesh that renders a camera frustum as a wireframe.
47+
* This class extends jME3's Mesh and is designed to visually represent
48+
* the viewing volume of a camera, which can be useful for debugging
49+
* or visualization purposes.
50+
* <p>
51+
* The frustum is defined by eight points: four for the near plane
52+
* and four for the far plane. These points are connected by lines
53+
* to form a wireframe cube-like structure.
54+
*/
4255
public class WireFrustum extends Mesh {
4356

4457
/**
45-
* This constructor is for serialization only. Do not use.
58+
* For Serialization only. Do not use.
4659
*/
4760
protected WireFrustum() {
4861
}
4962

50-
public WireFrustum(Vector3f[] points){
51-
initGeom(this, points);
52-
}
53-
54-
public static Mesh makeFrustum(Vector3f[] points){
55-
Mesh m = new Mesh();
56-
initGeom(m, points);
57-
return m;
63+
/**
64+
* Constructs a new `WireFrustum` mesh using the specified frustum corner points.
65+
* The points should represent the 8 corners of the frustum.
66+
* The expected order of points is typically:
67+
* 0-3: Near plane (e.g., bottom-left, bottom-right, top-right, top-left)
68+
* 4-7: Far plane (e.g., bottom-left, bottom-right, top-right, top-left)
69+
*
70+
* @param points An array of 8 `Vector3f` objects representing the frustum's corners.
71+
* If the array is null or does not contain 8 points, an
72+
* `IllegalArgumentException` will be thrown.
73+
*/
74+
public WireFrustum(Vector3f[] points) {
75+
if (points == null || points.length != 8) {
76+
throw new IllegalArgumentException("Frustum points array must not be null and must contain 8 points.");
77+
}
78+
setGeometryData(points);
5879
}
5980

60-
private static void initGeom(Mesh m, Vector3f[] points) {
61-
if (points != null)
62-
m.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(points));
81+
/**
82+
* Initializes the mesh's geometric data, setting up the vertex positions and indices.
83+
* This method is called during the construction of the `WireFrustum`.
84+
*
85+
* @param points The 8 `Vector3f` points defining the frustum's corners.
86+
*/
87+
private void setGeometryData(Vector3f[] points) {
88+
// Set vertex positions
89+
setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(points));
6390

64-
m.setBuffer(Type.Index, 2,
91+
// Set indices to draw lines connecting the frustum corners
92+
// The indices define 12 lines: 4 for near plane, 4 for far plane, and 4 connecting near to far.
93+
setBuffer(Type.Index, 2,
6594
new short[]{
95+
// Near plane
6696
0, 1,
6797
1, 2,
6898
2, 3,
6999
3, 0,
70100

101+
// Far plane
71102
4, 5,
72103
5, 6,
73104
6, 7,
74105
7, 4,
75106

107+
// Connecting lines (near to far)
76108
0, 4,
77109
1, 5,
78110
2, 6,
79111
3, 7,
80112
}
81113
);
82-
m.getBuffer(Type.Index).setUsage(Usage.Static);
83-
m.setMode(Mode.Lines);
114+
getBuffer(Type.Index).setUsage(Usage.Static);
115+
setMode(Mode.Lines);
116+
updateBound();
84117
}
85118

86-
public void update(Vector3f[] points){
119+
/**
120+
* Updates the vertex positions of the existing `WireFrustum` mesh.
121+
* This is more efficient than creating a new `WireFrustum` instance
122+
* if only the frustum's position or orientation changes.
123+
*
124+
* @param points An array of 8 `Vector3f` objects representing the new frustum's corners.
125+
* If the array is null or does not contain 8 points, an
126+
* `IllegalArgumentException` will be thrown.
127+
*/
128+
public void update(Vector3f[] points) {
129+
if (points == null || points.length != 8) {
130+
throw new IllegalArgumentException("Frustum points array must not be null and must contain 8 points.");
131+
}
132+
87133
VertexBuffer vb = getBuffer(Type.Position);
88-
if (vb == null){
89-
setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(points));
134+
if (vb == null) {
135+
// If for some reason the position buffer is missing, re-create it.
136+
// This case should ideally not happen if the object is constructed properly.
137+
setGeometryData(points);
90138
return;
91139
}
92140

93-
FloatBuffer b = BufferUtils.createFloatBuffer(points);
94-
FloatBuffer a = (FloatBuffer) vb.getData();
95-
b.rewind();
96-
a.rewind();
97-
a.put(b);
98-
a.rewind();
141+
// Create a new FloatBuffer from the updated points
142+
FloatBuffer newBuff = BufferUtils.createFloatBuffer(points);
143+
// Get the existing FloatBuffer from the VertexBuffer
144+
FloatBuffer currBuff = (FloatBuffer) vb.getData();
99145

100-
vb.updateData(a);
101-
146+
currBuff.clear(); // Clear
147+
currBuff.put(newBuff); // Copy
148+
currBuff.rewind(); // Rewind
149+
150+
// Update the VertexBuffer with the modified FloatBuffer data
151+
vb.updateData(currBuff);
152+
153+
// Update the mesh's bounding volume to reflect the new vertex positions
102154
updateBound();
103155
}
104156

157+
/**
158+
* A static factory method to create a new `WireFrustum` mesh.
159+
* This method provides a cleaner way to instantiate a `WireFrustum`.
160+
*
161+
* @param points An array of 8 `Vector3f` objects representing the frustum's corners.
162+
* @return A new `WireFrustum` instance.
163+
*/
164+
public static Mesh makeFrustum(Vector3f[] points) {
165+
return new WireFrustum(points);
166+
}
167+
168+
/**
169+
* Creates a `Geometry` object representing the wireframe frustum of a given camera.
170+
* The frustum points are calculated based on the camera's current view settings.
171+
* The returned `Geometry` can be directly attached to a scene graph.
172+
*
173+
* @param camera The `Camera` whose frustum is to be visualized.
174+
* @return A `Geometry` object containing the `WireFrustum` mesh.
175+
*/
176+
public static Geometry makeGeometry(Camera camera) {
177+
Vector3f[] frustumCorners = new Vector3f[8];
178+
for (int i = 0; i < 8; i++) {
179+
frustumCorners[i] = new Vector3f();
180+
}
181+
182+
Camera tempCam = camera.clone();
183+
tempCam.setLocation(new Vector3f(0, 0, 0));
184+
tempCam.lookAt(Vector3f.UNIT_Z, Vector3f.UNIT_Y);
185+
ShadowUtil.updateFrustumPoints2(tempCam, frustumCorners);
186+
187+
WireFrustum mesh = new WireFrustum(frustumCorners);
188+
return new Geometry("Viewing Frustum", mesh);
189+
}
190+
105191
}

0 commit comments

Comments
 (0)