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 属性
|
||||
|
||||
@@ -72,6 +72,8 @@ public class ModelPart {
|
||||
this.boundsDirty = true;
|
||||
|
||||
updateLocalTransform();
|
||||
// 初始时 worldTransform = localTransform(无父节点时)
|
||||
recomputeWorldTransformRecursive();
|
||||
}
|
||||
|
||||
// ==================== 层级管理 ====================
|
||||
@@ -88,7 +90,9 @@ public class ModelPart {
|
||||
}
|
||||
children.add(child);
|
||||
child.parent = this;
|
||||
markTransformDirty();
|
||||
child.markTransformDirty();
|
||||
// 确保子节点的 worldTransform 立即更新
|
||||
child.recomputeWorldTransformRecursive();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,7 +102,8 @@ public class ModelPart {
|
||||
boolean removed = children.remove(child);
|
||||
if (removed) {
|
||||
child.parent = null;
|
||||
markTransformDirty();
|
||||
child.markTransformDirty();
|
||||
child.recomputeWorldTransformRecursive();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
@@ -146,7 +151,7 @@ public class ModelPart {
|
||||
// ==================== 变换系统 ====================
|
||||
|
||||
/**
|
||||
* 更新世界变换
|
||||
* 更新世界变换(保留旧方法以兼容)
|
||||
*/
|
||||
public void updateWorldTransform(Matrix3f parentTransform, boolean recursive) {
|
||||
// 如果需要更新局部变换
|
||||
@@ -169,6 +174,21 @@ public class ModelPart {
|
||||
transformDirty = false;
|
||||
}
|
||||
|
||||
public void draw(int shaderProgram, org.joml.Matrix3f parentTransform) {
|
||||
// 先确保 worldTransform 是最新的
|
||||
updateWorldTransform(parentTransform, false);
|
||||
|
||||
// 绘制本节点的所有 mesh(将 worldTransform 作为 model 矩阵传入)
|
||||
for (Mesh2D mesh : meshes) {
|
||||
mesh.draw(shaderProgram, worldTransform);
|
||||
}
|
||||
|
||||
// 递归绘制子节点
|
||||
for (ModelPart child : children) {
|
||||
child.draw(shaderProgram, worldTransform);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新局部矩阵
|
||||
private void updateLocalTransform() {
|
||||
float cos = (float)Math.cos(rotation);
|
||||
@@ -189,15 +209,36 @@ public class ModelPart {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即重新计算本节点的 worldTransform(并递归到子节点)
|
||||
*/
|
||||
private void recomputeWorldTransformRecursive() {
|
||||
if (transformDirty) {
|
||||
updateLocalTransform();
|
||||
}
|
||||
|
||||
if (parent != null) {
|
||||
// parent.worldTransform 已经是最新(假设父节点正确维护)
|
||||
parent.worldTransform.mul(localTransform, worldTransform);
|
||||
} else {
|
||||
worldTransform.set(localTransform);
|
||||
}
|
||||
|
||||
// 打印世界坐标
|
||||
public void printWorldPosition() {
|
||||
float worldX = localTransform.m02;
|
||||
float worldY = localTransform.m12;
|
||||
System.out.println("World position: " + worldX + ", " + worldY);
|
||||
// 递归更新子节点
|
||||
for (ModelPart child : children) {
|
||||
child.recomputeWorldTransformRecursive();
|
||||
}
|
||||
|
||||
boundsDirty = true;
|
||||
transformDirty = false;
|
||||
}
|
||||
|
||||
// 打印世界坐标(修正为使用 worldTransform)
|
||||
public void printWorldPosition() {
|
||||
float worldX = worldTransform.m02();
|
||||
float worldY = worldTransform.m12();
|
||||
System.out.println("World position: " + worldX + ", " + worldY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记变换需要更新
|
||||
@@ -215,11 +256,15 @@ public class ModelPart {
|
||||
public void setPosition(float x, float y) {
|
||||
position.set(x, y);
|
||||
markTransformDirty();
|
||||
updateLocalTransform();
|
||||
recomputeWorldTransformRecursive();
|
||||
}
|
||||
|
||||
public void setPosition(Vector2f position) {
|
||||
this.position.set(position);
|
||||
markTransformDirty();
|
||||
updateLocalTransform();
|
||||
recomputeWorldTransformRecursive();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,11 +273,15 @@ public class ModelPart {
|
||||
public void translate(float dx, float dy) {
|
||||
position.add(dx, dy);
|
||||
markTransformDirty();
|
||||
updateLocalTransform();
|
||||
recomputeWorldTransformRecursive();
|
||||
}
|
||||
|
||||
public void translate(Vector2f delta) {
|
||||
position.add(delta);
|
||||
markTransformDirty();
|
||||
updateLocalTransform();
|
||||
recomputeWorldTransformRecursive();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,6 +290,8 @@ public class ModelPart {
|
||||
public void setRotation(float radians) {
|
||||
this.rotation = radians;
|
||||
markTransformDirty();
|
||||
updateLocalTransform();
|
||||
recomputeWorldTransformRecursive();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,6 +300,8 @@ public class ModelPart {
|
||||
public void rotate(float deltaRadians) {
|
||||
this.rotation += deltaRadians;
|
||||
markTransformDirty();
|
||||
updateLocalTransform();
|
||||
recomputeWorldTransformRecursive();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -257,16 +310,22 @@ public class ModelPart {
|
||||
public void setScale(float sx, float sy) {
|
||||
scale.set(sx, sy);
|
||||
markTransformDirty();
|
||||
updateLocalTransform();
|
||||
recomputeWorldTransformRecursive();
|
||||
}
|
||||
|
||||
public void setScale(float uniformScale) {
|
||||
scale.set(uniformScale, uniformScale);
|
||||
markTransformDirty();
|
||||
updateLocalTransform();
|
||||
recomputeWorldTransformRecursive();
|
||||
}
|
||||
|
||||
public void setScale(Vector2f scale) {
|
||||
this.scale.set(scale);
|
||||
markTransformDirty();
|
||||
updateLocalTransform();
|
||||
recomputeWorldTransformRecursive();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -275,6 +334,8 @@ public class ModelPart {
|
||||
public void scale(float sx, float sy) {
|
||||
scale.mul(sx, sy);
|
||||
markTransformDirty();
|
||||
updateLocalTransform();
|
||||
recomputeWorldTransformRecursive();
|
||||
}
|
||||
|
||||
// ==================== 网格管理 ====================
|
||||
@@ -283,6 +344,18 @@ public class ModelPart {
|
||||
* 添加网格
|
||||
*/
|
||||
public void addMesh(Mesh2D mesh) {
|
||||
if (mesh == null) return;
|
||||
|
||||
// 确保本节点的 worldTransform 是最新的(会递归更新子节点)
|
||||
recomputeWorldTransformRecursive();
|
||||
|
||||
// 将 mesh 的每个顶点从本地空间变换到世界空间(烘焙)
|
||||
int vc = mesh.getVertexCount();
|
||||
for (int i = 0; i < vc; i++) {
|
||||
org.joml.Vector2f local = mesh.getVertex(i);
|
||||
org.joml.Vector2f worldPt = Matrix3fUtils.transformPoint(this.worldTransform, local);
|
||||
mesh.setVertex(i, worldPt.x, worldPt.y);
|
||||
}
|
||||
meshes.add(mesh);
|
||||
boundsDirty = true;
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
/**
|
||||
* 2D网格类,用于存储和管理2D模型的几何数据
|
||||
* 支持顶点、UV坐标、索引和变形操作
|
||||
@@ -40,6 +39,7 @@ public class Mesh2D {
|
||||
private boolean dirty = true; // 数据是否已修改
|
||||
private BoundingBox bounds;
|
||||
private boolean boundsDirty = true;
|
||||
private boolean bakedToWorld = false;
|
||||
|
||||
// ==================== 常量 ====================
|
||||
public static final int POINTS = 0;
|
||||
@@ -178,8 +178,7 @@ public class Mesh2D {
|
||||
if (index < 0 || index >= getVertexCount()) {
|
||||
throw new IndexOutOfBoundsException("Vertex index out of bounds: " + index);
|
||||
}
|
||||
int baseIndex = index * 2;
|
||||
return dest.set(vertices[baseIndex], vertices[baseIndex + 1]);
|
||||
return dest.set(getX(index), getY(index));
|
||||
}
|
||||
|
||||
public Vector2f getVertex(int index) {
|
||||
@@ -308,7 +307,7 @@ public class Mesh2D {
|
||||
* 获取顶点缓冲区数据
|
||||
*/
|
||||
public FloatBuffer getVertexBuffer(FloatBuffer buffer) {
|
||||
if (buffer == null || buffer.capacity() < vertices.length) {
|
||||
if (buffer == null || buffer.remaining() < vertices.length) {
|
||||
throw new IllegalArgumentException("Buffer is null or too small");
|
||||
}
|
||||
buffer.clear();
|
||||
@@ -330,6 +329,20 @@ public class Mesh2D {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public float getX(int index) {
|
||||
if (index < 0 || index >= getVertexCount()) {
|
||||
throw new IndexOutOfBoundsException("Vertex index out of bounds: " + index);
|
||||
}
|
||||
return vertices[index * 2];
|
||||
}
|
||||
|
||||
public float getY(int index) {
|
||||
if (index < 0 || index >= getVertexCount()) {
|
||||
throw new IndexOutOfBoundsException("Vertex index out of bounds: " + index);
|
||||
}
|
||||
return vertices[index * 2 + 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取索引缓冲区数据
|
||||
*/
|
||||
@@ -350,17 +363,18 @@ public class Mesh2D {
|
||||
int vertexCount = getVertexCount();
|
||||
int floatCount = vertexCount * 4; // 每个顶点:x, y, u, v
|
||||
|
||||
if (buffer == null || buffer.capacity() < floatCount) {
|
||||
if (buffer == null || buffer.remaining() < floatCount) {
|
||||
throw new IllegalArgumentException("Buffer is null or too small");
|
||||
}
|
||||
|
||||
buffer.clear();
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
System.out.println("x:" + vertices[i * 2] + "y:" + vertices[i * 2 + 1]);
|
||||
buffer.put(vertices[i * 2]); // x
|
||||
buffer.put(vertices[i * 2 + 1]); // y
|
||||
buffer.put(uvs[i * 2]); // u
|
||||
buffer.put(uvs[i * 2 + 1]); // v
|
||||
// 明确使用定位方法,避免下标算错
|
||||
//System.out.println("x:"+ getX(i) + "y:"+ getY(i));
|
||||
buffer.put(getX(i)); // x
|
||||
buffer.put(getY(i)); // y
|
||||
buffer.put(uvs[i * 2]); // u
|
||||
buffer.put(uvs[i * 2 + 1]); // v
|
||||
}
|
||||
buffer.flip();
|
||||
return buffer;
|
||||
@@ -446,7 +460,7 @@ public class Mesh2D {
|
||||
/**
|
||||
* 绘制网格(会在第一次绘制时自动上传到 GPU)
|
||||
*/
|
||||
public void draw() {
|
||||
public void draw(int shaderProgram, org.joml.Matrix3f modelMatrix) {
|
||||
if (!visible) return;
|
||||
if (indices == null || indices.length == 0) return;
|
||||
|
||||
@@ -458,10 +472,46 @@ public class Mesh2D {
|
||||
texture.bind();
|
||||
}
|
||||
|
||||
// 绑定 VAO
|
||||
GL30.glBindVertexArray(vaoId);
|
||||
|
||||
// 将 modelMatrix 上传到 shader 的 uniform "uModel"(如果 shader 有此 uniform)
|
||||
int loc = GL20.glGetUniformLocation(shaderProgram, "uModel");
|
||||
if (loc != -1) {
|
||||
// 用一个 FloatBuffer 传递 3x3 矩阵
|
||||
java.nio.FloatBuffer fb = org.lwjgl.system.MemoryUtil.memAllocFloat(9);
|
||||
try {
|
||||
modelMatrix.get(fb); // JOML 将矩阵写入 buffer(列主序,适合 OpenGL)
|
||||
fb.flip();
|
||||
GL20.glUniformMatrix3fv(loc, false, fb);
|
||||
} finally {
|
||||
org.lwjgl.system.MemoryUtil.memFree(fb);
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制
|
||||
GL11.glDrawElements(GL11.GL_TRIANGLES, indexCount, GL11.GL_UNSIGNED_INT, 0);
|
||||
|
||||
// 解绑
|
||||
GL30.glBindVertexArray(0);
|
||||
|
||||
if (texture != null) {
|
||||
texture.unbind();
|
||||
}
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
if (!visible) return;
|
||||
if (indices == null || indices.length == 0) return;
|
||||
if (!uploaded) {
|
||||
uploadToGPU();
|
||||
}
|
||||
if (texture != null) {
|
||||
texture.bind();
|
||||
}
|
||||
GL30.glBindVertexArray(vaoId);
|
||||
GL11.glDrawElements(GL11.GL_TRIANGLES, indexCount, GL11.GL_UNSIGNED_INT, 0);
|
||||
GL30.glBindVertexArray(0);
|
||||
|
||||
if (texture != null) {
|
||||
texture.unbind();
|
||||
}
|
||||
@@ -582,6 +632,15 @@ public class Mesh2D {
|
||||
}
|
||||
}
|
||||
|
||||
/** 标记或查询网格顶点是否已经被烘焙到世界坐标 */
|
||||
public void setBakedToWorld(boolean baked) {
|
||||
this.bakedToWorld = baked;
|
||||
}
|
||||
|
||||
public boolean isBakedToWorld() {
|
||||
return bakedToWorld;
|
||||
}
|
||||
|
||||
// ==================== Object 方法 ====================
|
||||
|
||||
@Override
|
||||
|
||||
@@ -108,7 +108,7 @@ public class ModelRenderTest {
|
||||
|
||||
// body 放在屏幕中心
|
||||
ModelPart body = testModel.createPart("body");
|
||||
body.setPosition(400, 320);
|
||||
body.setPosition(0, 0);
|
||||
// 身体网格:宽 80 高 120
|
||||
Mesh2D bodyMesh = Mesh2D.createQuad("body_mesh", 80, 120);
|
||||
bodyMesh.setTexture(createSolidTexture(64, 128, 0xFF4A6AFF)); // 蓝衣
|
||||
@@ -151,6 +151,7 @@ public class ModelRenderTest {
|
||||
|
||||
// 建立层级:body 为根,其他作为 body 的子节点
|
||||
//testModel.addPart(body);
|
||||
|
||||
body.addChild(head);
|
||||
body.addChild(leftArm);
|
||||
body.addChild(rightArm);
|
||||
|
||||
Reference in New Issue
Block a user