refactor(model):重构模型数据包结构并增强光源系统
- 将 AnimationLayerData 类从 util 包移动到 data 包 - 将 BufferBuilder 类从 util 包移动到 buffer 包并更新包引用 - 为 LightSource 类添加辉光(Glow)支持及相关字段 - 扩展 LightSourceData 序列化类以包含辉光相关字段 - 新增 MeshData 类用于网格数据的序列化- 更新 Model2D 和 ModelData 的包引用以适应新的类结构 - 移除 ModelData 中重复的内部类定义,统一使用 data 包中的类- 为多个类添加作者信息注解
This commit is contained in:
@@ -2,13 +2,12 @@ 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.model.util.LightSource;
|
||||
import com.chuangzhou.vivid2D.render.model.util.Mesh2D;
|
||||
import com.chuangzhou.vivid2D.render.model.util.PhysicsSystem; // 引入 PhysicsSystem
|
||||
import com.chuangzhou.vivid2D.render.model.util.Texture;
|
||||
import com.chuangzhou.vivid2D.render.model.util.PhysicsSystem;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector4f;
|
||||
import org.lwjgl.opengl.*;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
@@ -149,78 +148,116 @@ public final class ModelRender {
|
||||
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;
|
||||
|
||||
// 如果没有光源,跳过光照计算(性能更好并且保持原始贴图色)
|
||||
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); // 小环境光补偿
|
||||
// 如果没有光源,仅返回基础颜色(节约性能)
|
||||
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 += ambient;
|
||||
lighting += ambientBase;
|
||||
|
||||
// 对每个非环境光计算基于距离的衰减与简单高光
|
||||
// 对每个非环境光源计算物理式衰减 + 漫反射 + 简单高光 + 辉光(若启用)
|
||||
for (int i = 0; i < uLightCount; ++i) {
|
||||
if (uLightsIsAmbient[i] == 1) continue;
|
||||
|
||||
vec2 toLight = uLightsPos[i] - vWorldPos;
|
||||
float dist = length(toLight);
|
||||
// 标准物理式衰减
|
||||
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;
|
||||
|
||||
// 漫反射:在纯2D情景下,法线与视线近似固定(Z向),
|
||||
// 所以漫反射对所有片元是恒定的。我们用一个基于距离的柔和因子来模拟明暗变化。
|
||||
float diffuseFactor = clamp(1.0 - (dist * 0.0015), 0.0, 1.0); // 通过调节常数控制半径感觉
|
||||
// 漫反射(在二维中基于距离模拟衰减的明暗)
|
||||
// 使用更平滑的距离曲线: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;
|
||||
|
||||
// 简单高光(基于视向与反射的大致模拟,产生亮点)
|
||||
vec3 lightDir3 = normalize(vec3(toLight, 0.0));
|
||||
// 简单高光(在 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), 16.0); // 16 为高光粗糙度,可调
|
||||
float specIntensity = 0.2; // 高光强度系数
|
||||
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 = min(lighting + specularAccum, vec3(2.0));
|
||||
// 合并直接光照与高光后进行简单的色调映射(避免过曝)
|
||||
vec3 totalLighting = lighting + specularAccum;
|
||||
// 防止数值过大,进行 Reinhard tone mapping
|
||||
vec3 litMapped = toneMap(totalLighting);
|
||||
vec3 finalColor = baseColor * litMapped;
|
||||
|
||||
// 将光照应用到基础颜色
|
||||
vec3 finalColor = baseColor * totalLighting;
|
||||
// 将辉光作为屏幕加色(加法混合),然后再做一次 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);
|
||||
@@ -276,12 +313,19 @@ public final class ModelRender {
|
||||
com.chuangzhou.vivid2D.render.model.util.LightSource l = lights.get(i);
|
||||
if (!l.isEnabled()) continue;
|
||||
|
||||
// 环境光的 position 在 shader 中不会用于距离计算,但我们也上传(安全)
|
||||
// 基础属性
|
||||
setUniformVec2Internal(sp, "uLightsPos[" + idx + "]", l.isAmbient() ? new org.joml.Vector2f(0f, 0f) : l.getPosition());
|
||||
setUniformVec3Internal(sp, "uLightsColor[" + idx + "]", l.getColor());
|
||||
setUniformFloatInternal(sp, "uLightsIntensity[" + idx + "]", l.getIntensity());
|
||||
setUniformIntInternal(sp, "uLightsIsAmbient[" + idx + "]", l.isAmbient() ? 1 : 0);
|
||||
|
||||
// 辉光相关(如果没有被设置也安全地上传默认值)
|
||||
setUniformIntInternal(sp, "uLightsIsGlow[" + idx + "]", l.isGlow() ? 1 : 0);
|
||||
setUniformVec2Internal(sp, "uLightsGlowDir[" + idx + "]", l.getGlowDirection() != null ? l.getGlowDirection() : new org.joml.Vector2f(0f, 0f));
|
||||
setUniformFloatInternal(sp, "uLightsGlowIntensity[" + idx + "]", l.getGlowIntensity());
|
||||
setUniformFloatInternal(sp, "uLightsGlowRadius[" + idx + "]", l.getGlowRadius());
|
||||
setUniformFloatInternal(sp, "uLightsGlowAmount[" + idx + "]", l.getGlowAmount());
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
@@ -292,9 +336,15 @@ public final class ModelRender {
|
||||
for (int i = idx; i < 8; i++) {
|
||||
setUniformFloatInternal(sp, "uLightsIntensity[" + i + "]", 0f);
|
||||
setUniformIntInternal(sp, "uLightsIsAmbient[" + i + "]", 0);
|
||||
// color/pos 不严格必要,但清零更稳健
|
||||
setUniformVec3Internal(sp, "uLightsColor[" + i + "]", new org.joml.Vector3f(0f, 0f, 0f));
|
||||
setUniformVec2Internal(sp, "uLightsPos[" + i + "]", new org.joml.Vector2f(0f, 0f));
|
||||
|
||||
// 关闭辉光槽
|
||||
setUniformIntInternal(sp, "uLightsIsGlow[" + i + "]", 0);
|
||||
setUniformVec2Internal(sp, "uLightsGlowDir[" + i + "]", new org.joml.Vector2f(0f, 0f));
|
||||
setUniformFloatInternal(sp, "uLightsGlowIntensity[" + i + "]", 0f);
|
||||
setUniformFloatInternal(sp, "uLightsGlowRadius[" + i + "]", 0f);
|
||||
setUniformFloatInternal(sp, "uLightsGlowAmount[" + i + "]", 0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,8 +512,8 @@ public final class ModelRender {
|
||||
if (!light.isEnabled()) continue;
|
||||
|
||||
// 绘制光源位置
|
||||
com.chuangzhou.vivid2D.render.util.BufferBuilder bb =
|
||||
new com.chuangzhou.vivid2D.render.util.BufferBuilder(1 * 4);
|
||||
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();
|
||||
@@ -569,7 +619,7 @@ public final class ModelRender {
|
||||
*/
|
||||
private static void drawCircleColliderWire(Vector2f center, float radius) {
|
||||
int segments = Math.max(8, CIRCLE_SEGMENTS);
|
||||
com.chuangzhou.vivid2D.render.util.BufferBuilder bb = new com.chuangzhou.vivid2D.render.util.BufferBuilder(segments * 4);
|
||||
BufferBuilder bb = new BufferBuilder(segments * 4);
|
||||
bb.begin(GL11.GL_LINE_LOOP, segments);
|
||||
for (int i = 0; i < segments; i++) {
|
||||
double ang = 2.0 * Math.PI * i / segments;
|
||||
@@ -587,7 +637,7 @@ public final class ModelRender {
|
||||
private static void drawRectangleColliderWire(Vector2f center, float width, float height) {
|
||||
float halfW = width / 2.0f;
|
||||
float halfH = height / 2.0f;
|
||||
com.chuangzhou.vivid2D.render.util.BufferBuilder bb = new com.chuangzhou.vivid2D.render.util.BufferBuilder(4 * 4);
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user