refactor(render):重构Mesh2D渲染逻辑并优化着色器代码
- 将Mesh2D的渲染方法移至Mesh2D类中,简化ModelRender职责 - 移除冗余的纹理绑定逻辑,交由Mesh.draw()处理 - 更新顶点着色器和片段着色器以支持调试模式- 弃用旧的uploadMeshData方法,改用Mesh.draw() - 添加getVaoId方法暴露VAO ID用于外部访问-修正uniform location获取方式为静态导入- 添加调试输出用于网格顶点坐标检查 - 移除无用的注释和冗余变量声明
This commit is contained in:
@@ -16,8 +16,11 @@ import java.nio.IntBuffer;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重构后的 ModelRender:更模块化、健壮的渲染子系统
|
* 重构后的 ModelRender:更模块化、健壮的渲染子系统
|
||||||
|
* @author tzdwindows 7
|
||||||
*/
|
*/
|
||||||
public final class ModelRender {
|
public final class ModelRender {
|
||||||
|
|
||||||
@@ -60,7 +63,7 @@ public final class ModelRender {
|
|||||||
|
|
||||||
int getUniformLocation(String name) {
|
int getUniformLocation(String name) {
|
||||||
return uniformCache.computeIfAbsent(name, k -> {
|
return uniformCache.computeIfAbsent(name, k -> {
|
||||||
int loc = GL20.glGetUniformLocation(programId, k);
|
int loc = glGetUniformLocation(programId, k);
|
||||||
if (loc == -1) {
|
if (loc == -1) {
|
||||||
// debug 时可以打开
|
// debug 时可以打开
|
||||||
// System.err.println("Warning: uniform not found: " + k);
|
// System.err.println("Warning: uniform not found: " + k);
|
||||||
@@ -92,37 +95,48 @@ public final class ModelRender {
|
|||||||
|
|
||||||
// ================== 着色器源 ==================
|
// ================== 着色器源 ==================
|
||||||
private static final String VERTEX_SHADER_SRC =
|
private static final String VERTEX_SHADER_SRC =
|
||||||
"#version 330 core\n" +
|
"""
|
||||||
"layout(location = 0) in vec2 aPosition;\n" +
|
#version 330 core
|
||||||
"layout(location = 1) in vec2 aTexCoord;\n" +
|
layout(location = 0) in vec2 aPosition;
|
||||||
"out vec2 vTexCoord;\n" +
|
layout(location = 1) in vec2 aTexCoord;
|
||||||
"uniform mat3 uModelMatrix;\n" +
|
out vec2 vTexCoord;
|
||||||
"uniform mat3 uViewMatrix;\n" +
|
out vec2 vDebugPos;
|
||||||
"uniform mat3 uProjectionMatrix;\n" +
|
uniform mat3 uModelMatrix;
|
||||||
"void main() {\n" +
|
uniform mat3 uViewMatrix;
|
||||||
" vec3 p = uProjectionMatrix * uViewMatrix * uModelMatrix * vec3(aPosition, 1.0);\n" +
|
uniform mat3 uProjectionMatrix;
|
||||||
" gl_Position = vec4(p.xy, 0.0, 1.0);\n" +
|
void main() {
|
||||||
" vTexCoord = aTexCoord;\n" +
|
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 =
|
private static final String FRAGMENT_SHADER_SRC =
|
||||||
"#version 330 core\n" +
|
"""
|
||||||
"in vec2 vTexCoord;\n" +
|
#version 330 core
|
||||||
"out vec4 FragColor;\n" +
|
in vec2 vTexCoord;
|
||||||
"uniform sampler2D uTexture;\n" +
|
in vec2 vDebugPos;
|
||||||
"uniform vec4 uColor;\n" +
|
out vec4 FragColor;
|
||||||
"uniform float uOpacity;\n" +
|
uniform sampler2D uTexture;
|
||||||
"uniform int uBlendMode;\n" +
|
uniform vec4 uColor;
|
||||||
"void main() {\n" +
|
uniform float uOpacity;
|
||||||
" vec4 tex = texture(uTexture, vTexCoord);\n" +
|
uniform int uBlendMode;
|
||||||
" vec4 finalColor = tex * uColor;\n" +
|
uniform int uDebugMode;
|
||||||
" if (uBlendMode == 1) finalColor.rgb = tex.rgb + uColor.rgb;\n" +
|
void main() {
|
||||||
" else if (uBlendMode == 2) finalColor.rgb = tex.rgb * uColor.rgb;\n" +
|
if (uDebugMode == 1) {
|
||||||
" else if (uBlendMode == 3) finalColor.rgb = 1.0 - (1.0 - tex.rgb) * (1.0 - uColor.rgb);\n" +
|
FragColor = vec4(vDebugPos * 0.5 + 0.5, 0.0, 1.0);
|
||||||
" finalColor.a = tex.a * uOpacity;\n" +
|
return;
|
||||||
" if (finalColor.a <= 0.001) discard;\n" +
|
}
|
||||||
" FragColor = finalColor;\n" +
|
|
||||||
"}";
|
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() {
|
public static synchronized void initialize() {
|
||||||
@@ -284,6 +298,8 @@ public final class ModelRender {
|
|||||||
// 使用默认 shader(保持绑定直到完成渲染)
|
// 使用默认 shader(保持绑定直到完成渲染)
|
||||||
defaultProgram.use();
|
defaultProgram.use();
|
||||||
|
|
||||||
|
// setUniformIntInternal(defaultProgram, "uDebugMode", 0); 设置debug模式
|
||||||
|
|
||||||
// 设置投影与视图(3x3 正交投影用于 2D)
|
// 设置投影与视图(3x3 正交投影用于 2D)
|
||||||
Matrix3f proj = buildOrthoProjection(viewportWidth, viewportHeight);
|
Matrix3f proj = buildOrthoProjection(viewportWidth, viewportHeight);
|
||||||
setUniformMatrix3(defaultProgram, "uProjectionMatrix", proj);
|
setUniformMatrix3(defaultProgram, "uProjectionMatrix", proj);
|
||||||
@@ -302,14 +318,13 @@ public final class ModelRender {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void renderPartRecursive(ModelPart part, Matrix3f parentMat) {
|
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
|
Matrix3f world = new Matrix3f(parentMat).mul(local); // world = parent * local
|
||||||
|
|
||||||
// 从 world 矩阵取世界坐标
|
// 从 world 矩阵取世界坐标
|
||||||
//float worldX = world.m02;
|
//float worldX = world.m02;
|
||||||
//float worldY = world.m12;
|
//float worldY = world.m12;
|
||||||
//System.out.println("Rendering part: " + part.getName() + " at world position: " + worldX + ", " + worldY);
|
//System.out.println("Rendering part: " + part.getName() + " at world position: " + worldX + ", " + worldY);
|
||||||
|
|
||||||
// 传入 shader
|
// 传入 shader
|
||||||
setUniformMatrix3(defaultProgram, "uModelMatrix", world);
|
setUniformMatrix3(defaultProgram, "uModelMatrix", world);
|
||||||
setPartUniforms(defaultProgram, part);
|
setPartUniforms(defaultProgram, part);
|
||||||
@@ -325,34 +340,7 @@ public final class ModelRender {
|
|||||||
|
|
||||||
|
|
||||||
private static void renderMesh(Mesh2D mesh) {
|
private static void renderMesh(Mesh2D mesh) {
|
||||||
// 确保 mesh 的 GL 资源已上传(ModelRender 管理 upload)
|
mesh.draw();
|
||||||
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);
|
|
||||||
|
|
||||||
checkGLError("renderMesh");
|
checkGLError("renderMesh");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,60 +356,79 @@ public final class ModelRender {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================== 上传数据 ==================
|
// ================== 上传数据 ==================(被弃用)
|
||||||
private static void uploadMeshData(Mesh2D mesh, MeshGLResources res) {
|
//private static void uploadMeshData(Mesh2D mesh, MeshGLResources res) {
|
||||||
System.out.println("Uploading mesh data: " + mesh.getName());
|
// System.out.println("Uploading mesh data: " + mesh.getName());
|
||||||
|
//
|
||||||
res.vao = GL30.glGenVertexArrays();
|
// res.vao = GL30.glGenVertexArrays();
|
||||||
GL30.glBindVertexArray(res.vao);
|
// GL30.glBindVertexArray(res.vao);
|
||||||
|
//
|
||||||
res.vbo = GL15.glGenBuffers();
|
// res.vbo = GL15.glGenBuffers();
|
||||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, res.vbo);
|
// GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, res.vbo);
|
||||||
|
//
|
||||||
float[] verts = mesh.getVertices();
|
// float[] verts = mesh.getVertices();
|
||||||
float[] uvs = mesh.getUVs();
|
// float[] uvs = mesh.getUVs();
|
||||||
int vertexCount = mesh.getVertexCount();
|
// int vertexCount = mesh.getVertexCount();
|
||||||
if (verts == null || verts.length == 0) throw new IllegalStateException("Mesh has no vertices: " + mesh.getName());
|
// if (verts == null || verts.length == 0) throw new IllegalStateException("Mesh has no vertices: " + mesh.getName());
|
||||||
|
//
|
||||||
FloatBuffer inter = MemoryUtil.memAllocFloat(vertexCount * 4);
|
// FloatBuffer inter = MemoryUtil.memAllocFloat(vertexCount * 4);
|
||||||
for (int i = 0; i < vertexCount; i++) {
|
//
|
||||||
inter.put(verts[i*2]);
|
// // ========== 添加调试输出 ==========
|
||||||
inter.put(verts[i*2+1]);
|
// System.out.println("=== Vertex data debug output ===");
|
||||||
inter.put(uvs[i*2]);
|
// System.out.println("Grid name: " + mesh.getName());
|
||||||
inter.put(uvs[i*2+1]);
|
// System.out.println("Number of vertices: " + vertexCount);
|
||||||
}
|
// System.out.println("Vertex coordinates (x, y):");
|
||||||
inter.flip();
|
//
|
||||||
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, inter, GL15.GL_STATIC_DRAW);
|
// for (int i = 0; i < vertexCount; i++) {
|
||||||
MemoryUtil.memFree(inter);
|
// float x = verts[i*2];
|
||||||
|
// float y = verts[i*2+1];
|
||||||
// 设置 attribute(位置 / uv),layout 已在 shader 中固定
|
// float u = uvs[i*2];
|
||||||
int stride = 4 * Float.BYTES;
|
// float v = uvs[i*2+1];
|
||||||
GL20.glEnableVertexAttribArray(0);
|
//
|
||||||
GL20.glVertexAttribPointer(0, 2, GL11.GL_FLOAT, false, stride, 0);
|
// // 输出每个顶点的坐标和UV
|
||||||
GL20.glEnableVertexAttribArray(1);
|
// System.out.printf("vertex %d: location(%.3f, %.3f), UV(%.3f, %.3f)%n",
|
||||||
GL20.glVertexAttribPointer(1, 2, GL11.GL_FLOAT, false, stride, 2 * Float.BYTES);
|
// i, x, y, u, v);
|
||||||
|
//
|
||||||
int[] indices = mesh.getIndices();
|
// inter.put(x);
|
||||||
if (indices != null && indices.length > 0) {
|
// inter.put(y);
|
||||||
res.ebo = GL15.glGenBuffers();
|
// inter.put(u);
|
||||||
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, res.ebo);
|
// inter.put(v);
|
||||||
IntBuffer ib = MemoryUtil.memAllocInt(indices.length);
|
// }
|
||||||
ib.put(indices).flip();
|
// System.out.println("=== Vertex data output is over ===");
|
||||||
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, ib, GL15.GL_STATIC_DRAW);
|
// // ========== 调试输出结束 ==========
|
||||||
MemoryUtil.memFree(ib);
|
//
|
||||||
res.vertexCount = indices.length; // drawElements 使用 count
|
// inter.flip();
|
||||||
} else {
|
// GL15.glBufferData(GL15.GL_ARRAY_BUFFER, inter, GL15.GL_STATIC_DRAW);
|
||||||
res.vertexCount = vertexCount;
|
// MemoryUtil.memFree(inter);
|
||||||
}
|
//
|
||||||
|
// // 设置 attribute(位置 / uv),layout 已在 shader 中固定
|
||||||
// 不解绑 ELEMENT_ARRAY_BUFFER(它属于 VAO),解绑 ARRAY_BUFFER
|
// int stride = 4 * Float.BYTES;
|
||||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
// GL20.glEnableVertexAttribArray(0);
|
||||||
GL30.glBindVertexArray(0);
|
// GL20.glVertexAttribPointer(0, 2, GL11.GL_FLOAT, false, stride, 0);
|
||||||
|
// GL20.glEnableVertexAttribArray(1);
|
||||||
res.initialized = true;
|
// GL20.glVertexAttribPointer(1, 2, GL11.GL_FLOAT, false, stride, 2 * Float.BYTES);
|
||||||
checkGLError("uploadMeshData");
|
//
|
||||||
System.out.println("Uploaded mesh: " + mesh.getName() + " (v=" + vertexCount + ")");
|
// 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 已绑定) ==================
|
// ================== uniform 设置辅助(内部使用,确保 program 已绑定) ==================
|
||||||
private static void setUniformIntInternal(ShaderProgram sp, String name, int value) {
|
private static void setUniformIntInternal(ShaderProgram sp, String name, int value) {
|
||||||
|
|||||||
@@ -356,6 +356,7 @@ public class Mesh2D {
|
|||||||
|
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
for (int i = 0; i < vertexCount; i++) {
|
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]); // x
|
||||||
buffer.put(vertices[i * 2 + 1]); // y
|
buffer.put(vertices[i * 2 + 1]); // y
|
||||||
buffer.put(uvs[i * 2]); // u
|
buffer.put(uvs[i * 2]); // u
|
||||||
@@ -454,7 +455,6 @@ public class Mesh2D {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (texture != null) {
|
if (texture != null) {
|
||||||
// 假设 Texture 提供 bind()/unbind() 方法
|
|
||||||
texture.bind();
|
texture.bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,6 +563,10 @@ public class Mesh2D {
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getVaoId() {
|
||||||
|
return vaoId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取绘制模式字符串
|
* 获取绘制模式字符串
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user