Added support for instancing at the mesh level.

(so far only for lwjgl because I'm lazy)
Went ahead and added in divisor support while I was
at it because it doesn't cost anything and there might
be use-cases for it.
Mesh now knows about instances and you can directly
ask it for an instance count.  I haven't added support
for proper bounding box calculation but it should
at least be possible now.
experimental
pspeed42 11 years ago
parent 7ca599dfd9
commit 216f874175
  1. 26
      jme3-core/src/main/java/com/jme3/scene/Mesh.java
  2. 54
      jme3-core/src/main/java/com/jme3/scene/VertexBuffer.java
  3. 7
      jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java

@ -174,6 +174,7 @@ public class Mesh implements Savable, Cloneable {
private int vertCount = -1;
private int elementCount = -1;
private int instanceCount = -1;
private int maxNumWeights = -1; // only if using skeletal animation
private int[] elementLengths;
@ -242,6 +243,7 @@ public class Mesh implements Savable, Cloneable {
clone.vertexArrayID = -1;
clone.vertCount = vertCount;
clone.elementCount = elementCount;
clone.instanceCount = instanceCount;
// although this could change
// if the bone weight/index buffers are modified
@ -718,6 +720,17 @@ public class Mesh implements Savable, Cloneable {
}
}
private int computeInstanceCount() {
// Whatever the max of the base instance counts
int max = 0;
for( VertexBuffer vb : buffersList ) {
if( vb.getBaseInstanceCount() > max ) {
max = vb.getBaseInstanceCount();
}
}
return max;
}
/**
* Update the {@link #getVertexCount() vertex} and
* {@link #getTriangleCount() triangle} counts for this mesh
@ -741,7 +754,8 @@ public class Mesh implements Savable, Cloneable {
elementCount = computeNumElements(ib.getData().limit());
}else{
elementCount = computeNumElements(vertCount);
}
}
instanceCount = computeInstanceCount();
}
/**
@ -789,6 +803,14 @@ public class Mesh implements Savable, Cloneable {
public int getVertexCount(){
return vertCount;
}
/**
* Returns the number of instances this mesh contains. The instance
* count is based on any VertexBuffers with instancing set.
*/
public int getInstanceCount() {
return instanceCount;
}
/**
* Gets the triangle vertex positions at the given triangle index
@ -1333,6 +1355,7 @@ public class Mesh implements Savable, Cloneable {
out.write(meshBound, "modelBound", null);
out.write(vertCount, "vertCount", -1);
out.write(elementCount, "elementCount", -1);
out.write(instanceCount, "instanceCount", -1);
out.write(maxNumWeights, "max_num_weights", -1);
out.write(mode, "mode", Mode.Triangles);
out.write(collisionTree, "collisionTree", null);
@ -1370,6 +1393,7 @@ public class Mesh implements Savable, Cloneable {
meshBound = (BoundingVolume) in.readSavable("modelBound", null);
vertCount = in.readInt("vertCount", -1);
elementCount = in.readInt("elementCount", -1);
instanceCount = in.readInt("instanceCount", -1);
maxNumWeights = in.readInt("max_num_weights", -1);
mode = in.readEnum("mode", Mode.class, Mode.Triangles);
elementLengths = in.readIntArray("elementLengths", null);

@ -333,7 +333,7 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
protected Type bufType;
protected Format format;
protected boolean normalized = false;
protected transient boolean instanced = false;
protected int instanceSpan = 0;
protected transient boolean dataSizeChanged = false;
/**
@ -545,14 +545,39 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
}
/**
* TODO:
* Sets the instanceSpan to 1 or 0 depending on
* the value of instanced and the existing value of
* instanceSpan.
*/
public void setInstanced(boolean instanced) {
this.instanced = instanced;
if( instanced && instanceSpan == 0 ) {
instanceSpan = 1;
} else if( !instanced ) {
instanceSpan = 0;
}
}
/**
* Returns true if instanceSpan is more than 0 indicating
* that this vertex buffer contains per-instance data.
*/
public boolean isInstanced() {
return instanced;
return instanceSpan > 0;
}
/**
* Sets how this vertex buffer matches with rendered instances
* where 0 means no instancing at all, ie: all elements are
* per vertex. If set to 1 then each element goes with one
* instance. If set to 2 then each element goes with two
* instances and so on.
*/
public void setInstanceSpan(int i) {
this.instanceSpan = i;
}
public int getInstanceSpan() {
return instanceSpan;
}
/**
@ -587,6 +612,20 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
return elements;
}
/**
* Returns the number of 'instances' in this VertexBuffer. This
* is dependent on the current instanceSpan. When instanceSpan
* is 0 then 'instances' is 1. Otherwise, instances is elements *
* instanceSpan. It is possible to render a mesh with more instances
* but the instance data begins to repeat.
*/
public int getBaseInstanceCount() {
if( instanceSpan == 0 ) {
return 1;
}
return getNumElements() * instanceSpan;
}
/**
* Called to initialize the data in the <code>VertexBuffer</code>. Must only
* be called once.
@ -1009,7 +1048,7 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
vb.handleRef = new Object();
vb.id = -1;
vb.normalized = normalized;
vb.instanced = instanced;
vb.instanceSpan = instanceSpan;
vb.offset = offset;
vb.stride = stride;
vb.updateNeeded = true;
@ -1060,9 +1099,6 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
@Override
public void write(JmeExporter ex) throws IOException {
if (instanced) {
throw new IOException("Serialization of instanced data not allowed");
}
OutputCapsule oc = ex.getCapsule(this);
oc.write(components, "components", 0);
@ -1072,6 +1108,7 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
oc.write(normalized, "normalized", false);
oc.write(offset, "offset", 0);
oc.write(stride, "stride", 0);
oc.write(instanceSpan, "instanceSpan", 0);
String dataName = "data" + format.name();
Buffer roData = getDataReadOnly();
@ -1107,6 +1144,7 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
normalized = ic.readBoolean("normalized", false);
offset = ic.readInt("offset", 0);
stride = ic.readInt("stride", 0);
instanceSpan = ic.readInt("instanceSpan", 0);
componentsLength = components * format.getComponentSize();
String dataName = "data" + format.name();

@ -2294,7 +2294,7 @@ public class LwjglRenderer implements Renderer {
int slot = loc + i;
if (vb.isInstanced() && (attribs[slot] == null || !attribs[slot].isInstanced())) {
// non-instanced -> instanced
glVertexAttribDivisorARB(slot, 1);
glVertexAttribDivisorARB(slot, vb.getInstanceSpan());
} else if (!vb.isInstanced() && attribs[slot] != null && attribs[slot].isInstanced()) {
// instanced -> non-instanced
glVertexAttribDivisorARB(slot, 0);
@ -2491,6 +2491,11 @@ public class LwjglRenderer implements Renderer {
}
private void renderMeshDefault(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) {
// Here while count is still passed in. Can be removed when/if
// the method is collapsed again. -pspeed
count = Math.max(mesh.getInstanceCount(), count);
VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData);
if (interleavedData != null && interleavedData.isUpdateNeeded()) {
updateBufferData(interleavedData);

Loading…
Cancel
Save