瀏覽代碼

BatchNode now uses absolute world transforsm to update the underlying batch mesh, instead of computing the offset from next frame.
The real geometry mesh data is now used as a bind pose.
This avoids errors accumulations over time in some case and is less expensive.
See this post for the original issue http://hub.jmonkeyengine.org/forum/topic/batchnode-bug/

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10647 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

rem..om 12 年之前
父節點
當前提交
4c4e235e61

+ 30 - 18
engine/src/core/com/jme3/scene/BatchNode.java

@@ -139,28 +139,37 @@ public class BatchNode extends Node implements Savable {
         assert refreshFlags == 0;
     }
 
-    protected Transform getTransforms(Geometry geom) {
-        return geom.getWorldTransform();
+    protected Matrix4f getTransformMatrix(Geometry g){
+        return g.cachedWorldMat;
     }
-
+    
     protected void updateSubBatch(Geometry bg) {
         Batch batch = batchesByGeom.get(bg);
         if (batch != null) {
             Mesh mesh = batch.geometry.getMesh();
+            Mesh origMesh = bg.getMesh();
 
             VertexBuffer pvb = mesh.getBuffer(VertexBuffer.Type.Position);
             FloatBuffer posBuf = (FloatBuffer) pvb.getData();
             VertexBuffer nvb = mesh.getBuffer(VertexBuffer.Type.Normal);
             FloatBuffer normBuf = (FloatBuffer) nvb.getData();
-
+          
+            VertexBuffer opvb = origMesh.getBuffer(VertexBuffer.Type.Position);
+            FloatBuffer oposBuf = (FloatBuffer) opvb.getData();
+            VertexBuffer onvb = origMesh.getBuffer(VertexBuffer.Type.Normal);
+            FloatBuffer onormBuf = (FloatBuffer) onvb.getData();
+            Matrix4f transformMat = getTransformMatrix(bg);
+            
             if (mesh.getBuffer(VertexBuffer.Type.Tangent) != null) {
 
                 VertexBuffer tvb = mesh.getBuffer(VertexBuffer.Type.Tangent);
                 FloatBuffer tanBuf = (FloatBuffer) tvb.getData();
-                doTransformsTangents(posBuf, normBuf, tanBuf, bg.startIndex, bg.startIndex + bg.getVertexCount(), bg.cachedOffsetMat);
+                VertexBuffer otvb = origMesh.getBuffer(VertexBuffer.Type.Tangent);
+                FloatBuffer otanBuf = (FloatBuffer) otvb.getData();
+                doTransformsTangents(oposBuf, onormBuf, otanBuf, posBuf, normBuf, tanBuf, bg.startIndex, bg.startIndex + bg.getVertexCount(), transformMat);
                 tvb.updateData(tanBuf);
             } else {
-                doTransforms(posBuf, normBuf, bg.startIndex, bg.startIndex + bg.getVertexCount(), bg.cachedOffsetMat);
+                doTransforms(oposBuf, onormBuf, posBuf, normBuf, bg.startIndex, bg.startIndex + bg.getVertexCount(), transformMat);
             }
             pvb.updateData(posBuf);
             nvb.updateData(normBuf);
@@ -585,7 +594,7 @@ public class BatchNode extends Node implements Savable {
         }
     }
 
-    private void doTransforms(FloatBuffer bufPos, FloatBuffer bufNorm, int start, int end, Matrix4f transform) {
+    private void doTransforms(FloatBuffer bindBufPos, FloatBuffer bindBufNorm, FloatBuffer bufPos, FloatBuffer bufNorm, int start, int end, Matrix4f transform) {
         TempVars vars = TempVars.get();
         Vector3f pos = vars.vect1;
         Vector3f norm = vars.vect2;
@@ -595,10 +604,12 @@ public class BatchNode extends Node implements Savable {
         // offset is given in element units
         // convert to be in component units
         int offset = start * 3;
-        bufPos.position(offset);
-        bufNorm.position(offset);
-        bufPos.get(tmpFloat, 0, length);
-        bufNorm.get(tmpFloatN, 0, length);
+        bindBufPos.rewind();
+        bindBufNorm.rewind();
+        //bufPos.position(offset);
+        //bufNorm.position(offset);
+        bindBufPos.get(tmpFloat, 0, length);
+        bindBufNorm.get(tmpFloatN, 0, length);
         int index = 0;
         while (index < length) {
             pos.x = tmpFloat[index];
@@ -629,7 +640,7 @@ public class BatchNode extends Node implements Savable {
         bufNorm.put(tmpFloatN, 0, length);
     }
 
-    private void doTransformsTangents(FloatBuffer bufPos, FloatBuffer bufNorm, FloatBuffer bufTangents, int start, int end, Matrix4f transform) {
+    private void doTransformsTangents(FloatBuffer bindBufPos, FloatBuffer bindBufNorm, FloatBuffer bindBufTangents,FloatBuffer bufPos, FloatBuffer bufNorm, FloatBuffer bufTangents, int start, int end, Matrix4f transform) {
         TempVars vars = TempVars.get();
         Vector3f pos = vars.vect1;
         Vector3f norm = vars.vect2;
@@ -643,12 +654,13 @@ public class BatchNode extends Node implements Savable {
         int offset = start * 3;
         int tanOffset = start * 4;
 
-        bufPos.position(offset);
-        bufNorm.position(offset);
-        bufTangents.position(tanOffset);
-        bufPos.get(tmpFloat, 0, length);
-        bufNorm.get(tmpFloatN, 0, length);
-        bufTangents.get(tmpFloatT, 0, tanLength);
+        
+        bindBufPos.rewind();
+        bindBufNorm.rewind();
+        bindBufTangents.rewind();
+        bindBufPos.get(tmpFloat, 0, length);
+        bindBufNorm.get(tmpFloatN, 0, length);
+        bindBufTangents.get(tmpFloatT, 0, tanLength);
 
         int index = 0;
         int tanIndex = 0;

+ 4 - 50
engine/src/core/com/jme3/scene/Geometry.java

@@ -78,16 +78,7 @@ public class Geometry extends Spatial {
     /**
      * the start index of this geom's mesh in the batchNode mesh
      */
-    protected int startIndex;
-    /**
-     * the previous transforms of the geometry used to compute world transforms
-     */
-    protected Transform prevBatchTransforms = null;
-    /**
-     * the cached offset matrix used when the geometry is batched
-     */
-    protected Matrix4f cachedOffsetMat = null;
-
+    protected int startIndex;    
     /**
      * Serialization only. Do not use.
      */
@@ -291,11 +282,8 @@ public class Geometry extends Spatial {
         super.updateWorldTransforms();
         computeWorldMatrix();
 
-        if (isBatched()) {
-            computeOffsetTransform();
-            batchNode.updateSubBatch(this);
-            prevBatchTransforms.set(batchNode.getTransforms(this));
-
+        if (isBatched()) {        
+            batchNode.updateSubBatch(this);     
         }
         // geometry requires lights to be sorted
         worldLights.sort(true);
@@ -308,9 +296,7 @@ public class Geometry extends Spatial {
      */
     protected void batch(BatchNode node, int startIndex) {
         this.batchNode = node;
-        this.startIndex = startIndex;
-        prevBatchTransforms = new Transform();
-        cachedOffsetMat = new Matrix4f();
+        this.startIndex = startIndex;       
         setCullHint(CullHint.Always);
     }
 
@@ -319,8 +305,6 @@ public class Geometry extends Spatial {
      */
     protected void unBatch() {
         this.startIndex = 0;
-        prevBatchTransforms = null;
-        cachedOffsetMat = null;
         //once the geometry is removed from the screnegraph the batchNode needs to be rebatched.
         if (batchNode != null) {
             this.batchNode.setNeedsFullRebatch(true);
@@ -343,36 +327,6 @@ public class Geometry extends Spatial {
         }
     }
 
-    /**
-     * Recomputes the cached offset matrix used when the geometry is batched     * 
-     */
-    public void computeOffsetTransform() {
-        TempVars vars = TempVars.get();
-        Matrix4f tmpMat = vars.tempMat42;
-
-        // Compute the cached world matrix
-        cachedOffsetMat.loadIdentity();
-        cachedOffsetMat.setRotationQuaternion(prevBatchTransforms.getRotation());
-        cachedOffsetMat.setTranslation(prevBatchTransforms.getTranslation());
-
-
-        Matrix4f scaleMat = vars.tempMat4;
-        scaleMat.loadIdentity();
-        scaleMat.scale(prevBatchTransforms.getScale());
-        cachedOffsetMat.multLocal(scaleMat);
-        cachedOffsetMat.invertLocal();
-
-        tmpMat.loadIdentity();
-        tmpMat.setRotationQuaternion(batchNode.getTransforms(this).getRotation());
-        tmpMat.setTranslation(batchNode.getTransforms(this).getTranslation());
-        scaleMat.loadIdentity();
-        scaleMat.scale(batchNode.getTransforms(this).getScale());
-        tmpMat.multLocal(scaleMat);
-
-        tmpMat.mult(cachedOffsetMat, cachedOffsetMat);
-
-        vars.release();
-    }
 
     /**
      * Indicate that the transform of this spatial has changed and that

+ 19 - 3
engine/src/core/com/jme3/scene/SimpleBatchNode.java

@@ -31,7 +31,9 @@
  */
 package com.jme3.scene;
 
+import com.jme3.math.Matrix4f;
 import com.jme3.math.Transform;
+import com.jme3.util.TempVars;
 
 /**
  * 
@@ -70,10 +72,24 @@ public class SimpleBatchNode extends BatchNode {
             batch.geometry.setTransformRefresh();
         }
     }
-    
-     protected Transform getTransforms(Geometry geom){
-        return geom.getLocalTransform();
+    private Matrix4f cachedLocalMat = new Matrix4f();
+
+    @Override
+    protected Matrix4f getTransformMatrix(Geometry g){
+        // Compute the Local matrix for the geometry
+        cachedLocalMat.loadIdentity();
+        cachedLocalMat.setRotationQuaternion(g.localTransform.getRotation());
+        cachedLocalMat.setTranslation(g.localTransform.getTranslation());
+
+        TempVars vars = TempVars.get();
+        Matrix4f scaleMat = vars.tempMat4;
+        scaleMat.loadIdentity();
+        scaleMat.scale(g.localTransform.getScale());
+        cachedLocalMat.multLocal(scaleMat);
+        vars.release();
+        return cachedLocalMat;
     }
+    
 
     @Override
     public void batch() {