batch渲染目的是降低渲染drawcall次数,但是这个降低的成本是以cpu计算为代价的
理论上只要材质相同都可以使用,但是考虑cpu计算成本,所以batch使用的条件是
每个模型定点数很小才合算,否则降低的gpu负担结果导致cpu负担过重,所以合适
用batch渲染莫过于粒子草皮之类的~
以jme为例,可能是为了追求通用行,效率真的很低,每个顶点先通过矩阵变换,再
做顶点修改过去
下面是jme3每帧调用顶点操作堆栈
BatchNode.updateSubBatch(Geometry) line: 133
BatchNode.onTransformChange(Geometry) line: 104
Geometry.updateWorldTransforms() line: 315
Geometry(Spatial).updateGeometricState() line: 905
BatchNode(Node).updateGeometricState() line: 271
Node.updateGeometricState() line: 271
TestBatchNode(SimpleApplication).update() line: 245
LwjglDisplay(LwjglAbstractDisplay).runLoop() line: 151
@Override
protected void updateWorldTransforms() {
super.updateWorldTransforms();
computeWorldMatrix();
if (isGrouped()) {//如果是普通geometry,只要矩阵计算一下就可以了,但是isGrouped为真的时候,需要cpu中变换顶点且更新到合并后的顶点buffer中
//当然在渲染流程中有isGrouped为真就会跳过渲染,当作被裁剪掉了
groupNode.onTransformChange(this);
}
// geometry requires lights to be sorted
worldLights.sort(true);
}
public void updateGeometricState(){
if (refreshFlags == 0) {
// This branch has no geometric state that requires updates.
return;
}
if ((refreshFlags & RF_LIGHTLIST) != 0){
updateWorldLightList();
}
if ((refreshFlags & RF_TRANSFORM) != 0){
// combine with parent transforms- same for all spatial
// subclasses.
updateWorldTransforms();
}
if ((refreshFlags & RF_MATPARAM_OVERRIDE) != 0) {
updateMatParamOverrides();
}
refreshFlags &= ~RF_CHILD_LIGHTLIST;
if (!children.isEmpty()) {
// the important part- make sure child geometric state is refreshed
// first before updating own world bound. This saves
// a round-trip later on.
// NOTE 9/19/09
// Although it does save a round trip,
for (Spatial child : children.getArray()) {//这里会要求每个geometry更新过去
child.updateGeometricState();
}
}
下面是挨个顶点更新过去,不是像粒子那样就是几个顶点就不要玩合并了,如果确定是不更新的,就是初始化时候更新那还好,不过jme好像没有关闭更新接口
如果针对静态不变的需要加个接口控制
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;
int length = (end - start) * 3;
// offset is given in element units
// convert to be in component units
int offset = start * 3;
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];
norm.x = tmpFloatN[index++];
pos.y = tmpFloat[index];
norm.y = tmpFloatN[index++];
pos.z = tmpFloat[index];
norm.z = tmpFloatN[index];
transform.mult(pos, pos);
transform.multNormal(norm, norm);
index -= 2;
tmpFloat[index] = pos.x;
tmpFloatN[index++] = norm.x;
tmpFloat[index] = pos.y;
tmpFloatN[index++] = norm.y;
tmpFloat[index] = pos.z;
tmpFloatN[index++] = norm.z;
}
vars.release();
bufPos.position(offset);
//using bulk put as it's faster
bufPos.put(tmpFloat, 0, length);
bufNorm.position(offset);
//using bulk put as it's faster
bufNorm.put(tmpFloatN, 0, length);
}