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+ };
14+
15+ struct VSOutput
16+ {
17+ float4 Pos : SV_POSITION;
18+ float3 Normal;
19+ float3 Color;
20+ float2 UV;
21+ float3 ViewVec;
22+ float3 LightVec;
23+ };
24+
25+ struct UBO
26+ {
27+ float4x4 projection;
28+ float4x4 model;
29+ float4 lightPos;
30+ };
31+ ConstantBuffer < UBO> ubo;
32+
33+ Sampler2D samplerColormap;
34+ Sampler2D samplerDiscard;
35+
36+ // We use this constant to control the flow of the shader depending on the
37+ // lighting model selected at pipeline creation time
38+ [[SpecializationConstant]] const int LIGHTING_MODEL = 0 ;
39+ // Parameter for the toon shading part of the shader
40+ [[SpecializationConstant]] const int PARAM_TOON_DESATURATION = 0 ;
41+
42+ [shader(" vertex" )]
43+ VSOutput vertexMain(VSInput input)
44+ {
45+ VSOutput output;
46+ output .Normal = input .Normal ;
47+ output .Color = input .Color ;
48+ output .UV = input .UV ;
49+ output .Pos = mul(ubo .projection , mul(ubo .model , float4(input .Pos .xyz , 1 . 0 )));
50+
51+ float4 pos = mul(ubo .model , float4(input .Pos , 1 . 0 ));
52+ output .Normal = mul((float3x3 )ubo .model , input .Normal );
53+ float3 lPos = mul((float3x3 )ubo .model , ubo .lightPos .xyz );
54+ output .LightVec = lPos - pos .xyz ;
55+ output .ViewVec = - pos .xyz ;
56+ return output;
57+ }
58+
59+ [shader(" fragment" )]
60+ float4 fragmentMain(VSOutput input) : SV_TARGET
61+ {
62+ switch (LIGHTING_MODEL) {
63+ case 0 : // Phong
64+ {
65+ float3 ambient = input .Color * float3(0 . 25 , 0 . 25 , 0 . 25 );
66+ float3 N = normalize(input .Normal );
67+ float3 L = normalize(input .LightVec );
68+ float3 V = normalize(input .ViewVec );
69+ float3 R = reflect(- L, N);
70+ float3 diffuse = max(dot(N, L), 0 . 0 ) * input .Color ;
71+ float3 specular = pow(max(dot(R, V), 0 . 0 ), 32 . 0 ) * float3(0 . 75 , 0 . 75 , 0 . 75 );
72+ return float4(ambient + diffuse * 1 . 75 + specular, 1 . 0 );
73+ }
74+ case 1 : // Toon
75+ {
76+
77+ float3 N = normalize(input .Normal );
78+ float3 L = normalize(input .LightVec );
79+ float intensity = dot(N,L);
80+ float3 color;
81+ if (intensity > 0 . 98 )
82+ color = input .Color * 1 . 5 ;
83+ else if (intensity > 0 . 9 )
84+ color = input .Color * 1 . 0 ;
85+ else if (intensity > 0 . 5 )
86+ color = input .Color * 0 . 6 ;
87+ else if (intensity > 0 . 25 )
88+ color = input .Color * 0 . 4 ;
89+ else
90+ color = input .Color * 0 . 2 ;
91+ // Desaturate a bit
92+ color = float3(lerp(color, dot(float3(0 . 2126 ,0 . 7152 ,0 . 0722 ), color).xxx , asfloat(PARAM_TOON_DESATURATION)));
93+ return float4(color, 1 );
94+ }
95+ case 2 : // Textured
96+ {
97+ float4 color = samplerColormap .Sample (input .UV ).rrra ;
98+ float3 ambient = color .rgb * float3(0 . 25 , 0 . 25 , 0 . 25 ) * input .Color ;
99+ float3 N = normalize(input .Normal );
100+ float3 L = normalize(input .LightVec );
101+ float3 V = normalize(input .ViewVec );
102+ float3 R = reflect(- L, N);
103+ float3 diffuse = max(dot(N, L), 0 . 0 ) * color .rgb ;
104+ float specular = pow(max(dot(R, V), 0 . 0 ), 32 . 0 ) * color .a ;
105+ return float4(ambient + diffuse + specular .xxx , 1 . 0 );
106+ }
107+ }
108+
109+ return float4(0 , 0 , 0 , 0 );
110+ }
0 commit comments