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