1+ /* Copyright (c) 2025, Sascha Willems
2+ *
3+ * SPDX-License-Identifier: MIT
4+ *
5+ */
6+
7+ struct VSInput
8+ {
9+ float3 Pos;
10+ float3 Normal;
11+ };
12+
13+ struct VSOutput
14+ {
15+ float4 Pos : SV_POSITION;
16+ float3 WorldPos;
17+ float3 Normal;
18+ };
19+
20+ struct UBO
21+ {
22+ float4x4 projection;
23+ float4x4 model;
24+ float4x4 view;
25+ float3 camPos;
26+ };
27+ ConstantBuffer < UBO> ubo;
28+
29+ struct UBOParams {
30+ float4 lights [4 ];
31+ };
32+ ConstantBuffer < UBOParams> uboParams;
33+
34+ struct Material {
35+ [[vk::offset(12 )]] float roughness;
36+ [[vk::offset(16 )]] float metallic;
37+ [[vk::offset(20 )]] float r;
38+ [[vk::offset(24 )]] float g;
39+ [[vk::offset(28 )]] float b;
40+ };
41+ [[vk::push_constant]] Material material;
42+
43+ static const float PI = 3 . 14159265359 ;
44+
45+ // Normal Distribution function --------------------------------------
46+ float D_GGX(float dotNH, float roughness)
47+ {
48+ float alpha = roughness * roughness;
49+ float alpha2 = alpha * alpha;
50+ float denom = dotNH * dotNH * (alpha2 - 1 . 0 ) + 1 . 0 ;
51+ return (alpha2)/ (PI * denom* denom);
52+ }
53+
54+ // Geometric Shadowing function --------------------------------------
55+ float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness)
56+ {
57+ float r = (roughness + 1 . 0 );
58+ float k = (r* r) / 8 . 0 ;
59+ float GL = dotNL / (dotNL * (1 . 0 - k) + k);
60+ float GV = dotNV / (dotNV * (1 . 0 - k) + k);
61+ return GL * GV;
62+ }
63+
64+ // Fresnel function ----------------------------------------------------
65+ float3 F_Schlick(float cosTheta, Material material)
66+ {
67+ float3 F0 = lerp(float3(0 . 04 , 0 . 04 , 0 . 04 ), float3(material .r , material .g , material .b ), material .metallic ); // * material.specular
68+ float3 F = F0 + (1 . 0 - F0) * pow(1 . 0 - cosTheta, 5 . 0 );
69+ return F;
70+ }
71+
72+ // Specular BRDF composition --------------------------------------------
73+
74+ float3 BRDF(float3 L, float3 V, float3 N, Material material)
75+ {
76+ // Precalculate vectors and dot products
77+ float3 H = normalize (V + L);
78+ float dotNV = clamp(dot(N, V), 0 . 0 , 1 . 0 );
79+ float dotNL = clamp(dot(N, L), 0 . 0 , 1 . 0 );
80+ float dotLH = clamp(dot(L, H), 0 . 0 , 1 . 0 );
81+ float dotNH = clamp(dot(N, H), 0 . 0 , 1 . 0 );
82+
83+ // Light color fixed
84+ float3 lightColor = float3(1 . 0 , 1 . 0 , 1 . 0 );
85+
86+ float3 color = float3(0 . 0 , 0 . 0 , 0 . 0 );
87+
88+ if (dotNL > 0 . 0 )
89+ {
90+ float rroughness = max(0 . 05 , material .roughness );
91+ // D = Normal distribution (Distribution of the microfacets)
92+ float D = D_GGX(dotNH, material .roughness );
93+ // G = Geometric shadowing term (Microfacets shadowing)
94+ float G = G_SchlicksmithGGX(dotNL, dotNV, rroughness);
95+ // F = Fresnel factor (Reflectance depending on angle of incidence)
96+ float3 F = F_Schlick(dotNV, material);
97+
98+ float3 spec = D * F * G / (4 . 0 * dotNL * dotNV);
99+
100+ color += spec * dotNL * lightColor;
101+ }
102+
103+ return color;
104+ }
105+
106+ [shader(" vertex" )]
107+ VSOutput vertexMain(VSInput input, uniform float3 objPos)
108+ {
109+ VSOutput output;
110+ float3 locPos = mul(ubo .model , float4(input .Pos , 1 . 0 )).xyz ;
111+ output .WorldPos = locPos + objPos;
112+ output .Normal = mul((float3x3 )ubo .model , input .Normal );
113+ output .Pos = mul(ubo .projection , mul(ubo .view , float4(output .WorldPos , 1 . 0 )));
114+ return output;
115+ }
116+
117+ [shader(" fragment" )]
118+ float4 fragmentMain(VSOutput input)
119+ {
120+ float3 N = normalize(input .Normal );
121+ float3 V = normalize(ubo .camPos - input .WorldPos );
122+
123+ // Specular contribution
124+ float3 Lo = float3(0 . 0 , 0 . 0 , 0 . 0 );
125+ for (int i = 0 ; i < 4 ; i++ ) {
126+ float3 L = normalize(uboParams .lights [i].xyz - input .WorldPos );
127+ Lo += BRDF(L, V, N, material);
128+ };
129+
130+ // Combine with ambient
131+ float3 color = float3(material .r , material .g , material .b ) * 0 . 02 ;
132+ color += Lo;
133+
134+ // Gamma correct
135+ color = pow(color, float3(0 . 4545 , 0 . 4545 , 0 . 4545 ));
136+
137+ return float4(color, 1 . 0 );
138+ }
0 commit comments