mesh_pbr.wgsl (5263B)
1 struct VertexInput { 2 @location(0) position: vec4<f32>, 3 @location(1) normal: vec3<f32>, 4 @location(2) tex_coord: vec3<f32>, 5 @location(3) tangent: vec3<f32>, 6 @location(4) bitangent: vec3<f32>, 7 }; 8 9 struct VertexOutput { 10 @builtin(position) clip_position: vec4<f32>, 11 @location(0) tex_coord: vec3<f32>, 12 @location(1) pt_fragment: vec3<f32>, 13 @location(2) pt_light: vec3<f32>, 14 @location(3) pt_camera: vec3<f32>, 15 @location(4) @interpolate(flat) instance_id: u32, 16 }; 17 18 @group(0) @binding(0) 19 var<storage, read> instances: array<Instance>; 20 struct Instance { 21 model_matrix: mat4x4<f32>, 22 material: Material, 23 }; 24 struct Material { 25 albedo: u32, 26 normal: u32, 27 roughness: u32, 28 metalness: u32, 29 }; 30 31 @group(0) @binding(1) 32 var<uniform> uniform_data: UniformData; 33 struct UniformData { 34 pw_camera: vec3<f32>, 35 view_matrix: mat4x4<f32>, 36 proj_matrix: mat4x4<f32>, 37 }; 38 39 @vertex fn vertex( 40 in: VertexInput, 41 @builtin(instance_index) idx: u32, 42 ) -> VertexOutput { 43 let model_matrix = instances[idx].model_matrix; 44 let camera_matrix = uniform_data.proj_matrix * uniform_data.view_matrix; 45 46 let t = normalize((model_matrix * vec4(in.tangent, 0.0)).xyz); 47 let b = normalize((model_matrix * vec4(in.bitangent, 0.0)).xyz); 48 let n = normalize((model_matrix * vec4(in.normal, 0.0)).xyz); 49 let tangent_matrix = transpose(mat3x3<f32>(t, b, n)); 50 51 let world_position = model_matrix * in.position; 52 let tangent_position = tangent_matrix * world_position.xyz; 53 54 let light_position = vec3<f32>(20, 80, 20); 55 let tangent_light_position = tangent_matrix * light_position; 56 57 let pt_camera = tangent_matrix * uniform_data.pw_camera; 58 59 return VertexOutput( 60 camera_matrix * world_position, 61 in.tex_coord, 62 tangent_position, 63 tangent_light_position, 64 pt_camera, 65 idx, 66 ); 67 } 68 69 70 @group(0) @binding(2) var material_sampler: sampler; 71 @group(0) @binding(3) var material_texture: texture_2d_array<f32>; 72 73 fn diffuse_lambert(albedo: vec3<f32>) -> vec3<f32> { 74 return albedo * 0.31830988618; 75 } 76 77 fn distribution_trowbridge_reitz_ggx( 78 n_dot_h: f32, 79 alpha: f32, 80 ) -> f32 { 81 let alpha_squared = alpha * alpha; 82 let n_dot_h_squared = n_dot_h * n_dot_h; 83 let denom = n_dot_h_squared * (alpha_squared - 1) + 1; 84 let denom_squared = denom * denom; 85 return alpha_squared / (3.14159265359 * denom_squared); 86 } 87 88 fn geometry_schlick_ggx( 89 n_dot_x: f32, 90 alpha: f32, 91 ) -> f32 { 92 let k = 0.5 * alpha; 93 let denom = n_dot_x * (1.0 - k) + k; 94 return n_dot_x / denom; 95 } 96 97 fn geometry_smith( 98 n_dot_l: f32, 99 n_dot_v: f32, 100 alpha: f32, 101 ) -> f32 { 102 let g1 = geometry_schlick_ggx(n_dot_l, alpha); 103 let g2 = geometry_schlick_ggx(n_dot_v, alpha); 104 return g1 * g2; 105 } 106 107 fn fresnel_schlick( 108 f0: vec3<f32>, 109 v_dot_h: f32, 110 ) -> vec3<f32> { 111 return f0 + (1.0 - f0) * pow(1.0 - v_dot_h, 5.0); 112 } 113 114 fn cook_torrance( 115 n_dot_v: f32, 116 n_dot_l: f32, 117 n_dot_h: f32, 118 roughness: f32, 119 ) -> f32 { 120 let alpha = roughness * roughness; 121 let distribution = distribution_trowbridge_reitz_ggx( 122 n_dot_h, 123 alpha, 124 ); 125 let geometry = geometry_smith( 126 n_dot_l, 127 n_dot_v, 128 alpha, 129 ); 130 let denom = 4.0 * n_dot_v * n_dot_l + 0.000001; 131 return (distribution * geometry) / denom; 132 } 133 134 fn lighting( 135 normal: vec3<f32>, 136 p_fragment: vec3<f32>, 137 p_camera: vec3<f32>, 138 p_light: vec3<f32>, 139 c_light: vec3<f32>, 140 albedo: vec3<f32>, 141 roughness: f32, 142 metalness: f32, 143 ) -> vec3<f32> { 144 let v = normalize(p_camera - p_fragment); 145 let l = normalize(p_light - p_fragment); 146 let h = normalize(v + l); 147 148 let n_dot_v = max(dot(normal, v), 0.0); 149 let n_dot_l = max(dot(normal, l), 0.0); 150 let n_dot_h = max(dot(normal, h), 0.0); 151 let v_dot_h = max(dot(v, h), 0.0); 152 153 let f0 = mix(vec3<f32>(0.04), albedo, metalness); 154 let k_s = fresnel_schlick(f0, v_dot_h); 155 let k_d = 1.0 - k_s; 156 157 let diffuse = k_d * diffuse_lambert(albedo); 158 let specular = k_s * cook_torrance(n_dot_v, n_dot_l, n_dot_h, roughness); 159 let brdf = (diffuse + specular) * n_dot_l; 160 return brdf * c_light; 161 } 162 163 @fragment fn fragment(in: VertexOutput) -> @location(0) vec4<f32> { 164 let material = instances[in.instance_id].material; 165 let uv = vec2<f32>(in.tex_coord.x, 1 - in.tex_coord.y); 166 var albedo = textureSample(material_texture, material_sampler, uv, material.albedo).rgb; 167 albedo = pow(albedo, vec3<f32>(2.2)); 168 var normal = textureSample(material_texture, material_sampler, uv, material.normal).rgb; 169 normal = normalize(normal * 2.0 - 1.0); 170 var roughness = textureSample(material_texture, material_sampler, uv, material.roughness).r; 171 var metalness = textureSample(material_texture, material_sampler, uv, material.metalness).r; 172 173 let light_color = normalize(vec3<f32>(23.47, 21.31, 20.79)); 174 var c = lighting( 175 normal, 176 in.pt_fragment, 177 in.pt_camera, 178 in.pt_light, 179 light_color, 180 albedo.rgb, 181 roughness, 182 metalness, 183 ); 184 185 let ambient = vec3<f32>(0.03) * albedo; 186 c += ambient; 187 188 c = c / (c + 1.0); 189 c = pow(c, vec3<f32>(1.0/2.2)); 190 191 return vec4<f32>(c, 1.0); 192 }