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
3.0
rem..om 13 years ago
parent 446c03935e
commit 03da8d5316
  1. 36
      engine/src/core/com/jme3/scene/BatchNode.java
  2. 4
      engine/src/core/com/jme3/scene/Geometry.java

@ -80,6 +80,7 @@ public class BatchNode extends Node implements Savable {
private float[] tmpFloatT; private float[] tmpFloatT;
int maxVertCount = 0; int maxVertCount = 0;
boolean useTangents = false; boolean useTangents = false;
boolean needsFullRebatch = true;
/** /**
* Construct a batchNode * Construct a batchNode
@ -178,16 +179,25 @@ public class BatchNode extends Node implements Savable {
} }
protected void doBatch() { protected void doBatch() {
///List<Geometry> tmpList = new ArrayList<Geometry>();
Map<Material, List<Geometry>> matMap = new HashMap<Material, List<Geometry>>(); Map<Material, List<Geometry>> matMap = new HashMap<Material, List<Geometry>>();
maxVertCount = 0; maxVertCount = 0;
gatherGeomerties(matMap, this);
batches.clear();
int nbGeoms = 0; int nbGeoms = 0;
gatherGeomerties(matMap, this, needsFullRebatch);
if (needsFullRebatch) {
for (Batch batch : batches.values()) {
batch.geometry.removeFromParent();
}
batches.clear();
}
for (Material material : matMap.keySet()) { for (Material material : matMap.keySet()) {
Mesh m = new Mesh(); Mesh m = new Mesh();
List<Geometry> list = matMap.get(material); List<Geometry> list = matMap.get(material);
nbGeoms += list.size(); nbGeoms += list.size();
if (!needsFullRebatch) {
list.add(batches.get(material).geometry);
}
mergeGeometries(m, list); mergeGeometries(m, list);
m.setDynamic(); m.setDynamic();
Batch batch = new Batch(); Batch batch = new Batch();
@ -202,21 +212,25 @@ public class BatchNode extends Node implements Savable {
batch.geometry.getMesh().updateBound(); batch.geometry.getMesh().updateBound();
batches.put(material, batch); batches.put(material, batch);
} }
logger.log(Level.INFO, "Batched {0} geometries in {1} batches.", new Object[]{nbGeoms, batches.size()});
//init temp float arrays //init temp float arrays
tmpFloat = new float[maxVertCount * 3]; tmpFloat = new float[maxVertCount * 3];
tmpFloatN = new float[maxVertCount * 3]; tmpFloatN = new float[maxVertCount * 3];
if (useTangents) { if (useTangents) {
tmpFloatT = new float[maxVertCount * 4]; tmpFloatT = new float[maxVertCount * 4];
} }
logger.log(Level.INFO, "Batched {0} geometries in {1} batches.", new Object[]{nbGeoms, batches.size()});
} }
private void gatherGeomerties(Map<Material, List<Geometry>> map, Spatial n) { private void gatherGeomerties(Map<Material, List<Geometry>> map, Spatial n, boolean rebatch) {
if (n.getClass() == Geometry.class) { if (n.getClass() == Geometry.class) {
if (!isBatch(n) && n.getBatchHint() != BatchHint.Never) { if (!isBatch(n) && n.getBatchHint() != BatchHint.Never) {
Geometry g = (Geometry) n; Geometry g = (Geometry) n;
if (!g.isBatched() || rebatch) {
if (g.getMaterial() == null) { if (g.getMaterial() == null) {
throw new IllegalStateException("No material is set for Geometry: " + g.getName() + " please set a material before batching"); throw new IllegalStateException("No material is set for Geometry: " + g.getName() + " please set a material before batching");
} }
@ -225,15 +239,17 @@ public class BatchNode extends Node implements Savable {
list = new ArrayList<Geometry>(); list = new ArrayList<Geometry>();
map.put(g.getMaterial(), list); map.put(g.getMaterial(), list);
} }
g.setTransformRefresh();
list.add(g); list.add(g);
} }
}
} else if (n instanceof Node) { } else if (n instanceof Node) {
for (Spatial child : ((Node) n).getChildren()) { for (Spatial child : ((Node) n).getChildren()) {
if (child instanceof BatchNode) { if (child instanceof BatchNode) {
continue; continue;
} }
gatherGeomerties(map, child); gatherGeomerties(map, child, rebatch);
} }
} }
@ -626,4 +642,12 @@ public class BatchNode extends Node implements Savable {
Geometry geometry; Geometry geometry;
boolean needMeshUpdate = false; boolean needMeshUpdate = false;
} }
protected void setNeedsFullRebatch(boolean needsFullRebatch) {
this.needsFullRebatch = needsFullRebatch;
}
public int getOffsetIndex(Geometry batchedGeometry){
return batchedGeometry.startIndex;
}
} }

@ -322,8 +322,8 @@ public class Geometry extends Spatial {
this.startIndex = 0; this.startIndex = 0;
prevBatchTransforms = null; prevBatchTransforms = null;
cachedOffsetMat = null; cachedOffsetMat = null;
//once the geometry is removed from the screnegraph we call batch on the batchNode before unreferencing it. //once the geometry is removed from the screnegraph the batchNode needs to be rebatched.
this.batchNode.batch(); this.batchNode.setNeedsFullRebatch(true);
this.batchNode = null; this.batchNode = null;
setCullHint(CullHint.Dynamic); setCullHint(CullHint.Dynamic);
} }

Loading…
Cancel
Save