@ifc-lite/renderer 1.26.0 → 1.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,5 +3,5 @@
3
3
  * Features: PBR lighting, section plane clipping, selection highlight,
4
4
  * glass fresnel, ACES tone mapping, screen-space edge enhancement.
5
5
  */
6
- export declare const mainShaderSource = "\n struct Uniforms {\n viewProj: mat4x4<f32>,\n model: mat4x4<f32>,\n baseColor: vec4<f32>,\n metallicRoughness: vec2<f32>, // x = metallic, y = roughness\n _padding1: vec2<f32>,\n sectionPlane: vec4<f32>, // xyz = plane normal, w = plane distance\n flags: vec4<u32>, // x = isSelected, y = sectionEnabled, z = edgeEnabled, w = edgeIntensityMilli\n }\n @binding(0) @group(0) var<uniform> uniforms: Uniforms;\n\n struct VertexInput {\n @location(0) position: vec3<f32>,\n @location(1) normal: vec3<f32>,\n @location(2) entityId: u32,\n }\n\n struct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) worldPos: vec3<f32>,\n @location(1) normal: vec3<f32>,\n @location(2) @interpolate(flat) entityId: u32,\n @location(3) viewPos: vec3<f32>, // For edge detection\n }\n\n @vertex\n fn vs_main(input: VertexInput, @builtin(instance_index) instanceIndex: u32) -> VertexOutput {\n var output: VertexOutput;\n let worldPos = uniforms.model * vec4<f32>(input.position, 1.0);\n output.position = uniforms.viewProj * worldPos;\n // Anti z-fighting: deterministic depth nudge per entity.\n // Knuth multiplicative hash spreads sequential IDs across 0-255\n // so coplanar faces from different entities always get distinct depths.\n // At 1e-6 per step the max world-space offset is <3mm at 10m \u2014 invisible.\n let zHash = (input.entityId * 2654435761u) & 255u;\n output.position.z *= 1.0 + f32(zHash) * 1e-6;\n output.worldPos = worldPos.xyz;\n output.normal = normalize((uniforms.model * vec4<f32>(input.normal, 0.0)).xyz);\n output.entityId = input.entityId;\n // Store view-space position for edge detection\n output.viewPos = (uniforms.viewProj * worldPos).xyz;\n return output;\n }\n\n // PBR helper functions\n fn fresnelSchlick(cosTheta: f32, F0: vec3<f32>) -> vec3<f32> {\n return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);\n }\n\n fn distributionGGX(NdotH: f32, roughness: f32) -> f32 {\n let a = roughness * roughness;\n let a2 = a * a;\n let NdotH2 = NdotH * NdotH;\n let num = a2;\n let denomBase = (NdotH2 * (a2 - 1.0) + 1.0);\n let denom = 3.14159265 * denomBase * denomBase;\n return num / max(denom, 0.0000001);\n }\n\n fn geometrySchlickGGX(NdotV: f32, roughness: f32) -> f32 {\n let r = (roughness + 1.0);\n let k = (r * r) / 8.0;\n let num = NdotV;\n let denom = NdotV * (1.0 - k) + k;\n return num / max(denom, 0.0000001);\n }\n\n fn geometrySmith(NdotV: f32, NdotL: f32, roughness: f32) -> f32 {\n let ggx2 = geometrySchlickGGX(NdotV, roughness);\n let ggx1 = geometrySchlickGGX(NdotL, roughness);\n return ggx1 * ggx2;\n }\n\n fn encodeId24(id: u32) -> vec4<f32> {\n let r = f32((id >> 16u) & 255u) / 255.0;\n let g = f32((id >> 8u) & 255u) / 255.0;\n let b = f32(id & 255u) / 255.0;\n return vec4<f32>(r, g, b, 1.0);\n }\n\n struct FragmentOutput {\n @location(0) color: vec4<f32>,\n @location(1) objectIdEncoded: vec4<f32>,\n }\n\n @fragment\n fn fs_main(input: VertexOutput) -> FragmentOutput {\n // Section plane clipping - discard fragments ABOVE the plane.\n // flags.y packs two bits: bit 0 = enabled, bit 1 = flipped.\n let sectionEnabled = (uniforms.flags.y & 1u) == 1u;\n if (sectionEnabled) {\n let planeNormal = uniforms.sectionPlane.xyz;\n let planeDistance = uniforms.sectionPlane.w;\n let flipped = (uniforms.flags.y & 2u) == 2u;\n let side = select(1.0, -1.0, flipped);\n let distToPlane = (dot(input.worldPos, planeNormal) - planeDistance) * side;\n if (distToPlane > 0.0) {\n discard;\n }\n }\n\n // Compute normal via derivative-based flat shading.\n //\n // Industry-standard solution for BIM/CAD viewers \u2014 what\n // Three.js (material.flatShading = true), Autodesk Forge,\n // Speckle, and xeokit all do for opaque surfaces. Rationale:\n //\n // * BIM geometry is overwhelmingly flat surfaces (walls,\n // slabs, roofs, beams), and CSG operations (opening\n // subtraction, layer slicing) emit those surfaces as\n // dense strips of coplanar triangles. Per-vertex normal\n // averaging gives a SLIGHTLY-different normal at each\n // vertex due to f32 noise from boolean output; the\n // boundary between strips then reads as a visible darker/\n // brighter scar line \u2014 the horizontal striations on\n // walls, stripes on roofs, visible triangulation reports\n // across every CSG kernel we have tried (legacy BSP,\n // Manifold).\n // * cross(dpdx, dpdy) of world position evaluates to the\n // EXACT face normal in the fragment shader. Every\n // fragment on a flat face \u2014 across an arbitrarily-fine\n // triangulation \u2014 gets the IDENTICAL normal, so coplanar\n // splits become invisible by construction. No CPU-side\n // welding, smooth-grouping, or coplanar-face merging\n // fixes the symptom as cleanly.\n //\n // Trade-off: genuinely curved surfaces (cylinder tessellations,\n // BSpline approximations) shade with visible facets. For BIM\n // that's acceptable \u2014 curved surfaces are < 5 % of typical\n // model triangle count and the faceting matches CAD-tool\n // (Revit, ArchiCAD) on-screen behaviour at default quality.\n //\n // We still fall back to the vertex normal when derivatives\n // are unavailable (extreme polygon degeneracy where dpdx /\n // dpdy collapse to zero \u2014 practically never on real geometry).\n let faceN = cross(dpdx(input.worldPos), dpdy(input.worldPos));\n let fLen2 = dot(faceN, faceN);\n var N: vec3<f32>;\n if (fLen2 > 1e-10) {\n N = faceN * inverseSqrt(fLen2);\n } else {\n // Degenerate derivative \u2014 fall back to the vertex normal\n // if it's populated, else +Y.\n N = input.normal;\n let nLen2 = dot(N, N);\n if (nLen2 > 1e-6) {\n N = N * inverseSqrt(nLen2);\n } else {\n N = vec3<f32>(0.0, 1.0, 0.0);\n }\n }\n\n // Stabilize the SIGN of the derivative face normal with the vertex\n // normal. The screen-space cross product gives the exact face\n // normal DIRECTION for coplanar strips (the scar-line fix), but at\n // grazing angles its SIGN becomes numerically unstable per quad \u2014\n // hemisphere/rim lighting then band-flips across large regions of\n // flat walls/slabs (diagonal lighter/darker bands). The interpolated\n // vertex normal is quad-noise-free, so use it only to orient N.\n // Guard: skip when the vertex normal is missing or nearly\n // perpendicular to the face normal (unreliable witness).\n let vN = input.normal;\n let alignDot = dot(N, vN);\n if (alignDot * alignDot > 0.03 * dot(vN, vN)) {\n N = N * sign(alignDot);\n }\n\n // Enhanced lighting with multiple sources\n let sunLight = normalize(vec3<f32>(0.5, 1.0, 0.3)); // Main directional light\n let fillLight = normalize(vec3<f32>(-0.5, 0.3, -0.3)); // Fill light\n let rimLight = normalize(vec3<f32>(0.0, 0.2, -1.0)); // Rim light for edge definition\n\n // Hemisphere ambient - reduced for less washed-out look\n let skyColor = vec3<f32>(0.3, 0.35, 0.4); // Darker sky\n let groundColor = vec3<f32>(0.15, 0.1, 0.08); // Darker ground\n let hemisphereFactor = N.y * 0.5 + 0.5;\n let ambient = mix(groundColor, skyColor, hemisphereFactor) * 0.25;\n\n // Two-sided sun light so inner faces (I-beam channels) stay visible\n let NdotL = abs(dot(N, sunLight));\n let wrap = 0.3;\n let diffuseSun = max((NdotL + wrap) / (1.0 + wrap), 0.0) * 0.55;\n\n // Fill light - two-sided\n let NdotFill = abs(dot(N, fillLight));\n let diffuseFill = NdotFill * 0.15;\n\n // Rim light for edge definition\n let NdotRim = max(dot(N, rimLight), 0.0);\n let rim = pow(NdotRim, 4.0) * 0.15;\n\n var baseColor = uniforms.baseColor.rgb;\n\n // Detect if the color is close to white/gray (low saturation)\n let baseGray = dot(baseColor, vec3<f32>(0.299, 0.587, 0.114));\n let baseSaturation = length(baseColor - vec3<f32>(baseGray)) / max(baseGray, 0.001);\n let isWhiteish = 1.0 - smoothstep(0.0, 0.3, baseSaturation);\n\n // Darken whites/grays more to reduce washed-out appearance\n baseColor = mix(baseColor, baseColor * 0.7, isWhiteish * 0.4);\n\n // Combine all lighting\n var color = baseColor * (ambient + diffuseSun + diffuseFill + rim);\n\n // flags.x is a bitfield:\n // bit 0 (value 1) = isSelected \u2192 selection-highlight + force opaque\n // bit 1 (value 2) = isOverlay \u2192 color-override pass; preserve\n // baseColor.a (overlay pipeline has\n // src-alpha blending) AND skip the\n // glass-fresnel branch so low-alpha\n // ghost tints don't pick up the\n // near-white reflection tint meant\n // for real glass materials.\n let isSelected = (uniforms.flags.x & 1u) == 1u;\n let isOverlay = (uniforms.flags.x & 2u) == 2u;\n\n // Selection highlight \u2014 a single FLAT selection colour.\n //\n // No lighting-dependent (luminance) or view-dependent (fresnel)\n // term: the selected object must read as one uniform colour, not\n // a shaded/gradient surface. The previous fresnel-glow mix left\n // 80 % of the lit object colour visible at face centres (the\n // green-site / red-roof bleed-through). A constant colour here\n // also stays flat through the downstream tone-mapping, since\n // those are per-pixel functions of a now-constant input.\n if (isSelected) {\n color = vec3<f32>(0.3, 0.6, 1.0);\n }\n\n // Beautiful fresnel effect for transparent materials (glass)\n // Skip when selected \u2014 the glass shine and desaturation wash out the\n // blue highlight, making it appear white instead of blue.\n // Also force alpha to 1.0 for selected objects so the highlight is\n // fully opaque (the selection pipeline has no alpha blending).\n var finalAlpha = select(uniforms.baseColor.a, 1.0, isSelected);\n if (finalAlpha < 0.99 && !isSelected && !isOverlay) {\n // Calculate view direction for fresnel\n let V = normalize(-input.worldPos);\n let NdotV = max(dot(N, V), 0.0);\n\n // Enhanced fresnel effect - stronger at edges (grazing angles)\n // Using Schlick's approximation for realistic glass reflection\n let fresnelPower = 1.5; // Higher = softer edge reflections\n let fresnel = pow(1.0 - NdotV, fresnelPower);\n\n // Glass reflection tint (sky/environment reflection at edges)\n let reflectionTint = vec3<f32>(0.92, 0.96, 1.0); // Cool sky reflection\n let reflectionStrength = fresnel * 0.6; // Strong edge reflections\n\n // Mix in reflection tint at edges\n color = mix(color, color * reflectionTint, reflectionStrength);\n\n // Add realistic glass shine - brighter at edges where light reflects\n let glassShine = fresnel * 0.12;\n color += glassShine;\n\n // Slight desaturation at edges (glass reflects environment, not just color)\n let edgeDesaturation = fresnel * 0.25;\n let gray = dot(color, vec3<f32>(0.299, 0.587, 0.114));\n color = mix(color, vec3<f32>(gray), edgeDesaturation);\n\n // Make glass more transparent (reduce opacity by 30%)\n finalAlpha = finalAlpha * 0.7;\n }\n\n // Exposure adjustment - darken overall\n color *= 0.85;\n\n // Contrast enhancement\n color = (color - 0.5) * 1.15 + 0.5;\n color = max(color, vec3<f32>(0.0));\n\n // Saturation boost - stronger for colored surfaces, less for whites\n let gray = dot(color, vec3<f32>(0.299, 0.587, 0.114));\n let satBoost = mix(1.4, 1.1, isWhiteish); // More saturation for colored surfaces\n color = mix(vec3<f32>(gray), color, satBoost);\n\n // ACES filmic tone mapping\n let a = 2.51;\n let b = 0.03;\n let c = 2.43;\n let d = 0.59;\n let e = 0.14;\n color = clamp((color * (a * color + b)) / (color * (c * color + d) + e), vec3<f32>(0.0), vec3<f32>(1.0));\n\n // Subtle edge enhancement using screen-space derivatives.\n //\n // Use the SHADED normal (face normal from dpdx/dpdy above)\n // for the normal-gradient term, not the interpolated vertex\n // normal \u2014 otherwise we get spurious dark stripes on flat\n // surfaces whose vertex normals carry numerical noise from\n // CSG output (the visible scar-line symptom would just\n // resurface here even after the lit-normal fix). With the\n // face normal, coplanar adjacent triangles agree exactly \u2192\n // zero normal gradient \u2192 no false edge; only the genuine\n // creases between perpendicular faces produce a real\n // gradient and get the intended outline.\n let depthGradient = length(vec2<f32>(\n dpdx(input.viewPos.z),\n dpdy(input.viewPos.z)\n ));\n let normalGradient = length(vec2<f32>(\n length(dpdx(N)),\n length(dpdy(N))\n ));\n\n if (uniforms.flags.z == 1u) {\n // Threshold filters subtle normal discontinuities at internal\n // triangle edges between coplanar entities in the same batch.\n let edgeFactor = smoothstep(0.02, 0.12, depthGradient * 10.0 + normalGradient * 5.0);\n let edgeIntensity = f32(uniforms.flags.w) / 1000.0;\n let edgeDarkenStrength = clamp(0.25 * edgeIntensity, 0.0, 0.85);\n let edgeDarken = mix(1.0, 1.0 - edgeDarkenStrength, edgeFactor);\n color *= edgeDarken;\n }\n\n // Gamma correction\n color = pow(color, vec3<f32>(1.0 / 2.2));\n\n var out: FragmentOutput;\n out.color = vec4<f32>(color, finalAlpha);\n out.objectIdEncoded = encodeId24(input.entityId);\n return out;\n }\n ";
6
+ export declare const mainShaderSource = "\n struct Uniforms {\n viewProj: mat4x4<f32>,\n model: mat4x4<f32>,\n baseColor: vec4<f32>,\n metallicRoughness: vec2<f32>, // x = metallic, y = roughness\n _padding1: vec2<f32>,\n sectionPlane: vec4<f32>, // xyz = plane normal, w = plane distance\n flags: vec4<u32>, // x = isSelected, y = sectionEnabled, z = edgeEnabled, w = edgeIntensityMilli\n }\n @binding(0) @group(0) var<uniform> uniforms: Uniforms;\n\n // Global lighting environment \u2014 one buffer shared by every mesh in\n // the pass (bound once per frame at group(1)). Field packing must\n // match packEnvironmentUniforms() in environment.ts.\n struct Environment {\n sunDirection: vec3<f32>, // unit vector TOWARD the sun\n sunIntensity: f32,\n sunColor: vec3<f32>,\n ambientIntensity: f32,\n skyColor: vec3<f32>, // hemisphere-ambient sky tint\n exposure: f32,\n groundColor: vec3<f32>, // hemisphere-ambient ground tint\n fillIntensity: f32,\n rimIntensity: f32,\n _pad0: f32,\n _pad1: f32,\n _pad2: f32,\n }\n @binding(0) @group(1) var<uniform> env: Environment;\n\n struct VertexInput {\n @location(0) position: vec3<f32>,\n @location(1) normal: vec3<f32>,\n @location(2) entityId: u32,\n }\n\n struct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) worldPos: vec3<f32>,\n @location(1) normal: vec3<f32>,\n @location(2) @interpolate(flat) entityId: u32,\n @location(3) viewPos: vec3<f32>, // For edge detection\n }\n\n @vertex\n fn vs_main(input: VertexInput, @builtin(instance_index) instanceIndex: u32) -> VertexOutput {\n var output: VertexOutput;\n let worldPos = uniforms.model * vec4<f32>(input.position, 1.0);\n output.position = uniforms.viewProj * worldPos;\n // Anti z-fighting: deterministic depth nudge per entity.\n // Knuth multiplicative hash spreads sequential IDs across 0-255\n // so coplanar faces from different entities always get distinct depths.\n // At 1e-6 per step the max world-space offset is <3mm at 10m \u2014 invisible.\n let zHash = (input.entityId * 2654435761u) & 255u;\n output.position.z *= 1.0 + f32(zHash) * 1e-6;\n output.worldPos = worldPos.xyz;\n output.normal = normalize((uniforms.model * vec4<f32>(input.normal, 0.0)).xyz);\n output.entityId = input.entityId;\n // Store view-space position for edge detection\n output.viewPos = (uniforms.viewProj * worldPos).xyz;\n return output;\n }\n\n // PBR helper functions\n fn fresnelSchlick(cosTheta: f32, F0: vec3<f32>) -> vec3<f32> {\n return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);\n }\n\n fn distributionGGX(NdotH: f32, roughness: f32) -> f32 {\n let a = roughness * roughness;\n let a2 = a * a;\n let NdotH2 = NdotH * NdotH;\n let num = a2;\n let denomBase = (NdotH2 * (a2 - 1.0) + 1.0);\n let denom = 3.14159265 * denomBase * denomBase;\n return num / max(denom, 0.0000001);\n }\n\n fn geometrySchlickGGX(NdotV: f32, roughness: f32) -> f32 {\n let r = (roughness + 1.0);\n let k = (r * r) / 8.0;\n let num = NdotV;\n let denom = NdotV * (1.0 - k) + k;\n return num / max(denom, 0.0000001);\n }\n\n fn geometrySmith(NdotV: f32, NdotL: f32, roughness: f32) -> f32 {\n let ggx2 = geometrySchlickGGX(NdotV, roughness);\n let ggx1 = geometrySchlickGGX(NdotL, roughness);\n return ggx1 * ggx2;\n }\n\n fn encodeId24(id: u32) -> vec4<f32> {\n let r = f32((id >> 16u) & 255u) / 255.0;\n let g = f32((id >> 8u) & 255u) / 255.0;\n let b = f32(id & 255u) / 255.0;\n return vec4<f32>(r, g, b, 1.0);\n }\n\n struct FragmentOutput {\n @location(0) color: vec4<f32>,\n @location(1) objectIdEncoded: vec4<f32>,\n }\n\n @fragment\n fn fs_main(input: VertexOutput) -> FragmentOutput {\n // Section plane clipping - discard fragments ABOVE the plane.\n // flags.y packs two bits: bit 0 = enabled, bit 1 = flipped.\n let sectionEnabled = (uniforms.flags.y & 1u) == 1u;\n if (sectionEnabled) {\n let planeNormal = uniforms.sectionPlane.xyz;\n let planeDistance = uniforms.sectionPlane.w;\n let flipped = (uniforms.flags.y & 2u) == 2u;\n let side = select(1.0, -1.0, flipped);\n let distToPlane = (dot(input.worldPos, planeNormal) - planeDistance) * side;\n if (distToPlane > 0.0) {\n discard;\n }\n }\n\n // Compute normal via derivative-based flat shading.\n //\n // Industry-standard solution for BIM/CAD viewers \u2014 what\n // Three.js (material.flatShading = true), Autodesk Forge,\n // Speckle, and xeokit all do for opaque surfaces. Rationale:\n //\n // * BIM geometry is overwhelmingly flat surfaces (walls,\n // slabs, roofs, beams), and CSG operations (opening\n // subtraction, layer slicing) emit those surfaces as\n // dense strips of coplanar triangles. Per-vertex normal\n // averaging gives a SLIGHTLY-different normal at each\n // vertex due to f32 noise from boolean output; the\n // boundary between strips then reads as a visible darker/\n // brighter scar line \u2014 the horizontal striations on\n // walls, stripes on roofs, visible triangulation reports\n // across every CSG kernel we have tried (legacy BSP,\n // Manifold).\n // * cross(dpdx, dpdy) of world position evaluates to the\n // EXACT face normal in the fragment shader. Every\n // fragment on a flat face \u2014 across an arbitrarily-fine\n // triangulation \u2014 gets the IDENTICAL normal, so coplanar\n // splits become invisible by construction. No CPU-side\n // welding, smooth-grouping, or coplanar-face merging\n // fixes the symptom as cleanly.\n //\n // Trade-off: genuinely curved surfaces (cylinder tessellations,\n // BSpline approximations) shade with visible facets. For BIM\n // that's acceptable \u2014 curved surfaces are < 5 % of typical\n // model triangle count and the faceting matches CAD-tool\n // (Revit, ArchiCAD) on-screen behaviour at default quality.\n //\n // We still fall back to the vertex normal when derivatives\n // are unavailable (extreme polygon degeneracy where dpdx /\n // dpdy collapse to zero \u2014 practically never on real geometry).\n let faceN = cross(dpdx(input.worldPos), dpdy(input.worldPos));\n let fLen2 = dot(faceN, faceN);\n var N: vec3<f32>;\n if (fLen2 > 1e-10) {\n N = faceN * inverseSqrt(fLen2);\n } else {\n // Degenerate derivative \u2014 fall back to the vertex normal\n // if it's populated, else +Y.\n N = input.normal;\n let nLen2 = dot(N, N);\n if (nLen2 > 1e-6) {\n N = N * inverseSqrt(nLen2);\n } else {\n N = vec3<f32>(0.0, 1.0, 0.0);\n }\n }\n\n // Stabilize the SIGN of the derivative face normal with the vertex\n // normal. The screen-space cross product gives the exact face\n // normal DIRECTION for coplanar strips (the scar-line fix), but at\n // grazing angles its SIGN becomes numerically unstable per quad \u2014\n // hemisphere/rim lighting then band-flips across large regions of\n // flat walls/slabs (diagonal lighter/darker bands). The interpolated\n // vertex normal is quad-noise-free, so use it only to orient N.\n // Guard: skip when the vertex normal is missing or nearly\n // perpendicular to the face normal (unreliable witness).\n let vN = input.normal;\n let alignDot = dot(N, vN);\n if (alignDot * alignDot > 0.03 * dot(vN, vN)) {\n N = N * sign(alignDot);\n }\n\n // Lighting environment \u2014 sun/hemisphere/exposure come from the\n // global env uniform (defaults reproduce the historic hardcoded\n // values); fill + rim directions stay fixed in view-agnostic\n // world space as stylistic shaping lights.\n let sunLight = env.sunDirection;\n let fillLight = normalize(vec3<f32>(-0.5, 0.3, -0.3)); // Fill light\n let rimLight = normalize(vec3<f32>(0.0, 0.2, -1.0)); // Rim light for edge definition\n\n // Hemisphere ambient\n let hemisphereFactor = N.y * 0.5 + 0.5;\n let ambient = mix(env.groundColor, env.skyColor, hemisphereFactor) * env.ambientIntensity;\n\n // Two-sided sun light so inner faces (I-beam channels) stay visible\n let NdotL = abs(dot(N, sunLight));\n let wrap = 0.3;\n let diffuseSun = max((NdotL + wrap) / (1.0 + wrap), 0.0) * env.sunIntensity;\n\n // Fill light - two-sided\n let NdotFill = abs(dot(N, fillLight));\n let diffuseFill = NdotFill * env.fillIntensity;\n\n // Rim light for edge definition\n let NdotRim = max(dot(N, rimLight), 0.0);\n let rim = pow(NdotRim, 4.0) * env.rimIntensity;\n\n var baseColor = uniforms.baseColor.rgb;\n\n // Detect if the color is close to white/gray (low saturation)\n let baseGray = dot(baseColor, vec3<f32>(0.299, 0.587, 0.114));\n let baseSaturation = length(baseColor - vec3<f32>(baseGray)) / max(baseGray, 0.001);\n let isWhiteish = 1.0 - smoothstep(0.0, 0.3, baseSaturation);\n\n // Darken whites/grays more to reduce washed-out appearance\n baseColor = mix(baseColor, baseColor * 0.7, isWhiteish * 0.4);\n\n // Combine all lighting\n var color = baseColor * (ambient + env.sunColor * diffuseSun + vec3<f32>(diffuseFill + rim));\n\n // flags.x is a bitfield:\n // bit 0 (value 1) = isSelected \u2192 selection-highlight + force opaque\n // bit 1 (value 2) = isOverlay \u2192 color-override pass; preserve\n // baseColor.a (overlay pipeline has\n // src-alpha blending) AND skip the\n // glass-fresnel branch so low-alpha\n // ghost tints don't pick up the\n // near-white reflection tint meant\n // for real glass materials.\n let isSelected = (uniforms.flags.x & 1u) == 1u;\n let isOverlay = (uniforms.flags.x & 2u) == 2u;\n\n // Selection highlight \u2014 a single FLAT selection colour.\n //\n // No lighting-dependent (luminance) or view-dependent (fresnel)\n // term: the selected object must read as one uniform colour, not\n // a shaded/gradient surface. The previous fresnel-glow mix left\n // 80 % of the lit object colour visible at face centres (the\n // green-site / red-roof bleed-through). A constant colour here\n // also stays flat through the downstream tone-mapping, since\n // those are per-pixel functions of a now-constant input.\n if (isSelected) {\n color = vec3<f32>(0.3, 0.6, 1.0);\n }\n\n // Beautiful fresnel effect for transparent materials (glass)\n // Skip when selected \u2014 the glass shine and desaturation wash out the\n // blue highlight, making it appear white instead of blue.\n // Also force alpha to 1.0 for selected objects so the highlight is\n // fully opaque (the selection pipeline has no alpha blending).\n var finalAlpha = select(uniforms.baseColor.a, 1.0, isSelected);\n if (finalAlpha < 0.99 && !isSelected && !isOverlay) {\n // Calculate view direction for fresnel\n let V = normalize(-input.worldPos);\n let NdotV = max(dot(N, V), 0.0);\n\n // Enhanced fresnel effect - stronger at edges (grazing angles)\n // Using Schlick's approximation for realistic glass reflection\n let fresnelPower = 1.5; // Higher = softer edge reflections\n let fresnel = pow(1.0 - NdotV, fresnelPower);\n\n // Glass reflection tint (sky/environment reflection at edges)\n let reflectionTint = vec3<f32>(0.92, 0.96, 1.0); // Cool sky reflection\n let reflectionStrength = fresnel * 0.6; // Strong edge reflections\n\n // Mix in reflection tint at edges\n color = mix(color, color * reflectionTint, reflectionStrength);\n\n // Add realistic glass shine - brighter at edges where light reflects\n let glassShine = fresnel * 0.12;\n color += glassShine;\n\n // Slight desaturation at edges (glass reflects environment, not just color)\n let edgeDesaturation = fresnel * 0.25;\n let gray = dot(color, vec3<f32>(0.299, 0.587, 0.114));\n color = mix(color, vec3<f32>(gray), edgeDesaturation);\n\n // Make glass more transparent (reduce opacity by 30%)\n finalAlpha = finalAlpha * 0.7;\n }\n\n // Exposure adjustment (historic default 0.85 darkens overall)\n color *= env.exposure;\n\n // Contrast enhancement\n color = (color - 0.5) * 1.15 + 0.5;\n color = max(color, vec3<f32>(0.0));\n\n // Saturation boost - stronger for colored surfaces, less for whites\n let gray = dot(color, vec3<f32>(0.299, 0.587, 0.114));\n let satBoost = mix(1.4, 1.1, isWhiteish); // More saturation for colored surfaces\n color = mix(vec3<f32>(gray), color, satBoost);\n\n // ACES filmic tone mapping\n let a = 2.51;\n let b = 0.03;\n let c = 2.43;\n let d = 0.59;\n let e = 0.14;\n color = clamp((color * (a * color + b)) / (color * (c * color + d) + e), vec3<f32>(0.0), vec3<f32>(1.0));\n\n // Subtle edge enhancement using screen-space derivatives.\n //\n // Use the SHADED normal (face normal from dpdx/dpdy above)\n // for the normal-gradient term, not the interpolated vertex\n // normal \u2014 otherwise we get spurious dark stripes on flat\n // surfaces whose vertex normals carry numerical noise from\n // CSG output (the visible scar-line symptom would just\n // resurface here even after the lit-normal fix). With the\n // face normal, coplanar adjacent triangles agree exactly \u2192\n // zero normal gradient \u2192 no false edge; only the genuine\n // creases between perpendicular faces produce a real\n // gradient and get the intended outline.\n let depthGradient = length(vec2<f32>(\n dpdx(input.viewPos.z),\n dpdy(input.viewPos.z)\n ));\n let normalGradient = length(vec2<f32>(\n length(dpdx(N)),\n length(dpdy(N))\n ));\n\n if (uniforms.flags.z == 1u) {\n // Threshold filters subtle normal discontinuities at internal\n // triangle edges between coplanar entities in the same batch.\n let edgeFactor = smoothstep(0.02, 0.12, depthGradient * 10.0 + normalGradient * 5.0);\n let edgeIntensity = f32(uniforms.flags.w) / 1000.0;\n let edgeDarkenStrength = clamp(0.25 * edgeIntensity, 0.0, 0.85);\n let edgeDarken = mix(1.0, 1.0 - edgeDarkenStrength, edgeFactor);\n color *= edgeDarken;\n }\n\n // Gamma correction\n color = pow(color, vec3<f32>(1.0 / 2.2));\n\n var out: FragmentOutput;\n out.color = vec4<f32>(color, finalAlpha);\n out.objectIdEncoded = encodeId24(input.entityId);\n return out;\n }\n ";
7
7
  //# sourceMappingURL=main.wgsl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"main.wgsl.d.ts","sourceRoot":"","sources":["../../src/shaders/main.wgsl.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,g6eAqUtB,CAAC"}
1
+ {"version":3,"file":"main.wgsl.d.ts","sourceRoot":"","sources":["../../src/shaders/main.wgsl.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,wzgBAyVtB,CAAC"}
@@ -18,6 +18,25 @@ export const mainShaderSource = `
18
18
  }
19
19
  @binding(0) @group(0) var<uniform> uniforms: Uniforms;
20
20
 
21
+ // Global lighting environment — one buffer shared by every mesh in
22
+ // the pass (bound once per frame at group(1)). Field packing must
23
+ // match packEnvironmentUniforms() in environment.ts.
24
+ struct Environment {
25
+ sunDirection: vec3<f32>, // unit vector TOWARD the sun
26
+ sunIntensity: f32,
27
+ sunColor: vec3<f32>,
28
+ ambientIntensity: f32,
29
+ skyColor: vec3<f32>, // hemisphere-ambient sky tint
30
+ exposure: f32,
31
+ groundColor: vec3<f32>, // hemisphere-ambient ground tint
32
+ fillIntensity: f32,
33
+ rimIntensity: f32,
34
+ _pad0: f32,
35
+ _pad1: f32,
36
+ _pad2: f32,
37
+ }
38
+ @binding(0) @group(1) var<uniform> env: Environment;
39
+
21
40
  struct VertexInput {
22
41
  @location(0) position: vec3<f32>,
23
42
  @location(1) normal: vec3<f32>,
@@ -174,29 +193,30 @@ export const mainShaderSource = `
174
193
  N = N * sign(alignDot);
175
194
  }
176
195
 
177
- // Enhanced lighting with multiple sources
178
- let sunLight = normalize(vec3<f32>(0.5, 1.0, 0.3)); // Main directional light
196
+ // Lighting environment sun/hemisphere/exposure come from the
197
+ // global env uniform (defaults reproduce the historic hardcoded
198
+ // values); fill + rim directions stay fixed in view-agnostic
199
+ // world space as stylistic shaping lights.
200
+ let sunLight = env.sunDirection;
179
201
  let fillLight = normalize(vec3<f32>(-0.5, 0.3, -0.3)); // Fill light
180
202
  let rimLight = normalize(vec3<f32>(0.0, 0.2, -1.0)); // Rim light for edge definition
181
203
 
182
- // Hemisphere ambient - reduced for less washed-out look
183
- let skyColor = vec3<f32>(0.3, 0.35, 0.4); // Darker sky
184
- let groundColor = vec3<f32>(0.15, 0.1, 0.08); // Darker ground
204
+ // Hemisphere ambient
185
205
  let hemisphereFactor = N.y * 0.5 + 0.5;
186
- let ambient = mix(groundColor, skyColor, hemisphereFactor) * 0.25;
206
+ let ambient = mix(env.groundColor, env.skyColor, hemisphereFactor) * env.ambientIntensity;
187
207
 
188
208
  // Two-sided sun light so inner faces (I-beam channels) stay visible
189
209
  let NdotL = abs(dot(N, sunLight));
190
210
  let wrap = 0.3;
191
- let diffuseSun = max((NdotL + wrap) / (1.0 + wrap), 0.0) * 0.55;
211
+ let diffuseSun = max((NdotL + wrap) / (1.0 + wrap), 0.0) * env.sunIntensity;
192
212
 
193
213
  // Fill light - two-sided
194
214
  let NdotFill = abs(dot(N, fillLight));
195
- let diffuseFill = NdotFill * 0.15;
215
+ let diffuseFill = NdotFill * env.fillIntensity;
196
216
 
197
217
  // Rim light for edge definition
198
218
  let NdotRim = max(dot(N, rimLight), 0.0);
199
- let rim = pow(NdotRim, 4.0) * 0.15;
219
+ let rim = pow(NdotRim, 4.0) * env.rimIntensity;
200
220
 
201
221
  var baseColor = uniforms.baseColor.rgb;
202
222
 
@@ -209,7 +229,7 @@ export const mainShaderSource = `
209
229
  baseColor = mix(baseColor, baseColor * 0.7, isWhiteish * 0.4);
210
230
 
211
231
  // Combine all lighting
212
- var color = baseColor * (ambient + diffuseSun + diffuseFill + rim);
232
+ var color = baseColor * (ambient + env.sunColor * diffuseSun + vec3<f32>(diffuseFill + rim));
213
233
 
214
234
  // flags.x is a bitfield:
215
235
  // bit 0 (value 1) = isSelected → selection-highlight + force opaque
@@ -272,8 +292,8 @@ export const mainShaderSource = `
272
292
  finalAlpha = finalAlpha * 0.7;
273
293
  }
274
294
 
275
- // Exposure adjustment - darken overall
276
- color *= 0.85;
295
+ // Exposure adjustment (historic default 0.85 darkens overall)
296
+ color *= env.exposure;
277
297
 
278
298
  // Contrast enhancement
279
299
  color = (color - 0.5) * 1.15 + 0.5;
@@ -1 +1 @@
1
- {"version":3,"file":"main.wgsl.js","sourceRoot":"","sources":["../../src/shaders/main.wgsl.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqUzB,CAAC"}
1
+ {"version":3,"file":"main.wgsl.js","sourceRoot":"","sources":["../../src/shaders/main.wgsl.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyVzB,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Procedural sky background — a single fullscreen triangle drawn at the far
3
+ * plane (reverse-Z: z = 0) before any geometry. Analytic zenith/horizon/
4
+ * ground gradient plus a sun disc + glow, driven by the same sun direction
5
+ * the geometry lighting uses.
6
+ *
7
+ * Tonemapping note: the geometry shader applies ACES + gamma at the end of
8
+ * its fragment stage (not in a post pass), so the sky must apply the same
9
+ * curve here or it would read as a different "film stock" than the model.
10
+ */
11
+ export declare const skyShaderSource = "\n struct SkyUniforms {\n camRight: vec3<f32>,\n tanHalfFovX: f32,\n camUp: vec3<f32>,\n tanHalfFovY: f32,\n camForward: vec3<f32>,\n exposure: f32,\n sunDirection: vec3<f32>,\n sunIntensity: f32,\n zenithColor: vec3<f32>,\n _pad0: f32,\n horizonColor: vec3<f32>,\n _pad1: f32,\n groundColor: vec3<f32>,\n _pad2: f32,\n }\n @binding(0) @group(0) var<uniform> sky: SkyUniforms;\n\n struct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) ndc: vec2<f32>,\n }\n\n @vertex\n fn vs_main(@builtin(vertex_index) vi: u32) -> VertexOutput {\n // Fullscreen triangle: (-1,-1), (3,-1), (-1,3).\n let x = f32((vi << 1u) & 2u) * 2.0 - 1.0;\n let y = f32(vi & 2u) * 2.0 - 1.0;\n var out: VertexOutput;\n // z = 0 is the far plane under reverse-Z, so any geometry drawn\n // later wins the depth test without the sky writing depth.\n out.position = vec4<f32>(x, y, 0.0, 1.0);\n out.ndc = vec2<f32>(x, y);\n return out;\n }\n\n // Same ACES filmic curve as the geometry fragment shader.\n fn acesTonemap(c: vec3<f32>) -> vec3<f32> {\n let a = 2.51;\n let b = 0.03;\n let cc = 2.43;\n let d = 0.59;\n let e = 0.14;\n return clamp((c * (a * c + b)) / (c * (cc * c + d) + e), vec3<f32>(0.0), vec3<f32>(1.0));\n }\n\n struct FragmentOutput {\n @location(0) color: vec4<f32>,\n // Matches the pass's object-id attachment clear value so the sky\n // never registers as a pickable entity.\n @location(1) objectIdEncoded: vec4<f32>,\n }\n\n @fragment\n fn fs_main(input: VertexOutput) -> FragmentOutput {\n // Per-pixel view ray from the camera basis. Used for orthographic\n // cameras too \u2014 parallel rays would collapse the sky to a single\n // colour, so a perspective-style fan reads better in both modes.\n let dir = normalize(\n sky.camForward\n + input.ndc.x * sky.tanHalfFovX * sky.camRight\n + input.ndc.y * sky.tanHalfFovY * sky.camUp\n );\n let elevation = dir.y;\n\n // Horizon \u2192 zenith gradient with a slow falloff near the horizon.\n let zenithMix = pow(clamp(elevation, 0.0, 1.0), 0.45);\n var color = mix(sky.horizonColor, sky.zenithColor, zenithMix);\n\n // Below the horizon: fade quickly into the ground colour.\n let groundMix = smoothstep(0.0, -0.1, elevation);\n color = mix(color, sky.groundColor, groundMix);\n\n // Sun disc + glow. The disc is slightly oversized vs the real\n // ~0.53\u00B0 sun so it stays visible at typical canvas resolutions.\n let cosSun = dot(dir, sky.sunDirection);\n let disc = smoothstep(0.99985, 0.99995, cosSun);\n let glow = pow(max(cosSun, 0.0), 350.0) * 0.5\n + pow(max(cosSun, 0.0), 24.0) * 0.12;\n // Hide the disc once the sun sets, and never draw it on the ground.\n let sunVisible = smoothstep(-0.06, 0.02, sky.sunDirection.y) * (1.0 - groundMix);\n let sunTint = vec3<f32>(1.0, 0.92, 0.78);\n color += (disc * 6.0 + glow) * max(sky.sunIntensity, 0.0) * sunVisible * sunTint;\n\n // Match the geometry pipeline: exposure \u2192 ACES \u2192 gamma.\n color *= sky.exposure;\n color = acesTonemap(color);\n color = pow(color, vec3<f32>(1.0 / 2.2));\n\n var out: FragmentOutput;\n out.color = vec4<f32>(color, 1.0);\n out.objectIdEncoded = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n return out;\n }\n ";
12
+ //# sourceMappingURL=sky.wgsl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sky.wgsl.d.ts","sourceRoot":"","sources":["../../src/shaders/sky.wgsl.ts"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,k0HA+FrB,CAAC"}
@@ -0,0 +1,110 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * Procedural sky background — a single fullscreen triangle drawn at the far
6
+ * plane (reverse-Z: z = 0) before any geometry. Analytic zenith/horizon/
7
+ * ground gradient plus a sun disc + glow, driven by the same sun direction
8
+ * the geometry lighting uses.
9
+ *
10
+ * Tonemapping note: the geometry shader applies ACES + gamma at the end of
11
+ * its fragment stage (not in a post pass), so the sky must apply the same
12
+ * curve here or it would read as a different "film stock" than the model.
13
+ */
14
+ export const skyShaderSource = `
15
+ struct SkyUniforms {
16
+ camRight: vec3<f32>,
17
+ tanHalfFovX: f32,
18
+ camUp: vec3<f32>,
19
+ tanHalfFovY: f32,
20
+ camForward: vec3<f32>,
21
+ exposure: f32,
22
+ sunDirection: vec3<f32>,
23
+ sunIntensity: f32,
24
+ zenithColor: vec3<f32>,
25
+ _pad0: f32,
26
+ horizonColor: vec3<f32>,
27
+ _pad1: f32,
28
+ groundColor: vec3<f32>,
29
+ _pad2: f32,
30
+ }
31
+ @binding(0) @group(0) var<uniform> sky: SkyUniforms;
32
+
33
+ struct VertexOutput {
34
+ @builtin(position) position: vec4<f32>,
35
+ @location(0) ndc: vec2<f32>,
36
+ }
37
+
38
+ @vertex
39
+ fn vs_main(@builtin(vertex_index) vi: u32) -> VertexOutput {
40
+ // Fullscreen triangle: (-1,-1), (3,-1), (-1,3).
41
+ let x = f32((vi << 1u) & 2u) * 2.0 - 1.0;
42
+ let y = f32(vi & 2u) * 2.0 - 1.0;
43
+ var out: VertexOutput;
44
+ // z = 0 is the far plane under reverse-Z, so any geometry drawn
45
+ // later wins the depth test without the sky writing depth.
46
+ out.position = vec4<f32>(x, y, 0.0, 1.0);
47
+ out.ndc = vec2<f32>(x, y);
48
+ return out;
49
+ }
50
+
51
+ // Same ACES filmic curve as the geometry fragment shader.
52
+ fn acesTonemap(c: vec3<f32>) -> vec3<f32> {
53
+ let a = 2.51;
54
+ let b = 0.03;
55
+ let cc = 2.43;
56
+ let d = 0.59;
57
+ let e = 0.14;
58
+ return clamp((c * (a * c + b)) / (c * (cc * c + d) + e), vec3<f32>(0.0), vec3<f32>(1.0));
59
+ }
60
+
61
+ struct FragmentOutput {
62
+ @location(0) color: vec4<f32>,
63
+ // Matches the pass's object-id attachment clear value so the sky
64
+ // never registers as a pickable entity.
65
+ @location(1) objectIdEncoded: vec4<f32>,
66
+ }
67
+
68
+ @fragment
69
+ fn fs_main(input: VertexOutput) -> FragmentOutput {
70
+ // Per-pixel view ray from the camera basis. Used for orthographic
71
+ // cameras too — parallel rays would collapse the sky to a single
72
+ // colour, so a perspective-style fan reads better in both modes.
73
+ let dir = normalize(
74
+ sky.camForward
75
+ + input.ndc.x * sky.tanHalfFovX * sky.camRight
76
+ + input.ndc.y * sky.tanHalfFovY * sky.camUp
77
+ );
78
+ let elevation = dir.y;
79
+
80
+ // Horizon → zenith gradient with a slow falloff near the horizon.
81
+ let zenithMix = pow(clamp(elevation, 0.0, 1.0), 0.45);
82
+ var color = mix(sky.horizonColor, sky.zenithColor, zenithMix);
83
+
84
+ // Below the horizon: fade quickly into the ground colour.
85
+ let groundMix = smoothstep(0.0, -0.1, elevation);
86
+ color = mix(color, sky.groundColor, groundMix);
87
+
88
+ // Sun disc + glow. The disc is slightly oversized vs the real
89
+ // ~0.53° sun so it stays visible at typical canvas resolutions.
90
+ let cosSun = dot(dir, sky.sunDirection);
91
+ let disc = smoothstep(0.99985, 0.99995, cosSun);
92
+ let glow = pow(max(cosSun, 0.0), 350.0) * 0.5
93
+ + pow(max(cosSun, 0.0), 24.0) * 0.12;
94
+ // Hide the disc once the sun sets, and never draw it on the ground.
95
+ let sunVisible = smoothstep(-0.06, 0.02, sky.sunDirection.y) * (1.0 - groundMix);
96
+ let sunTint = vec3<f32>(1.0, 0.92, 0.78);
97
+ color += (disc * 6.0 + glow) * max(sky.sunIntensity, 0.0) * sunVisible * sunTint;
98
+
99
+ // Match the geometry pipeline: exposure → ACES → gamma.
100
+ color *= sky.exposure;
101
+ color = acesTonemap(color);
102
+ color = pow(color, vec3<f32>(1.0 / 2.2));
103
+
104
+ var out: FragmentOutput;
105
+ out.color = vec4<f32>(color, 1.0);
106
+ out.objectIdEncoded = vec4<f32>(0.0, 0.0, 0.0, 0.0);
107
+ return out;
108
+ }
109
+ `;
110
+ //# sourceMappingURL=sky.wgsl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sky.wgsl.js","sourceRoot":"","sources":["../../src/shaders/sky.wgsl.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+FxB,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Procedural sky background pass.
3
+ *
4
+ * Draws one fullscreen triangle into the main render pass BEFORE any
5
+ * geometry (the pass's colour attachments are cleared either way, so the
6
+ * sky simply replaces the flat clear colour). Reverse-Z places it at the
7
+ * far plane (z = 0) with depth writes off, so geometry always wins the
8
+ * depth test and transparent surfaces blend over the sky correctly.
9
+ *
10
+ * The pipeline targets must mirror the main pass exactly: colour + object-id
11
+ * attachments and the MSAA sample count. The object-id output is the
12
+ * attachment's clear value, so picking still reads "background" on sky.
13
+ */
14
+ import type { ResolvedEnvironment } from './environment.js';
15
+ export interface SkyPassFormats {
16
+ colorFormat: GPUTextureFormat;
17
+ objectIdFormat: GPUTextureFormat;
18
+ depthFormat: GPUTextureFormat;
19
+ sampleCount: number;
20
+ }
21
+ export interface SkyCamera {
22
+ /** Camera world position → target direction, unit. */
23
+ forward: [number, number, number];
24
+ /** Screen-right in world space, unit. */
25
+ right: [number, number, number];
26
+ /** Screen-up in world space, unit. */
27
+ up: [number, number, number];
28
+ /** Vertical field of view in radians. */
29
+ fovY: number;
30
+ /** Viewport width / height. */
31
+ aspect: number;
32
+ }
33
+ export declare class SkyPass {
34
+ private device;
35
+ private pipeline;
36
+ private uniformBuffer;
37
+ private bindGroup;
38
+ private scratch;
39
+ private destroyed;
40
+ constructor(device: GPUDevice, formats: SkyPassFormats, shaderSource: string);
41
+ /**
42
+ * Record the sky draw into an already-begun render pass. Callers must
43
+ * re-set their own pipeline + group(0) afterwards (the main loop does
44
+ * this per batch anyway).
45
+ */
46
+ draw(pass: GPURenderPassEncoder, camera: SkyCamera, env: ResolvedEnvironment): void;
47
+ destroy(): void;
48
+ }
49
+ //# sourceMappingURL=sky-pass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sky-pass.d.ts","sourceRoot":"","sources":["../src/sky-pass.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,gBAAgB,CAAC;IAC9B,cAAc,EAAE,gBAAgB,CAAC;IACjC,WAAW,EAAE,gBAAgB,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,sDAAsD;IACtD,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,yCAAyC;IACzC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,sCAAsC;IACtC,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,qBAAa,OAAO;IAClB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,SAAS,CAAe;IAChC,OAAO,CAAC,OAAO,CAAwC;IACvD,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM;IA+C5E;;;;OAIG;IACH,IAAI,CAAC,IAAI,EAAE,oBAAoB,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,mBAAmB,GAAG,IAAI;IA2BnF,OAAO,IAAI,IAAI;CAKhB"}
@@ -0,0 +1,106 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ const SKY_UNIFORM_FLOATS = 28; // 7 × vec4 rows = 112 bytes
5
+ export class SkyPass {
6
+ device;
7
+ pipeline;
8
+ uniformBuffer;
9
+ bindGroup;
10
+ scratch = new Float32Array(SKY_UNIFORM_FLOATS);
11
+ destroyed = false;
12
+ constructor(device, formats, shaderSource) {
13
+ this.device = device;
14
+ this.uniformBuffer = device.createBuffer({
15
+ label: 'sky-uniforms',
16
+ size: SKY_UNIFORM_FLOATS * 4,
17
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
18
+ });
19
+ const bindGroupLayout = device.createBindGroupLayout({
20
+ label: 'sky-bgl',
21
+ entries: [
22
+ {
23
+ binding: 0,
24
+ visibility: GPUShaderStage.FRAGMENT,
25
+ buffer: { type: 'uniform' },
26
+ },
27
+ ],
28
+ });
29
+ this.bindGroup = device.createBindGroup({
30
+ layout: bindGroupLayout,
31
+ entries: [{ binding: 0, resource: { buffer: this.uniformBuffer } }],
32
+ });
33
+ const module = device.createShaderModule({ label: 'sky-shader', code: shaderSource });
34
+ this.pipeline = device.createRenderPipeline({
35
+ label: 'sky-pipeline',
36
+ layout: device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout] }),
37
+ vertex: { module, entryPoint: 'vs_main' },
38
+ fragment: {
39
+ module,
40
+ entryPoint: 'fs_main',
41
+ targets: [{ format: formats.colorFormat }, { format: formats.objectIdFormat }],
42
+ },
43
+ primitive: { topology: 'triangle-list' },
44
+ depthStencil: {
45
+ format: formats.depthFormat,
46
+ depthWriteEnabled: false,
47
+ // Drawn first into a depth buffer cleared to 0.0 (reverse-Z far),
48
+ // so z = 0 passes everywhere; kept as a real compare (not 'always')
49
+ // in case the draw ever moves after opaque geometry.
50
+ depthCompare: 'greater-equal',
51
+ },
52
+ multisample: { count: formats.sampleCount },
53
+ });
54
+ }
55
+ /**
56
+ * Record the sky draw into an already-begun render pass. Callers must
57
+ * re-set their own pipeline + group(0) afterwards (the main loop does
58
+ * this per batch anyway).
59
+ */
60
+ draw(pass, camera, env) {
61
+ if (this.destroyed)
62
+ return;
63
+ const tanHalfFovY = Math.tan(camera.fovY / 2);
64
+ const tanHalfFovX = tanHalfFovY * camera.aspect;
65
+ const u = this.scratch;
66
+ u[0] = camera.right[0];
67
+ u[1] = camera.right[1];
68
+ u[2] = camera.right[2];
69
+ u[3] = tanHalfFovX;
70
+ u[4] = camera.up[0];
71
+ u[5] = camera.up[1];
72
+ u[6] = camera.up[2];
73
+ u[7] = tanHalfFovY;
74
+ u[8] = camera.forward[0];
75
+ u[9] = camera.forward[1];
76
+ u[10] = camera.forward[2];
77
+ u[11] = env.exposure;
78
+ u[12] = env.sunDirection[0];
79
+ u[13] = env.sunDirection[1];
80
+ u[14] = env.sunDirection[2];
81
+ u[15] = env.sunIntensity;
82
+ u[16] = env.sky.zenith[0];
83
+ u[17] = env.sky.zenith[1];
84
+ u[18] = env.sky.zenith[2];
85
+ u[19] = 0;
86
+ u[20] = env.sky.horizon[0];
87
+ u[21] = env.sky.horizon[1];
88
+ u[22] = env.sky.horizon[2];
89
+ u[23] = 0;
90
+ u[24] = env.sky.ground[0];
91
+ u[25] = env.sky.ground[1];
92
+ u[26] = env.sky.ground[2];
93
+ u[27] = 0;
94
+ this.device.queue.writeBuffer(this.uniformBuffer, 0, u);
95
+ pass.setPipeline(this.pipeline);
96
+ pass.setBindGroup(0, this.bindGroup);
97
+ pass.draw(3);
98
+ }
99
+ destroy() {
100
+ if (this.destroyed)
101
+ return;
102
+ this.destroyed = true;
103
+ this.uniformBuffer.destroy();
104
+ }
105
+ }
106
+ //# sourceMappingURL=sky-pass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sky-pass.js","sourceRoot":"","sources":["../src/sky-pass.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -130,6 +130,12 @@ export interface VisualEnhancementOptions {
130
130
  }
131
131
  export interface RenderOptions {
132
132
  clearColor?: [number, number, number, number];
133
+ /**
134
+ * Global lighting environment (sun direction/colour, hemisphere ambient,
135
+ * exposure, procedural sky). Omitted/empty reproduces the legacy hardcoded
136
+ * look exactly. See {@link import('./environment.js').LightingEnvironment}.
137
+ */
138
+ environment?: import('./environment.js').LightingEnvironment;
133
139
  enableDepthTest?: boolean;
134
140
  enableFrustumCulling?: boolean;
135
141
  spatialIndex?: import('@ifc-lite/spatial').SpatialIndex;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ifc-lite/renderer",
3
- "version": "1.26.0",
3
+ "version": "1.27.0",
4
4
  "description": "WebGPU renderer for IFC-Lite",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -13,8 +13,7 @@
13
13
  }
14
14
  },
15
15
  "dependencies": {
16
- "@ifc-lite/geometry": "^2.6.0",
17
- "@ifc-lite/wasm": "^2.7.0",
16
+ "@ifc-lite/geometry": "^2.6.1",
18
17
  "@ifc-lite/spatial": "^1.14.8"
19
18
  },
20
19
  "devDependencies": {