diff --git a/src/main/java/com/chuangzhou/vivid2D/render/ModelRender.java b/src/main/java/com/chuangzhou/vivid2D/render/ModelRender.java index fc4e890..258a3d0 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/ModelRender.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/ModelRender.java @@ -16,8 +16,11 @@ import java.nio.IntBuffer; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; +import static org.lwjgl.opengl.GL20.glGetUniformLocation; + /** * 重构后的 ModelRender:更模块化、健壮的渲染子系统 + * @author tzdwindows 7 */ public final class ModelRender { @@ -60,7 +63,7 @@ public final class ModelRender { int getUniformLocation(String name) { return uniformCache.computeIfAbsent(name, k -> { - int loc = GL20.glGetUniformLocation(programId, k); + int loc = glGetUniformLocation(programId, k); if (loc == -1) { // debug 时可以打开 // System.err.println("Warning: uniform not found: " + k); @@ -92,37 +95,48 @@ public final class ModelRender { // ================== 着色器源 ================== private static final String VERTEX_SHADER_SRC = - "#version 330 core\n" + - "layout(location = 0) in vec2 aPosition;\n" + - "layout(location = 1) in vec2 aTexCoord;\n" + - "out vec2 vTexCoord;\n" + - "uniform mat3 uModelMatrix;\n" + - "uniform mat3 uViewMatrix;\n" + - "uniform mat3 uProjectionMatrix;\n" + - "void main() {\n" + - " vec3 p = uProjectionMatrix * uViewMatrix * uModelMatrix * vec3(aPosition, 1.0);\n" + - " gl_Position = vec4(p.xy, 0.0, 1.0);\n" + - " vTexCoord = aTexCoord;\n" + - "}"; + """ + #version 330 core + layout(location = 0) in vec2 aPosition; + layout(location = 1) in vec2 aTexCoord; + out vec2 vTexCoord; + out vec2 vDebugPos; + uniform mat3 uModelMatrix; + uniform mat3 uViewMatrix; + uniform mat3 uProjectionMatrix; + void main() { + vec3 p = uProjectionMatrix * uViewMatrix * uModelMatrix * vec3(aPosition, 1.0); + gl_Position = vec4(p.xy, 0.0, 1.0); + vTexCoord = aTexCoord; + vDebugPos = p.xy; + }"""; private static final String FRAGMENT_SHADER_SRC = - "#version 330 core\n" + - "in vec2 vTexCoord;\n" + - "out vec4 FragColor;\n" + - "uniform sampler2D uTexture;\n" + - "uniform vec4 uColor;\n" + - "uniform float uOpacity;\n" + - "uniform int uBlendMode;\n" + - "void main() {\n" + - " vec4 tex = texture(uTexture, vTexCoord);\n" + - " vec4 finalColor = tex * uColor;\n" + - " if (uBlendMode == 1) finalColor.rgb = tex.rgb + uColor.rgb;\n" + - " else if (uBlendMode == 2) finalColor.rgb = tex.rgb * uColor.rgb;\n" + - " else if (uBlendMode == 3) finalColor.rgb = 1.0 - (1.0 - tex.rgb) * (1.0 - uColor.rgb);\n" + - " finalColor.a = tex.a * uOpacity;\n" + - " if (finalColor.a <= 0.001) discard;\n" + - " FragColor = finalColor;\n" + - "}"; + """ + #version 330 core + in vec2 vTexCoord; + in vec2 vDebugPos; + out vec4 FragColor; + uniform sampler2D uTexture; + uniform vec4 uColor; + uniform float uOpacity; + uniform int uBlendMode; + uniform int uDebugMode; + void main() { + if (uDebugMode == 1) { + FragColor = vec4(vDebugPos * 0.5 + 0.5, 0.0, 1.0); + return; + } + + vec4 tex = texture(uTexture, vTexCoord); + vec4 finalColor = tex * uColor; + if (uBlendMode == 1) finalColor.rgb = tex.rgb + uColor.rgb; + else if (uBlendMode == 2) finalColor.rgb = tex.rgb * uColor.rgb; + else if (uBlendMode == 3) finalColor.rgb = 1.0 - (1.0 - tex.rgb) * (1.0 - uColor.rgb); + finalColor.a = tex.a * uOpacity; + if (finalColor.a <= 0.001) discard; + FragColor = finalColor; + }"""; // ================== 初始化 / 清理 ================== public static synchronized void initialize() { @@ -284,6 +298,8 @@ public final class ModelRender { // 使用默认 shader(保持绑定直到完成渲染) defaultProgram.use(); + // setUniformIntInternal(defaultProgram, "uDebugMode", 0); 设置debug模式 + // 设置投影与视图(3x3 正交投影用于 2D) Matrix3f proj = buildOrthoProjection(viewportWidth, viewportHeight); setUniformMatrix3(defaultProgram, "uProjectionMatrix", proj); @@ -302,14 +318,13 @@ public final class ModelRender { } private static void renderPartRecursive(ModelPart part, Matrix3f parentMat) { - Matrix3f local = part.getLocalTransform(); // 局部矩阵 + Matrix3f local = part.getLocalTransform(); Matrix3f world = new Matrix3f(parentMat).mul(local); // world = parent * local // 从 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); setPartUniforms(defaultProgram, part); @@ -325,34 +340,7 @@ public final class ModelRender { private static void renderMesh(Mesh2D mesh) { - // 确保 mesh 的 GL 资源已上传(ModelRender 管理 upload) - MeshGLResources res = meshResources.computeIfAbsent(mesh, k -> new MeshGLResources()); - if (!res.initialized) uploadMeshData(mesh, res); - - // 绑定纹理到单元0(我们使用 0 固定) - Texture tex = mesh.getTexture(); - int texId = (tex != null && !tex.isDisposed()) ? tex.getTextureId() : defaultTextureId; - - // active unit & bind — 确保 shader 已被 use()(调用者保证) - GL13.glActiveTexture(GL13.GL_TEXTURE0); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, texId); - // 将 sampler 设为 0(内部函数保证 program 绑定) - setUniformIntInternal(defaultProgram, "uTexture", 0); - - // 绑定 VAO 并绘制 - GL30.glBindVertexArray(res.vao); - int drawMode = getGLDrawMode(mesh.getDrawMode()); - if (mesh.getIndices().length > 0 && - (drawMode == GL11.GL_TRIANGLES || drawMode == GL11.GL_TRIANGLE_STRIP || drawMode == GL11.GL_TRIANGLE_FAN)) { - GL11.glDrawElements(drawMode, mesh.getIndices().length, GL11.GL_UNSIGNED_INT, 0); - } else { - GL11.glDrawArrays(drawMode, 0, res.vertexCount); - } - GL30.glBindVertexArray(0); - - // 解绑纹理(避免污染后续 state) - GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); - + mesh.draw(); checkGLError("renderMesh"); } @@ -368,60 +356,79 @@ 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); - for (int i = 0; i < vertexCount; i++) { - inter.put(verts[i*2]); - inter.put(verts[i*2+1]); - inter.put(uvs[i*2]); - inter.put(uvs[i*2+1]); - } - 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 + ")"); - } + // ================== 上传数据 ==================(被弃用) + //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) { diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/Mesh2D.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/Mesh2D.java index c2bc913..7ee0d08 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/Mesh2D.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/Mesh2D.java @@ -356,6 +356,7 @@ public class Mesh2D { 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 @@ -454,7 +455,6 @@ public class Mesh2D { } if (texture != null) { - // 假设 Texture 提供 bind()/unbind() 方法 texture.bind(); } @@ -563,6 +563,10 @@ public class Mesh2D { return copy; } + public int getVaoId() { + return vaoId; + } + /** * 获取绘制模式字符串 */