feat(render): 实现模型图层管理与选中高亮功能
- 添加 ModelLayerPanel 图层管理面板,支持图层增删、重排、重命名- 实现 Mesh2D 选中状态管理与可视化高亮边框绘制 - 添加模型点击与悬停事件监听接口 ModelClickListener - 引入完整着色器接口 CompleteShader 及默认片段着色器实现 - 改进 BufferUploader 支持颜色 uniform 传递- 完善 Mesh2D 复制逻辑与边界框计算方法 - 重构部分工具类包路径并增强矩阵工具功能 - 移除 LightSourceData 中冗余的构造逻辑 重要更新 - 更新了一个可视化界面可以控制图层顺序(ModelLayerPanel),并且给ModelRenderPanel增加了很多新功能,比如设置模型图层位置、大小 - 重写了逻辑着色器(Shader)、BufferUploader逻辑,让着色器能够规范的注册和使用
This commit is contained in:
@@ -8,7 +8,9 @@ import com.chuangzhou.vivid2D.render.model.util.LightSource;
|
||||
import com.chuangzhou.vivid2D.render.model.util.Mesh2D;
|
||||
import com.chuangzhou.vivid2D.render.model.util.PhysicsSystem;
|
||||
import com.chuangzhou.vivid2D.render.systems.RenderSystem;
|
||||
import com.chuangzhou.vivid2D.render.systems.ShaderSources;
|
||||
import com.chuangzhou.vivid2D.render.systems.sources.CompleteShader;
|
||||
import com.chuangzhou.vivid2D.render.systems.sources.ShaderProgram;
|
||||
import com.chuangzhou.vivid2D.render.systems.sources.ShaderManagement;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector4f;
|
||||
@@ -19,8 +21,6 @@ import org.slf4j.LoggerFactory;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
|
||||
|
||||
/**
|
||||
* vivid2D 模型完整渲染系统
|
||||
*
|
||||
@@ -106,24 +106,20 @@ public final class ModelRender {
|
||||
*/
|
||||
private static final boolean enableBlending = true;
|
||||
|
||||
private static final int SHADER_MAX_LIGHTS = 8;
|
||||
/**
|
||||
* 最大光源数量,用于限制同时启用的光源数量
|
||||
* 默认值:80
|
||||
*/
|
||||
private static final int MAX_LIGHTS = 80;
|
||||
|
||||
// ================== 着色器与资源管理 ==================
|
||||
|
||||
/**
|
||||
* 着色器程序缓存映射,按名称存储已编译的着色器程序
|
||||
* 键:着色器名称(如 "default")
|
||||
* 值:对应的着色器程序对象
|
||||
* @see ShaderSources.ShaderProgram
|
||||
*/
|
||||
private static final Map<String, ShaderSources.ShaderProgram> shaderMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 默认着色器程序,用于大多数模型的渲染
|
||||
* 包含基础的光照、纹理和变换功能
|
||||
* @see #compileDefaultShader()
|
||||
*/
|
||||
private static ShaderSources.ShaderProgram defaultProgram = null;
|
||||
private static ShaderProgram defaultProgram = null;
|
||||
|
||||
/**
|
||||
* 网格GPU资源缓存,管理已上传到GPU的网格数据
|
||||
@@ -183,7 +179,7 @@ public final class ModelRender {
|
||||
*/
|
||||
public static boolean renderLightPositions = true;
|
||||
|
||||
// ================== 内部类:ShaderSources.ShaderProgram ==================
|
||||
// ================== 内部类:ShaderProgram ==================
|
||||
|
||||
|
||||
// ================== 内部类:MeshGLResources ==================
|
||||
@@ -216,6 +212,10 @@ public final class ModelRender {
|
||||
|
||||
try {
|
||||
compileDefaultShader();
|
||||
|
||||
// 初始化所有非默认着色器的基础信息
|
||||
initNonDefaultShaders();
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
logger.error("Failed to compile default shader: {}", ex.getMessage());
|
||||
throw ex;
|
||||
@@ -229,6 +229,76 @@ public final class ModelRender {
|
||||
logger.info("ModelRender initialized successfully");
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化所有非默认着色器的基础信息(顶点坐标等)
|
||||
*/
|
||||
private static void initNonDefaultShaders() {
|
||||
List<CompleteShader> shaderList = ShaderManagement.getShaderList();
|
||||
if (shaderList == null || shaderList.isEmpty()) {
|
||||
logger.info("No shaders found to initialize");
|
||||
return;
|
||||
}
|
||||
|
||||
int nonDefaultCount = 0;
|
||||
for (CompleteShader shader : shaderList) {
|
||||
// 跳过默认着色器,只初始化非默认的
|
||||
if (shader.isDefaultShader()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取着色器程序
|
||||
ShaderProgram program = ShaderManagement.getShaderProgram(shader.getShaderName());
|
||||
if (program == null) {
|
||||
logger.warn("Shader program not found for: {}", shader.getShaderName());
|
||||
continue;
|
||||
}
|
||||
|
||||
// 设置着色器的基础uniforms(主要是顶点坐标相关的)
|
||||
initShaderBasicUniforms(program, shader);
|
||||
nonDefaultCount++;
|
||||
|
||||
logger.debug("Initialized non-default shader: {}", shader.getShaderName());
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to initialize non-default shader: {}", shader.getShaderName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Initialized {} non-default shaders", nonDefaultCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化着色器的基础uniforms(顶点坐标相关)
|
||||
*/
|
||||
private static void initShaderBasicUniforms(ShaderProgram program, CompleteShader shader) {
|
||||
program.use();
|
||||
|
||||
try {
|
||||
// 设置基础的变换矩阵为单位矩阵
|
||||
setUniformMatrix3(program, "uModelMatrix", new Matrix3f().identity());
|
||||
setUniformMatrix3(program, "uViewMatrix", new Matrix3f().identity());
|
||||
|
||||
// 设置投影矩阵(使用当前视口尺寸)
|
||||
Matrix3f projection = buildOrthoProjection(viewportWidth, viewportHeight);
|
||||
setUniformMatrix3(program, "uProjectionMatrix", projection);
|
||||
|
||||
// 设置基础颜色为白色
|
||||
setUniformVec4Internal(program, "uColor", new Vector4f(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
|
||||
// 设置基础不透明度
|
||||
setUniformFloatInternal(program, "uOpacity", 1.0f);
|
||||
|
||||
// 设置纹理单元(如果有纹理的话)
|
||||
setUniformIntInternal(program, "uTexture", 0);
|
||||
|
||||
RenderSystem.checkGLError("initShaderBasicUniforms_" + shader.getShaderName());
|
||||
|
||||
} finally {
|
||||
program.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private static void logGLInfo() {
|
||||
logger.info("OpenGL Vendor: {}", RenderSystem.getVendor());
|
||||
logger.info("OpenGL Renderer: {}", RenderSystem.getRenderer());
|
||||
@@ -238,12 +308,11 @@ public final class ModelRender {
|
||||
}
|
||||
|
||||
|
||||
private static void uploadLightsToShader(ShaderSources.ShaderProgram sp, Model2D model) {
|
||||
private static void uploadLightsToShader(ShaderProgram sp, Model2D model) {
|
||||
List<com.chuangzhou.vivid2D.render.model.util.LightSource> lights = model.getLights();
|
||||
int idx = 0;
|
||||
|
||||
// 只上传已启用的光源,最多 MAX_LIGHTS(8)
|
||||
for (int i = 0; i < lights.size() && idx < 8; i++) {
|
||||
for (int i = 0; i < lights.size() && idx < MAX_LIGHTS; i++) {
|
||||
com.chuangzhou.vivid2D.render.model.util.LightSource l = lights.get(i);
|
||||
if (!l.isEnabled()) continue;
|
||||
|
||||
@@ -267,7 +336,7 @@ public final class ModelRender {
|
||||
setUniformIntInternal(sp, "uLightCount", idx);
|
||||
|
||||
// 禁用剩余槽位(确保 shader 中不会读取到垃圾值)
|
||||
for (int i = idx; i < 8; i++) {
|
||||
for (int i = idx; i < MAX_LIGHTS; i++) {
|
||||
setUniformFloatInternal(sp, "uLightsIntensity[" + i + "]", 0f);
|
||||
setUniformIntInternal(sp, "uLightsIsAmbient[" + i + "]", 0);
|
||||
setUniformVec3Internal(sp, "uLightsColor[" + i + "]", new org.joml.Vector3f(0f, 0f, 0f));
|
||||
@@ -284,53 +353,48 @@ public final class ModelRender {
|
||||
|
||||
|
||||
private static void setupGLState() {
|
||||
RenderSystem.checkGLError("setupGLState_start");
|
||||
|
||||
RenderSystem.clearColor(CLEAR_COLOR.x, CLEAR_COLOR.y, CLEAR_COLOR.z, CLEAR_COLOR.w);
|
||||
RenderSystem.checkGLError("after_clearColor");
|
||||
|
||||
if (enableBlending) {
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.checkGLError("after_enableBlend");
|
||||
|
||||
RenderSystem.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
RenderSystem.checkGLError("after_blendFunc");
|
||||
} else {
|
||||
RenderSystem.disableBlend();
|
||||
RenderSystem.checkGLError("after_disableBlend");
|
||||
}
|
||||
|
||||
if (enableDepthTest) {
|
||||
RenderSystem.enableDepthTest();
|
||||
RenderSystem.checkGLError("after_enableDepthTest");
|
||||
|
||||
RenderSystem.depthFunc(GL11.GL_LEQUAL);
|
||||
RenderSystem.checkGLError("after_depthFunc");
|
||||
|
||||
RenderSystem.depthMask(true);
|
||||
RenderSystem.checkGLError("after_depthMask");
|
||||
|
||||
RenderSystem.clearDepth(1.0);
|
||||
RenderSystem.checkGLError("after_clearDepth");
|
||||
} else {
|
||||
RenderSystem.disableDepthTest();
|
||||
RenderSystem.checkGLError("after_disableDepthTest");
|
||||
}
|
||||
|
||||
RenderSystem.checkGLError("setupGLState");
|
||||
RenderSystem.checkGLError("after_disableCullFace");
|
||||
}
|
||||
|
||||
private static void compileDefaultShader() {
|
||||
int vs = compileShader(GL20.GL_VERTEX_SHADER, ShaderSources.VERTEX_SHADER_SRC);
|
||||
int fs = compileShader(GL20.GL_FRAGMENT_SHADER, ShaderSources.FRAGMENT_SHADER_SRC);
|
||||
int prog = linkProgram(vs, fs);
|
||||
ShaderSources.ShaderProgram sp = new ShaderSources.ShaderProgram(prog);
|
||||
shaderMap.put("default", sp);
|
||||
defaultProgram = sp;
|
||||
|
||||
sp.use();
|
||||
setUniformIntInternal(sp, "uTexture", 0);
|
||||
setUniformFloatInternal(sp, "uOpacity", 1.0f);
|
||||
setUniformVec4Internal(sp, "uColor", new Vector4f(1,1,1,1));
|
||||
setUniformIntInternal(sp, "uBlendMode", 0);
|
||||
setUniformIntInternal(sp, "uDebugMode", 0);
|
||||
setUniformIntInternal(sp, "uLightCount", 0); // 默认没有光源
|
||||
sp.stop();
|
||||
}
|
||||
|
||||
private static int compileShader(int type, String src) {
|
||||
RenderSystem.assertOnRenderThread();
|
||||
return RenderSystem.compileShader(type, src);
|
||||
}
|
||||
|
||||
private static int linkProgram(int vs, int fs) {
|
||||
RenderSystem.assertOnRenderThread();
|
||||
return RenderSystem.linkProgram(vs, fs);
|
||||
ShaderManagement.compileAllShaders();
|
||||
defaultProgram = ShaderManagement.getDefaultProgram();
|
||||
if (defaultProgram == null) {
|
||||
throw new RuntimeException("Failed to compile default shader: no default shader found");
|
||||
}
|
||||
}
|
||||
|
||||
private static void createDefaultTexture() {
|
||||
@@ -348,9 +412,8 @@ public final class ModelRender {
|
||||
for (MeshGLResources r : meshResources.values()) r.dispose();
|
||||
meshResources.clear();
|
||||
|
||||
// shaders
|
||||
for (ShaderSources.ShaderProgram sp : shaderMap.values()) sp.delete();
|
||||
shaderMap.clear();
|
||||
// 使用新的着色器管理系统清理着色器
|
||||
ShaderManagement.cleanup();
|
||||
defaultProgram = null;
|
||||
|
||||
// textures
|
||||
@@ -393,25 +456,33 @@ public final class ModelRender {
|
||||
return;
|
||||
}
|
||||
|
||||
defaultProgram.use();
|
||||
RenderSystem.checkGLError("after_use_program");
|
||||
|
||||
// 设置投影与视图
|
||||
// 设置投影与视图矩阵(所有着色器都需要)
|
||||
Matrix3f proj = buildOrthoProjection(viewportWidth, viewportHeight);
|
||||
setUniformMatrix3(defaultProgram, "uProjectionMatrix", proj);
|
||||
setUniformMatrix3(defaultProgram, "uViewMatrix", new Matrix3f().identity());
|
||||
RenderSystem.checkGLError("after_set_matrices");
|
||||
Matrix3f view = new Matrix3f().identity();
|
||||
|
||||
// 添加光源数据上传
|
||||
// 1. 首先设置默认着色器
|
||||
defaultProgram.use();
|
||||
RenderSystem.checkGLError("after_use_default_program");
|
||||
|
||||
// 设置默认着色器的投影与视图
|
||||
setUniformMatrix3(defaultProgram, "uProjectionMatrix", proj);
|
||||
setUniformMatrix3(defaultProgram, "uViewMatrix", view);
|
||||
RenderSystem.checkGLError("after_set_default_matrices");
|
||||
|
||||
// 添加光源数据上传到默认着色器
|
||||
uploadLightsToShader(defaultProgram, model);
|
||||
RenderSystem.checkGLError("after_upload_lights");
|
||||
|
||||
// 2. 设置非默认着色器的顶点坐标相关uniform
|
||||
setupNonDefaultShaders(proj, view);
|
||||
RenderSystem.checkGLError("after_setup_non_default_shaders");
|
||||
|
||||
// 在渲染光源位置前检查
|
||||
RenderSystem.checkGLError("before_render_light_positions");
|
||||
renderLightPositions(model);
|
||||
RenderSystem.checkGLError("after_render_light_positions");
|
||||
|
||||
// 递归渲染所有根部件
|
||||
// 递归渲染所有根部件(使用默认着色器)
|
||||
Matrix3f identity = new Matrix3f().identity();
|
||||
for (ModelPart p : model.getParts()) {
|
||||
if (p.getParent() != null) continue;
|
||||
@@ -428,6 +499,55 @@ public final class ModelRender {
|
||||
RenderSystem.checkGLError("render_end");
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置所有非默认着色器的顶点坐标相关uniform
|
||||
*/
|
||||
private static void setupNonDefaultShaders(Matrix3f projection, Matrix3f view) {
|
||||
List<CompleteShader> shaderList = ShaderManagement.getShaderList();
|
||||
if (shaderList == null || shaderList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存当前绑定的着色器程序
|
||||
int currentProgram = GL11.glGetInteger(GL20.GL_CURRENT_PROGRAM);
|
||||
|
||||
try {
|
||||
for (CompleteShader shader : shaderList) {
|
||||
// 跳过默认着色器
|
||||
if (shader.isDefaultShader()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取着色器程序
|
||||
ShaderProgram program = ShaderManagement.getShaderProgram(shader.getShaderName());
|
||||
if (program == null || program.programId == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
program.use();
|
||||
|
||||
// 只设置顶点坐标相关的uniform
|
||||
setUniformMatrix3(program, "uProjectionMatrix", projection);
|
||||
setUniformMatrix3(program, "uViewMatrix", view);
|
||||
|
||||
// 设置基础模型矩阵为单位矩阵
|
||||
setUniformMatrix3(program, "uModelMatrix", new Matrix3f().identity());
|
||||
|
||||
RenderSystem.checkGLError("setupNonDefaultShaders_" + shader.getShaderName());
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to setup non-default shader: {}", shader.getShaderName(), e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// 恢复之前绑定的着色器程序
|
||||
if (currentProgram != 0) {
|
||||
GL20.glUseProgram(currentProgram);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void renderLightPositions(Model2D model) {
|
||||
if (!renderLightPositions) return;
|
||||
// 设置灯泡颜色为光源的颜色
|
||||
@@ -658,39 +778,39 @@ public final class ModelRender {
|
||||
}
|
||||
|
||||
// ================== uniform 设置辅助(内部使用,确保 program 已绑定) ==================
|
||||
private static void setUniformIntInternal(ShaderSources.ShaderProgram sp, String name, int value) {
|
||||
private static void setUniformIntInternal(ShaderProgram sp, String name, int value) {
|
||||
int loc = sp.getUniformLocation(name);
|
||||
if (loc != -1) RenderSystem.uniform1i(loc, value);
|
||||
}
|
||||
|
||||
private static void setUniformVec3Internal(ShaderSources.ShaderProgram sp, String name, org.joml.Vector3f vec) {
|
||||
private static void setUniformVec3Internal(ShaderProgram sp, String name, org.joml.Vector3f vec) {
|
||||
int loc = sp.getUniformLocation(name);
|
||||
if (loc != -1) RenderSystem.uniform3f(loc, vec);
|
||||
}
|
||||
|
||||
private static void setUniformVec2Internal(ShaderSources.ShaderProgram sp, String name, org.joml.Vector2f vec) {
|
||||
private static void setUniformVec2Internal(ShaderProgram sp, String name, org.joml.Vector2f vec) {
|
||||
int loc = sp.getUniformLocation(name);
|
||||
if (loc != -1) RenderSystem.uniform2f(loc, vec);
|
||||
}
|
||||
|
||||
private static void setUniformFloatInternal(ShaderSources.ShaderProgram sp, String name, float value) {
|
||||
private static void setUniformFloatInternal(ShaderProgram sp, String name, float value) {
|
||||
int loc = sp.getUniformLocation(name);
|
||||
if (loc != -1) RenderSystem.uniform1f(loc, value);
|
||||
}
|
||||
|
||||
private static void setUniformVec4Internal(ShaderSources.ShaderProgram sp, String name, org.joml.Vector4f vec) {
|
||||
private static void setUniformVec4Internal(ShaderProgram sp, String name, org.joml.Vector4f vec) {
|
||||
int loc = sp.getUniformLocation(name);
|
||||
if (loc != -1) RenderSystem.uniform4f(loc, vec);
|
||||
}
|
||||
|
||||
private static void setUniformMatrix3(ShaderSources.ShaderProgram sp, String name, org.joml.Matrix3f m) {
|
||||
private static void setUniformMatrix3(ShaderProgram sp, String name, org.joml.Matrix3f m) {
|
||||
int loc = sp.getUniformLocation(name);
|
||||
if (loc == -1) return;
|
||||
RenderSystem.uniformMatrix3(loc, m);
|
||||
}
|
||||
|
||||
// ================== 部件属性 ==================
|
||||
private static void setPartUniforms(ShaderSources.ShaderProgram sp, ModelPart part) {
|
||||
private static void setPartUniforms(ShaderProgram sp, ModelPart part) {
|
||||
setUniformFloatInternal(sp, "uOpacity", part.getOpacity());
|
||||
int blend = 0;
|
||||
ModelPart.BlendMode bm = part.getBlendMode();
|
||||
|
||||
Reference in New Issue
Block a user