少女祈祷中...

模型烘焙,就是把一个四边形,通过一步步方法,烘焙成供mc渲染管线使用来渲染一个四边形面的BakedQuad对象。
可以首先来看看BakedModel的构造方法

1
2
3
4
5
6
7
8
public BakedQuad(int[] pVertices, int pTintIndex, Direction pDirection, TextureAtlasSprite pSprite, boolean pShade, boolean hasAmbientOcclusion) {
this.vertices = pVertices;
this.tintIndex = pTintIndex;
this.direction = pDirection;
this.sprite = pSprite;
this.shade = pShade;
this.hasAmbientOcclusion = hasAmbientOcclusion;
}

其中vertices是最重要的顶点数据,是int[32]数组,它是由四个顶点构成,每个顶点数据由8个int数据构成,拼接为32长度的数组。
direction是这个面的朝向,用于mc进行单面剔除来优化渲染。
sprite是这个面的材质精灵图。
这时候我们来看一下烘焙模型的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
for (ModelQuadLayer pc : mpc) {
// 将ModelQuadLayer和FaceRegion转换为BakedQuad
getFaceUvs(uvs, direction ,from, to,pc.uvs);
BlockFaceUV blockFaceUV = new BlockFaceUV(uvs,0);
TextureAtlasSprite sprite = pc.sprite;
int tint = pc.tint;
var data = net.minecraftforge.client.model.ForgeFaceData.DEFAULT;
var pVertices = makeVertices(sprite,blockFaceUV,pos,direction,to,from);
BakedQuad quad = new BakedQuad(pVertices,tint,direction,sprite,true,true);
applyingLightmap(data.blockLight(), data.skyLight()).processInPlace(quad);
applyingColor(data.color()).processInPlace(quad);
if (region.isEdge) {
builder.getList(direction).add(quad);
} else {
builder.getList(null).add(quad);
}
}

getFaceUVs方法中将float[4] uvs进行变换,由from和to两个Vector3f对象和direction方向得出在材质平面上的长方形的两个顶点坐标。
得到float[4]{u1,v1,u2,v2}
得到了uv,就要开始烘焙顶点数据了,也就是makeVertices方法,这个方法从原版的模型烘焙类FaceBakery中抄来

1
2
3
4
5
6
7
8
9
10
private int[] makeVertices(TextureAtlasSprite sprite, BlockFaceUV pBlockFaceUV,float[] pos, Direction direction, int[] to, int[] from) {
int[] data = new int[32];

for(int vertexNum = 0; vertexNum < 4; ++vertexNum) {
getVertexPos(pos, direction, vertexNum, to, from);
this.fillVertex(data, vertexNum, new Vector3f(pos[0],pos[1],pos[2]), sprite, pBlockFaceUV);
}

return data;
}

在这里分别把四个顶点的数据通过fillVertex方法写进data[32],返回装好了顶点数据的浮点数数组

1
2
3
4
5
6
7
8
private void fillVertex(int[] pVertexData, int pVertexIndex, Vector3f pVector, TextureAtlasSprite pSprite, BlockFaceUV pBlockFaceUV) {
int i = pVertexIndex * 8;
pVertexData[i] = Float.floatToRawIntBits(pVector.x());
pVertexData[i + 1] = Float.floatToRawIntBits(pVector.y());
pVertexData[i + 2] = Float.floatToRawIntBits(pVector.z());
pVertexData[i + 4] = Float.floatToRawIntBits(pSprite.getU((double)pBlockFaceUV.getU(pVertexIndex) * .999 + pBlockFaceUV.getU((pVertexIndex + 2) % 4) * .001));
pVertexData[i + 4 + 1] = Float.floatToRawIntBits(pSprite.getV((double)pBlockFaceUV.getV(pVertexIndex) * .999 + pBlockFaceUV.getV((pVertexIndex + 2) % 4) * .001));
}

最后再用原版方法为面补上色彩和光照数据,结束模型烘焙

1
2
applyingLightmap(data.blockLight(), data.skyLight()).processInPlace(quad);
applyingColor(data.color()).processInPlace(quad);