From 03da8d5316dc01f96489f290f88d24aa5a024aa1 Mon Sep 17 00:00:00 2001 From: "rem..om" Date: Sat, 18 Feb 2012 11:22:07 +0000 Subject: [PATCH] BatchNode enhancements : - batching after adding a new geometry only does an incremental batch instead of rebatching all geometries - there is now a getOffsetIndex(geometry) method that returns the index of the first vertex of the geometry in the batch. git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9176 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- engine/src/core/com/jme3/scene/BatchNode.java | 64 +++++++++++++------ engine/src/core/com/jme3/scene/Geometry.java | 4 +- 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/engine/src/core/com/jme3/scene/BatchNode.java b/engine/src/core/com/jme3/scene/BatchNode.java index 8a4986259..bc1b2cb50 100644 --- a/engine/src/core/com/jme3/scene/BatchNode.java +++ b/engine/src/core/com/jme3/scene/BatchNode.java @@ -80,6 +80,7 @@ public class BatchNode extends Node implements Savable { private float[] tmpFloatT; int maxVertCount = 0; boolean useTangents = false; + boolean needsFullRebatch = true; /** * Construct a batchNode @@ -178,16 +179,25 @@ public class BatchNode extends Node implements Savable { } protected void doBatch() { - ///List tmpList = new ArrayList(); Map> matMap = new HashMap>(); maxVertCount = 0; - gatherGeomerties(matMap, this); - batches.clear(); int nbGeoms = 0; + + gatherGeomerties(matMap, this, needsFullRebatch); + if (needsFullRebatch) { + for (Batch batch : batches.values()) { + batch.geometry.removeFromParent(); + } + batches.clear(); + } + for (Material material : matMap.keySet()) { Mesh m = new Mesh(); List list = matMap.get(material); nbGeoms += list.size(); + if (!needsFullRebatch) { + list.add(batches.get(material).geometry); + } mergeGeometries(m, list); m.setDynamic(); Batch batch = new Batch(); @@ -202,30 +212,36 @@ public class BatchNode extends Node implements Savable { batch.geometry.getMesh().updateBound(); batches.put(material, batch); } + + logger.log(Level.INFO, "Batched {0} geometries in {1} batches.", new Object[]{nbGeoms, batches.size()}); + + //init temp float arrays tmpFloat = new float[maxVertCount * 3]; tmpFloatN = new float[maxVertCount * 3]; if (useTangents) { tmpFloatT = new float[maxVertCount * 4]; } - logger.log(Level.INFO, "Batched {0} geometries in {1} batches.", new Object[]{nbGeoms, batches.size()}); } - private void gatherGeomerties(Map> map, Spatial n) { + private void gatherGeomerties(Map> map, Spatial n, boolean rebatch) { if (n.getClass() == Geometry.class) { if (!isBatch(n) && n.getBatchHint() != BatchHint.Never) { Geometry g = (Geometry) n; - if (g.getMaterial() == null) { - throw new IllegalStateException("No material is set for Geometry: " + g.getName() + " please set a material before batching"); - } - List list = map.get(g.getMaterial()); - if (list == null) { - list = new ArrayList(); - map.put(g.getMaterial(), list); + if (!g.isBatched() || rebatch) { + if (g.getMaterial() == null) { + throw new IllegalStateException("No material is set for Geometry: " + g.getName() + " please set a material before batching"); + } + List list = map.get(g.getMaterial()); + if (list == null) { + list = new ArrayList(); + map.put(g.getMaterial(), list); + } + g.setTransformRefresh(); + list.add(g); } - list.add(g); } } else if (n instanceof Node) { @@ -233,7 +249,7 @@ public class BatchNode extends Node implements Savable { if (child instanceof BatchNode) { continue; } - gatherGeomerties(map, child); + gatherGeomerties(map, child, rebatch); } } @@ -465,12 +481,12 @@ public class BatchNode extends Node implements Savable { } } else if (VertexBuffer.Type.Position.ordinal() == bufType) { FloatBuffer inPos = (FloatBuffer) inBuf.getData(); - FloatBuffer outPos = (FloatBuffer) outBuf.getData(); - doCopyBuffer(inPos, globalVertIndex, outPos,3); + FloatBuffer outPos = (FloatBuffer) outBuf.getData(); + doCopyBuffer(inPos, globalVertIndex, outPos, 3); } else if (VertexBuffer.Type.Normal.ordinal() == bufType || VertexBuffer.Type.Tangent.ordinal() == bufType) { FloatBuffer inPos = (FloatBuffer) inBuf.getData(); - FloatBuffer outPos = (FloatBuffer) outBuf.getData(); - doCopyBuffer(inPos, globalVertIndex, outPos,compsForBuf[bufType]); + FloatBuffer outPos = (FloatBuffer) outBuf.getData(); + doCopyBuffer(inPos, globalVertIndex, outPos, compsForBuf[bufType]); if (VertexBuffer.Type.Tangent.ordinal() == bufType) { useTangents = true; } @@ -584,9 +600,9 @@ public class BatchNode extends Node implements Savable { tmpFloatT[tanIndex++] = tan.x; tmpFloatT[tanIndex++] = tan.y; tmpFloatT[tanIndex++] = tan.z; - + //Skipping 4th element of tangent buffer (handedness) - tanIndex++; + tanIndex++; } vars.release(); @@ -626,4 +642,12 @@ public class BatchNode extends Node implements Savable { Geometry geometry; boolean needMeshUpdate = false; } + + protected void setNeedsFullRebatch(boolean needsFullRebatch) { + this.needsFullRebatch = needsFullRebatch; + } + + public int getOffsetIndex(Geometry batchedGeometry){ + return batchedGeometry.startIndex; + } } diff --git a/engine/src/core/com/jme3/scene/Geometry.java b/engine/src/core/com/jme3/scene/Geometry.java index e5de09c42..b02196da9 100644 --- a/engine/src/core/com/jme3/scene/Geometry.java +++ b/engine/src/core/com/jme3/scene/Geometry.java @@ -322,8 +322,8 @@ public class Geometry extends Spatial { this.startIndex = 0; prevBatchTransforms = null; cachedOffsetMat = null; - //once the geometry is removed from the screnegraph we call batch on the batchNode before unreferencing it. - this.batchNode.batch(); + //once the geometry is removed from the screnegraph the batchNode needs to be rebatched. + this.batchNode.setNeedsFullRebatch(true); this.batchNode = null; setCullHint(CullHint.Dynamic); }