feat(render): 实现模型渲染层级变换与网格世界坐标烘焙

- 为 Mesh2D 添加 getX/Y 方法并优化顶点访问逻辑
-修复 FloatBuffer 剩余空间判断逻辑
- 添加 bakedToWorld 标志支持网格世界坐标烘焙- 重构 ModelPart 变换更新逻辑,增加递归重计算
- 实现 ModelPart.draw() 方法支持 shader 传参绘制
- 更新 ModelRender 渲染流程,支持 worldTransform 传递
-修正网格顶点坐标上传逻辑,兼容 baked 状态- 移除废弃的调试与上传方法
- 增强部件变换时的局部与世界矩阵同步
- 修复 printWorldPosition 使用 worldTransform 坐标
- 调整测试模型初始位置与层级结构

重点:
- 修复了XY轴无法设置的重大问题
This commit is contained in:
tzdwindows 7
2025-10-08 16:49:26 +08:00
parent 52ed33b5c8
commit becf789cb8
4 changed files with 204 additions and 112 deletions

View File

@@ -317,33 +317,58 @@ public final class ModelRender {
checkGLError("render");
}
/**
* 关键修改点:在渲染前确保更新 part 的 worldTransform
* 然后直接使用 part.getWorldTransform() 作为 uModelMatrix 传入 shader。
*/
private static void renderPartRecursive(ModelPart part, Matrix3f parentMat) {
Matrix3f local = part.getLocalTransform();
Matrix3f world = new Matrix3f(parentMat).mul(local); // world = parent * local
// 确保 part 的 local/world 矩阵被计算(会更新 transformDirty
part.updateWorldTransform(parentMat, false);
// 从 world 矩阵取世界坐标
//float worldX = world.m02;
//float worldY = world.m12;
//System.out.println("Rendering part: " + part.getName() + " at world position: " + worldX + ", " + worldY);
// 传入 shader
setUniformMatrix3(defaultProgram, "uModelMatrix", world);
// 直接使用已经计算好的 worldTransform
Matrix3f world = part.getWorldTransform();
// 先设置部件相关的 uniformopacity / blendMode / color 等)
setPartUniforms(defaultProgram, part);
// 把 world 矩阵传给 shader兼容 uModelMatrix 和 可能的 uModel
setUniformMatrix3(defaultProgram, "uModelMatrix", world);
setUniformMatrix3(defaultProgram, "uModel", world);
// 绘制本节点的所有 mesh将 world 传入 renderMesh
for (Mesh2D mesh : part.getMeshes()) {
renderMesh(mesh);
renderMesh(mesh, world);
}
// 递归渲染子节点,继续传入当前 world 作为子节点的 parent
for (ModelPart child : part.getChildren()) {
renderPartRecursive(child, world);
}
}
private static void renderMesh(Mesh2D mesh, Matrix3f modelMatrix) {
// 使用默认 shader保证 shader 已被 use
defaultProgram.use();
// 如果 mesh 已经被烘焙到世界坐标,则传 identity 矩阵给 shader防止重复变换
Matrix3f matToUse = mesh.isBakedToWorld() ? new Matrix3f().identity() : modelMatrix;
// 确保 shader 中的矩阵 uniform 已更新(再次设置以防遗漏)
setUniformMatrix3(defaultProgram, "uModelMatrix", matToUse);
setUniformMatrix3(defaultProgram, "uModel", matToUse);
// 调用 Mesh2D 的 draw 重载(传 program id 与实际矩阵)
try {
mesh.draw(defaultProgram.programId, matToUse);
} catch (AbstractMethodError | NoSuchMethodError e) {
// 回退:仍然兼容旧的无参 draw在这种情况下 shader 的 uModelMatrix 已经被设置)
mesh.draw();
}
private static void renderMesh(Mesh2D mesh) {
mesh.draw();
checkGLError("renderMesh");
}
private static int getGLDrawMode(int meshDrawMode) {
switch (meshDrawMode) {
case Mesh2D.POINTS: return GL11.GL_POINTS;
@@ -357,78 +382,7 @@ public final class ModelRender {
}
// ================== 上传数据 ==================(被弃用)
//private static void uploadMeshData(Mesh2D mesh, MeshGLResources res) {
// System.out.println("Uploading mesh data: " + mesh.getName());
//
// res.vao = GL30.glGenVertexArrays();
// GL30.glBindVertexArray(res.vao);
//
// res.vbo = GL15.glGenBuffers();
// GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, res.vbo);
//
// float[] verts = mesh.getVertices();
// float[] uvs = mesh.getUVs();
// int vertexCount = mesh.getVertexCount();
// if (verts == null || verts.length == 0) throw new IllegalStateException("Mesh has no vertices: " + mesh.getName());
//
// FloatBuffer inter = MemoryUtil.memAllocFloat(vertexCount * 4);
//
// // ========== 添加调试输出 ==========
// System.out.println("=== Vertex data debug output ===");
// System.out.println("Grid name: " + mesh.getName());
// System.out.println("Number of vertices: " + vertexCount);
// System.out.println("Vertex coordinates (x, y):");
//
// for (int i = 0; i < vertexCount; i++) {
// float x = verts[i*2];
// float y = verts[i*2+1];
// float u = uvs[i*2];
// float v = uvs[i*2+1];
//
// // 输出每个顶点的坐标和UV
// System.out.printf("vertex %d: location(%.3f, %.3f), UV(%.3f, %.3f)%n",
// i, x, y, u, v);
//
// inter.put(x);
// inter.put(y);
// inter.put(u);
// inter.put(v);
// }
// System.out.println("=== Vertex data output is over ===");
// // ========== 调试输出结束 ==========
//
// inter.flip();
// GL15.glBufferData(GL15.GL_ARRAY_BUFFER, inter, GL15.GL_STATIC_DRAW);
// MemoryUtil.memFree(inter);
//
// // 设置 attribute位置 / uvlayout 已在 shader 中固定
// int stride = 4 * Float.BYTES;
// GL20.glEnableVertexAttribArray(0);
// GL20.glVertexAttribPointer(0, 2, GL11.GL_FLOAT, false, stride, 0);
// GL20.glEnableVertexAttribArray(1);
// GL20.glVertexAttribPointer(1, 2, GL11.GL_FLOAT, false, stride, 2 * Float.BYTES);
//
// int[] indices = mesh.getIndices();
// if (indices != null && indices.length > 0) {
// res.ebo = GL15.glGenBuffers();
// GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, res.ebo);
// IntBuffer ib = MemoryUtil.memAllocInt(indices.length);
// ib.put(indices).flip();
// GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, ib, GL15.GL_STATIC_DRAW);
// MemoryUtil.memFree(ib);
// res.vertexCount = indices.length; // drawElements 使用 count
// } else {
// res.vertexCount = vertexCount;
// }
//
// // 不解绑 ELEMENT_ARRAY_BUFFER它属于 VAO解绑 ARRAY_BUFFER
// GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
// GL30.glBindVertexArray(0);
//
// res.initialized = true;
// checkGLError("uploadMeshData");
// System.out.println("Uploaded mesh: " + mesh.getName() + " (v=" + vertexCount + ")");
//}
// ================== uniform 设置辅助(内部使用,确保 program 已绑定) ==================
private static void setUniformIntInternal(ShaderProgram sp, String name, int value) {
@@ -480,11 +434,16 @@ public final class ModelRender {
private static void setPartUniforms(ShaderProgram sp, ModelPart part) {
setUniformFloatInternal(sp, "uOpacity", part.getOpacity());
int blend = 0;
switch (part.getBlendMode()) {
case ADDITIVE: blend = 1; break;
case MULTIPLY: blend = 2; break;
case SCREEN: blend = 3; break;
case NORMAL: default: blend = 0;
ModelPart.BlendMode bm = part.getBlendMode();
if (bm != null) {
switch (bm) {
case ADDITIVE: blend = 1; break;
case MULTIPLY: blend = 2; break;
case SCREEN: blend = 3; break;
case NORMAL: default: blend = 0;
}
} else {
blend = 0;
}
setUniformIntInternal(sp, "uBlendMode", blend);
// 这里保留为白色,若需要部件 tint 请替换为 part 的 color 属性