struct FragmentInput { @location(0) uv: vec2, @location(1) normal: vec3, @location(2) world_pos: vec3, } struct FragmentOutput { @location(0) color: vec4, } struct Material { albedo: vec3, metallic: f32, roughness: f32, } @group(0) @binding(0) var material: Material; @group(0) @binding(1) var light_dir: vec3; @group(0) @binding(2) var camera_pos: vec3; @group(0) @binding(3) var albedo_tex_tex: texture_2d; @group(0) @binding(4) var albedo_tex_samp: sampler; fn fresnel_schlick(cos_theta: f32, f0: vec3) -> vec3 { return (f0 + ((vec3(1.0, 1.0, 1.0) - f0) * pow((1.0 - cos_theta), 5.0))); } fn compute_lighting(normal: vec3, view_dir: vec3, albedo: vec3) -> vec3 { let n = normalize(normal); let l = normalize(light_dir); let h = normalize((l + view_dir)); let ndotl = max(dot(n, l), 0.0); let ndoth = max(dot(n, h), 0.0); let f0 = mix(vec3(0.04, 0.04, 0.04), albedo, material.metallic); let f = fresnel_schlick(max(dot(h, view_dir), 0.0), f0); let specular = (f * pow(ndoth, ((1.0 - material.roughness) * 256.0))); let diffuse = ((albedo * ndotl) * (vec3(1.0, 1.0, 1.0) - f)); return (diffuse + specular); } @fragment fn fs_main(input: FragmentInput) -> FragmentOutput { var __luma_output: FragmentOutput; let tex_color = textureSample(albedo_tex_tex, albedo_tex_samp, input.uv); let albedo = (tex_color.rgb * material.albedo); let view_dir = normalize((camera_pos - input.world_pos)); let color = compute_lighting(input.normal, view_dir, albedo); __luma_output.color = vec4(color, tex_color.a); return __luma_output; }