Files
HelloVulkan/shaders/simple_shader.vert
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

73 lines
2.8 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 vec3 inPosition;
layout(location = 1) in vec3 inNormal;
layout(location = 2) in vec2 inUV;
layout(location = 3) in vec3 inTangent;
layout(location = 0) out vec2 fragUV;
layout(location = 1) out vec3 fragNormal;
layout(location = 2) out vec3 fragWorldPos;
layout(location = 3) out float fragViewDepth; // CSM:视图深度(级联选择)
layout(location = 4) out vec2 fragVelocity; // TAA:clip 空间运动向量
layout(location = 5) out vec3 fragTangent; // 世界空间切线(法线贴图)
// GPUDriven:模型矩阵从实例缓冲按实例索引取。
// 同一 mesh 的 N 个实体 = 1 次 drawIndexed(instanceCount=N),
// draw 侧用 firstInstance 指向该 batch 在实例数组中的起始下标。
layout(std430, set = 0, binding = 1) readonly buffer ObjectBuffer {
mat4 models[]; // 连续 mat4 数组(16B 对齐,std430/std140 布局一致)
} objects;
// 上一帧实例矩阵(与 ObjectBuffer 同下标 = 同一实例的上一帧姿态)
layout(std430, set = 0, binding = 2) readonly buffer PrevObjectBuffer {
mat4 prevModels[];
} prevObjects;
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;
void main() {
mat4 model = objects.models[gl_InstanceIndex];
vec4 worldPos = model * vec4(inPosition, 1.0);
gl_Position = ubo.proj * ubo.view * worldPos;
// ---- TAA velocity:当前帧与上一帧的 clip 空间位置差(UV 空间)----
// 抖动只进光栅化 gl_Position,不进 velocity(否则抖动本身被当成运动)
vec4 currClip = ubo.projNoJitter * ubo.view * worldPos;
vec4 prevWorldPos = prevObjects.prevModels[gl_InstanceIndex] * vec4(inPosition, 1.0);
vec4 prevClip = ubo.prevProj * ubo.prevView * prevWorldPos;
fragVelocity = (currClip.xy / currClip.w - prevClip.xy / prevClip.w) * 0.5;
fragWorldPos = worldPos.xyz;
// CSM:视图深度(正值,与 cascadeSplits 同尺度)
fragViewDepth = -(ubo.view * worldPos).z;
mat3 normalMatrix = mat3(transpose(inverse(model)));
fragNormal = normalize(normalMatrix * inNormal);
// 切线随模型变换(法线贴图 TBN;无切线数据保持零,frag 侧退回几何法线)
fragTangent = normalize(mat3(model) * inTangent);
// 零向量 normalize 产生 NaN,这里直接透传零,frag 判长度
fragTangent = dot(inTangent, inTangent) > 0.0 ? fragTangent : vec3(0.0);
fragUV = inUV;
}