feat(model): 添加液化笔划数据的序列化与反序列化支持
- 在 ModelData.PartData 中新增 liquifyStrokes 字段用于保存液化笔划- 实现通过反射读取 ModelPart 的液化笔划数据(兼容旧版本)- 支持多种数据结构形式的液化点读取(Vector2f、自定义类、Map) - 反序列化时自动重放液化笔划到 ModelPart- 添加 LiquifyStrokeData 和 LiquifyPointData 用于序列化存储 - 提供深度拷贝支持以确保 liquifyStrokes 数据完整复制 - 增加 ModelLoadTest 测试类用于验证模型加载与结构检查
This commit is contained in:
@@ -149,43 +149,83 @@ public final class ModelRender {
|
||||
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() {
|
||||
if (uDebugMode == 1) {
|
||||
FragColor = vec4(vWorldPos * 0.5 + 0.5, 0.0, 1.0);
|
||||
// 先采样纹理
|
||||
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;
|
||||
}
|
||||
|
||||
vec4 tex = texture(uTexture, vTexCoord);
|
||||
vec3 finalColor = tex.rgb * uColor.rgb;
|
||||
vec3 lighting = vec3(0.0);
|
||||
// 基础颜色(纹理 * 部件颜色)
|
||||
vec3 baseColor = tex.rgb * uColor.rgb;
|
||||
|
||||
for (int i = 0; i < uLightCount; i++) {
|
||||
// 全局环境光基线(可以适度提高以避免全黑)
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < uLightCount; i++) {
|
||||
// 加上基线环境光
|
||||
lighting += ambient;
|
||||
|
||||
// 对每个非环境光计算基于距离的衰减与简单高光
|
||||
for (int i = 0; i < uLightCount; ++i) {
|
||||
if (uLightsIsAmbient[i] == 1) continue;
|
||||
|
||||
float intensity = uLightsIntensity[i];
|
||||
if (intensity <= 0.0) continue;
|
||||
|
||||
vec2 lightDir = uLightsPos[i] - vWorldPos;
|
||||
float dist = length(lightDir);
|
||||
float atten = 1.0 / (1.0 + 0.1 * dist + 0.01 * dist * dist);
|
||||
lighting += uLightsColor[i] * intensity * atten;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
finalColor *= min(lighting, vec3(2.0));
|
||||
|
||||
if (uBlendMode == 1) finalColor.rgb = tex.rgb + uColor.rgb;
|
||||
else if (uBlendMode == 2) finalColor.rgb = tex.rgb * uColor.rgb;
|
||||
else if (uBlendMode == 3) finalColor.rgb = 1.0 - (1.0 - tex.rgb) * (1.0 - uColor.rgb);
|
||||
|
||||
float alpha = tex.a * uOpacity;
|
||||
if (alpha <= 0.001) discard;
|
||||
|
||||
|
||||
// 限制光照的最大值以避免过曝(可根据场景调整)
|
||||
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);
|
||||
}
|
||||
""";
|
||||
@@ -228,31 +268,33 @@ public final class ModelRender {
|
||||
}
|
||||
|
||||
private static void uploadLightsToShader(ShaderProgram sp, Model2D model) {
|
||||
List<LightSource> lights = model.getLights();
|
||||
int lightCount = Math.min(lights.size(), 8);
|
||||
List<com.chuangzhou.vivid2D.render.model.util.LightSource> lights = model.getLights();
|
||||
int idx = 0;
|
||||
|
||||
// 设置光源数量
|
||||
setUniformIntInternal(sp, "uLightCount", lightCount);
|
||||
|
||||
for (int i = 0; i < lightCount; i++) {
|
||||
LightSource l = lights.get(i);
|
||||
// 只上传已启用的光源,最多 MAX_LIGHTS(8)
|
||||
for (int i = 0; i < lights.size() && idx < 8; i++) {
|
||||
com.chuangzhou.vivid2D.render.model.util.LightSource l = lights.get(i);
|
||||
if (!l.isEnabled()) continue;
|
||||
|
||||
// 设置光源位置(环境光位置设为0)
|
||||
Vector2f pos = l.isAmbient() ? new Vector2f(0, 0) : l.getPosition();
|
||||
setUniformVec2Internal(sp, "uLightsPos[" + i + "]", pos);
|
||||
// 环境光的 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);
|
||||
|
||||
setUniformVec3Internal(sp, "uLightsColor[" + i + "]", l.getColor());
|
||||
setUniformFloatInternal(sp, "uLightsIntensity[" + i + "]", l.getIntensity());
|
||||
|
||||
// 设置是否为环境光
|
||||
setUniformIntInternal(sp, "uLightsIsAmbient[" + i + "]", l.isAmbient() ? 1 : 0);
|
||||
idx++;
|
||||
}
|
||||
|
||||
// 禁用未使用的光源
|
||||
for (int i = lightCount; i < 8; i++) {
|
||||
// 上传实际有效光源数量
|
||||
setUniformIntInternal(sp, "uLightCount", idx);
|
||||
|
||||
// 禁用剩余槽位(确保 shader 中不会读取到垃圾值)
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user