瀏覽代碼

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.

pspeed42 11 年之前
父節點
當前提交
216f874175

+ 25 - 1
jme3-core/src/main/java/com/jme3/scene/Mesh.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);

+ 46 - 8
jme3-core/src/main/java/com/jme3/scene/VertexBuffer.java

@@ -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();

+ 6 - 1
jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java

@@ -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);