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.
This commit is contained in:
parent
7ca599dfd9
commit
216f874175
@ -174,6 +174,7 @@ public class Mesh implements Savable, Cloneable {
|
|||||||
|
|
||||||
private int vertCount = -1;
|
private int vertCount = -1;
|
||||||
private int elementCount = -1;
|
private int elementCount = -1;
|
||||||
|
private int instanceCount = -1;
|
||||||
private int maxNumWeights = -1; // only if using skeletal animation
|
private int maxNumWeights = -1; // only if using skeletal animation
|
||||||
|
|
||||||
private int[] elementLengths;
|
private int[] elementLengths;
|
||||||
@ -242,6 +243,7 @@ public class Mesh implements Savable, Cloneable {
|
|||||||
clone.vertexArrayID = -1;
|
clone.vertexArrayID = -1;
|
||||||
clone.vertCount = vertCount;
|
clone.vertCount = vertCount;
|
||||||
clone.elementCount = elementCount;
|
clone.elementCount = elementCount;
|
||||||
|
clone.instanceCount = instanceCount;
|
||||||
|
|
||||||
// although this could change
|
// although this could change
|
||||||
// if the bone weight/index buffers are modified
|
// 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
|
* Update the {@link #getVertexCount() vertex} and
|
||||||
* {@link #getTriangleCount() triangle} counts for this mesh
|
* {@link #getTriangleCount() triangle} counts for this mesh
|
||||||
@ -742,6 +755,7 @@ public class Mesh implements Savable, Cloneable {
|
|||||||
}else{
|
}else{
|
||||||
elementCount = computeNumElements(vertCount);
|
elementCount = computeNumElements(vertCount);
|
||||||
}
|
}
|
||||||
|
instanceCount = computeInstanceCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -790,6 +804,14 @@ public class Mesh implements Savable, Cloneable {
|
|||||||
return vertCount;
|
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
|
* Gets the triangle vertex positions at the given triangle index
|
||||||
* and stores them into the v1, v2, v3 arguments.
|
* and stores them into the v1, v2, v3 arguments.
|
||||||
@ -1333,6 +1355,7 @@ public class Mesh implements Savable, Cloneable {
|
|||||||
out.write(meshBound, "modelBound", null);
|
out.write(meshBound, "modelBound", null);
|
||||||
out.write(vertCount, "vertCount", -1);
|
out.write(vertCount, "vertCount", -1);
|
||||||
out.write(elementCount, "elementCount", -1);
|
out.write(elementCount, "elementCount", -1);
|
||||||
|
out.write(instanceCount, "instanceCount", -1);
|
||||||
out.write(maxNumWeights, "max_num_weights", -1);
|
out.write(maxNumWeights, "max_num_weights", -1);
|
||||||
out.write(mode, "mode", Mode.Triangles);
|
out.write(mode, "mode", Mode.Triangles);
|
||||||
out.write(collisionTree, "collisionTree", null);
|
out.write(collisionTree, "collisionTree", null);
|
||||||
@ -1370,6 +1393,7 @@ public class Mesh implements Savable, Cloneable {
|
|||||||
meshBound = (BoundingVolume) in.readSavable("modelBound", null);
|
meshBound = (BoundingVolume) in.readSavable("modelBound", null);
|
||||||
vertCount = in.readInt("vertCount", -1);
|
vertCount = in.readInt("vertCount", -1);
|
||||||
elementCount = in.readInt("elementCount", -1);
|
elementCount = in.readInt("elementCount", -1);
|
||||||
|
instanceCount = in.readInt("instanceCount", -1);
|
||||||
maxNumWeights = in.readInt("max_num_weights", -1);
|
maxNumWeights = in.readInt("max_num_weights", -1);
|
||||||
mode = in.readEnum("mode", Mode.class, Mode.Triangles);
|
mode = in.readEnum("mode", Mode.class, Mode.Triangles);
|
||||||
elementLengths = in.readIntArray("elementLengths", null);
|
elementLengths = in.readIntArray("elementLengths", null);
|
||||||
|
@ -333,7 +333,7 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
|
|||||||
protected Type bufType;
|
protected Type bufType;
|
||||||
protected Format format;
|
protected Format format;
|
||||||
protected boolean normalized = false;
|
protected boolean normalized = false;
|
||||||
protected transient boolean instanced = false;
|
protected int instanceSpan = 0;
|
||||||
protected transient boolean dataSizeChanged = false;
|
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) {
|
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() {
|
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;
|
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
|
* Called to initialize the data in the <code>VertexBuffer</code>. Must only
|
||||||
* be called once.
|
* be called once.
|
||||||
@ -1009,7 +1048,7 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
|
|||||||
vb.handleRef = new Object();
|
vb.handleRef = new Object();
|
||||||
vb.id = -1;
|
vb.id = -1;
|
||||||
vb.normalized = normalized;
|
vb.normalized = normalized;
|
||||||
vb.instanced = instanced;
|
vb.instanceSpan = instanceSpan;
|
||||||
vb.offset = offset;
|
vb.offset = offset;
|
||||||
vb.stride = stride;
|
vb.stride = stride;
|
||||||
vb.updateNeeded = true;
|
vb.updateNeeded = true;
|
||||||
@ -1060,9 +1099,6 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(JmeExporter ex) throws IOException {
|
public void write(JmeExporter ex) throws IOException {
|
||||||
if (instanced) {
|
|
||||||
throw new IOException("Serialization of instanced data not allowed");
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputCapsule oc = ex.getCapsule(this);
|
OutputCapsule oc = ex.getCapsule(this);
|
||||||
oc.write(components, "components", 0);
|
oc.write(components, "components", 0);
|
||||||
@ -1072,6 +1108,7 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
|
|||||||
oc.write(normalized, "normalized", false);
|
oc.write(normalized, "normalized", false);
|
||||||
oc.write(offset, "offset", 0);
|
oc.write(offset, "offset", 0);
|
||||||
oc.write(stride, "stride", 0);
|
oc.write(stride, "stride", 0);
|
||||||
|
oc.write(instanceSpan, "instanceSpan", 0);
|
||||||
|
|
||||||
String dataName = "data" + format.name();
|
String dataName = "data" + format.name();
|
||||||
Buffer roData = getDataReadOnly();
|
Buffer roData = getDataReadOnly();
|
||||||
@ -1107,6 +1144,7 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
|
|||||||
normalized = ic.readBoolean("normalized", false);
|
normalized = ic.readBoolean("normalized", false);
|
||||||
offset = ic.readInt("offset", 0);
|
offset = ic.readInt("offset", 0);
|
||||||
stride = ic.readInt("stride", 0);
|
stride = ic.readInt("stride", 0);
|
||||||
|
instanceSpan = ic.readInt("instanceSpan", 0);
|
||||||
componentsLength = components * format.getComponentSize();
|
componentsLength = components * format.getComponentSize();
|
||||||
|
|
||||||
String dataName = "data" + format.name();
|
String dataName = "data" + format.name();
|
||||||
|
@ -2294,7 +2294,7 @@ public class LwjglRenderer implements Renderer {
|
|||||||
int slot = loc + i;
|
int slot = loc + i;
|
||||||
if (vb.isInstanced() && (attribs[slot] == null || !attribs[slot].isInstanced())) {
|
if (vb.isInstanced() && (attribs[slot] == null || !attribs[slot].isInstanced())) {
|
||||||
// non-instanced -> instanced
|
// non-instanced -> instanced
|
||||||
glVertexAttribDivisorARB(slot, 1);
|
glVertexAttribDivisorARB(slot, vb.getInstanceSpan());
|
||||||
} else if (!vb.isInstanced() && attribs[slot] != null && attribs[slot].isInstanced()) {
|
} else if (!vb.isInstanced() && attribs[slot] != null && attribs[slot].isInstanced()) {
|
||||||
// instanced -> non-instanced
|
// instanced -> non-instanced
|
||||||
glVertexAttribDivisorARB(slot, 0);
|
glVertexAttribDivisorARB(slot, 0);
|
||||||
@ -2491,6 +2491,11 @@ public class LwjglRenderer implements Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void renderMeshDefault(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) {
|
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);
|
VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData);
|
||||||
if (interleavedData != null && interleavedData.isUpdateNeeded()) {
|
if (interleavedData != null && interleavedData.isUpdateNeeded()) {
|
||||||
updateBufferData(interleavedData);
|
updateBufferData(interleavedData);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user