1+ #![ cfg_attr( target_arch = "spirv" , no_std) ]
2+ #![ allow( clippy:: missing_safety_doc) ]
3+
4+ use spirv_std:: { spirv, glam:: { mat3, vec3, vec4, Mat4 , Vec3 , Vec4 } , num_traits:: Float } ;
5+ use core:: f32:: consts:: PI ;
6+
7+ #[ repr( C ) ]
8+ #[ derive( Copy , Clone ) ]
9+ pub struct Ubo {
10+ pub projection : Mat4 ,
11+ pub model : Mat4 ,
12+ pub view : Mat4 ,
13+ pub cam_pos : Vec3 ,
14+ }
15+
16+ #[ repr( C ) ]
17+ #[ derive( Copy , Clone ) ]
18+ pub struct PushConsts {
19+ pub obj_pos : Vec3 ,
20+ }
21+
22+ #[ repr( C ) ]
23+ #[ derive( Copy , Clone ) ]
24+ pub struct UniformInline {
25+ pub roughness : f32 ,
26+ pub metallic : f32 ,
27+ pub r : f32 ,
28+ pub g : f32 ,
29+ pub b : f32 ,
30+ pub ambient : f32 ,
31+ }
32+
33+ #[ spirv( vertex) ]
34+ pub fn main_vs (
35+ in_pos : Vec3 ,
36+ in_normal : Vec3 ,
37+ #[ spirv( uniform, descriptor_set = 0 , binding = 0 ) ] ubo : & Ubo ,
38+ #[ spirv( push_constant) ] push_consts : & PushConsts ,
39+ #[ spirv( position) ] out_position : & mut Vec4 ,
40+ out_world_pos : & mut Vec3 ,
41+ out_normal : & mut Vec3 ,
42+ ) {
43+ let loc_pos = ( ubo. model * vec4 ( in_pos. x , in_pos. y , in_pos. z , 1.0 ) ) . truncate ( ) ;
44+ * out_world_pos = loc_pos + push_consts. obj_pos ;
45+ let model_mat3 = mat3 (
46+ ubo. model . x_axis . truncate ( ) ,
47+ ubo. model . y_axis . truncate ( ) ,
48+ ubo. model . z_axis . truncate ( ) ,
49+ ) ;
50+ * out_normal = model_mat3 * in_normal;
51+ * out_position = ubo. projection * ubo. view * vec4 ( out_world_pos. x , out_world_pos. y , out_world_pos. z , 1.0 ) ;
52+ }
53+
54+ // Normal Distribution function --------------------------------------
55+ fn d_ggx ( dot_nh : f32 , roughness : f32 ) -> f32 {
56+ let alpha = roughness * roughness;
57+ let alpha2 = alpha * alpha;
58+ let denom = dot_nh * dot_nh * ( alpha2 - 1.0 ) + 1.0 ;
59+ alpha2 / ( PI * denom * denom)
60+ }
61+
62+ // Geometric Shadowing function --------------------------------------
63+ fn g_schlicksmith_ggx ( dot_nl : f32 , dot_nv : f32 , roughness : f32 ) -> f32 {
64+ let r = roughness + 1.0 ;
65+ let k = ( r * r) / 8.0 ;
66+ let gl = dot_nl / ( dot_nl * ( 1.0 - k) + k) ;
67+ let gv = dot_nv / ( dot_nv * ( 1.0 - k) + k) ;
68+ gl * gv
69+ }
70+
71+ // Fresnel function ----------------------------------------------------
72+ fn f_schlick ( cos_theta : f32 , metallic : f32 , material_color : Vec3 ) -> Vec3 {
73+ let f0 = vec3 ( 0.04 , 0.04 , 0.04 ) . lerp ( material_color, metallic) ;
74+ f0 + ( vec3 ( 1.0 , 1.0 , 1.0 ) - f0) * ( 1.0 - cos_theta) . powf ( 5.0 )
75+ }
76+
77+ // Specular BRDF composition --------------------------------------------
78+ fn brdf ( l : Vec3 , v : Vec3 , n : Vec3 , metallic : f32 , roughness : f32 , material_color : Vec3 ) -> Vec3 {
79+ // Precalculate vectors and dot products
80+ let h = ( v + l) . normalize ( ) ;
81+ let dot_nv = n. dot ( v) . clamp ( 0.0 , 1.0 ) ;
82+ let dot_nl = n. dot ( l) . clamp ( 0.0 , 1.0 ) ;
83+ let _dot_lh = l. dot ( h) . clamp ( 0.0 , 1.0 ) ;
84+ let dot_nh = n. dot ( h) . clamp ( 0.0 , 1.0 ) ;
85+
86+ // Light color fixed
87+ let light_color = vec3 ( 1.0 , 1.0 , 1.0 ) ;
88+
89+ let mut color = vec3 ( 0.0 , 0.0 , 0.0 ) ;
90+
91+ if dot_nl > 0.0 {
92+ let rroughness = roughness. max ( 0.05 ) ;
93+ // D = Normal distribution (Distribution of the microfacets)
94+ let d = d_ggx ( dot_nh, rroughness) ;
95+ // G = Geometric shadowing term (Microfacets shadowing)
96+ let g = g_schlicksmith_ggx ( dot_nl, dot_nv, rroughness) ;
97+ // F = Fresnel factor (Reflectance depending on angle of incidence)
98+ let f = f_schlick ( dot_nv, metallic, material_color) ;
99+
100+ let spec = d * f * g / ( 4.0 * dot_nl * dot_nv) ;
101+
102+ color += spec * dot_nl * light_color;
103+ }
104+
105+ color
106+ }
107+
108+ #[ spirv( fragment) ]
109+ pub fn main_fs (
110+ in_world_pos : Vec3 ,
111+ in_normal : Vec3 ,
112+ #[ spirv( uniform, descriptor_set = 0 , binding = 0 ) ] ubo : & Ubo ,
113+ #[ spirv( uniform, descriptor_set = 1 , binding = 0 ) ] material : & UniformInline ,
114+ out_color : & mut Vec4 ,
115+ ) {
116+ let n = in_normal. normalize ( ) ;
117+ let v = ( ubo. cam_pos - in_world_pos) . normalize ( ) ;
118+
119+ let roughness = material. roughness ;
120+ let material_color = vec3 ( material. r , material. g , material. b ) ;
121+
122+ // Specular contribution
123+ let light_pos = vec3 ( 0.0 , 0.0 , 10.0 ) ;
124+ let mut lo = vec3 ( 0.0 , 0.0 , 0.0 ) ;
125+ let l = ( light_pos - in_world_pos) . normalize ( ) ;
126+ lo += brdf ( l, v, n, material. metallic , roughness, material_color) ;
127+
128+ // Combine with ambient
129+ let mut color = material_color * material. ambient ;
130+ color += lo;
131+
132+ // Gamma correct
133+ color = color. powf ( 0.4545 ) ;
134+
135+ * out_color = vec4 ( color. x , color. y , color. z , 1.0 ) ;
136+ }
0 commit comments