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
3.0
rem..om 12 years ago
parent 9b8060bac2
commit 4c4e235e61
  1. 44
      engine/src/core/com/jme3/scene/BatchNode.java
  2. 46
      engine/src/core/com/jme3/scene/Geometry.java
  3. 20
      engine/src/core/com/jme3/scene/SimpleBatchNode.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;

@ -79,15 +79,6 @@ 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;
/**
* Serialization only. Do not use.
*/
@ -292,10 +283,7 @@ public class Geometry extends Spatial {
computeWorldMatrix();
if (isBatched()) {
computeOffsetTransform();
batchNode.updateSubBatch(this);
prevBatchTransforms.set(batchNode.getTransforms(this));
}
// geometry requires lights to be sorted
worldLights.sort(true);
@ -309,8 +297,6 @@ public class Geometry extends Spatial {
protected void batch(BatchNode node, int startIndex) {
this.batchNode = node;
this.startIndex = startIndex;
prevBatchTransforms = new Transform();
cachedOffsetMat = new Matrix4f();
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

@ -31,7 +31,9 @@
*/
package com.jme3.scene;
import com.jme3.math.Matrix4f;
import com.jme3.math.Transform;
import com.jme3.util.TempVars;
/**
*
@ -70,11 +72,25 @@ public class SimpleBatchNode extends BatchNode {
batch.geometry.setTransformRefresh();
}
}
private Matrix4f cachedLocalMat = new Matrix4f();
protected Transform getTransforms(Geometry geom){
return geom.getLocalTransform();
@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() {
doBatch();

Loading…
Cancel
Save