Files
HelloVulkan/shaders/simple_shader.frag
T
atdunbg c54f60c5ea feat: 材质系统 v1——4 纹理槽(albedo/normal/specular/emissive)+ 法线贴图
- Material:单贴图 → 4 槽(binding=Slot 枚举),MakeCacheKey 组合键
  保持材质去重(同贴图组合共享描述符集)
- Model:读取 aiTextureType DIFFUSE/NORMALS/SPECULAR/EMISSIVE 四类路径;
  aiProcess_CalcTangentSpace 生成切线(Vertex +tangent 属性,location 3);
  每槽默认纹理兜底(白/平法线(128,128,255)/黑/黑,1x1)
- 纹理 sRGB 语义按槽位:颜色图 SRGB 变体,数据图(Normal/Specular)线性
  UNORM——Texture 路径加载加 srgb 参数;修复 InitFromPixels 图文 format
  不一致的 validation 警告
- UBO 尾部追加 cameraPos(Blinn-Phong V 向量)
- simple_shader.frag:TBN 法线贴图(无切线/平法线退化回几何法线)+
  Blinn-Phong 高光(specular 图强度系数)+ 自发光直加
- SunTemple 实测:148 张 DDS 全槽位加载(96 张线性变体)、1056 mesh、
  validation 零警告
2026-09-23 14:50:10 +08:00

112 lines
3.9 KiB
GLSL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#version 450
const int MAX_LIGHTS = 4;
struct Light {
vec4 direction;
vec4 color;
};
layout(location = 0) in vec2 fragUV;
layout(location = 1) in vec3 fragNormal;
layout(location = 2) in vec3 fragWorldPos;
layout(location = 3) in float fragViewDepth;
layout(location = 4) in vec2 fragVelocity;
layout(location = 5) in vec3 fragTangent;
layout(location = 0) out vec4 outColor;
layout(location = 1) out vec2 outVelocity; // TAA velocity 附件
layout(set = 0, binding = 0) uniform UniformBufferObject {
mat4 view;
mat4 proj;
mat4 lightSpace[3]; // CSM 各级联光空间 VP
vec4 cascadeSplits; // xyz = 级联 0..2 远边界(视图深度)
vec4 ambientColor;
Light lights[MAX_LIGHTS];
mat4 projNoJitter;
mat4 prevView;
mat4 prevProj;
vec4 cameraPos;
} ubo;
// 材质纹理槽(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 = 3) uniform sampler2D emissiveMap;
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 受光。
// 级联按视图深度选择;采样器均 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; }
}
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;
if (cascade == 0) closest = texture(shadowMap0, uv).r;
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);
return (proj.z - bias > closest) ? 0.3 : 1.0;
}
// 法线贴图 → 世界空间法线(TBN 构建)。
// 无切线数据(零向量)或平法线贴图时退回几何法线。
vec3 MappedNormal(vec3 geomN, vec3 T, vec2 uv) {
if (dot(T, T) < 1e-4) return geomN;
vec3 N = geomN;
vec3 nT = normalize(T - N * dot(N, T)); // 正交化
vec3 B = cross(N, nT);
vec3 sampled = texture(normalMap, uv).xyz * 2.0 - 1.0;
if (dot(sampled, sampled) < 1e-4) return geomN;
return normalize(nT * sampled.x + B * sampled.y + N * sampled.z);
}
void main() {
vec3 albedo = texture(albedoMap, fragUV).rgb;
float specIntensity = texture(specularMap, fragUV).r;
vec3 emissive = texture(emissiveMap, fragUV).rgb;
vec3 N = MappedNormal(normalize(fragNormal), fragTangent, fragUV);
vec3 V = normalize(ubo.cameraPos.xyz - fragWorldPos);
vec3 result = ubo.ambientColor.rgb * albedo;
for (int i = 0; i < MAX_LIGHTS; ++i) {
vec3 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;
result += ubo.lights[i].color.rgb * ubo.lights[i].color.a *
(albedo * diff + vec3(spec)) * shade;
}
// 自发光不经光照/阴影直接叠加
result += emissive;
outColor = vec4(result, 1.0);
outVelocity = fragVelocity;
}