/** * Shared PBR WGSL functions and light loop code. * Concatenated into both shader.ts (standard PBR), terrain-shader.ts (splat PBR), * and custom shader codegen. */ /** Scene struct definitions shared by PBR, terrain, and custom shaders. */ export declare const SCENE_STRUCTS_WGSL = "\nstruct DirLight {\n direction: vec4,\n color: vec4,\n};\n\nstruct PointLight {\n position: vec4, // xyz=position, w=range\n color: vec4, // rgb=color, w=intensity\n};\n\nstruct SpotLight {\n position: vec4, // xyz=position, w=range\n direction: vec4, // xyz=direction, w=outerCos\n color: vec4, // rgb=color, w=intensity\n extra: vec4, // x=innerCos\n};\n\nstruct SceneUniforms {\n cameraPos: vec4, // xyz=position, w=time (seconds)\n numDirLights: u32,\n numPointLights: u32,\n numSpotLights: u32,\n _pad1: u32,\n dirLights: array,\n pointLights: array,\n spotLights: array,\n fogEnabled: u32,\n fogMode: u32,\n fogDensity: f32,\n fogStart: f32,\n fogEnd: f32,\n cameraNear: f32,\n cameraFar: f32,\n _fogPad2: f32,\n fogColor: vec4,\n};\n"; /** PBR helper functions: GGX distribution, geometry, Fresnel, computePBR, computeTBN */ export declare const PBR_FUNCTIONS_WGSL = "\n// GGX/Trowbridge-Reitz normal distribution\nfn distributionGGX(N: vec3, H: vec3, roughness: f32) -> f32 {\n let a = roughness * roughness;\n let a2 = a * a;\n let NdotH = max(dot(N, H), 0.0);\n let NdotH2 = NdotH * NdotH;\n let denom = NdotH2 * (a2 - 1.0) + 1.0;\n return a2 / (PI * denom * denom);\n}\n\n// Schlick-GGX geometry function\nfn geometrySchlickGGX(NdotV: f32, roughness: f32) -> f32 {\n let r = roughness + 1.0;\n let k = (r * r) / 8.0;\n return NdotV / (NdotV * (1.0 - k) + k);\n}\n\n// Smith's geometry function\nfn geometrySmith(N: vec3, V: vec3, L: vec3, roughness: f32) -> f32 {\n let NdotV = max(dot(N, V), 0.0);\n let NdotL = max(dot(N, L), 0.0);\n return geometrySchlickGGX(NdotV, roughness) * geometrySchlickGGX(NdotL, roughness);\n}\n\n// Fresnel-Schlick approximation\nfn fresnelSchlick(cosTheta: f32, F0: vec3) -> vec3 {\n return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);\n}\n\n// Compute PBR contribution from a single light direction\nfn computePBR(\n N: vec3, V: vec3, L: vec3,\n albedo: vec3, metallic: f32, roughness: f32,\n F0: vec3, radiance: vec3,\n) -> vec3 {\n let H = normalize(V + L);\n let NDF = distributionGGX(N, H, roughness);\n let G = geometrySmith(N, V, L, roughness);\n let F = fresnelSchlick(max(dot(H, V), 0.0), F0);\n\n let numerator = NDF * G * F;\n let denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001;\n let specular = numerator / denominator;\n\n let kS = F;\n let kD = (vec3(1.0) - kS) * (1.0 - metallic);\n let NdotL = max(dot(N, L), 0.0);\n\n return (kD * albedo / PI + specular) * radiance * NdotL;\n}\n\n// Compute cotangent-frame TBN from screen-space derivatives\nfn computeTBN(worldPos: vec3, worldNormal: vec3, uv: vec2) -> mat3x3 {\n let dp1 = dpdx(worldPos);\n let dp2 = dpdy(worldPos);\n let duv1 = dpdx(uv);\n let duv2 = dpdy(uv);\n let T = normalize(dp1 * duv2.y - dp2 * duv1.y);\n let B = normalize(dp2 * duv1.x - dp1 * duv2.x);\n let N = normalize(worldNormal);\n return mat3x3(T, B, N);\n}\n"; /** Light loop WGSL: iterates dir/point/spot lights with PBR + shadow sampling. * Expects: N, V, albedo, metallic, roughness, F0, worldPosition in scope. Writes to Lo. */ export declare const LIGHT_LOOP_WGSL = "\n // Directional lights\n for (var i = 0u; i < scene.numDirLights; i = i + 1u) {\n let light = scene.dirLights[i];\n let L = normalize(-light.direction.xyz);\n let intensity = light.color.w;\n let radiance = light.color.rgb * intensity;\n var contribution = computePBR(N, V, L, albedo, metallic, roughness, F0, radiance);\n let dirSlot = shadow.dirLightToSlot[i];\n if (dirSlot != 0xFFFFFFFFu) {\n contribution = contribution * sampleDirShadow(dirSlot, worldPosition, N, length(worldPosition - scene.cameraPos.xyz));\n }\n Lo = Lo + contribution;\n }\n\n // Point lights\n for (var i = 0u; i < scene.numPointLights; i = i + 1u) {\n let light = scene.pointLights[i];\n let lightPos = light.position.xyz;\n let range = light.position.w;\n let intensity = light.color.w;\n\n let toLight = lightPos - worldPosition;\n let dist = length(toLight);\n let L = toLight / max(dist, 0.0001);\n\n // Smooth distance attenuation with range cutoff\n let attenuation = max(1.0 - (dist * dist) / (range * range), 0.0);\n let radiance = light.color.rgb * intensity * attenuation * attenuation;\n\n var contribution = computePBR(N, V, L, albedo, metallic, roughness, F0, radiance);\n let pointSlot = shadow.pointLightToSlot[i];\n if (pointSlot != 0xFFFFFFFFu) {\n contribution = contribution * samplePointShadow(pointSlot, worldPosition, N);\n }\n Lo = Lo + contribution;\n }\n\n // Spot lights\n for (var i = 0u; i < scene.numSpotLights; i = i + 1u) {\n let light = scene.spotLights[i];\n let lightPos = light.position.xyz;\n let range = light.position.w;\n let spotDir = light.direction.xyz;\n let outerCos = light.direction.w;\n let innerCos = light.extra.x;\n let intensity = light.color.w;\n\n let toLight = lightPos - worldPosition;\n let dist = length(toLight);\n let L = toLight / max(dist, 0.0001);\n\n // Distance attenuation (same as point light)\n let distAtt = max(1.0 - (dist * dist) / (range * range), 0.0);\n\n // Cone attenuation: smoothstep between outer and inner cosines\n let cosAngle = dot(-L, spotDir);\n let coneAtt = smoothstep(outerCos, innerCos, cosAngle);\n\n let attenuation = distAtt * distAtt * coneAtt;\n let radiance = light.color.rgb * intensity * attenuation;\n\n var contribution = computePBR(N, V, L, albedo, metallic, roughness, F0, radiance);\n let spotSlot = shadow.spotLightToSlot[i];\n if (spotSlot != 0xFFFFFFFFu) {\n contribution = contribution * sampleSpotShadow(spotSlot, worldPosition, N);\n }\n Lo = Lo + contribution;\n }\n"; /** Fog calculation WGSL. Expects: scene, worldPosition, color in scope. Modifies color. */ export declare const FOG_WGSL = "\n // Distance fog\n if (scene.fogEnabled != 0u) {\n let fogDist = length(scene.cameraPos.xyz - worldPosition);\n var fogFactor: f32;\n if (scene.fogMode == 0u) {\n // Linear\n fogFactor = saturate((scene.fogEnd - fogDist) / (scene.fogEnd - scene.fogStart));\n } else {\n // Exponential\u00B2\n let d = scene.fogDensity * fogDist;\n fogFactor = exp(-(d * d));\n }\n color = mix(scene.fogColor.rgb, color, fogFactor);\n }\n"; //# sourceMappingURL=pbr-wgsl.d.ts.map