* Some javadoc for Mesh

* Added Mesh.getIndicesAsList() for easy access to triangle data
 * Added UserData.JME_PHYSICSIGNORE to indicate to physics engine that geometry should be excluded from collision shape generation
 * Physics engine now supports all possible mesh formats (non-indexed, triangle strip, etc)

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7670 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
sha..rd 14 years ago
parent 93d968a12b
commit 31027a0b2c
  1. 2
      engine/src/core/com/jme3/math/Spline.java
  2. 218
      engine/src/core/com/jme3/scene/Mesh.java
  3. 6
      engine/src/core/com/jme3/scene/UserData.java
  4. 20
      engine/src/core/com/jme3/scene/mesh/IndexBuffer.java
  5. 31
      engine/src/core/com/jme3/scene/mesh/WrappedIndexBuffer.java
  6. 6
      engine/src/jbullet/com/jme3/bullet/util/CollisionShapeFactory.java
  7. 5
      engine/src/jbullet/com/jme3/bullet/util/Converter.java
  8. 7
      engine/src/tools/jme3tools/optimize/GeometryBatchFactory.java

@ -22,12 +22,12 @@ import com.jme3.export.Savable;
public class Spline implements Savable { public class Spline implements Savable {
public enum SplineType { public enum SplineType {
Linear, Linear,
CatmullRom, CatmullRom,
Bezier, Bezier,
Nurb Nurb
} }
private List<Vector3f> controlPoints = new ArrayList<Vector3f>(); private List<Vector3f> controlPoints = new ArrayList<Vector3f>();
private List<Float> knots; //knots of NURBS spline private List<Float> knots; //knots of NURBS spline
private float[] weights; //weights of NURBS spline private float[] weights; //weights of NURBS spline

@ -94,14 +94,14 @@ public class Mesh implements Savable, Cloneable {
* A primitive is a single point in space. The size of the points * A primitive is a single point in space. The size of the points
* can be specified with {@link Mesh#setPointSize(float) }. * can be specified with {@link Mesh#setPointSize(float) }.
*/ */
Points, Points(true),
/** /**
* A primitive is a line segment. Every two vertices specify * A primitive is a line segment. Every two vertices specify
* a single line. {@link Mesh#setLineWidth(float) } can be used * a single line. {@link Mesh#setLineWidth(float) } can be used
* to set the width of the lines. * to set the width of the lines.
*/ */
Lines, Lines(true),
/** /**
* A primitive is a line segment. The first two vertices specify * A primitive is a line segment. The first two vertices specify
@ -109,7 +109,7 @@ public class Mesh implements Savable, Cloneable {
* previous vertex to make a line. {@link Mesh#setLineWidth(float) } can * previous vertex to make a line. {@link Mesh#setLineWidth(float) } can
* be used to set the width of the lines. * be used to set the width of the lines.
*/ */
LineStrip, LineStrip(false),
/** /**
* Identical to {@link #LineStrip} except that at the end * Identical to {@link #LineStrip} except that at the end
@ -117,27 +117,27 @@ public class Mesh implements Savable, Cloneable {
* {@link Mesh#setLineWidth(float) } can be used * {@link Mesh#setLineWidth(float) } can be used
* to set the width of the lines. * to set the width of the lines.
*/ */
LineLoop, LineLoop(false),
/** /**
* A primitive is a triangle. Each 3 vertices specify a single * A primitive is a triangle. Each 3 vertices specify a single
* triangle. * triangle.
*/ */
Triangles, Triangles(true),
/** /**
* Similar to {@link #Triangles}, the first 3 vertices * Similar to {@link #Triangles}, the first 3 vertices
* specify a triangle, while subsequent vertices are combined with * specify a triangle, while subsequent vertices are combined with
* the previous two to form a triangle. * the previous two to form a triangle.
*/ */
TriangleStrip, TriangleStrip(false),
/** /**
* Similar to {@link #Triangles}, the first 3 vertices * Similar to {@link #Triangles}, the first 3 vertices
* specify a triangle, each 2 subsequent vertices are combined * specify a triangle, each 2 subsequent vertices are combined
* with the very first vertex to make a triangle. * with the very first vertex to make a triangle.
*/ */
TriangleFan, TriangleFan(false),
/** /**
* A combination of various triangle modes. It is best to avoid * A combination of various triangle modes. It is best to avoid
@ -146,7 +146,26 @@ public class Mesh implements Savable, Cloneable {
* {@link Mesh#setElementLengths(int[]) element lengths} must * {@link Mesh#setElementLengths(int[]) element lengths} must
* be specified for this mode. * be specified for this mode.
*/ */
Hybrid; Hybrid(false);
private boolean listMode = false;
private Mode(boolean listMode){
this.listMode = listMode;
}
/**
* Returns true if the specified mode is a list mode (meaning
* ,it specifies the indices as a linear list and not some special
* format).
* Will return true for the types {@link #Points}, {@link #Lines} and
* {@link #Triangles}.
*
* @return true if the mode is a list type mode
*/
public boolean isListMode(){
return listMode;
}
} }
/** /**
@ -691,31 +710,44 @@ public class Mesh implements Savable, Cloneable {
} }
/** /**
* Returns how many triangles are on this Mesh. * Returns how many triangles or elements are on this Mesh.
* This value is only updated when {@link #updateCounts() } is called. * This value is only updated when {@link #updateCounts() } is called.
* If the mesh mode is not a triangle mode, then this returns the
* number of elements/primitives, e.g. how many lines or how many points,
* instead of how many triangles.
* *
* @return how many triangles are on this Mesh. * @return how many triangles/elements are on this Mesh.
*/ */
public int getTriangleCount(){ public int getTriangleCount(){
return elementCount; return elementCount;
} }
/**
* Returns the number of vertices on this mesh.
* The value is computed based on the position buffer, which
* must be set on all meshes.
*
* @return Number of vertices on the mesh
*/
public int getVertexCount(){ public int getVertexCount(){
return vertCount; return vertCount;
} }
/**
* Gets the triangle vertex positions at the given triangle index
* and stores them into the v1, v2, v3 arguments.
*
* @param index The index of the triangle.
* Should be between 0 and {@link #getTriangleCount()}.
*
* @param v1 Vector to contain first vertex position
* @param v2 Vector to contain second vertex position
* @param v3 Vector to contain third vertex position
*/
public void getTriangle(int index, Vector3f v1, Vector3f v2, Vector3f v3){ public void getTriangle(int index, Vector3f v1, Vector3f v2, Vector3f v3){
VertexBuffer pb = getBuffer(Type.Position); VertexBuffer pb = getBuffer(Type.Position);
IndexBuffer ib = getIndicesAsList();
IndexBuffer ib = getIndexBuffer(); if (pb != null && pb.getFormat() == Format.Float && pb.getNumComponents() == 3){
if (ib == null){
ib = new VirtualIndexBuffer(vertCount, mode);
}else if (mode != Mode.Triangles){
ib = new WrappedIndexBuffer(this);
}
if (pb.getFormat() == Format.Float){
FloatBuffer fpb = (FloatBuffer) pb.getData(); FloatBuffer fpb = (FloatBuffer) pb.getData();
// aquire triangle's vertex indices // aquire triangle's vertex indices
@ -727,33 +759,56 @@ public class Mesh implements Savable, Cloneable {
BufferUtils.populateFromBuffer(v1, fpb, vert1); BufferUtils.populateFromBuffer(v1, fpb, vert1);
BufferUtils.populateFromBuffer(v2, fpb, vert2); BufferUtils.populateFromBuffer(v2, fpb, vert2);
BufferUtils.populateFromBuffer(v3, fpb, vert3); BufferUtils.populateFromBuffer(v3, fpb, vert3);
}else{
throw new UnsupportedOperationException("Position buffer not set or "
+ " has incompatible format");
} }
} }
/**
* Gets the triangle vertex positions at the given triangle index
* and stores them into the {@link Triangle} argument.
* Also sets the triangle index to the <code>index</code> argument.
*
* @param index The index of the triangle.
* Should be between 0 and {@link #getTriangleCount()}.
*
* @param tri The triangle to store the positions in
*/
public void getTriangle(int index, Triangle tri){ public void getTriangle(int index, Triangle tri){
getTriangle(index, tri.get1(), tri.get2(), tri.get3()); getTriangle(index, tri.get1(), tri.get2(), tri.get3());
tri.setIndex(index); tri.setIndex(index);
} }
/**
* Gets the triangle vertex indices at the given triangle index
* and stores them into the given int array.
*
* @param index The index of the triangle.
* Should be between 0 and {@link #getTriangleCount()}.
*
* @param indices Indices of the triangle's vertices
*/
public void getTriangle(int index, int[] indices){ public void getTriangle(int index, int[] indices){
VertexBuffer ib = getBuffer(Type.Index); IndexBuffer ib = getIndicesAsList();
if (ib.getFormat() == Format.UnsignedShort){
// accepted format for buffers
ShortBuffer sib = (ShortBuffer) ib.getData();
// acquire triangle's vertex indices // acquire triangle's vertex indices
int vertIndex = index * 3; int vertIndex = index * 3;
indices[0] = sib.get(vertIndex); indices[0] = ib.get(vertIndex);
indices[1] = sib.get(vertIndex+1); indices[1] = ib.get(vertIndex+1);
indices[2] = sib.get(vertIndex+2); indices[2] = ib.get(vertIndex+2);
}
} }
/**
* Returns the mesh's VAO ID. Internal use only.
*/
public int getId(){ public int getId(){
return vertexArrayID; return vertexArrayID;
} }
/**
* Sets the mesh's VAO ID. Internal use only.
*/
public void setId(int id){ public void setId(int id){
if (vertexArrayID != -1) if (vertexArrayID != -1)
throw new IllegalStateException("ID has already been set."); throw new IllegalStateException("ID has already been set.");
@ -761,12 +816,24 @@ public class Mesh implements Savable, Cloneable {
vertexArrayID = id; vertexArrayID = id;
} }
/**
* Generates a collision tree for the mesh.
* Called automatically by {@link #collideWith(com.jme3.collision.Collidable,
* com.jme3.math.Matrix4f,
* com.jme3.bounding.BoundingVolume,
* com.jme3.collision.CollisionResults) }.
*/
public void createCollisionData(){ public void createCollisionData(){
BIHTree tree = new BIHTree(this); BIHTree tree = new BIHTree(this);
tree.construct(); tree.construct();
collisionTree = tree; collisionTree = tree;
} }
/**
* Handles collision detection, internal use only.
* User code should only use collideWith() on scene
* graph elements such as {@link Spatial}s.
*/
public int collideWith(Collidable other, public int collideWith(Collidable other,
Matrix4f worldMatrix, Matrix4f worldMatrix,
BoundingVolume worldBound, BoundingVolume worldBound,
@ -779,6 +846,17 @@ public class Mesh implements Savable, Cloneable {
return collisionTree.collideWith(other, worldMatrix, worldBound, results); return collisionTree.collideWith(other, worldMatrix, worldBound, results);
} }
/**
* Set a floating point {@link VertexBuffer} on the mesh.
*
* @param type The type of {@link VertexBuffer},
* e.g. {@link Type#Position}, {@link Type#Normal}, etc.
*
* @param components Number of components on the vertex buffer, should
* be between 1 and 4.
*
* @param buf The floating point data to contain
*/
public void setBuffer(Type type, int components, FloatBuffer buf) { public void setBuffer(Type type, int components, FloatBuffer buf) {
// VertexBuffer vb = buffers.get(type); // VertexBuffer vb = buffers.get(type);
VertexBuffer vb = buffers.get(type.ordinal()); VertexBuffer vb = buffers.get(type.ordinal());
@ -851,6 +929,13 @@ public class Mesh implements Savable, Cloneable {
updateCounts(); updateCounts();
} }
/**
* Clears or unsets the {@link VertexBuffer} set on this mesh
* with the given type.
* Does nothing if the vertex buffer type is not set initially
*
* @param type The type to remove
*/
public void clearBuffer(VertexBuffer.Type type){ public void clearBuffer(VertexBuffer.Type type){
VertexBuffer vb = buffers.remove(type.ordinal()); VertexBuffer vb = buffers.remove(type.ordinal());
if (vb != null){ if (vb != null){
@ -863,10 +948,24 @@ public class Mesh implements Savable, Cloneable {
setBuffer(type, components, BufferUtils.createShortBuffer(buf)); setBuffer(type, components, BufferUtils.createShortBuffer(buf));
} }
/**
* Get the {@link VertexBuffer} stored on this mesh with the given
* type.
*
* @param type The type of VertexBuffer
* @return the VertexBuffer data, or null if not set
*/
public VertexBuffer getBuffer(Type type){ public VertexBuffer getBuffer(Type type){
return buffers.get(type.ordinal()); return buffers.get(type.ordinal());
} }
/**
* Get the {@link VertexBuffer} data stored on this mesh in float
* format.
*
* @param type The type of VertexBuffer
* @return the VertexBuffer data, or null if not set
*/
public FloatBuffer getFloatBuffer(Type type) { public FloatBuffer getFloatBuffer(Type type) {
VertexBuffer vb = getBuffer(type); VertexBuffer vb = getBuffer(type);
if (vb == null) if (vb == null)
@ -875,6 +974,13 @@ public class Mesh implements Savable, Cloneable {
return (FloatBuffer) vb.getData(); return (FloatBuffer) vb.getData();
} }
/**
* Get the {@link VertexBuffer} data stored on this mesh in short
* format.
*
* @param type The type of VertexBuffer
* @return the VertexBuffer data, or null if not set
*/
public ShortBuffer getShortBuffer(Type type) { public ShortBuffer getShortBuffer(Type type) {
VertexBuffer vb = getBuffer(type); VertexBuffer vb = getBuffer(type);
if (vb == null) if (vb == null)
@ -883,6 +989,42 @@ public class Mesh implements Savable, Cloneable {
return (ShortBuffer) vb.getData(); return (ShortBuffer) vb.getData();
} }
/**
* Acquires an index buffer that will read the vertices on the mesh
* as a list.
*
* @param mesh The mesh to read from
* @return A virtual or wrapped index buffer to read the data as a list
*/
public IndexBuffer getIndicesAsList(){
if (mode == Mode.Hybrid)
throw new UnsupportedOperationException("Hybrid mode not supported");
IndexBuffer ib = getIndexBuffer();
if (ib != null){
if (mode.isListMode()){
// already in list mode
return ib;
}else{
// not in list mode but it does have an index buffer
// wrap it so the data is converted to list format
return new WrappedIndexBuffer(this);
}
}else{
// return a virtual index buffer that will supply
// "fake" indices in list format
return new VirtualIndexBuffer(vertCount, mode);
}
}
/**
* Get the index buffer for this mesh.
* Will return <code>null</code> if no index buffer is set.
*
* @return The index buffer of this mesh.
*
* @see Type#Index
*/
public IndexBuffer getIndexBuffer() { public IndexBuffer getIndexBuffer() {
VertexBuffer vb = getBuffer(Type.Index); VertexBuffer vb = getBuffer(Type.Index);
if (vb == null) if (vb == null)
@ -902,10 +1044,20 @@ public class Mesh implements Savable, Cloneable {
/** /**
* Scales the texture coordinate buffer on this mesh by the given * Scales the texture coordinate buffer on this mesh by the given
* scale factor. * scale factor.
* <p>
* Note that values above 1 will cause the
* texture to tile, while values below 1 will cause the texture
* to stretch.
* </p>
* *
* @param scaleFactor The scale factor to scale by. Every texture
* coordinate is multiplied by this vector to get the result.
* *
* @param scaleFactor * @throws IllegalStateException If there's no texture coordinate
* buffer on the mesh
* @throws UnsupportedOperationException If the texture coordinate
* buffer is not in 2D float format.
*/ */
public void scaleTextureCoordinates(Vector2f scaleFactor){ public void scaleTextureCoordinates(Vector2f scaleFactor){
VertexBuffer tc = getBuffer(Type.TexCoord); VertexBuffer tc = getBuffer(Type.TexCoord);

@ -47,6 +47,12 @@ import java.io.IOException;
*/ */
public final class UserData implements Savable { public final class UserData implements Savable {
/**
* Boolean type on Geometries to indicate that physics collision
* shape generation should ignore them.
*/
public static final String JME_PHYSICSIGNORE = "JmePhysicsIgnore";
protected byte type; protected byte type;
protected Object value; protected Object value;

@ -32,6 +32,7 @@
package com.jme3.scene.mesh; package com.jme3.scene.mesh;
import com.jme3.util.BufferUtils;
import java.nio.Buffer; import java.nio.Buffer;
/** /**
@ -42,6 +43,25 @@ import java.nio.Buffer;
* @author lex * @author lex
*/ */
public abstract class IndexBuffer { public abstract class IndexBuffer {
/**
* Creates an index buffer that can contain the given amount
* of vertices.
* Returns {@link IndexShortBuffer}
*
* @param vertexCount The amount of vertices to contain
* @param indexCount The amount of indices
* to contain.
* @return A new index buffer
*/
public static IndexBuffer createIndexBuffer(int vertexCount, int indexCount){
if (vertexCount > 65535){
return new IndexIntBuffer(BufferUtils.createIntBuffer(indexCount));
}else{
return new IndexShortBuffer(BufferUtils.createShortBuffer(indexCount));
}
}
/** /**
* Returns the vertex index for the given index in the index buffer. * Returns the vertex index for the given index in the index buffer.
* *

@ -54,28 +54,29 @@ public class WrappedIndexBuffer extends VirtualIndexBuffer {
public Buffer getBuffer() { public Buffer getBuffer() {
return ib.getBuffer(); return ib.getBuffer();
} }
public static void convertToList(Mesh mesh){ public static void convertToList(Mesh mesh){
IndexBuffer inBuf = mesh.getIndexBuffer(); IndexBuffer inBuf = mesh.getIndicesAsList();
if (inBuf == null){ IndexBuffer outBuf = IndexBuffer.createIndexBuffer(mesh.getVertexCount(),
inBuf = new VirtualIndexBuffer(mesh.getVertexCount(), mesh.getMode()); inBuf.size());
}else{
inBuf = new WrappedIndexBuffer(mesh);
}
IndexBuffer outBuf;
if (inBuf.size() > Short.MAX_VALUE * 2){
outBuf = new IndexIntBuffer(BufferUtils.createIntBuffer(inBuf.size()));
}else{
outBuf = new IndexShortBuffer(BufferUtils.createShortBuffer(inBuf.size()));
}
for (int i = 0; i < inBuf.size(); i++){ for (int i = 0; i < inBuf.size(); i++){
outBuf.put(i, inBuf.get(i)); outBuf.put(i, inBuf.get(i));
} }
mesh.clearBuffer(Type.Index); mesh.clearBuffer(Type.Index);
mesh.setMode(Mode.Triangles); switch (mesh.getMode()){
case LineLoop:
case LineStrip:
mesh.setMode(Mode.Lines);
break;
case TriangleStrip:
case TriangleFan:
mesh.setMode(Mode.Triangles);
break;
default:
break;
}
if (outBuf instanceof IndexIntBuffer){ if (outBuf instanceof IndexIntBuffer){
mesh.setBuffer(Type.Index, 3, (IntBuffer)outBuf.getBuffer()); mesh.setBuffer(Type.Index, 3, (IntBuffer)outBuf.getBuffer());
}else{ }else{

@ -46,6 +46,7 @@ import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh; import com.jme3.scene.Mesh;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.scene.UserData;
import com.jme3.terrain.geomipmap.TerrainPatch; import com.jme3.terrain.geomipmap.TerrainPatch;
import com.jme3.terrain.geomipmap.TerrainQuad; import com.jme3.terrain.geomipmap.TerrainQuad;
import java.util.Iterator; import java.util.Iterator;
@ -91,6 +92,11 @@ public class CollisionShapeFactory {
if (spatial instanceof Node) { if (spatial instanceof Node) {
createCompoundShape(realRootNode, (Node) spatial, shape, meshAccurate, dynamic); createCompoundShape(realRootNode, (Node) spatial, shape, meshAccurate, dynamic);
} else if (spatial instanceof Geometry) { } else if (spatial instanceof Geometry) {
Boolean bool = spatial.getUserData(UserData.JME_PHYSICSIGNORE);
if (bool != null && bool.booleanValue()){
continue; // go to the next child in the loop
}
if (meshAccurate) { if (meshAccurate) {
CollisionShape childShape = dynamic CollisionShape childShape = dynamic
? createSingleDynamicMeshShape((Geometry) spatial, realRootNode) ? createSingleDynamicMeshShape((Geometry) spatial, realRootNode)

@ -37,6 +37,7 @@ import com.jme3.math.FastMath;
import com.jme3.scene.mesh.IndexBuffer; import com.jme3.scene.mesh.IndexBuffer;
import com.jme3.scene.Mesh; import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer.Type; import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.mesh.WrappedIndexBuffer;
import com.jme3.util.BufferUtils; import com.jme3.util.BufferUtils;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
@ -224,12 +225,12 @@ public class Converter {
} }
public static IndexedMesh convert(Mesh mesh) { public static IndexedMesh convert(Mesh mesh) {
IndexedMesh jBulletIndexedMesh = new IndexedMesh(); IndexedMesh jBulletIndexedMesh = new IndexedMesh();
jBulletIndexedMesh.triangleIndexBase = ByteBuffer.allocate(mesh.getTriangleCount() * 3 * 4); jBulletIndexedMesh.triangleIndexBase = ByteBuffer.allocate(mesh.getTriangleCount() * 3 * 4);
jBulletIndexedMesh.vertexBase = ByteBuffer.allocate(mesh.getVertexCount() * 3 * 4); jBulletIndexedMesh.vertexBase = ByteBuffer.allocate(mesh.getVertexCount() * 3 * 4);
IndexBuffer indices = mesh.getIndexBuffer(); IndexBuffer indices = mesh.getIndicesAsList();
FloatBuffer vertices = mesh.getFloatBuffer(Type.Position); FloatBuffer vertices = mesh.getFloatBuffer(Type.Position);
vertices.rewind(); vertices.rewind();

@ -176,12 +176,7 @@ public class GeometryBatchFactory {
if (Type.Index.ordinal() == bufType) { if (Type.Index.ordinal() == bufType) {
int components = compsForBuf[bufType]; int components = compsForBuf[bufType];
IndexBuffer inIdx = inMesh.getIndexBuffer(); IndexBuffer inIdx = inMesh.getIndicesAsList();
if (inIdx == null) {
inIdx = new VirtualIndexBuffer(geomVertCount, inMesh.getMode());
} else if (inMesh.getMode() != mode) {
inIdx = new WrappedIndexBuffer(inMesh);
}
IndexBuffer outIdx = outMesh.getIndexBuffer(); IndexBuffer outIdx = outMesh.getIndexBuffer();
for (int tri = 0; tri < geomTriCount; tri++) { for (int tri = 0; tri < geomTriCount; tri++) {

Loading…
Cancel
Save