refactor(render):重构渲染系统架构
- 将 BufferBuilder 移至 systems.buffer 包并增强功能- 添加 BuiltBuffer 和 RenderState 内部类支持状态管理- 新增 BufferUploader 类处理缓冲区上传和状态应用 - 引入 RenderSystem 统一封装 OpenGL 调用 - Mesh2D 和 ModelRender 更新使用新的渲染系统接口- ModelGLPanel 适配新包结构并使用 RenderSystem 初始化 - 移除旧版 LightSource 构造函数- 整体提升渲染代码的模块化和可维护性 重要更新 - 重写渲染器 - 移除辉光,采用旧版着色器渲染,任何有关辉光的将在下一个版本彻底删除
This commit is contained in:
@@ -2,20 +2,20 @@ package com.chuangzhou.vivid2D.render;
|
||||
|
||||
import com.chuangzhou.vivid2D.render.model.Model2D;
|
||||
import com.chuangzhou.vivid2D.render.model.ModelPart;
|
||||
import com.chuangzhou.vivid2D.render.model.buffer.BufferBuilder;
|
||||
import com.chuangzhou.vivid2D.render.systems.buffer.BufferBuilder;
|
||||
import com.chuangzhou.vivid2D.render.systems.buffer.Tesselator;
|
||||
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 org.joml.Matrix3f;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector4f;
|
||||
import org.lwjgl.opengl.*;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@@ -45,82 +45,152 @@ import static org.lwjgl.opengl.GL20.glGetUniformLocation;
|
||||
* </ul>
|
||||
*
|
||||
* @author tzdwindows
|
||||
* @version 1.0
|
||||
* @version 1.2
|
||||
* @since 2025-10-13
|
||||
*/
|
||||
public final class ModelRender {
|
||||
/**
|
||||
* 渲染系统日志记录器,用于记录渲染过程中的调试信息、错误和性能数据
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(ModelRender.class);
|
||||
|
||||
/**
|
||||
* 私有构造函数,防止外部实例化 - 这是一个工具类,只包含静态方法
|
||||
*/
|
||||
private ModelRender() { /* no instances */ }
|
||||
|
||||
// ================== 全局状态 ==================
|
||||
// ================== 全局状态 ==================
|
||||
|
||||
/**
|
||||
* 渲染系统初始化状态标志,确保系统只初始化一次
|
||||
* @see #initialize()
|
||||
* @see #isInitialized()
|
||||
*/
|
||||
private static boolean initialized = false;
|
||||
|
||||
/**
|
||||
* 视口宽度(像素),定义渲染区域的大小
|
||||
* 默认值:800像素
|
||||
* @see #setViewport(int, int)
|
||||
*/
|
||||
private static int viewportWidth = 800;
|
||||
|
||||
/**
|
||||
* 视口高度(像素),定义渲染区域的大小
|
||||
* 默认值:600像素
|
||||
* @see #setViewport(int, int)
|
||||
*/
|
||||
private static int viewportHeight = 600;
|
||||
|
||||
/**
|
||||
* 清除颜色(RGBA),用于在每帧开始时清空颜色缓冲区
|
||||
* 默认值:黑色不透明 (0.0f, 0.0f, 0.0f, 1.0f)
|
||||
* @see RenderSystem#clearColor(float, float, float, float)
|
||||
*/
|
||||
private static final Vector4f CLEAR_COLOR = new Vector4f(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
/**
|
||||
* 深度测试启用标志,控制是否进行深度缓冲测试
|
||||
* 在2D渲染中通常禁用以提高性能
|
||||
* 默认值:false(禁用)
|
||||
* @see RenderSystem#enableDepthTest()
|
||||
* @see RenderSystem#disableDepthTest()
|
||||
*/
|
||||
private static final boolean enableDepthTest = false;
|
||||
|
||||
/**
|
||||
* 混合功能启用标志,控制透明度和颜色混合
|
||||
* 默认值:true(启用)
|
||||
* @see RenderSystem#enableBlend()
|
||||
* @see RenderSystem#disableBlend()
|
||||
*/
|
||||
private static final boolean enableBlending = true;
|
||||
|
||||
// 着色器与资源
|
||||
private static final Map<String, ShaderProgram> shaderMap = new HashMap<>();
|
||||
private static ShaderProgram defaultProgram = null;
|
||||
private static final int SHADER_MAX_LIGHTS = 8;
|
||||
|
||||
// ================== 着色器与资源管理 ==================
|
||||
|
||||
/**
|
||||
* 着色器程序缓存映射,按名称存储已编译的着色器程序
|
||||
* 键:着色器名称(如 "default")
|
||||
* 值:对应的着色器程序对象
|
||||
* @see ShaderSources.ShaderProgram
|
||||
*/
|
||||
private static final Map<String, ShaderSources.ShaderProgram> shaderMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 默认着色器程序,用于大多数模型的渲染
|
||||
* 包含基础的光照、纹理和变换功能
|
||||
* @see #compileDefaultShader()
|
||||
*/
|
||||
private static ShaderSources.ShaderProgram defaultProgram = null;
|
||||
|
||||
/**
|
||||
* 网格GPU资源缓存,管理已上传到GPU的网格数据
|
||||
* 键:Mesh2D对象
|
||||
* 值:对应的OpenGL资源(VAO、VBO、EBO)
|
||||
* @see MeshGLResources
|
||||
*/
|
||||
private static final Map<Mesh2D, MeshGLResources> meshResources = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 纹理单元分配器,用于管理多个纹理的绑定
|
||||
* 确保不同的纹理绑定到正确的纹理单元
|
||||
* 默认从0开始递增分配
|
||||
*/
|
||||
private static final AtomicInteger textureUnitAllocator = new AtomicInteger(0);
|
||||
|
||||
// 默认白色纹理
|
||||
/**
|
||||
* 默认白色纹理ID,当模型没有指定纹理时使用
|
||||
* 这是一个1x1的纯白色纹理,确保模型有基本的颜色显示
|
||||
* @see #createDefaultTexture()
|
||||
*/
|
||||
private static int defaultTextureId = 0;
|
||||
|
||||
// ================== 碰撞箱渲染配置 ==================
|
||||
// 是否在渲染时绘制碰撞箱(线框)
|
||||
public static boolean renderColliders = false;
|
||||
// 碰撞箱线宽
|
||||
public static float colliderLineWidth = 2.0f;
|
||||
// 碰撞箱颜色(默认白色)
|
||||
// ================== 碰撞箱渲染配置 ==================
|
||||
|
||||
/**
|
||||
* 碰撞箱渲染开关,控制是否在场景中显示物理碰撞体的轮廓
|
||||
* 调试时非常有用,可以直观看到碰撞边界
|
||||
* 默认值:true(启用)
|
||||
*/
|
||||
public static boolean renderColliders = true;
|
||||
|
||||
/**
|
||||
* 碰撞箱线框宽度,控制碰撞体轮廓线的粗细
|
||||
* 单位:像素
|
||||
* 默认值:1.0f
|
||||
*/
|
||||
public static float colliderLineWidth = 1.0f;
|
||||
|
||||
/**
|
||||
* 碰撞箱颜色(RGBA),定义碰撞体轮廓的显示颜色
|
||||
* 默认值:白色不透明 (1.0f, 1.0f, 1.0f, 1.0f)
|
||||
*/
|
||||
public static Vector4f colliderColor = new Vector4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
// 圆形碰撞体绘制细分(越高越圆)
|
||||
|
||||
/**
|
||||
* 圆形碰撞体细分数量,控制圆形碰撞体的平滑度
|
||||
* 值越高圆形越平滑,但渲染开销也越大
|
||||
* 默认值:32(在性能和视觉效果间取得平衡)
|
||||
*/
|
||||
private static final int CIRCLE_SEGMENTS = 32;
|
||||
// 是否在渲染时绘制碰撞箱
|
||||
|
||||
/**
|
||||
* 光源位置渲染开关,控制是否在场景中显示光源的位置
|
||||
* 用点状标记显示每个启用的光源位置
|
||||
* 默认值:true(启用)
|
||||
*/
|
||||
public static boolean renderLightPositions = true;
|
||||
|
||||
// ================== 内部类:ShaderProgram ==================
|
||||
private static class ShaderProgram {
|
||||
final int programId;
|
||||
final Map<String, Integer> uniformCache = new HashMap<>();
|
||||
// ================== 内部类:ShaderSources.ShaderProgram ==================
|
||||
|
||||
ShaderProgram(int programId) {
|
||||
this.programId = programId;
|
||||
}
|
||||
|
||||
void use() {
|
||||
GL20.glUseProgram(programId);
|
||||
}
|
||||
|
||||
void stop() {
|
||||
GL20.glUseProgram(0);
|
||||
}
|
||||
|
||||
int getUniformLocation(String name) {
|
||||
return uniformCache.computeIfAbsent(name, k -> {
|
||||
int loc = glGetUniformLocation(programId, k);
|
||||
if (loc == -1) {
|
||||
// debug 时可以打开
|
||||
logger.warn("Warning: uniform not found: {}", k);
|
||||
}
|
||||
return loc;
|
||||
});
|
||||
}
|
||||
|
||||
void delete() {
|
||||
if (GL20.glIsProgram(programId)) GL20.glDeleteProgram(programId);
|
||||
}
|
||||
}
|
||||
|
||||
// ================== 内部类:MeshGLResources ==================
|
||||
private static class MeshGLResources {
|
||||
int vao = 0;
|
||||
int vbo = 0;
|
||||
int ebo = 0;
|
||||
int vertexCount = 0;
|
||||
boolean initialized = false;
|
||||
|
||||
void dispose() {
|
||||
@@ -131,179 +201,19 @@ public final class ModelRender {
|
||||
}
|
||||
}
|
||||
|
||||
// ================== 着色器源 ==================
|
||||
private static final String VERTEX_SHADER_SRC =
|
||||
"""
|
||||
#version 330 core
|
||||
layout(location = 0) in vec2 aPosition;
|
||||
layout(location = 1) in vec2 aTexCoord;
|
||||
out vec2 vTexCoord;
|
||||
out vec2 vWorldPos;
|
||||
|
||||
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;
|
||||
vWorldPos = (uModelMatrix * vec3(aPosition, 1.0)).xy;
|
||||
}
|
||||
""";
|
||||
|
||||
private static final String FRAGMENT_SHADER_SRC =
|
||||
"""
|
||||
#version 330 core
|
||||
in vec2 vTexCoord;
|
||||
in vec2 vWorldPos;
|
||||
out vec4 FragColor;
|
||||
|
||||
uniform sampler2D uTexture;
|
||||
uniform vec4 uColor;
|
||||
uniform float uOpacity;
|
||||
uniform int uBlendMode;
|
||||
uniform int uDebugMode;
|
||||
|
||||
#define MAX_LIGHTS 8
|
||||
uniform vec2 uLightsPos[MAX_LIGHTS];
|
||||
uniform vec3 uLightsColor[MAX_LIGHTS];
|
||||
uniform float uLightsIntensity[MAX_LIGHTS];
|
||||
uniform int uLightsIsAmbient[MAX_LIGHTS];
|
||||
uniform int uLightCount;
|
||||
|
||||
// 辉光相关
|
||||
uniform int uLightsIsGlow[MAX_LIGHTS];
|
||||
uniform vec2 uLightsGlowDir[MAX_LIGHTS];
|
||||
uniform float uLightsGlowIntensity[MAX_LIGHTS];
|
||||
uniform float uLightsGlowRadius[MAX_LIGHTS];
|
||||
uniform float uLightsGlowAmount[MAX_LIGHTS];
|
||||
|
||||
// 常用衰减系数(可在 shader 内微调)
|
||||
const float ATT_CONST = 1.0;
|
||||
const float ATT_LINEAR = 0.09;
|
||||
const float ATT_QUAD = 0.032;
|
||||
|
||||
// 简单 Reinhard tone mapping,避免过曝
|
||||
vec3 toneMap(vec3 color) {
|
||||
return color / (color + vec3(1.0));
|
||||
}
|
||||
|
||||
void main() {
|
||||
// 先采样纹理
|
||||
vec4 tex = texture(uTexture, vTexCoord);
|
||||
float alpha = tex.a * uOpacity;
|
||||
if (alpha <= 0.001) discard;
|
||||
|
||||
// 基础颜色(纹理 * 部件颜色)
|
||||
vec3 baseColor = tex.rgb * uColor.rgb;
|
||||
|
||||
// 如果没有光源,仅返回基础颜色(节约性能)
|
||||
if (uLightCount == 0) {
|
||||
vec3 outCol = clamp(baseColor, 0.0, 1.0);
|
||||
if (uBlendMode == 1) outCol = tex.rgb + uColor.rgb;
|
||||
else if (uBlendMode == 2) outCol = tex.rgb * uColor.rgb;
|
||||
else if (uBlendMode == 3) outCol = 1.0 - (1.0 - tex.rgb) * (1.0 - uColor.rgb);
|
||||
FragColor = vec4(outCol, alpha);
|
||||
return;
|
||||
}
|
||||
|
||||
// 环境光基线
|
||||
vec3 ambientBase = vec3(0.06);
|
||||
vec3 lighting = vec3(0.0);
|
||||
vec3 glowAccum = vec3(0.0);
|
||||
vec3 specularAccum = vec3(0.0);
|
||||
|
||||
// 累积显式标记为环境光的光源
|
||||
for (int i = 0; i < uLightCount; ++i) {
|
||||
if (uLightsIsAmbient[i] == 1) {
|
||||
lighting += uLightsColor[i] * uLightsIntensity[i];
|
||||
}
|
||||
}
|
||||
lighting += ambientBase;
|
||||
|
||||
// 对每个非环境光源计算物理式衰减 + 漫反射 + 简单高光 + 辉光(若启用)
|
||||
for (int i = 0; i < uLightCount; ++i) {
|
||||
if (uLightsIsAmbient[i] == 1) continue;
|
||||
|
||||
vec2 toLight2 = uLightsPos[i] - vWorldPos;
|
||||
float dist = length(toLight2);
|
||||
// 物理风格衰减
|
||||
float attenuation = ATT_CONST / (ATT_CONST + ATT_LINEAR * dist + ATT_QUAD * dist * dist);
|
||||
float radiance = uLightsIntensity[i] * attenuation;
|
||||
|
||||
// 漫反射(在二维中基于距离模拟衰减的明暗)
|
||||
// 使用更平滑的距离曲线:max(0, 1 - (dist / (radiusApprox)))
|
||||
float radiusApprox = max(1.0, 1000.0 * attenuation); // 通过衰减估算影响半径
|
||||
float diffuseFactor = clamp(1.0 - (dist / (radiusApprox + 0.0001)), 0.0, 1.0);
|
||||
vec3 diff = uLightsColor[i] * radiance * diffuseFactor;
|
||||
lighting += diff;
|
||||
|
||||
// 简单高光(在 2D 中模拟亮点)
|
||||
vec3 viewDir = vec3(0.0, 0.0, 1.0);
|
||||
vec3 lightDir3 = normalize(vec3(toLight2, 0.0));
|
||||
vec3 normal = vec3(0.0, 0.0, 1.0);
|
||||
vec3 reflectDir = reflect(-lightDir3, normal);
|
||||
float specFactor = pow(max(dot(viewDir, reflectDir), 0.0), 32.0);
|
||||
float specIntensity = 0.25;
|
||||
specularAccum += uLightsColor[i] * radiance * specFactor * specIntensity;
|
||||
|
||||
// 若启用了辉光(glow),使用高斯风格衰减,并支持方向性辉光
|
||||
if (uLightsIsGlow[i] == 1) {
|
||||
float glowRadius = max(0.0001, uLightsGlowRadius[i]);
|
||||
float gdist = dist;
|
||||
// 高斯分布:exp(-(d^2) / (2 * sigma^2))
|
||||
float sigma = glowRadius * 0.5; // sigma = radius * 0.5(经验值)
|
||||
float gauss = exp(- (gdist * gdist) / (2.0 * sigma * sigma));
|
||||
|
||||
// 方向性因子:如果给出方向,使用方向与片元向量点积来增强朝向一侧的辉光
|
||||
float dirFactor = 1.0;
|
||||
vec2 glowDir = uLightsGlowDir[i];
|
||||
if (length(glowDir) > 0.0001) {
|
||||
vec2 ndir = normalize(glowDir);
|
||||
vec2 toFrag = normalize(vWorldPos - uLightsPos[i]);
|
||||
dirFactor = max(dot(ndir, toFrag), 0.0); // 只在方向半球贡献
|
||||
}
|
||||
float gIntensity = uLightsGlowIntensity[i];
|
||||
float gAmount = uLightsGlowAmount[i];
|
||||
vec3 glow = uLightsColor[i] * gauss * gIntensity * gAmount * dirFactor;
|
||||
glowAccum += glow;
|
||||
}
|
||||
}
|
||||
|
||||
// 合并直接光照与高光后进行简单的色调映射(避免过曝)
|
||||
vec3 totalLighting = lighting + specularAccum;
|
||||
// 防止数值过大,进行 Reinhard tone mapping
|
||||
vec3 litMapped = toneMap(totalLighting);
|
||||
vec3 finalColor = baseColor * litMapped;
|
||||
|
||||
// 将辉光作为屏幕加色(加法混合),然后再做一次 tone map 以稳定输出
|
||||
finalColor += glowAccum;
|
||||
finalColor = toneMap(finalColor);
|
||||
|
||||
// 支持简单的 blend 模式(保留已有行为)
|
||||
if (uBlendMode == 1) finalColor = tex.rgb + uColor.rgb;
|
||||
else if (uBlendMode == 2) finalColor = tex.rgb * uColor.rgb;
|
||||
else if (uBlendMode == 3) finalColor = 1.0 - (1.0 - tex.rgb) * (1.0 - uColor.rgb);
|
||||
|
||||
finalColor = clamp(finalColor, 0.0, 1.0);
|
||||
FragColor = vec4(finalColor, alpha);
|
||||
}
|
||||
""";
|
||||
|
||||
// ================== 初始化 / 清理 ==================
|
||||
public static synchronized void initialize() {
|
||||
if (initialized) return;
|
||||
|
||||
logger.info("Initializing ModelRender...");
|
||||
|
||||
// 需要在外部创建 OpenGL 上下文并调用 GL.createCapabilities()
|
||||
logGLInfo();
|
||||
// 初始化渲染系统
|
||||
RenderSystem.beginInitialization();
|
||||
RenderSystem.initRenderThread();
|
||||
|
||||
// 初始 GL 状态
|
||||
logGLInfo();
|
||||
setupGLState();
|
||||
|
||||
// 创建默认 shader
|
||||
try {
|
||||
compileDefaultShader();
|
||||
} catch (RuntimeException ex) {
|
||||
@@ -311,24 +221,24 @@ public final class ModelRender {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
// 创建默认纹理
|
||||
createDefaultTexture();
|
||||
|
||||
// 初始化视口
|
||||
GL11.glViewport(0, 0, viewportWidth, viewportHeight);
|
||||
RenderSystem.viewport(0, 0, viewportWidth, viewportHeight);
|
||||
RenderSystem.finishInitialization();
|
||||
|
||||
initialized = true;
|
||||
logger.info("ModelRender initialized successfully");
|
||||
}
|
||||
|
||||
private static void logGLInfo() {
|
||||
logger.info("OpenGL Vendor: {}", GL11.glGetString(GL11.GL_VENDOR));
|
||||
logger.info("OpenGL Renderer: {}", GL11.glGetString(GL11.GL_RENDERER));
|
||||
logger.info("OpenGL Version: {}", GL11.glGetString(GL11.GL_VERSION));
|
||||
logger.info("GLSL Version: {}", GL20.glGetString(GL20.GL_SHADING_LANGUAGE_VERSION));
|
||||
logger.info("OpenGL Vendor: {}", RenderSystem.getVendor());
|
||||
logger.info("OpenGL Renderer: {}", RenderSystem.getRenderer());
|
||||
logger.info("OpenGL Version: {}", RenderSystem.getOpenGLVersion());
|
||||
logger.info("GLSL Version: {}", RenderSystem.getGLSLVersion());
|
||||
RenderSystem.logDetailedGLInfo();
|
||||
}
|
||||
|
||||
private static void uploadLightsToShader(ShaderProgram sp, Model2D model) {
|
||||
|
||||
private static void uploadLightsToShader(ShaderSources.ShaderProgram sp, Model2D model) {
|
||||
List<com.chuangzhou.vivid2D.render.model.util.LightSource> lights = model.getLights();
|
||||
int idx = 0;
|
||||
|
||||
@@ -372,33 +282,34 @@ public final class ModelRender {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void setupGLState() {
|
||||
GL11.glClearColor(CLEAR_COLOR.x, CLEAR_COLOR.y, CLEAR_COLOR.z, CLEAR_COLOR.w);
|
||||
RenderSystem.clearColor(CLEAR_COLOR.x, CLEAR_COLOR.y, CLEAR_COLOR.z, CLEAR_COLOR.w);
|
||||
|
||||
if (enableBlending) {
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
} else {
|
||||
GL11.glDisable(GL11.GL_BLEND);
|
||||
RenderSystem.disableBlend();
|
||||
}
|
||||
|
||||
if (enableDepthTest) {
|
||||
GL11.glEnable(GL11.GL_DEPTH_TEST);
|
||||
GL11.glDepthFunc(GL11.GL_LEQUAL);
|
||||
RenderSystem.enableDepthTest();
|
||||
RenderSystem.depthFunc(GL11.GL_LEQUAL);
|
||||
RenderSystem.depthMask(true);
|
||||
RenderSystem.clearDepth(1.0);
|
||||
} else {
|
||||
GL11.glDisable(GL11.GL_DEPTH_TEST);
|
||||
RenderSystem.disableDepthTest();
|
||||
}
|
||||
|
||||
GL11.glDisable(GL11.GL_CULL_FACE);
|
||||
|
||||
checkGLError("setupGLState");
|
||||
RenderSystem.checkGLError("setupGLState");
|
||||
}
|
||||
|
||||
private static void compileDefaultShader() {
|
||||
int vs = compileShader(GL20.GL_VERTEX_SHADER, VERTEX_SHADER_SRC);
|
||||
int fs = compileShader(GL20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER_SRC);
|
||||
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);
|
||||
ShaderProgram sp = new ShaderProgram(prog);
|
||||
ShaderSources.ShaderProgram sp = new ShaderSources.ShaderProgram(prog);
|
||||
shaderMap.put("default", sp);
|
||||
defaultProgram = sp;
|
||||
|
||||
@@ -413,50 +324,19 @@ public final class ModelRender {
|
||||
}
|
||||
|
||||
private static int compileShader(int type, String src) {
|
||||
int shader = GL20.glCreateShader(type);
|
||||
GL20.glShaderSource(shader, src);
|
||||
GL20.glCompileShader(shader);
|
||||
int status = GL20.glGetShaderi(shader, GL20.GL_COMPILE_STATUS);
|
||||
if (status == GL11.GL_FALSE) {
|
||||
String log = GL20.glGetShaderInfoLog(shader);
|
||||
GL20.glDeleteShader(shader);
|
||||
throw new RuntimeException("Shader compilation failed: " + log);
|
||||
}
|
||||
return shader;
|
||||
RenderSystem.assertOnRenderThread();
|
||||
return RenderSystem.compileShader(type, src);
|
||||
}
|
||||
|
||||
private static int linkProgram(int vs, int fs) {
|
||||
int prog = GL20.glCreateProgram();
|
||||
GL20.glAttachShader(prog, vs);
|
||||
GL20.glAttachShader(prog, fs);
|
||||
GL20.glLinkProgram(prog);
|
||||
int status = GL20.glGetProgrami(prog, GL20.GL_LINK_STATUS);
|
||||
if (status == GL11.GL_FALSE) {
|
||||
String log = GL20.glGetProgramInfoLog(prog);
|
||||
GL20.glDeleteProgram(prog);
|
||||
throw new RuntimeException("Program link failed: " + log);
|
||||
}
|
||||
// shaders can be deleted after linking
|
||||
GL20.glDetachShader(prog, vs);
|
||||
GL20.glDetachShader(prog, fs);
|
||||
GL20.glDeleteShader(vs);
|
||||
GL20.glDeleteShader(fs);
|
||||
return prog;
|
||||
RenderSystem.assertOnRenderThread();
|
||||
return RenderSystem.linkProgram(vs, fs);
|
||||
}
|
||||
|
||||
private static void createDefaultTexture() {
|
||||
// 使用 GL11.glGenTextures() 获取单个 id(更直观,避免 IntBuffer 问题)
|
||||
defaultTextureId = GL11.glGenTextures();
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, defaultTextureId);
|
||||
ByteBuffer white = MemoryUtil.memAlloc(4);
|
||||
white.put((byte)255).put((byte)255).put((byte)255).put((byte)255).flip();
|
||||
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, 1, 1, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, white);
|
||||
MemoryUtil.memFree(white);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
|
||||
|
||||
checkGLError("createDefaultTexture");
|
||||
RenderSystem.assertOnRenderThread();
|
||||
defaultTextureId = RenderSystem.createDefaultTexture();
|
||||
RenderSystem.checkGLError("createDefaultTexture");
|
||||
}
|
||||
|
||||
public static synchronized void cleanup() {
|
||||
@@ -469,13 +349,13 @@ public final class ModelRender {
|
||||
meshResources.clear();
|
||||
|
||||
// shaders
|
||||
for (ShaderProgram sp : shaderMap.values()) sp.delete();
|
||||
for (ShaderSources.ShaderProgram sp : shaderMap.values()) sp.delete();
|
||||
shaderMap.clear();
|
||||
defaultProgram = null;
|
||||
|
||||
// textures
|
||||
if (defaultTextureId != 0) {
|
||||
GL11.glDeleteTextures(defaultTextureId);
|
||||
RenderSystem.deleteTextures(defaultTextureId);
|
||||
defaultTextureId = 0;
|
||||
}
|
||||
|
||||
@@ -488,6 +368,12 @@ public final class ModelRender {
|
||||
if (!initialized) throw new IllegalStateException("ModelRender not initialized");
|
||||
if (model == null) return;
|
||||
|
||||
// 确保在渲染线程
|
||||
RenderSystem.assertOnRenderThread();
|
||||
|
||||
// 添加前置错误检查
|
||||
RenderSystem.checkGLError("render_start");
|
||||
|
||||
// 物理系统更新
|
||||
PhysicsSystem physics = model.getPhysics();
|
||||
if (physics != null && physics.isEnabled()) {
|
||||
@@ -496,18 +382,34 @@ public final class ModelRender {
|
||||
|
||||
model.update(deltaTime);
|
||||
|
||||
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | (enableDepthTest ? GL11.GL_DEPTH_BUFFER_BIT : 0));
|
||||
// 检查清除操作前的状态
|
||||
RenderSystem.checkGLError("before_clear");
|
||||
RenderSystem.clear(GL11.GL_COLOR_BUFFER_BIT | (enableDepthTest ? GL11.GL_DEPTH_BUFFER_BIT : 0));
|
||||
RenderSystem.checkGLError("after_clear");
|
||||
|
||||
// 检查着色器程序
|
||||
if (defaultProgram == null || defaultProgram.programId == 0) {
|
||||
logger.error("Default shader program is not initialized");
|
||||
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");
|
||||
|
||||
// 添加光源数据上传
|
||||
uploadLightsToShader(defaultProgram, model);
|
||||
RenderSystem.checkGLError("after_upload_lights");
|
||||
|
||||
// 在渲染光源位置前检查
|
||||
RenderSystem.checkGLError("before_render_light_positions");
|
||||
renderLightPositions(model);
|
||||
RenderSystem.checkGLError("after_render_light_positions");
|
||||
|
||||
// 递归渲染所有根部件
|
||||
Matrix3f identity = new Matrix3f().identity();
|
||||
@@ -515,36 +417,81 @@ public final class ModelRender {
|
||||
if (p.getParent() != null) continue;
|
||||
renderPartRecursive(p, identity);
|
||||
}
|
||||
RenderSystem.checkGLError("after_render_parts");
|
||||
|
||||
if (renderColliders && physics != null) {
|
||||
renderPhysicsColliders(physics);
|
||||
RenderSystem.checkGLError("after_render_colliders");
|
||||
}
|
||||
|
||||
|
||||
|
||||
defaultProgram.stop();
|
||||
checkGLError("render");
|
||||
RenderSystem.checkGLError("render_end");
|
||||
}
|
||||
|
||||
private static void renderLightPositions(Model2D model) {
|
||||
if (!renderLightPositions) return;
|
||||
|
||||
GL11.glPointSize(10.0f);
|
||||
setUniformIntInternal(defaultProgram, "uDebugMode", 1);
|
||||
|
||||
// 设置灯泡颜色为光源的颜色
|
||||
for (LightSource light : model.getLights()) {
|
||||
if (!light.isEnabled()) continue;
|
||||
|
||||
// 绘制光源位置
|
||||
BufferBuilder bb =
|
||||
new BufferBuilder(1 * 4);
|
||||
bb.begin(GL11.GL_POINTS, 1);
|
||||
bb.vertex(light.getPosition().x, light.getPosition().y, 0.5f, 0.5f);
|
||||
bb.end();
|
||||
}
|
||||
// 使用光源的颜色来绘制灯泡
|
||||
Vector4f lightColor = new Vector4f(light.getColor().x, light.getColor().y, light.getColor().z, 1.0f);
|
||||
setUniformVec4Internal(defaultProgram, "uColor", lightColor);
|
||||
|
||||
setUniformIntInternal(defaultProgram, "uDebugMode", 0);
|
||||
GL11.glPointSize(1.0f);
|
||||
// 绘制灯泡形状
|
||||
drawLightBulb(light.getPosition(), light.getIntensity());
|
||||
|
||||
if (light.isAmbient()) {
|
||||
drawCrossMark(light.getPosition(), light.getIntensity());
|
||||
}
|
||||
}
|
||||
// 恢复原始颜色
|
||||
setUniformVec4Internal(defaultProgram, "uColor", new Vector4f(1,1,1,1));
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制简洁的灯泡形状
|
||||
* @param position 灯泡位置
|
||||
* @param intensity 光源强度,用于控制灯泡大小
|
||||
*/
|
||||
private static void drawLightBulb(Vector2f position, float intensity) {
|
||||
Tesselator tesselator = Tesselator.getInstance();
|
||||
BufferBuilder builder = tesselator.getBuilder();
|
||||
float bulbSize = 3.0f + (intensity / 10.0f);
|
||||
int segments = 16;
|
||||
builder.begin(RenderSystem.DRAW_TRIANGLE_FAN, segments + 2);
|
||||
|
||||
builder.vertex(position.x, position.y, 0.5f, 0.5f);
|
||||
|
||||
for (int i = 0; i <= segments; i++) {
|
||||
double angle = 2.0 * Math.PI * i / segments;
|
||||
float x = position.x + bulbSize * (float) Math.cos(angle);
|
||||
float y = position.y + bulbSize * (float) Math.sin(angle);
|
||||
builder.vertex(x, y, 0.5f, 0.5f);
|
||||
}
|
||||
tesselator.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制十字标记(用于环境光)
|
||||
*/
|
||||
private static void drawCrossMark(Vector2f position, float size) {
|
||||
Tesselator tesselator = Tesselator.getInstance();
|
||||
BufferBuilder builder = tesselator.getBuilder();
|
||||
|
||||
float crossSize = size * 0.8f;
|
||||
|
||||
// 绘制水平线
|
||||
builder.begin(RenderSystem.DRAW_LINES, 2);
|
||||
builder.vertex(position.x - crossSize, position.y, 0.5f, 0.5f);
|
||||
builder.vertex(position.x + crossSize, position.y, 0.5f, 0.5f);
|
||||
tesselator.end();
|
||||
|
||||
// 绘制垂直线
|
||||
builder.begin(RenderSystem.DRAW_LINES, 2);
|
||||
builder.vertex(position.x, position.y - crossSize, 0.5f, 0.5f);
|
||||
builder.vertex(position.x, position.y + crossSize, 0.5f, 0.5f);
|
||||
tesselator.end();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -587,7 +534,7 @@ public final class ModelRender {
|
||||
setUniformIntInternal(defaultProgram, "uTexture", 0);
|
||||
} else {
|
||||
// 使用默认白色纹理
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, defaultTextureId);
|
||||
RenderSystem.bindTexture(defaultTextureId);
|
||||
setUniformIntInternal(defaultProgram, "uTexture", 0);
|
||||
}
|
||||
|
||||
@@ -597,43 +544,78 @@ public final class ModelRender {
|
||||
// 调用 Mesh2D 的 draw 方法,传入当前使用的着色器程序和变换矩阵
|
||||
mesh.draw(defaultProgram.programId, matToUse);
|
||||
|
||||
checkGLError("renderMesh");
|
||||
RenderSystem.checkGLError("renderMesh");
|
||||
}
|
||||
|
||||
// ================== 渲染碰撞箱相关实现 ==================
|
||||
|
||||
private static void renderPhysicsColliders(PhysicsSystem physics) {
|
||||
// 设置渲染状态
|
||||
GL11.glLineWidth(colliderLineWidth);
|
||||
if (physics == null) {
|
||||
logger.warn("renderPhysicsColliders: physics system is null");
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置渲染状态
|
||||
RenderSystem.checkGLError("before_set_line_width");
|
||||
RenderSystem.lineWidth(colliderLineWidth);
|
||||
RenderSystem.checkGLError("after_set_line_width");
|
||||
|
||||
RenderSystem.activeTexture(RenderSystem.GL_TEXTURE0);
|
||||
RenderSystem.bindTexture(defaultTextureId);
|
||||
RenderSystem.checkGLError("after_bind_texture");
|
||||
|
||||
// 绑定默认纹理(shader 依赖 uTexture)并设置颜色/opacity
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, defaultTextureId);
|
||||
setUniformIntInternal(defaultProgram, "uTexture", 0);
|
||||
setUniformVec4Internal(defaultProgram, "uColor", colliderColor);
|
||||
setUniformFloatInternal(defaultProgram, "uOpacity", 1.0f);
|
||||
setUniformIntInternal(defaultProgram, "uBlendMode", 0);
|
||||
setUniformIntInternal(defaultProgram, "uDebugMode", 0);
|
||||
RenderSystem.checkGLError("after_set_uniforms");
|
||||
|
||||
// 使用单位矩阵作为 model(碰撞体顶点按世界坐标提供)
|
||||
setUniformMatrix3(defaultProgram, "uModelMatrix", new Matrix3f().identity());
|
||||
RenderSystem.checkGLError("after_set_model_matrix");
|
||||
|
||||
for (PhysicsSystem.PhysicsCollider collider : physics.getColliders()) {
|
||||
if (!collider.isEnabled()) continue;
|
||||
List<PhysicsSystem.PhysicsCollider> colliders = physics.getColliders();
|
||||
if (colliders == null || colliders.isEmpty()) {
|
||||
logger.debug("No colliders to render");
|
||||
return;
|
||||
}
|
||||
|
||||
int enabledColliders = 0;
|
||||
for (PhysicsSystem.PhysicsCollider collider : colliders) {
|
||||
if (collider == null || !collider.isEnabled()) continue;
|
||||
|
||||
RenderSystem.checkGLError("before_render_collider_" + enabledColliders);
|
||||
|
||||
if (collider instanceof PhysicsSystem.CircleCollider) {
|
||||
PhysicsSystem.CircleCollider c = (PhysicsSystem.CircleCollider) collider;
|
||||
drawCircleColliderWire(c.getCenter(), c.getRadius());
|
||||
if (c.getCenter() != null && c.getRadius() > 0) {
|
||||
drawCircleColliderWire(c.getCenter(), c.getRadius());
|
||||
enabledColliders++;
|
||||
} else {
|
||||
logger.warn("Invalid CircleCollider: center={}, radius={}", c.getCenter(), c.getRadius());
|
||||
}
|
||||
} else if (collider instanceof PhysicsSystem.RectangleCollider) {
|
||||
PhysicsSystem.RectangleCollider r = (PhysicsSystem.RectangleCollider) collider;
|
||||
drawRectangleColliderWire(r.getCenter(), r.getWidth(), r.getHeight());
|
||||
if (r.getCenter() != null && r.getWidth() > 0 && r.getHeight() > 0) {
|
||||
drawRectangleColliderWire(r.getCenter(), r.getWidth(), r.getHeight());
|
||||
enabledColliders++;
|
||||
} else {
|
||||
logger.warn("Invalid RectangleCollider: center={}, width={}, height={}",
|
||||
r.getCenter(), r.getWidth(), r.getHeight());
|
||||
}
|
||||
} else {
|
||||
// 未知类型:尝试调用 collidesWith 以获取位置(跳过)
|
||||
logger.warn("Unknown collider type: {}", collider.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
RenderSystem.checkGLError("after_render_collider_" + enabledColliders);
|
||||
}
|
||||
|
||||
logger.debug("Rendered {} enabled colliders", enabledColliders);
|
||||
|
||||
// 恢复默认线宽
|
||||
GL11.glLineWidth(1.0f);
|
||||
RenderSystem.lineWidth(1.0f);
|
||||
RenderSystem.checkGLError("after_reset_line_width");
|
||||
}
|
||||
|
||||
|
||||
@@ -643,16 +625,18 @@ public final class ModelRender {
|
||||
*/
|
||||
private static void drawCircleColliderWire(Vector2f center, float radius) {
|
||||
int segments = Math.max(8, CIRCLE_SEGMENTS);
|
||||
BufferBuilder bb = new BufferBuilder(segments * 4);
|
||||
bb.begin(GL11.GL_LINE_LOOP, segments);
|
||||
|
||||
Tesselator tesselator = Tesselator.getInstance();
|
||||
BufferBuilder builder = tesselator.getBuilder();
|
||||
|
||||
builder.begin(RenderSystem.DRAW_LINE_LOOP, segments);
|
||||
for (int i = 0; i < segments; i++) {
|
||||
double ang = 2.0 * Math.PI * i / segments;
|
||||
float x = center.x + radius * (float) Math.cos(ang);
|
||||
float y = center.y + radius * (float) Math.sin(ang);
|
||||
// 给常量 texcoord
|
||||
bb.vertex(x, y, 0.5f, 0.5f);
|
||||
builder.vertex(x, y, 0.5f, 0.5f);
|
||||
}
|
||||
bb.end();
|
||||
tesselator.end();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -661,117 +645,52 @@ public final class ModelRender {
|
||||
private static void drawRectangleColliderWire(Vector2f center, float width, float height) {
|
||||
float halfW = width / 2.0f;
|
||||
float halfH = height / 2.0f;
|
||||
BufferBuilder bb = new BufferBuilder(4 * 4);
|
||||
bb.begin(GL11.GL_LINE_LOOP, 4);
|
||||
bb.vertex(center.x - halfW, center.y - halfH, 0.5f, 0.5f);
|
||||
bb.vertex(center.x + halfW, center.y - halfH, 0.5f, 0.5f);
|
||||
bb.vertex(center.x + halfW, center.y + halfH, 0.5f, 0.5f);
|
||||
bb.vertex(center.x - halfW, center.y + halfH, 0.5f, 0.5f);
|
||||
bb.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 float[] (x,y,u,v interleaved) 绘制 GL_LINE_LOOP
|
||||
*/
|
||||
private static void drawLineLoopFromFloatArray(float[] interleavedXYUV, int vertexCount) {
|
||||
// 创建 VAO/VBO
|
||||
int vao = GL30.glGenVertexArrays();
|
||||
int vbo = GL15.glGenBuffers();
|
||||
Tesselator tesselator = Tesselator.getInstance();
|
||||
BufferBuilder builder = tesselator.getBuilder();
|
||||
|
||||
GL30.glBindVertexArray(vao);
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo);
|
||||
|
||||
// 上传数据
|
||||
FloatBuffer fb = MemoryUtil.memAllocFloat(interleavedXYUV.length);
|
||||
fb.put(interleavedXYUV).flip();
|
||||
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, fb, GL15.GL_DYNAMIC_DRAW);
|
||||
MemoryUtil.memFree(fb);
|
||||
|
||||
// attrib 0 -> aPosition (vec2)
|
||||
GL20.glEnableVertexAttribArray(0);
|
||||
GL20.glVertexAttribPointer(0, 2, GL11.GL_FLOAT, false, 4 * Float.BYTES, 0);
|
||||
|
||||
// attrib 1 -> aTexCoord (vec2) (提供常量 texcoord)
|
||||
GL20.glEnableVertexAttribArray(1);
|
||||
GL20.glVertexAttribPointer(1, 2, GL11.GL_FLOAT, false, 4 * Float.BYTES, 2 * Float.BYTES);
|
||||
|
||||
// 绘制线环
|
||||
GL11.glDrawArrays(GL11.GL_LINE_LOOP, 0, vertexCount);
|
||||
|
||||
// 清理
|
||||
GL20.glDisableVertexAttribArray(0);
|
||||
GL20.glDisableVertexAttribArray(1);
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
GL30.glBindVertexArray(0);
|
||||
|
||||
GL15.glDeleteBuffers(vbo);
|
||||
GL30.glDeleteVertexArrays(vao);
|
||||
|
||||
checkGLError("drawLineLoopFromFloatArray");
|
||||
builder.begin(RenderSystem.DRAW_LINE_LOOP, 4);
|
||||
builder.vertex(center.x - halfW, center.y - halfH, 0.5f, 0.5f);
|
||||
builder.vertex(center.x + halfW, center.y - halfH, 0.5f, 0.5f);
|
||||
builder.vertex(center.x + halfW, center.y + halfH, 0.5f, 0.5f);
|
||||
builder.vertex(center.x - halfW, center.y + halfH, 0.5f, 0.5f);
|
||||
tesselator.end();
|
||||
}
|
||||
|
||||
// ================== uniform 设置辅助(内部使用,确保 program 已绑定) ==================
|
||||
private static void setUniformIntInternal(ShaderProgram sp, String name, int value) {
|
||||
private static void setUniformIntInternal(ShaderSources.ShaderProgram sp, String name, int value) {
|
||||
int loc = sp.getUniformLocation(name);
|
||||
if (loc != -1) GL20.glUniform1i(loc, value);
|
||||
if (loc != -1) RenderSystem.uniform1i(loc, value);
|
||||
}
|
||||
|
||||
private static void setUniformVec3Internal(ShaderProgram sp, String name, org.joml.Vector3f vec) {
|
||||
private static void setUniformVec3Internal(ShaderSources.ShaderProgram sp, String name, org.joml.Vector3f vec) {
|
||||
int loc = sp.getUniformLocation(name);
|
||||
if (loc != -1) {
|
||||
GL20.glUniform3f(loc, vec.x, vec.y, vec.z);
|
||||
}
|
||||
if (loc != -1) RenderSystem.uniform3f(loc, vec);
|
||||
}
|
||||
|
||||
private static void setUniformVec2Internal(ShaderProgram sp, String name, org.joml.Vector2f vec) {
|
||||
private static void setUniformVec2Internal(ShaderSources.ShaderProgram sp, String name, org.joml.Vector2f vec) {
|
||||
int loc = sp.getUniformLocation(name);
|
||||
if (loc != -1) {
|
||||
GL20.glUniform2f(loc, vec.x, vec.y);
|
||||
}
|
||||
if (loc != -1) RenderSystem.uniform2f(loc, vec);
|
||||
}
|
||||
|
||||
private static void setUniformFloatInternal(ShaderProgram sp, String name, float value) {
|
||||
private static void setUniformFloatInternal(ShaderSources.ShaderProgram sp, String name, float value) {
|
||||
int loc = sp.getUniformLocation(name);
|
||||
if (loc != -1) GL20.glUniform1f(loc, value);
|
||||
if (loc != -1) RenderSystem.uniform1f(loc, value);
|
||||
}
|
||||
|
||||
private static void setUniformVec4Internal(ShaderProgram sp, String name, Vector4f vec) {
|
||||
private static void setUniformVec4Internal(ShaderSources.ShaderProgram sp, String name, org.joml.Vector4f vec) {
|
||||
int loc = sp.getUniformLocation(name);
|
||||
if (loc != -1) GL20.glUniform4f(loc, vec.x, vec.y, vec.z, vec.w);
|
||||
if (loc != -1) RenderSystem.uniform4f(loc, vec);
|
||||
}
|
||||
|
||||
private static void setUniformMatrix3(ShaderProgram sp, String name, Matrix3f m) {
|
||||
private static void setUniformMatrix3(ShaderSources.ShaderProgram sp, String name, org.joml.Matrix3f m) {
|
||||
int loc = sp.getUniformLocation(name);
|
||||
if (loc == -1) return;
|
||||
FloatBuffer fb = MemoryUtil.memAllocFloat(9);
|
||||
try {
|
||||
m.get(fb);
|
||||
GL20.glUniformMatrix3fv(loc, false, fb);
|
||||
} finally {
|
||||
MemoryUtil.memFree(fb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 外部可用的统一设置(会自动切换到默认程序)
|
||||
private static void setUniformInt(String name, int value) {
|
||||
defaultProgram.use();
|
||||
setUniformIntInternal(defaultProgram, name, value);
|
||||
defaultProgram.stop();
|
||||
}
|
||||
private static void setUniformFloat(String name, float value) {
|
||||
defaultProgram.use();
|
||||
setUniformFloatInternal(defaultProgram, name, value);
|
||||
defaultProgram.stop();
|
||||
}
|
||||
private static void setUniformVec4(String name, Vector4f v) {
|
||||
defaultProgram.use();
|
||||
setUniformVec4Internal(defaultProgram, name, v);
|
||||
defaultProgram.stop();
|
||||
RenderSystem.uniformMatrix3(loc, m);
|
||||
}
|
||||
|
||||
// ================== 部件属性 ==================
|
||||
private static void setPartUniforms(ShaderProgram sp, ModelPart part) {
|
||||
private static void setPartUniforms(ShaderSources.ShaderProgram sp, ModelPart part) {
|
||||
setUniformFloatInternal(sp, "uOpacity", part.getOpacity());
|
||||
int blend = 0;
|
||||
ModelPart.BlendMode bm = part.getBlendMode();
|
||||
@@ -804,28 +723,7 @@ public final class ModelRender {
|
||||
public static void setViewport(int width, int height) {
|
||||
viewportWidth = Math.max(1, width);
|
||||
viewportHeight = Math.max(1, height);
|
||||
GL11.glViewport(0, 0, viewportWidth, viewportHeight);
|
||||
}
|
||||
|
||||
public static void setClearColor(float r, float g, float b, float a) {
|
||||
GL11.glClearColor(r,g,b,a);
|
||||
}
|
||||
|
||||
private static void checkGLError(String op) {
|
||||
int e = GL11.glGetError();
|
||||
if (e != GL11.GL_NO_ERROR) {
|
||||
//logger.error("OpenGL error during {}: {}", op, getGLErrorString(e));
|
||||
}
|
||||
}
|
||||
|
||||
private static String getGLErrorString(int err) {
|
||||
switch (err) {
|
||||
case GL11.GL_INVALID_ENUM: return "GL_INVALID_ENUM";
|
||||
case GL11.GL_INVALID_VALUE: return "GL_INVALID_VALUE";
|
||||
case GL11.GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
|
||||
case GL11.GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
|
||||
default: return "Unknown(0x" + Integer.toHexString(err) + ")";
|
||||
}
|
||||
RenderSystem.viewport(0, 0, viewportWidth, viewportHeight);
|
||||
}
|
||||
|
||||
// ================== 辅助:外部获取状态 ==================
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package com.chuangzhou.vivid2D.render;
|
||||
package com.chuangzhou.vivid2D.render.awt;
|
||||
|
||||
import com.chuangzhou.vivid2D.render.ModelRender;
|
||||
import com.chuangzhou.vivid2D.render.model.Model2D;
|
||||
import com.chuangzhou.vivid2D.render.systems.RenderSystem;
|
||||
import org.lwjgl.glfw.*;
|
||||
import org.lwjgl.opengl.GL;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -127,19 +128,24 @@ public class ModelGLPanel extends JPanel {
|
||||
GLFW.glfwMakeContextCurrent(windowId);
|
||||
GL.createCapabilities();
|
||||
|
||||
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
|
||||
// 使用 RenderSystem 初始化 OpenGL 状态
|
||||
RenderSystem.beginInitialization();
|
||||
RenderSystem.initRenderThread();
|
||||
|
||||
RenderSystem.pixelStore(RenderSystem.GL_PACK_ALIGNMENT, 1);
|
||||
|
||||
// 初始化 OpenGL 状态
|
||||
GL11.glEnable(GL11.GL_DEPTH_TEST);
|
||||
RenderSystem.enableDepthTest();
|
||||
|
||||
// 检查是否支持多重采样
|
||||
if (GL.getCapabilities().OpenGL13) {
|
||||
GL11.glEnable(GL13.GL_MULTISAMPLE);
|
||||
if (RenderSystem.isExtensionSupported("GL_ARB_multisample")) {
|
||||
RenderSystem.enable(RenderSystem.GL_MULTISAMPLE);
|
||||
logger.info("多重采样已启用");
|
||||
} else {
|
||||
logger.info("不支持多重采样,跳过启用");
|
||||
}
|
||||
|
||||
GL11.glViewport(0, 0, width, height);
|
||||
RenderSystem.viewport(0, 0, width, height);
|
||||
|
||||
// 按当前宽高分配像素读取缓冲
|
||||
int pixelCount = Math.max(1, width * height);
|
||||
@@ -150,6 +156,8 @@ public class ModelGLPanel extends JPanel {
|
||||
|
||||
ModelRender.initialize();
|
||||
|
||||
RenderSystem.finishInitialization();
|
||||
|
||||
// 在正确的上下文中加载模型(可能会耗时)
|
||||
loadModelInContext();
|
||||
|
||||
@@ -257,9 +265,9 @@ public class ModelGLPanel extends JPanel {
|
||||
Model2D currentModel = modelRef.get();
|
||||
if (currentModel != null) {
|
||||
try {
|
||||
// 清除缓冲区
|
||||
GL11.glClearColor(0.18f, 0.18f, 0.25f, 1f);
|
||||
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
||||
// 使用 RenderSystem 清除缓冲区
|
||||
RenderSystem.setClearColor(0.18f, 0.18f, 0.25f, 1f);
|
||||
RenderSystem.clear(RenderSystem.GL_COLOR_BUFFER_BIT | RenderSystem.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// 渲染模型
|
||||
ModelRender.render(1.0f / 60f, currentModel);
|
||||
@@ -302,8 +310,8 @@ public class ModelGLPanel extends JPanel {
|
||||
* 渲染默认背景
|
||||
*/
|
||||
private void renderDefaultBackground() {
|
||||
GL11.glClearColor(0.1f, 0.1f, 0.15f, 1f);
|
||||
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
||||
RenderSystem.setClearColor(0.1f, 0.1f, 0.15f, 1f);
|
||||
RenderSystem.clear(RenderSystem.GL_COLOR_BUFFER_BIT | RenderSystem.GL_DEPTH_BUFFER_BIT);
|
||||
readPixelsToImage();
|
||||
}
|
||||
|
||||
@@ -328,8 +336,8 @@ public class ModelGLPanel extends JPanel {
|
||||
}
|
||||
|
||||
pixelBuffer.clear();
|
||||
// 从 GPU 读取 RGBA 字节到本地缓冲
|
||||
GL11.glReadPixels(0, 0, w, h, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixelBuffer);
|
||||
// 从 GPU 读取 RGBA 字节到本地缓冲 - 使用 RenderSystem
|
||||
RenderSystem.readPixels(0, 0, w, h, RenderSystem.GL_RGBA, RenderSystem.GL_UNSIGNED_BYTE, pixelBuffer);
|
||||
|
||||
// 以 int 批量读取(依赖本机字节序),然后转换为带 alpha 的 ARGB 并垂直翻转
|
||||
IntBuffer ib = pixelBuffer.asIntBuffer();
|
||||
@@ -539,7 +547,7 @@ public class ModelGLPanel extends JPanel {
|
||||
GLFW.glfwSetWindowSize(windowId, this.width, this.height);
|
||||
|
||||
// 更新 OpenGL 视口与 ModelRender 的视口
|
||||
GL11.glViewport(0, 0, this.width, this.height);
|
||||
RenderSystem.viewport(0, 0, this.width, this.height);
|
||||
ModelRender.setViewport(this.width, this.height);
|
||||
|
||||
// 重新分配像素读取缓冲区(释放旧的)
|
||||
@@ -1,119 +0,0 @@
|
||||
package com.chuangzhou.vivid2D.render.model.buffer;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
* 简化版 BufferBuilder,用于按顶点流构建并一次性绘制几何体。
|
||||
* 每个顶点格式: float x, float y, float u, float v (共4个 float)
|
||||
*
|
||||
* 用法:
|
||||
* BufferBuilder bb = new BufferBuilder();
|
||||
* bb.begin(GL11.GL_LINE_LOOP, 16);
|
||||
* bb.vertex(x,y,u,v);
|
||||
* ...
|
||||
* bb.end(); // 立即绘制并 cleanup
|
||||
*
|
||||
* 设计原则:简单、可靠、方便把临时多顶点数据提交到 GPU。
|
||||
* @author tzdwindows 7
|
||||
*/
|
||||
public class BufferBuilder {
|
||||
private static final int COMPONENTS_PER_VERTEX = 4; // x,y,u,v
|
||||
private float[] array;
|
||||
private int size; // float 数量
|
||||
private int vertexCount;
|
||||
private int mode; // GL mode
|
||||
|
||||
public BufferBuilder() {
|
||||
this(256); // 默认容量:256 floats -> 64 顶点
|
||||
}
|
||||
|
||||
public BufferBuilder(int initialFloatCapacity) {
|
||||
this.array = new float[Math.max(16, initialFloatCapacity)];
|
||||
this.size = 0;
|
||||
this.vertexCount = 0;
|
||||
this.mode = GL11.GL_TRIANGLES;
|
||||
}
|
||||
|
||||
private void ensureCapacity(int additionalFloats) {
|
||||
int need = size + additionalFloats;
|
||||
if (need > array.length) {
|
||||
int newCap = array.length;
|
||||
while (newCap < need) newCap <<= 1;
|
||||
float[] na = new float[newCap];
|
||||
System.arraycopy(array, 0, na, 0, size);
|
||||
array = na;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始构建,传入要绘制的 GL 模式(例如 GL11.GL_LINE_LOOP)
|
||||
* estimatedVertexCount 可传 0 表示不估计
|
||||
*/
|
||||
public void begin(int glMode, int estimatedVertexCount) {
|
||||
this.mode = glMode;
|
||||
this.size = 0;
|
||||
this.vertexCount = 0;
|
||||
if (estimatedVertexCount > 0) {
|
||||
ensureCapacity(estimatedVertexCount * COMPONENTS_PER_VERTEX);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加顶点:x,y,u,v
|
||||
*/
|
||||
public void vertex(float x, float y, float u, float v) {
|
||||
ensureCapacity(COMPONENTS_PER_VERTEX);
|
||||
array[size++] = x;
|
||||
array[size++] = y;
|
||||
array[size++] = u;
|
||||
array[size++] = v;
|
||||
vertexCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即上传并绘制,然后释放临时 GPU 资源(方便、线程不复杂)。
|
||||
* 如果你想缓存 VAO/VBO 以便反复绘制,可以扩展本类。
|
||||
*/
|
||||
public void end() {
|
||||
if (vertexCount == 0) return;
|
||||
|
||||
// upload buffer
|
||||
FloatBuffer fb = MemoryUtil.memAllocFloat(size);
|
||||
fb.put(array, 0, size).flip();
|
||||
|
||||
int vao = GL30.glGenVertexArrays();
|
||||
int vbo = GL15.glGenBuffers();
|
||||
|
||||
GL30.glBindVertexArray(vao);
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo);
|
||||
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, fb, GL15.GL_DYNAMIC_DRAW);
|
||||
|
||||
// layout: attrib 0 -> vec2 position (x,y)
|
||||
GL20.glEnableVertexAttribArray(0);
|
||||
GL20.glVertexAttribPointer(0, 2, GL11.GL_FLOAT, false, COMPONENTS_PER_VERTEX * Float.BYTES, 0);
|
||||
|
||||
// layout: attrib 1 -> vec2 texcoord (u,v)
|
||||
GL20.glEnableVertexAttribArray(1);
|
||||
GL20.glVertexAttribPointer(1, 2, GL11.GL_FLOAT, false, COMPONENTS_PER_VERTEX * Float.BYTES, 2 * Float.BYTES);
|
||||
|
||||
// draw
|
||||
GL11.glDrawArrays(mode, 0, vertexCount);
|
||||
|
||||
// cleanup
|
||||
GL20.glDisableVertexAttribArray(0);
|
||||
GL20.glDisableVertexAttribArray(1);
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
GL30.glBindVertexArray(0);
|
||||
|
||||
GL15.glDeleteBuffers(vbo);
|
||||
GL30.glDeleteVertexArrays(vao);
|
||||
|
||||
MemoryUtil.memFree(fb);
|
||||
}
|
||||
}
|
||||
@@ -38,17 +38,17 @@ public class LightSource {
|
||||
}
|
||||
|
||||
// 带辉光参数
|
||||
public LightSource(Vector2f pos, Color color, float intensity,
|
||||
boolean isGlow, Vector2f glowDirection, float glowIntensity, float glowRadius, float glowAmount) {
|
||||
this.position = pos;
|
||||
this.color = colorToVector3f(color);
|
||||
this.intensity = intensity;
|
||||
this.isGlow = isGlow;
|
||||
this.glowDirection = glowDirection != null ? glowDirection : new Vector2f(0f, 0f);
|
||||
this.glowIntensity = glowIntensity;
|
||||
this.glowRadius = glowRadius;
|
||||
this.glowAmount = glowAmount;
|
||||
}
|
||||
//public LightSource(Vector2f pos, Color color, float intensity,
|
||||
// boolean isGlow, Vector2f glowDirection, float glowIntensity, float glowRadius, float glowAmount) {
|
||||
// this.position = pos;
|
||||
// this.color = colorToVector3f(color);
|
||||
// this.intensity = intensity;
|
||||
// this.isGlow = isGlow;
|
||||
// this.glowDirection = glowDirection != null ? glowDirection : new Vector2f(0f, 0f);
|
||||
// this.glowIntensity = glowIntensity;
|
||||
// this.glowRadius = glowRadius;
|
||||
// this.glowAmount = glowAmount;
|
||||
//}
|
||||
|
||||
public static Vector3f colorToVector3f(Color color) {
|
||||
if (color == null) return new Vector3f(1, 1, 1);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.chuangzhou.vivid2D.render.model.util;
|
||||
|
||||
import com.chuangzhou.vivid2D.render.systems.RenderSystem;
|
||||
import org.joml.Vector2f;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
@@ -411,6 +412,9 @@ public class Mesh2D {
|
||||
*/
|
||||
public void uploadToGPU() {
|
||||
if (uploaded) return;
|
||||
|
||||
RenderSystem.assertOnRenderThread();
|
||||
|
||||
// 组织 interleaved buffer (x,y,u,v)
|
||||
int vertexCount = getVertexCount();
|
||||
int floatCount = vertexCount * 4; // x,y,u,v
|
||||
@@ -421,29 +425,32 @@ public class Mesh2D {
|
||||
try {
|
||||
getIndexBuffer(ib);
|
||||
|
||||
vaoId = GL30.glGenVertexArrays();
|
||||
GL30.glBindVertexArray(vaoId);
|
||||
// 使用 RenderSystem 生成 VAO
|
||||
vaoId = RenderSystem.glGenVertexArrays();
|
||||
RenderSystem.glBindVertexArray(() -> vaoId);
|
||||
|
||||
vboId = GL15.glGenBuffers();
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboId);
|
||||
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, interleaved, GL15.GL_STATIC_DRAW);
|
||||
// 使用 RenderSystem 生成和绑定 VBO
|
||||
vboId = RenderSystem.glGenBuffers();
|
||||
RenderSystem.glBindBuffer(RenderSystem.GL_ARRAY_BUFFER, () -> vboId);
|
||||
RenderSystem.glBufferData(RenderSystem.GL_ARRAY_BUFFER, interleaved, RenderSystem.GL_STATIC_DRAW);
|
||||
|
||||
eboId = GL15.glGenBuffers();
|
||||
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, eboId);
|
||||
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, ib, GL15.GL_STATIC_DRAW);
|
||||
// 使用 RenderSystem 生成和绑定 EBO
|
||||
eboId = RenderSystem.glGenBuffers();
|
||||
RenderSystem.glBindBuffer(RenderSystem.GL_ELEMENT_ARRAY_BUFFER, () -> eboId);
|
||||
RenderSystem.glBufferData(RenderSystem.GL_ELEMENT_ARRAY_BUFFER, ib, RenderSystem.GL_STATIC_DRAW);
|
||||
|
||||
int stride = 4 * Float.BYTES; // x,y,u,v
|
||||
|
||||
// position attrib (location 0) -> vec2
|
||||
GL20.glEnableVertexAttribArray(0);
|
||||
GL20.glVertexAttribPointer(0, 2, GL11.GL_FLOAT, false, stride, 0);
|
||||
RenderSystem.enableVertexAttribArray(0);
|
||||
RenderSystem.vertexAttribPointer(0, 2, RenderSystem.GL_FLOAT, false, stride, 0);
|
||||
|
||||
// uv attrib (location 1) -> vec2
|
||||
GL20.glEnableVertexAttribArray(1);
|
||||
GL20.glVertexAttribPointer(1, 2, GL11.GL_FLOAT, false, stride, 2 * Float.BYTES);
|
||||
RenderSystem.enableVertexAttribArray(1);
|
||||
RenderSystem.vertexAttribPointer(1, 2, RenderSystem.GL_FLOAT, false, stride, 2 * Float.BYTES);
|
||||
|
||||
// unbind VAO (keep EBO bound to VAO on unbind)
|
||||
GL30.glBindVertexArray(0);
|
||||
RenderSystem.glBindVertexArray(() -> 0);
|
||||
|
||||
indexCount = indices.length;
|
||||
uploaded = true;
|
||||
@@ -454,7 +461,7 @@ public class Mesh2D {
|
||||
} finally {
|
||||
MemoryUtil.memFree(interleaved);
|
||||
// unbind array buffer
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
RenderSystem.glBindBuffer(RenderSystem.GL_ARRAY_BUFFER, () -> 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,46 +480,33 @@ public class Mesh2D {
|
||||
texture.bind();
|
||||
}
|
||||
|
||||
// 绑定 VAO
|
||||
GL30.glBindVertexArray(vaoId);
|
||||
// 绑定 VAO - 使用 RenderSystem
|
||||
RenderSystem.glBindVertexArray(() -> vaoId);
|
||||
|
||||
// 关键修改:使用传入的着色器程序
|
||||
GL20.glUseProgram(shaderProgram);
|
||||
// 使用着色器程序 - 使用 RenderSystem
|
||||
RenderSystem.useProgram(shaderProgram);
|
||||
|
||||
// 将 modelMatrix 上传到 shader 的 uniform "uModelMatrix"(与ModelRender中的命名一致)
|
||||
int loc = GL20.glGetUniformLocation(shaderProgram, "uModelMatrix");
|
||||
// 将 modelMatrix 上传到 shader 的 uniform
|
||||
int loc = RenderSystem.getUniformLocation(shaderProgram, "uModelMatrix");
|
||||
if (loc == -1) {
|
||||
// 如果找不到 uModelMatrix,尝试 uModel
|
||||
loc = GL20.glGetUniformLocation(shaderProgram, "uModel");
|
||||
loc = RenderSystem.getUniformLocation(shaderProgram, "uModel");
|
||||
}
|
||||
|
||||
if (loc != -1) {
|
||||
java.nio.FloatBuffer fb = org.lwjgl.system.MemoryUtil.memAllocFloat(9);
|
||||
try {
|
||||
modelMatrix.get(fb);
|
||||
fb.flip();
|
||||
GL20.glUniformMatrix3fv(loc, false, fb);
|
||||
|
||||
// 调试信息
|
||||
//System.out.println("Mesh2D: 应用模型矩阵到着色器 - " + name);
|
||||
//System.out.printf(" [%.2f, %.2f, %.2f]\n", modelMatrix.m00(), modelMatrix.m01(), modelMatrix.m02());
|
||||
//System.out.printf(" [%.2f, %.2f, %.2f]\n", modelMatrix.m10(), modelMatrix.m11(), modelMatrix.m12());
|
||||
//System.out.printf(" [%.2f, %.2f, %.2f]\n", modelMatrix.m20(), modelMatrix.m21(), modelMatrix.m22());
|
||||
} finally {
|
||||
org.lwjgl.system.MemoryUtil.memFree(fb);
|
||||
}
|
||||
RenderSystem.uniformMatrix3(loc, modelMatrix);
|
||||
} else {
|
||||
//logger.warn("警告: 着色器中未找到 uModelMatrix 或 uModel uniform");
|
||||
}
|
||||
|
||||
// 绘制
|
||||
GL11.glDrawElements(GL11.GL_TRIANGLES, indexCount, GL11.GL_UNSIGNED_INT, 0);
|
||||
// 绘制 - 使用 RenderSystem
|
||||
RenderSystem.drawElements(RenderSystem.DRAW_TRIANGLES, indexCount,
|
||||
RenderSystem.GL_UNSIGNED_INT, 0);
|
||||
|
||||
// 解绑
|
||||
GL30.glBindVertexArray(0);
|
||||
// 解绑 VAO
|
||||
RenderSystem.glBindVertexArray(() -> 0);
|
||||
|
||||
if (texture != null) {
|
||||
texture.unbind();
|
||||
texture.unbind(); // 需要检查 texture.unbind() 是否也需要封装
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.chuangzhou.vivid2D.render.model.util;
|
||||
|
||||
import com.chuangzhou.vivid2D.render.systems.RenderSystem;
|
||||
import org.lwjgl.opengl.GL;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
@@ -127,9 +128,6 @@ public class Texture {
|
||||
public int getGLWrap() { return glWrap; }
|
||||
}
|
||||
|
||||
// ==================== 构造器 ====================
|
||||
|
||||
|
||||
// ==================== STB 图像加载 ====================
|
||||
|
||||
static {
|
||||
@@ -463,25 +461,9 @@ public class Texture {
|
||||
throw new IllegalArgumentException("Invalid texture unit: " + textureUnit);
|
||||
}
|
||||
|
||||
// 如果支持 GL13,保存当前活动纹理单元并激活目标单元,绑定纹理后保持可以恢复
|
||||
boolean hasGL13 = GL.getCapabilities().OpenGL13;
|
||||
if (hasGL13) {
|
||||
try {
|
||||
// 保存之前的活动纹理单元(返回值是 GL_TEXTUREi 的枚举值)
|
||||
previousActiveTexture = GL11.glGetInteger(GL13.GL_ACTIVE_TEXTURE);
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0 + textureUnit);
|
||||
} catch (Exception e) {
|
||||
// 如果查询/激活失败,重置标志,不影响后续绑定(仍尝试绑定)
|
||||
previousActiveTexture = -1;
|
||||
System.err.println("Warning: failed to change active texture unit: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
previousActiveTexture = -1;
|
||||
}
|
||||
|
||||
// 绑定纹理到当前(已激活的)纹理单元
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId);
|
||||
checkGLError("glBindTexture");
|
||||
RenderSystem.activeTexture(GL13.GL_TEXTURE0 + textureUnit);
|
||||
RenderSystem.bindTexture(textureId);
|
||||
RenderSystem.checkGLError("Texture.bind");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -495,18 +477,15 @@ public class Texture {
|
||||
* 解绑纹理
|
||||
*/
|
||||
public void unbind() {
|
||||
// 解绑当前纹理目标
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
|
||||
|
||||
// 如果之前保存了活动纹理单元并且支持 GL13,尝试恢复它
|
||||
try {
|
||||
if (previousActiveTexture != -1 && GL.getCapabilities().OpenGL13) {
|
||||
GL13.glActiveTexture(previousActiveTexture);
|
||||
RenderSystem.bindTexture(0);
|
||||
if (previousActiveTexture != -1) {
|
||||
try {
|
||||
RenderSystem.activeTexture(previousActiveTexture);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Warning: failed to restore previous active texture unit: " + e.getMessage());
|
||||
} finally {
|
||||
previousActiveTexture = -1;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("Warning: failed to restore previous active texture unit: " + e.getMessage());
|
||||
} finally {
|
||||
previousActiveTexture = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -519,11 +498,7 @@ public class Texture {
|
||||
public void dispose() {
|
||||
if (!disposed) {
|
||||
try {
|
||||
IntBuffer textures = MemoryUtil.memAllocInt(1);
|
||||
textures.put(textureId);
|
||||
textures.flip();
|
||||
GL11.glDeleteTextures(textures);
|
||||
MemoryUtil.memFree(textures);
|
||||
RenderSystem.deleteTextures(textureId);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error disposing texture: " + e.getMessage());
|
||||
}
|
||||
@@ -680,10 +655,10 @@ public class Texture {
|
||||
ByteBuffer pixelData = MemoryUtil.memAlloc(dataSize);
|
||||
|
||||
// 从GPU读取纹理数据
|
||||
GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, format.getGLFormat(), type.getGLType(), pixelData);
|
||||
RenderSystem.getTexImage(GL11.GL_TEXTURE_2D, 0, format.getGLFormat(), type.getGLType(), pixelData);
|
||||
|
||||
// 检查OpenGL错误
|
||||
checkGLError("glGetTexImage");
|
||||
RenderSystem.checkGLError("Texture.extractTextureData");
|
||||
|
||||
pixelData.flip();
|
||||
return pixelData;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,168 @@
|
||||
package com.chuangzhou.vivid2D.render.systems;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
|
||||
|
||||
/**
|
||||
* 着色器源代码
|
||||
*
|
||||
* @author tzdwindows 7
|
||||
* @version 1.0
|
||||
* @since 2025-10-16
|
||||
*/
|
||||
public class ShaderSources {
|
||||
public static final String VERTEX_SHADER_SRC =
|
||||
"""
|
||||
#version 330 core
|
||||
layout(location = 0) in vec2 aPosition;
|
||||
layout(location = 1) in vec2 aTexCoord;
|
||||
out vec2 vTexCoord;
|
||||
out vec2 vWorldPos;
|
||||
|
||||
uniform mat3 uModelMatrix;
|
||||
uniform mat3 uViewMatrix;
|
||||
uniform mat3 uProjectionMatrix;
|
||||
|
||||
void main() {
|
||||
// 使用 3x3 矩阵链计算屏幕位置(假设矩阵是二维仿射)
|
||||
vec3 p = uProjectionMatrix * uViewMatrix * uModelMatrix * vec3(aPosition, 1.0);
|
||||
gl_Position = vec4(p.xy, 0.0, 1.0);
|
||||
vTexCoord = aTexCoord;
|
||||
// 输出 world-space 位置供 fragment shader 使用(仅 xy)
|
||||
vWorldPos = (uModelMatrix * vec3(aPosition, 1.0)).xy;
|
||||
}
|
||||
""";
|
||||
|
||||
public static final String FRAGMENT_SHADER_SRC =
|
||||
"""
|
||||
#version 330 core
|
||||
in vec2 vTexCoord;
|
||||
in vec2 vWorldPos;
|
||||
out vec4 FragColor;
|
||||
|
||||
uniform sampler2D uTexture;
|
||||
uniform vec4 uColor;
|
||||
uniform float uOpacity;
|
||||
uniform int uBlendMode;
|
||||
uniform int uDebugMode;
|
||||
|
||||
#define MAX_LIGHTS 8
|
||||
uniform vec2 uLightsPos[MAX_LIGHTS];
|
||||
uniform vec3 uLightsColor[MAX_LIGHTS];
|
||||
uniform float uLightsIntensity[MAX_LIGHTS];
|
||||
uniform int uLightsIsAmbient[MAX_LIGHTS];
|
||||
uniform int uLightCount;
|
||||
|
||||
// 常用衰减系数(可在 shader 内微调)
|
||||
const float ATT_CONST = 1.0;
|
||||
const float ATT_LINEAR = 0.09;
|
||||
const float ATT_QUAD = 0.032;
|
||||
|
||||
void main() {
|
||||
// 先采样纹理
|
||||
vec4 tex = texture(uTexture, vTexCoord);
|
||||
float alpha = tex.a * uOpacity;
|
||||
if (alpha <= 0.001) discard;
|
||||
|
||||
// 如果没有光源,跳过光照计算(性能更好并且保持原始贴图色)
|
||||
if (uLightCount == 0) {
|
||||
vec3 base = tex.rgb * uColor.rgb;
|
||||
// 简单的色调映射(防止数值过大)
|
||||
base = clamp(base, 0.0, 1.0);
|
||||
FragColor = vec4(base, alpha);
|
||||
return;
|
||||
}
|
||||
|
||||
// 基础颜色(纹理 * 部件颜色)
|
||||
vec3 baseColor = tex.rgb * uColor.rgb;
|
||||
|
||||
// 全局环境光基线(可以适度提高以避免全黑)
|
||||
vec3 ambient = vec3(0.06); // 小环境光补偿
|
||||
vec3 lighting = vec3(0.0);
|
||||
vec3 specularAccum = vec3(0.0);
|
||||
|
||||
// 累积环境光(来自被标记为环境光的光源)
|
||||
for (int i = 0; i < uLightCount; ++i) {
|
||||
if (uLightsIsAmbient[i] == 1) {
|
||||
lighting += uLightsColor[i] * uLightsIntensity[i];
|
||||
}
|
||||
}
|
||||
// 加上基线环境光
|
||||
lighting += ambient;
|
||||
|
||||
// 对每个非环境光计算基于距离的衰减与简单高光
|
||||
for (int i = 0; i < uLightCount; ++i) {
|
||||
if (uLightsIsAmbient[i] == 1) continue;
|
||||
|
||||
vec2 toLight = uLightsPos[i] - vWorldPos;
|
||||
float dist = length(toLight);
|
||||
// 标准物理式衰减
|
||||
float attenuation = ATT_CONST / (ATT_CONST + ATT_LINEAR * dist + ATT_QUAD * dist * dist);
|
||||
|
||||
// 强度受光源强度和衰减影响
|
||||
float radiance = uLightsIntensity[i] * attenuation;
|
||||
|
||||
// 漫反射:在纯2D情景下,法线与视线近似固定(Z向),
|
||||
// 所以漫反射对所有片元是恒定的。我们用一个基于距离的柔和因子来模拟明暗变化。
|
||||
float diffuseFactor = clamp(1.0 - (dist * 0.0015), 0.0, 1.0); // 通过调节常数控制半径感觉
|
||||
vec3 diff = uLightsColor[i] * radiance * diffuseFactor;
|
||||
lighting += diff;
|
||||
|
||||
// 简单高光(基于视向与反射的大致模拟,产生亮点)
|
||||
vec3 lightDir3 = normalize(vec3(toLight, 0.0));
|
||||
vec3 viewDir = vec3(0.0, 0.0, 1.0);
|
||||
vec3 normal = vec3(0.0, 0.0, 1.0);
|
||||
vec3 reflectDir = reflect(-lightDir3, normal);
|
||||
float specFactor = pow(max(dot(viewDir, reflectDir), 0.0), 16.0); // 16 为高光粗糙度,可调
|
||||
float specIntensity = 0.2; // 高光强度系数
|
||||
specularAccum += uLightsColor[i] * radiance * specFactor * specIntensity;
|
||||
}
|
||||
|
||||
// 限制光照的最大值以避免过曝(可根据场景调整)
|
||||
vec3 totalLighting = min(lighting + specularAccum, vec3(2.0));
|
||||
|
||||
// 将光照应用到基础颜色
|
||||
vec3 finalColor = baseColor * totalLighting;
|
||||
|
||||
// 支持简单混合模式(保留原有行为)
|
||||
if (uBlendMode == 1) finalColor = tex.rgb + uColor.rgb;
|
||||
else if (uBlendMode == 2) finalColor = tex.rgb * uColor.rgb;
|
||||
else if (uBlendMode == 3) finalColor = 1.0 - (1.0 - tex.rgb) * (1.0 - uColor.rgb);
|
||||
|
||||
finalColor = clamp(finalColor, 0.0, 1.0);
|
||||
FragColor = vec4(finalColor, alpha);
|
||||
}
|
||||
""";
|
||||
|
||||
|
||||
public static class ShaderProgram {
|
||||
public final int programId;
|
||||
public final Map<String, Integer> uniformCache = new HashMap<>();
|
||||
|
||||
public ShaderProgram(int programId) {
|
||||
this.programId = programId;
|
||||
}
|
||||
|
||||
public void use() {
|
||||
GL20.glUseProgram(programId);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
GL20.glUseProgram(0);
|
||||
}
|
||||
|
||||
public int getUniformLocation(String name) {
|
||||
return uniformCache.computeIfAbsent(name, k -> {
|
||||
return glGetUniformLocation(programId, k);
|
||||
});
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
if (GL20.glIsProgram(programId)) GL20.glDeleteProgram(programId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
package com.chuangzhou.vivid2D.render.systems.buffer;
|
||||
|
||||
import com.chuangzhou.vivid2D.render.systems.RenderSystem;
|
||||
import org.joml.Vector4f;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
* 简化版 BufferBuilder,用于按顶点流构建并一次性绘制几何体。
|
||||
* 每个顶点格式: float x, float y, float u, float v (共4个 float)
|
||||
*
|
||||
* 用法:
|
||||
* BufferBuilder bb = new BufferBuilder();
|
||||
* bb.begin(GL11.GL_LINE_LOOP, 16);
|
||||
* bb.vertex(x,y,u,v);
|
||||
* ...
|
||||
* bb.end(); // 立即绘制并 cleanup
|
||||
*
|
||||
* 设计原则:简单、可靠、方便把临时多顶点数据提交到 GPU。
|
||||
*
|
||||
*
|
||||
* @version 1.2
|
||||
* @since 2025-10-16
|
||||
* @author tzdwindows
|
||||
*/
|
||||
public class BufferBuilder {
|
||||
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(BufferBuilder.class);
|
||||
private static final int COMPONENTS_PER_VERTEX = 4; // x,y,u,v
|
||||
private float[] array;
|
||||
private int size; // float 数量
|
||||
private int vertexCount;
|
||||
private int mode; // GL mode
|
||||
private RenderState renderState = new RenderState();
|
||||
private boolean stateSaved = false;
|
||||
// 内置状态,用于构建完成的缓冲区
|
||||
public static class BuiltBuffer {
|
||||
private final int vao;
|
||||
private final int vbo;
|
||||
private final int vertexCount;
|
||||
private final int mode;
|
||||
private final RenderState renderState;
|
||||
|
||||
public BuiltBuffer(int vao, int vbo, int vertexCount, int mode, RenderState renderState) {
|
||||
this.vao = vao;
|
||||
this.vbo = vbo;
|
||||
this.vertexCount = vertexCount;
|
||||
this.mode = mode;
|
||||
this.renderState = renderState;
|
||||
}
|
||||
|
||||
public RenderState renderState() { return renderState; }
|
||||
|
||||
public int vao() { return vao; }
|
||||
public int vbo() { return vbo; }
|
||||
public int vertexCount() { return vertexCount; }
|
||||
public int mode() { return mode; }
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染状态容器类
|
||||
*/
|
||||
public static class RenderState {
|
||||
public int textureId = 0;
|
||||
public int textureUnit = 0;
|
||||
public int shaderProgram = 0;
|
||||
public Vector4f color = new Vector4f(1, 1, 1, 1);
|
||||
public float opacity = 1.0f;
|
||||
public int blendMode = 0;
|
||||
public boolean depthTest = false;
|
||||
public boolean blending = true;
|
||||
|
||||
// 保存当前状态
|
||||
public void saveCurrentState() {
|
||||
this.textureId = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
|
||||
this.shaderProgram = GL11.glGetInteger(GL20.GL_CURRENT_PROGRAM);
|
||||
}
|
||||
|
||||
// 应用保存的状态
|
||||
public void applyState() {
|
||||
if (textureId != 0) {
|
||||
RenderSystem.bindTexture(textureId);
|
||||
}
|
||||
if (shaderProgram != 0) {
|
||||
RenderSystem.useProgram(shaderProgram);
|
||||
}
|
||||
}
|
||||
|
||||
// 复制状态
|
||||
public RenderState copy() {
|
||||
RenderState copy = new RenderState();
|
||||
copy.textureId = this.textureId;
|
||||
copy.textureUnit = this.textureUnit;
|
||||
copy.shaderProgram = this.shaderProgram;
|
||||
copy.color = new Vector4f(this.color);
|
||||
copy.opacity = this.opacity;
|
||||
copy.blendMode = this.blendMode;
|
||||
copy.depthTest = this.depthTest;
|
||||
copy.blending = this.blending;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public BufferBuilder() {
|
||||
this(256); // 默认容量:256 floats -> 64 顶点
|
||||
}
|
||||
|
||||
public BufferBuilder(int initialFloatCapacity) {
|
||||
this.array = new float[Math.max(16, initialFloatCapacity)];
|
||||
this.size = 0;
|
||||
this.vertexCount = 0;
|
||||
this.mode = RenderSystem.DRAW_TRIANGLES;
|
||||
}
|
||||
|
||||
private void ensureCapacity(int additionalFloats) {
|
||||
int need = size + additionalFloats;
|
||||
if (need > array.length) {
|
||||
int newCap = array.length;
|
||||
while (newCap < need) newCap <<= 1;
|
||||
float[] na = new float[newCap];
|
||||
System.arraycopy(array, 0, na, 0, size);
|
||||
array = na;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始构建,传入要绘制的 GL 模式(例如 GL11.GL_LINE_LOOP)
|
||||
* estimatedVertexCount 可传 0 表示不估计
|
||||
*/
|
||||
public void begin(int glMode, int estimatedVertexCount) {
|
||||
this.mode = glMode;
|
||||
this.size = 0;
|
||||
this.vertexCount = 0;
|
||||
|
||||
// 保存当前渲染状态
|
||||
if (!stateSaved) {
|
||||
renderState.saveCurrentState();
|
||||
stateSaved = true;
|
||||
}
|
||||
|
||||
if (estimatedVertexCount > 0) {
|
||||
ensureCapacity(estimatedVertexCount * COMPONENTS_PER_VERTEX);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置纹理状态
|
||||
*/
|
||||
public void setTexture(int textureId, int textureUnit) {
|
||||
this.renderState.textureId = textureId;
|
||||
this.renderState.textureUnit = textureUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置着色器程序
|
||||
*/
|
||||
public void setShader(int programId) {
|
||||
this.renderState.shaderProgram = programId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置颜色
|
||||
*/
|
||||
public void setColor(Vector4f color) {
|
||||
this.renderState.color = new Vector4f(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置透明度
|
||||
*/
|
||||
public void setOpacity(float opacity) {
|
||||
this.renderState.opacity = opacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加顶点:x,y,u,v
|
||||
*/
|
||||
public void vertex(float x, float y, float u, float v) {
|
||||
ensureCapacity(COMPONENTS_PER_VERTEX);
|
||||
array[size++] = x;
|
||||
array[size++] = y;
|
||||
array[size++] = u;
|
||||
array[size++] = v;
|
||||
vertexCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束构建并返回 BuiltBuffer(不立即绘制)
|
||||
*/
|
||||
public BuiltBuffer end() {
|
||||
if (vertexCount == 0) return null;
|
||||
|
||||
RenderSystem.assertOnRenderThread();
|
||||
|
||||
// 上传缓冲区数据
|
||||
FloatBuffer fb = MemoryUtil.memAllocFloat(size);
|
||||
fb.put(array, 0, size).flip();
|
||||
|
||||
// 创建 GPU 资源
|
||||
int vao = RenderSystem.glGenVertexArrays();
|
||||
int vbo = RenderSystem.glGenBuffers();
|
||||
|
||||
RenderSystem.glBindVertexArray(() -> vao);
|
||||
RenderSystem.glBindBuffer(RenderSystem.GL_ARRAY_BUFFER, () -> vbo);
|
||||
RenderSystem.glBufferData(RenderSystem.GL_ARRAY_BUFFER, fb, RenderSystem.GL_DYNAMIC_DRAW);
|
||||
|
||||
// 设置顶点属性
|
||||
RenderSystem.enableVertexAttribArray(0);
|
||||
RenderSystem.vertexAttribPointer(0, 2, RenderSystem.GL_FLOAT, false,
|
||||
COMPONENTS_PER_VERTEX * Float.BYTES, 0);
|
||||
|
||||
RenderSystem.enableVertexAttribArray(1);
|
||||
RenderSystem.vertexAttribPointer(1, 2, RenderSystem.GL_FLOAT, false,
|
||||
COMPONENTS_PER_VERTEX * Float.BYTES, 2 * Float.BYTES);
|
||||
|
||||
MemoryUtil.memFree(fb);
|
||||
RenderSystem.glBindBuffer(RenderSystem.GL_ARRAY_BUFFER, () -> 0);
|
||||
RenderSystem.glBindVertexArray(() -> 0);
|
||||
|
||||
// 创建状态副本
|
||||
RenderState stateCopy = renderState.copy();
|
||||
|
||||
// 重置状态保存标志
|
||||
stateSaved = false;
|
||||
|
||||
return new BuiltBuffer(vao, vbo, vertexCount, mode, stateCopy);
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即上传并绘制(传统方式,向后兼容)
|
||||
*/
|
||||
public void endImmediate() {
|
||||
BuiltBuffer buffer = end();
|
||||
if (buffer != null) {
|
||||
BufferUploader.drawWithShader(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理构建器创建的所有 GPU 资源
|
||||
* 应该在确定不再需要这些资源时调用
|
||||
*/
|
||||
public static void dispose(BuiltBuffer buffer) {
|
||||
if (buffer != null) {
|
||||
RenderSystem.glDeleteVertexArrays(buffer.vao());
|
||||
RenderSystem.glDeleteBuffers(buffer.vbo());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除构建器状态以便重用
|
||||
*/
|
||||
public void clear() {
|
||||
this.size = 0;
|
||||
this.vertexCount = 0;
|
||||
}
|
||||
|
||||
public int getVertexCount() {
|
||||
return vertexCount;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return vertexCount == 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.chuangzhou.vivid2D.render.systems.buffer;
|
||||
|
||||
import com.chuangzhou.vivid2D.render.systems.RenderSystem;
|
||||
|
||||
/**
|
||||
* 缓冲区上传器
|
||||
*
|
||||
* @version 1.0
|
||||
* @author tzdwindows
|
||||
*/
|
||||
public class BufferUploader {
|
||||
|
||||
public static void drawWithShader(BufferBuilder.BuiltBuffer buffer) {
|
||||
if (buffer == null) return;
|
||||
|
||||
RenderSystem.assertOnRenderThread();
|
||||
|
||||
// 保存当前状态
|
||||
BufferBuilder.RenderState currentState = new BufferBuilder.RenderState();
|
||||
currentState.saveCurrentState();
|
||||
|
||||
try {
|
||||
// 应用缓冲区指定的渲染状态
|
||||
BufferBuilder.RenderState bufferState = buffer.renderState();
|
||||
applyRenderState(bufferState);
|
||||
|
||||
// 绑定 VAO 和绘制
|
||||
if (buffer.vao() != 0) {
|
||||
RenderSystem.glBindVertexArray(() -> buffer.vao());
|
||||
}
|
||||
|
||||
if (buffer.vertexCount() > 0) {
|
||||
RenderSystem.drawArrays(buffer.mode(), 0, buffer.vertexCount());
|
||||
}
|
||||
|
||||
if (buffer.vao() != 0) {
|
||||
RenderSystem.glBindVertexArray(() -> 0);
|
||||
}
|
||||
|
||||
} finally {
|
||||
// 恢复之前的状态
|
||||
restoreRenderState(currentState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用指定的渲染状态
|
||||
*/
|
||||
private static void applyRenderState(BufferBuilder.RenderState state) {
|
||||
// 应用纹理
|
||||
if (state.textureId != 0) {
|
||||
RenderSystem.activeTexture(RenderSystem.GL_TEXTURE0 + state.textureUnit);
|
||||
RenderSystem.bindTexture(state.textureId);
|
||||
}
|
||||
|
||||
// 应用着色器
|
||||
if (state.shaderProgram != 0) {
|
||||
RenderSystem.useProgram(state.shaderProgram);
|
||||
}
|
||||
|
||||
// 应用混合模式
|
||||
if (state.blending) {
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
} else {
|
||||
RenderSystem.disableBlend();
|
||||
}
|
||||
|
||||
// 应用深度测试
|
||||
if (state.depthTest) {
|
||||
RenderSystem.enableDepthTest();
|
||||
} else {
|
||||
RenderSystem.disableDepthTest();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复之前的渲染状态
|
||||
*/
|
||||
private static void restoreRenderState(BufferBuilder.RenderState previousState) {
|
||||
previousState.applyState();
|
||||
}
|
||||
|
||||
public static void draw(BufferBuilder.BuiltBuffer buffer) {
|
||||
drawWithShader(buffer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.chuangzhou.vivid2D.render.systems.buffer;
|
||||
|
||||
import com.chuangzhou.vivid2D.render.systems.RenderSystem;
|
||||
|
||||
/**
|
||||
* 管理缓存
|
||||
*
|
||||
* @version 1.0
|
||||
* @author tzdwindows
|
||||
*/
|
||||
public class Tesselator {
|
||||
private static final int DEFAULT_BUFFER_SIZE = 2097152; // 2MB
|
||||
private static final Tesselator INSTANCE = new Tesselator();
|
||||
|
||||
private final BufferBuilder builder;
|
||||
|
||||
public static Tesselator getInstance() {
|
||||
RenderSystem.assertOnRenderThreadOrInit();
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public Tesselator(int bufferSize) {
|
||||
this.builder = new BufferBuilder(bufferSize);
|
||||
}
|
||||
|
||||
public Tesselator() {
|
||||
this(DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
public void end() {
|
||||
RenderSystem.assertOnRenderThread();
|
||||
BufferUploader.drawWithShader(this.builder.end());
|
||||
}
|
||||
|
||||
public BufferBuilder getBuilder() {
|
||||
return this.builder;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import com.chuangzhou.vivid2D.render.model.ModelPart;
|
||||
import com.chuangzhou.vivid2D.render.model.util.LightSource;
|
||||
import com.chuangzhou.vivid2D.render.model.util.Mesh2D;
|
||||
import com.chuangzhou.vivid2D.render.model.util.Texture;
|
||||
import com.chuangzhou.vivid2D.render.systems.RenderSystem;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector3f;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
@@ -136,15 +137,15 @@ public class ModelRenderLightingTest {
|
||||
body.addChild(rightLeg);
|
||||
|
||||
LightSource ambientLight = new LightSource(
|
||||
Color.GRAY,
|
||||
Color.lightGray,
|
||||
0.3f
|
||||
);
|
||||
ambientLight.setAmbient(true);
|
||||
model.addLight(ambientLight);
|
||||
|
||||
// 添加光源
|
||||
model.addLight(new LightSource(new Vector2f(-100, -100), Color.ORANGE, 100f));
|
||||
//model.addLight(new LightSource(new Vector2f(150, 150), new Color(1f, 1f, 1f), 200f));
|
||||
model.addLight(new LightSource(new Vector2f(-100, -100), Color.lightGray, 200f));
|
||||
model.addLight(new LightSource(new Vector2f(150, 150), new Color(1f, 1f, 1f), 200f));
|
||||
}
|
||||
|
||||
private Texture createSolidTexture(int w, int h, int rgba) {
|
||||
@@ -221,7 +222,7 @@ public class ModelRenderLightingTest {
|
||||
}
|
||||
|
||||
private void render() {
|
||||
ModelRender.setClearColor(0.18f,0.18f,0.25f,1.0f);
|
||||
RenderSystem.setClearColor(0.18f,0.18f,0.25f,1.0f);
|
||||
ModelRender.render(1f/60f, model);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.chuangzhou.vivid2D.render.model.ModelPart;
|
||||
import com.chuangzhou.vivid2D.render.model.util.Mesh2D;
|
||||
import com.chuangzhou.vivid2D.render.model.util.PhysicsSystem;
|
||||
import com.chuangzhou.vivid2D.render.model.util.Texture;
|
||||
import com.chuangzhou.vivid2D.render.systems.RenderSystem;
|
||||
import org.joml.Vector2f;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.glfw.GLFWErrorCallback;
|
||||
@@ -261,7 +262,7 @@ public class ModelRenderTest {
|
||||
}
|
||||
|
||||
private void render() {
|
||||
ModelRender.setClearColor(0.18f, 0.18f, 0.25f, 1.0f);
|
||||
RenderSystem.setClearColor(0.18f, 0.18f, 0.25f, 1.0f);
|
||||
ModelRender.render(1.0f / 60.0f, testModel);
|
||||
|
||||
// 每 5 秒输出一次统计
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.chuangzhou.vivid2D.render.model.Model2D;
|
||||
import com.chuangzhou.vivid2D.render.model.ModelPart;
|
||||
import com.chuangzhou.vivid2D.render.model.util.Mesh2D;
|
||||
import com.chuangzhou.vivid2D.render.model.util.Texture;
|
||||
import com.chuangzhou.vivid2D.render.systems.RenderSystem;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector2f;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
@@ -214,7 +215,7 @@ public class ModelRenderTest2 {
|
||||
}
|
||||
|
||||
private void render() {
|
||||
ModelRender.setClearColor(0.2f, 0.2f, 0.3f, 1.0f);
|
||||
RenderSystem.setClearColor(0.2f, 0.2f, 0.3f, 1.0f);
|
||||
ModelRender.render(1.0f / 60.0f, testModel);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.chuangzhou.vivid2D.render.model.ModelPart;
|
||||
import com.chuangzhou.vivid2D.render.model.util.Mesh2D;
|
||||
import com.chuangzhou.vivid2D.render.model.util.Texture;
|
||||
import com.chuangzhou.vivid2D.render.model.util.PhysicsSystem;
|
||||
import com.chuangzhou.vivid2D.render.systems.RenderSystem;
|
||||
import org.joml.Vector2f;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.glfw.GLFWErrorCallback;
|
||||
@@ -666,7 +667,7 @@ public class ModelTest2 {
|
||||
}
|
||||
|
||||
private void render(long last) {
|
||||
ModelRender.setClearColor(0.1f, 0.1f, 0.15f, 1.0f);
|
||||
RenderSystem.setClearColor(0.1f, 0.1f, 0.15f, 1.0f);
|
||||
ModelRender.render(last, physicsModel);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.chuangzhou.vivid2D.test;
|
||||
|
||||
import com.chuangzhou.vivid2D.render.ModelGLPanel;
|
||||
import com.chuangzhou.vivid2D.render.awt.ModelGLPanel;
|
||||
import com.chuangzhou.vivid2D.render.model.Model2D;
|
||||
import com.chuangzhou.vivid2D.render.model.ModelPart;
|
||||
import com.chuangzhou.vivid2D.render.model.util.Mesh2D;
|
||||
|
||||
Reference in New Issue
Block a user