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+ float2 UV;
12+ float3 Color;
13+ float4 Tangent;
14+ };
15+
16+ struct VSOutput
17+ {
18+ float4 Pos : SV_POSITION;
19+ float3 Normal;
20+ float3 Color;
21+ float2 UV;
22+ float3 ViewVec;
23+ float3 LightVec;
24+ float4 Tangent;
25+ };
26+
27+ struct UBO
28+ {
29+ float4x4 projection;
30+ float4x4 view;
31+ float4x4 model;
32+ float4 lightPos;
33+ float4 viewPos;
34+ int colorShadingRates;
35+ };
36+ ConstantBuffer < UBO> ubo;
37+
38+ [[vk::binding(0 , 1 )]] Sampler2D samplerColorMap;
39+ [[vk::binding(1 , 1 )]] Sampler2D samplerNormalMap;
40+
41+ [[SpecializationConstant]] const bool ALPHA_MASK = false ;
42+ [[SpecializationConstant]] const float ALPHA_MASK_CUTOFF = 0 . 0 ;
43+
44+ [shader(" vertex" )]
45+ VSOutput vertexMain(VSInput input)
46+ {
47+ VSOutput output;
48+ output .Normal = input .Normal ;
49+ output .Color = input .Color ;
50+ output .UV = input .UV ;
51+ output .Tangent = input .Tangent ;
52+
53+ float4x4 modelView = mul(ubo .view , ubo .model );
54+
55+ output .Pos = mul(ubo .projection , mul(modelView, float4(input .Pos .xyz , 1 . 0 )));
56+
57+ output .Normal = mul((float3x3 )ubo .model , input .Normal );
58+ float4 pos = mul(ubo .model , float4(input .Pos , 1 . 0 ));
59+ output .LightVec = ubo .lightPos .xyz - pos .xyz ;
60+ output .ViewVec = ubo .viewPos .xyz - pos .xyz ;
61+ return output;
62+ }
63+
64+ static const uint SHADING_RATE_PER_PIXEL = 0 ;
65+ static const uint SHADING_RATE_PER_2X1_PIXELS = 6 ;
66+ static const uint SHADING_RATE_PER_1X2_PIXELS = 7 ;
67+ static const uint SHADING_RATE_PER_2X2_PIXELS = 8 ;
68+ static const uint SHADING_RATE_PER_4X2_PIXELS = 9 ;
69+ static const uint SHADING_RATE_PER_2X4_PIXELS = 10 ;
70+
71+ [shader(" fragment" )]
72+ float4 fragmentMain(VSOutput input, uint shadingRate : SV_ShadingRate)
73+ {
74+ float4 color = samplerColorMap .Sample (input .UV ) * float4(input .Color , 1 . 0 );
75+
76+ if (ALPHA_MASK) {
77+ if (color .a < ALPHA_MASK_CUTOFF) {
78+ discard ;
79+ }
80+ }
81+
82+ float3 N = normalize(input .Normal );
83+ float3 T = normalize(input .Tangent .xyz );
84+ float3 B = cross(input .Normal , input .Tangent .xyz ) * input .Tangent .w ;
85+ float3x3 TBN = float3x3(T, B, N);
86+ N = mul(normalize(samplerNormalMap .Sample (input .UV ).xyz * 2 . 0 - float3(1 . 0 , 1 . 0 , 1 . 0 )), TBN);
87+
88+ const float ambient = 0 . 1 ;
89+ float3 L = normalize(input .LightVec );
90+ float3 V = normalize(input .ViewVec );
91+ float3 R = reflect(- L, N);
92+ float3 diffuse = max(dot(N, L), ambient).rrr ;
93+ float3 specular = pow(max(dot(R, V), 0 . 0 ), 32 . 0 );
94+ color = float4(diffuse * color .rgb + specular, color .a );
95+
96+ if (ubo .colorShadingRates == 1 ) {
97+ switch (shadingRate) {
98+ case SHADING_RATE_PER_PIXEL:
99+ return color * float4 (0 . 0 , 0 . 8 , 0 . 4 , 1 . 0 );
100+ case SHADING_RATE_PER_2X1_PIXELS:
101+ return color * float4 (0 . 2 , 0 . 6 , 1 . 0 , 1 . 0 );
102+ case SHADING_RATE_PER_1X2_PIXELS:
103+ return color * float4 (0 . 0 , 0 . 4 , 0 . 8 , 1 . 0 );
104+ case SHADING_RATE_PER_2X2_PIXELS:
105+ return color * float4 (1 . 0 , 1 . 0 , 0 . 2 , 1 . 0 );
106+ case SHADING_RATE_PER_4X2_PIXELS:
107+ return color * float4 (0 . 8 , 0 . 8 , 0 . 0 , 1 . 0 );
108+ case SHADING_RATE_PER_2X4_PIXELS:
109+ return color * float4 (1 . 0 , 0 . 4 , 0 . 2 , 1 . 0 );
110+ default :
111+ return color * float4 (0 . 8 , 0 . 0 , 0 . 0 , 1 . 0 );
112+ }
113+ }
114+
115+ return color;
116+ }
0 commit comments