feat(render): 实现模型渲染层级变换与网格世界坐标烘焙
- 为 Mesh2D 添加 getX/Y 方法并优化顶点访问逻辑 -修复 FloatBuffer 剩余空间判断逻辑 - 添加 bakedToWorld 标志支持网格世界坐标烘焙- 重构 ModelPart 变换更新逻辑,增加递归重计算 - 实现 ModelPart.draw() 方法支持 shader 传参绘制 - 更新 ModelRender 渲染流程,支持 worldTransform 传递 -修正网格顶点坐标上传逻辑,兼容 baked 状态- 移除废弃的调试与上传方法 - 增强部件变换时的局部与世界矩阵同步 - 修复 printWorldPosition 使用 worldTransform 坐标 - 调整测试模型初始位置与层级结构 重点: - 修复了XY轴无法设置的重大问题
This commit is contained in:
@@ -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();
|
||||
|
||||
// 先设置部件相关的 uniform(opacity / 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(位置 / uv),layout 已在 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 属性
|
||||
|
||||
Reference in New Issue
Block a user