feat: 解析式 PBR(Cook-Torrance GGX,metallic-roughness 工作流)
- 修 void* 指针算术警告(Texture::InitFromDds) - Material:slot2 语义切为 metallicRoughness(glTF 约定 G=粗糙度 B=金属度)+ 新增材质因子参数 UBO(binding 4,per-slot ring, 创建时写死,metallic/roughness 因子乘 MR 贴图) - simple_shader.frag:Blinn-Phong → Cook-Torrance(GGX 分布 + Smith 几何 + Schlick Fresnel,k=(r+1)²/8 解析光源版);金属不参与 漫反射;环境光暂为常数(IBL 后续) - Model:读 aiTextureType_UNKNOWN(glTF MR 落点)+ AI_MATKEY_ METALLIC/ROUGHNESS_FACTOR(旧资产缺键退化为电介质 0/0.5); 材质缓存键含因子 - main.cpp:演示场景换回 backpack(旧资产走因子路径验证 PBR 全链路) - 旧 specular 贴图不再使用(语义被 MR 取代)
This commit is contained in:
+56
-18
@@ -1,6 +1,7 @@
|
||||
#version 450
|
||||
|
||||
const int MAX_LIGHTS = 4;
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
struct Light {
|
||||
vec4 color; // rgb = 颜色,a = 强度
|
||||
@@ -35,18 +36,20 @@ layout(set = 0, binding = 0) uniform UniformBufferObject {
|
||||
// 材质纹理槽(binding = Material::Slot)
|
||||
layout(set = 1, binding = 0) uniform sampler2D albedoMap;
|
||||
layout(set = 1, binding = 1) uniform sampler2D normalMap;
|
||||
layout(set = 1, binding = 2) uniform sampler2D specularMap;
|
||||
layout(set = 1, binding = 2) uniform sampler2D metallicRoughnessMap; // G=粗糙度 B=金属度
|
||||
layout(set = 1, binding = 3) uniform sampler2D emissiveMap;
|
||||
layout(set = 1, binding = 4) uniform MaterialParams {
|
||||
vec4 factors; // x = metallic 因子,y = roughness 因子
|
||||
} matParams;
|
||||
|
||||
layout(set = 2, binding = 0) uniform sampler2D shadowMap0; // CSM 级联 0(最近)
|
||||
layout(set = 2, binding = 1) uniform sampler2D shadowMap1; // 级联 1
|
||||
layout(set = 2, binding = 2) uniform sampler2D shadowMap2; // 级联 2(最远)
|
||||
|
||||
// 第 0 盏灯(KeyLight)的 CSM 阴影因子:0.3 影中 / 1.0 受光。
|
||||
// 第 0 盏方向光(KeyLight)的 CSM 阴影因子:0.3 影中 / 1.0 受光。
|
||||
// 级联按视图深度选择;采样器均 clamp-to-border 白色:
|
||||
// 光视锥外自动 1.0(无阴影),省出界分支。
|
||||
float ShadowFactor(vec3 N, float viewDepth) {
|
||||
// 级联选择:第一个 viewDepth < split 的级联
|
||||
int cascade = 2;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (viewDepth < ubo.cascadeSplits[i]) { cascade = i; break; }
|
||||
@@ -54,7 +57,6 @@ float ShadowFactor(vec3 N, float viewDepth) {
|
||||
|
||||
vec4 ls = ubo.lightSpace[cascade] * vec4(fragWorldPos, 1.0);
|
||||
vec3 proj = ls.xyz / ls.w;
|
||||
// NDC [-1,1] → UV [0,1](ortho 的 w=1)
|
||||
vec2 uv = proj.xy * 0.5 + 0.5;
|
||||
|
||||
float closest;
|
||||
@@ -62,7 +64,6 @@ float ShadowFactor(vec3 N, float viewDepth) {
|
||||
else if (cascade == 1) closest = texture(shadowMap1, uv).r;
|
||||
else closest = texture(shadowMap2, uv).r;
|
||||
|
||||
// 斜率缩放 bias:掠射面用更大的 bias 压 acne
|
||||
vec3 L = normalize(-ubo.lights[0].direction.xyz);
|
||||
float bias = max(0.004 * (1.0 - dot(N, L)), 0.0012);
|
||||
|
||||
@@ -83,15 +84,39 @@ vec3 MappedNormal(vec3 geomN, vec3 T, vec2 uv) {
|
||||
return normalize(nT * sampled.x + B * sampled.y + N * sampled.z);
|
||||
}
|
||||
|
||||
// ---- Cook-Torrance BRDF 各项 ----
|
||||
float DistributionGGX(float NdotH, float roughness) {
|
||||
float a = roughness * roughness;
|
||||
float a2 = a * a;
|
||||
float d = NdotH * NdotH * (a2 - 1.0) + 1.0;
|
||||
return a2 / (PI * d * d);
|
||||
}
|
||||
|
||||
float GeometrySmith(float NdotV, float NdotL, float roughness) {
|
||||
float r = roughness + 1.0;
|
||||
float k = (r * r) / 8.0; // 解析光源用此 k(IBL 才用 IBL 版本)
|
||||
float gv = NdotV / (NdotV * (1.0 - k) + k);
|
||||
float gl = NdotL / (NdotL * (1.0 - k) + k);
|
||||
return gv * gl;
|
||||
}
|
||||
|
||||
vec3 FresnelSchlick(float cosTheta, vec3 F0) {
|
||||
return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 albedo = texture(albedoMap, fragUV).rgb;
|
||||
float specIntensity = texture(specularMap, fragUV).r;
|
||||
vec4 mr = texture(metallicRoughnessMap, fragUV);
|
||||
float roughness = clamp(mr.g * matParams.factors.y, 0.045, 1.0);
|
||||
float metallic = clamp(mr.b * matParams.factors.x, 0.0, 1.0);
|
||||
vec3 emissive = texture(emissiveMap, fragUV).rgb;
|
||||
|
||||
vec3 N = MappedNormal(normalize(fragNormal), fragTangent, fragUV);
|
||||
vec3 V = normalize(ubo.cameraPos.xyz - fragWorldPos);
|
||||
float NdotV = max(dot(N, V), 1e-4);
|
||||
vec3 F0 = mix(vec3(0.04), albedo, metallic); // 电介质基准反射率 4%
|
||||
|
||||
vec3 result = ubo.ambientColor.rgb * albedo;
|
||||
vec3 Lo = vec3(0.0);
|
||||
|
||||
for (int i = 0; i < MAX_LIGHTS; ++i) {
|
||||
// 按类型分支:方向光无衰减;点光方向指向光源 + 平方距离衰减
|
||||
@@ -100,32 +125,45 @@ void main() {
|
||||
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; // 衰减半径外,跳过
|
||||
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; // 平方衰减,边缘更柔和
|
||||
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;
|
||||
vec3 radiance = ubo.lights[i].color.rgb * ubo.lights[i].color.a * atten;
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
if (NdotL <= 0.0) continue;
|
||||
|
||||
// Cook-Torrance 镜面项
|
||||
vec3 H = normalize(V + L);
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = max(dot(H, V), 0.0);
|
||||
float D = DistributionGGX(NdotH, roughness);
|
||||
float G = GeometrySmith(NdotV, NdotL, roughness);
|
||||
vec3 F = FresnelSchlick(NdotH2, F0);
|
||||
|
||||
vec3 kS = F;
|
||||
vec3 kD = (1.0 - kS) * (1.0 - metallic); // 金属不参与漫反射
|
||||
vec3 specular = (D * G * F) /
|
||||
max(4.0 * NdotV * NdotL, 1e-4);
|
||||
|
||||
// 阴影只来自第 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)) * atten * shade;
|
||||
Lo += (kD * albedo / PI + specular) * radiance * NdotL * shade;
|
||||
}
|
||||
|
||||
// 自发光不经光照/阴影直接叠加
|
||||
result += emissive;
|
||||
// 环境光:无 IBL 的简化版(半球常数);后续 IBL 替换
|
||||
vec3 ambient = ubo.ambientColor.rgb * albedo;
|
||||
|
||||
outColor = vec4(result, 1.0);
|
||||
vec3 color = ambient + Lo + emissive;
|
||||
|
||||
outColor = vec4(color, 1.0);
|
||||
outVelocity = fragVelocity;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user