feat: 多光源——点光源类型(距离衰减,位置来自 Transform)

- LightComponent 加 Type(Directional/Point)+ radius;点光位置取
  实体 Transform(固有组件首次实际受益)
- LightData shader 契约扩为 4×vec4(color/direction/position/params,
  每灯 64B,未用字段置零);UBO 688→816B
- 光照循环按类型分支:方向光无衰减;点光 L 指向光源 + 平方距离衰减,
  衰减半径外跳过;CSM 阴影只来自第 0 盏方向光
- main.cpp:SunTemple 场景加暖橙火坑光 + 冷蓝填充光(点光);
  KeyLight/FillLight 改 designated initializer
This commit is contained in:
2026-09-23 17:46:25 +08:00
parent d8c481ce48
commit 2c4efc5165
11 changed files with 108 additions and 40 deletions
+25 -5
View File
@@ -3,8 +3,10 @@
const int MAX_LIGHTS = 4;
struct Light {
vec4 direction;
vec4 color;
vec4 color; // rgb = 颜色,a = 强度
vec4 direction; // 方向光:xyz = 方向(已归一)
vec4 position; // 点光:xyz = 世界位置
vec4 params; // x = 类型(0=方向,1=点),y = 衰减半径
};
layout(location = 0) in vec2 fragUV;
@@ -92,15 +94,33 @@ void main() {
vec3 result = ubo.ambientColor.rgb * albedo;
for (int i = 0; i < MAX_LIGHTS; ++i) {
vec3 L = normalize(-ubo.lights[i].direction.xyz);
// 按类型分支:方向光无衰减;点光方向指向光源 + 平方距离衰减
vec3 L;
float atten = 1.0;
if (ubo.lights[i].params.x > 0.5) {
vec3 toLight = ubo.lights[i].position.xyz - fragWorldPos;
float d = length(toLight);
if (d >= ubo.lights[i].params.y) continue; // 衰减半径外,跳过
L = toLight / d;
float a = clamp(1.0 - (d * d) /
(ubo.lights[i].params.y * ubo.lights[i].params.y),
0.0, 1.0);
atten = a * a; // 平方衰减,边缘更柔和
} else {
L = normalize(-ubo.lights[i].direction.xyz);
}
float diff = max(dot(N, L), 0.0);
// Blinn-Phong 高光(半程向量;specular 图做强度系数)
vec3 H = normalize(L + V);
float spec = pow(max(dot(N, H), 0.0), 32.0) * specIntensity;
float shade = (i == 0) ? ShadowFactor(N, fragViewDepth) : 1.0;
// 阴影只来自第 0 盏方向光(CSM)
float shade = (i == 0 && ubo.lights[0].params.x < 0.5)
? ShadowFactor(N, fragViewDepth) : 1.0;
result += ubo.lights[i].color.rgb * ubo.lights[i].color.a *
(albedo * diff + vec3(spec)) * shade;
(albedo * diff + vec3(spec)) * atten * shade;
}
// 自发光不经光照/阴影直接叠加