From 4c4e235e6199cee47323eca525de7357d07340a9 Mon Sep 17 00:00:00 2001 From: "rem..om" Date: Sun, 9 Jun 2013 16:06:56 +0000 Subject: [PATCH] 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 --- engine/src/core/com/jme3/scene/BatchNode.java | 48 ++++++++++------- engine/src/core/com/jme3/scene/Geometry.java | 54 ++----------------- .../core/com/jme3/scene/SimpleBatchNode.java | 22 ++++++-- 3 files changed, 53 insertions(+), 71 deletions(-) diff --git a/engine/src/core/com/jme3/scene/BatchNode.java b/engine/src/core/com/jme3/scene/BatchNode.java index 2d8a20a02..656c8f8c2 100644 --- a/engine/src/core/com/jme3/scene/BatchNode.java +++ b/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; diff --git a/engine/src/core/com/jme3/scene/Geometry.java b/engine/src/core/com/jme3/scene/Geometry.java index 8953a26bb..7c381c15e 100644 --- a/engine/src/core/com/jme3/scene/Geometry.java +++ b/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 diff --git a/engine/src/core/com/jme3/scene/SimpleBatchNode.java b/engine/src/core/com/jme3/scene/SimpleBatchNode.java index ad2b31396..2c5a1773f 100644 --- a/engine/src/core/com/jme3/scene/SimpleBatchNode.java +++ b/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() {