@group(0) @binding(0) var viewProjectionMatrix : mat4x4; @group(0) @binding(1) var instancePositions : array>; @group(0) @binding(2) var cameraPosition : vec3; struct VertexOutput { @builtin(position) position : vec4, @location(0) worldPosition : vec3, @location(1) worldNormal : vec3, }; @vertex fn vertexEntryPoint( @location(0) position : vec3, @location(1) normal : vec3, @builtin(instance_index) instanceIndex : u32 ) -> VertexOutput { var output : VertexOutput; let instanceOffset = instancePositions[instanceIndex].xyz; let worldPosition = position + instanceOffset; output.worldPosition = worldPosition; output.worldNormal = normalize(normal); output.position = viewProjectionMatrix * vec4(worldPosition, 1.0); return output; } @fragment fn fragmentEntryPoint( @location(0) worldPosition : vec3, @location(1) worldNormal : vec3 ) -> @location(0) vec4 { let pi = 3.14159265; let invPi = 0.318309886; let N = normalize(worldNormal); let V = normalize(cameraPosition - worldPosition); let L = normalize(vec3(0.5, 1.0, 0.3)); let H = normalize(V + L); let baseColor = vec3(1.0); let metallic = 0.2; let roughness = 0.4; let rough2 = roughness * roughness; let lightColor = vec3(1.0); let NdotV = max(dot(N, V), 0.001); let NdotL = max(dot(N, L), 0.001); let NdotH = max(dot(N, H), 0.001); let HdotV = max(dot(H, V), 0.001); let F0 = mix(vec3(0.04), baseColor, metallic); let f = pow(1.0 - HdotV, 5.0); let F = F0 + (1.0 - F0) * f; let a2 = rough2 * rough2; let NdotH2 = NdotH * NdotH; let denom = NdotH2 * (a2 - 1.0) + 1.0; let NDF = a2 / (pi * denom * denom); let k = (roughness + 1.0); let k2 = (k * k) / 8.0; let Gv = NdotV / (NdotV * (1.0 - k2) + k2); let Gl = NdotL / (NdotL * (1.0 - k2) + k2); let G = Gv * Gl; let spec = (NDF * G * F) / (4.0 * NdotV * NdotL + 0.001); let kd = (vec3(1.0) - F) * (1.0 - metallic); let diff = kd * baseColor * invPi; let color = (diff + spec) * lightColor * NdotL + vec3(0.03) * baseColor; return vec4(pow(color, vec3(1.0 / 2.2)), 1.0); }