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
This commit is contained in:
parent
9b8060bac2
commit
4c4e235e61
@ -139,28 +139,37 @@ public class BatchNode extends Node implements Savable {
|
|||||||
assert refreshFlags == 0;
|
assert refreshFlags == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Transform getTransforms(Geometry geom) {
|
protected Matrix4f getTransformMatrix(Geometry g){
|
||||||
return geom.getWorldTransform();
|
return g.cachedWorldMat;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateSubBatch(Geometry bg) {
|
protected void updateSubBatch(Geometry bg) {
|
||||||
Batch batch = batchesByGeom.get(bg);
|
Batch batch = batchesByGeom.get(bg);
|
||||||
if (batch != null) {
|
if (batch != null) {
|
||||||
Mesh mesh = batch.geometry.getMesh();
|
Mesh mesh = batch.geometry.getMesh();
|
||||||
|
Mesh origMesh = bg.getMesh();
|
||||||
|
|
||||||
VertexBuffer pvb = mesh.getBuffer(VertexBuffer.Type.Position);
|
VertexBuffer pvb = mesh.getBuffer(VertexBuffer.Type.Position);
|
||||||
FloatBuffer posBuf = (FloatBuffer) pvb.getData();
|
FloatBuffer posBuf = (FloatBuffer) pvb.getData();
|
||||||
VertexBuffer nvb = mesh.getBuffer(VertexBuffer.Type.Normal);
|
VertexBuffer nvb = mesh.getBuffer(VertexBuffer.Type.Normal);
|
||||||
FloatBuffer normBuf = (FloatBuffer) nvb.getData();
|
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) {
|
if (mesh.getBuffer(VertexBuffer.Type.Tangent) != null) {
|
||||||
|
|
||||||
VertexBuffer tvb = mesh.getBuffer(VertexBuffer.Type.Tangent);
|
VertexBuffer tvb = mesh.getBuffer(VertexBuffer.Type.Tangent);
|
||||||
FloatBuffer tanBuf = (FloatBuffer) tvb.getData();
|
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);
|
tvb.updateData(tanBuf);
|
||||||
} else {
|
} 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);
|
pvb.updateData(posBuf);
|
||||||
nvb.updateData(normBuf);
|
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();
|
TempVars vars = TempVars.get();
|
||||||
Vector3f pos = vars.vect1;
|
Vector3f pos = vars.vect1;
|
||||||
Vector3f norm = vars.vect2;
|
Vector3f norm = vars.vect2;
|
||||||
@ -595,10 +604,12 @@ public class BatchNode extends Node implements Savable {
|
|||||||
// offset is given in element units
|
// offset is given in element units
|
||||||
// convert to be in component units
|
// convert to be in component units
|
||||||
int offset = start * 3;
|
int offset = start * 3;
|
||||||
bufPos.position(offset);
|
bindBufPos.rewind();
|
||||||
bufNorm.position(offset);
|
bindBufNorm.rewind();
|
||||||
bufPos.get(tmpFloat, 0, length);
|
//bufPos.position(offset);
|
||||||
bufNorm.get(tmpFloatN, 0, length);
|
//bufNorm.position(offset);
|
||||||
|
bindBufPos.get(tmpFloat, 0, length);
|
||||||
|
bindBufNorm.get(tmpFloatN, 0, length);
|
||||||
int index = 0;
|
int index = 0;
|
||||||
while (index < length) {
|
while (index < length) {
|
||||||
pos.x = tmpFloat[index];
|
pos.x = tmpFloat[index];
|
||||||
@ -629,7 +640,7 @@ public class BatchNode extends Node implements Savable {
|
|||||||
bufNorm.put(tmpFloatN, 0, length);
|
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();
|
TempVars vars = TempVars.get();
|
||||||
Vector3f pos = vars.vect1;
|
Vector3f pos = vars.vect1;
|
||||||
Vector3f norm = vars.vect2;
|
Vector3f norm = vars.vect2;
|
||||||
@ -643,12 +654,13 @@ public class BatchNode extends Node implements Savable {
|
|||||||
int offset = start * 3;
|
int offset = start * 3;
|
||||||
int tanOffset = start * 4;
|
int tanOffset = start * 4;
|
||||||
|
|
||||||
bufPos.position(offset);
|
|
||||||
bufNorm.position(offset);
|
bindBufPos.rewind();
|
||||||
bufTangents.position(tanOffset);
|
bindBufNorm.rewind();
|
||||||
bufPos.get(tmpFloat, 0, length);
|
bindBufTangents.rewind();
|
||||||
bufNorm.get(tmpFloatN, 0, length);
|
bindBufPos.get(tmpFloat, 0, length);
|
||||||
bufTangents.get(tmpFloatT, 0, tanLength);
|
bindBufNorm.get(tmpFloatN, 0, length);
|
||||||
|
bindBufTangents.get(tmpFloatT, 0, tanLength);
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int tanIndex = 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
|
* the start index of this geom's mesh in the batchNode mesh
|
||||||
*/
|
*/
|
||||||
protected int startIndex;
|
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.
|
* Serialization only. Do not use.
|
||||||
*/
|
*/
|
||||||
@ -292,10 +283,7 @@ public class Geometry extends Spatial {
|
|||||||
computeWorldMatrix();
|
computeWorldMatrix();
|
||||||
|
|
||||||
if (isBatched()) {
|
if (isBatched()) {
|
||||||
computeOffsetTransform();
|
|
||||||
batchNode.updateSubBatch(this);
|
batchNode.updateSubBatch(this);
|
||||||
prevBatchTransforms.set(batchNode.getTransforms(this));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// geometry requires lights to be sorted
|
// geometry requires lights to be sorted
|
||||||
worldLights.sort(true);
|
worldLights.sort(true);
|
||||||
@ -309,8 +297,6 @@ public class Geometry extends Spatial {
|
|||||||
protected void batch(BatchNode node, int startIndex) {
|
protected void batch(BatchNode node, int startIndex) {
|
||||||
this.batchNode = node;
|
this.batchNode = node;
|
||||||
this.startIndex = startIndex;
|
this.startIndex = startIndex;
|
||||||
prevBatchTransforms = new Transform();
|
|
||||||
cachedOffsetMat = new Matrix4f();
|
|
||||||
setCullHint(CullHint.Always);
|
setCullHint(CullHint.Always);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,8 +305,6 @@ public class Geometry extends Spatial {
|
|||||||
*/
|
*/
|
||||||
protected void unBatch() {
|
protected void unBatch() {
|
||||||
this.startIndex = 0;
|
this.startIndex = 0;
|
||||||
prevBatchTransforms = null;
|
|
||||||
cachedOffsetMat = null;
|
|
||||||
//once the geometry is removed from the screnegraph the batchNode needs to be rebatched.
|
//once the geometry is removed from the screnegraph the batchNode needs to be rebatched.
|
||||||
if (batchNode != null) {
|
if (batchNode != null) {
|
||||||
this.batchNode.setNeedsFullRebatch(true);
|
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
|
* Indicate that the transform of this spatial has changed and that
|
||||||
|
@ -31,7 +31,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.scene;
|
package com.jme3.scene;
|
||||||
|
|
||||||
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.math.Transform;
|
import com.jme3.math.Transform;
|
||||||
|
import com.jme3.util.TempVars;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -70,11 +72,25 @@ public class SimpleBatchNode extends BatchNode {
|
|||||||
batch.geometry.setTransformRefresh();
|
batch.geometry.setTransformRefresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private Matrix4f cachedLocalMat = new Matrix4f();
|
||||||
|
|
||||||
protected Transform getTransforms(Geometry geom){
|
@Override
|
||||||
return geom.getLocalTransform();
|
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
|
@Override
|
||||||
public void batch() {
|
public void batch() {
|
||||||
doBatch();
|
doBatch();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user