@ifc-lite/renderer 1.22.1 → 1.22.2
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.
|
@@ -6,5 +6,5 @@
|
|
|
6
6
|
* would mean two near-identical vertex inputs and duplicate camera structs.
|
|
7
7
|
*/
|
|
8
8
|
export declare const SYMBOLIC_FILL_WGSL = "\nstruct Camera {\n viewProj: mat4x4<f32>,\n};\n\n@group(0) @binding(0) var<uniform> camera: Camera;\n\nstruct VsIn {\n @location(0) position: vec3<f32>,\n @location(1) color: vec4<f32>,\n};\n\nstruct VsOut {\n @builtin(position) clipPos: vec4<f32>,\n @location(0) color: vec4<f32>,\n};\n\n@vertex\nfn vs_main(in: VsIn) -> VsOut {\n var out: VsOut;\n out.clipPos = camera.viewProj * vec4<f32>(in.position, 1.0);\n out.color = in.color;\n return out;\n}\n\n@fragment\nfn fs_main(in: VsOut) -> @location(0) vec4<f32> {\n // Premultiply alpha so the standard \"src * 1 + dst * (1-src.a)\" blend\n // produces the correct composite on top of the existing scene.\n return vec4<f32>(in.color.rgb * in.color.a, in.color.a);\n}\n";
|
|
9
|
-
export declare const SYMBOLIC_TEXT_WGSL = "\nstruct Camera {\n viewProj: mat4x4<f32>,\n // x = viewport width in physical pixels, y = viewport height\n // z = target glyph cap-height in screen pixels, w = padding\n viewportAndTarget: vec4<f32>,\n // Screen-aligned camera basis (world space). xyz = direction, w = padding.\n // Used by billboarded glyphs (grid tags) so they always face the camera \u2014\n // critical for top-down/ground views where world-up upAxis collapses to\n // zero screen extent and the tag becomes invisible.\n cameraRight: vec4<f32>,\n cameraUp: vec4<f32>,\n};\n\n@group(0) @binding(0) var<uniform> camera: Camera;\n@group(0) @binding(1) var atlasTex: texture_2d<f32>;\n@group(0) @binding(2) var atlasSamp: sampler;\n\n// Per-vertex (corner of the glyph quad).\nstruct VsIn {\n // Bit-packed corner index 0..3. The vertex buffer is just [0u, 1u, 2u, 3u].\n @location(0) corner: u32,\n};\n\n// Per-instance attributes \u2014 one record per glyph.\nstruct InstIn {\n // World-space origin of the glyph (bottom-left, after alignment + rotation).\n @location(1) origin: vec3<f32>,\n // Right axis in world space \u2014 encodes both glyph width and baseline rotation.\n @location(2) rightAxis: vec3<f32>,\n // Up axis in world space \u2014 encodes glyph height and baseline rotation.\n @location(3) upAxis: vec3<f32>,\n // Atlas UV bounds: (u0, v0, u1, v1).\n @location(4) uvBounds: vec4<f32>,\n // Glyph tint (sRGB straight-alpha).\n @location(5) color: vec4<f32>,\n // Shared text-label anchor (every glyph in the same label uses the same\n // anchor). Lets the shader compute one screen-space scale per label and\n // apply it uniformly to every glyph offset so row spacing stays in sync.\n @location(6) anchor: vec3<f32>,\n // Authored cap height in world units. Same value for every glyph in the\n // label; used to convert \"target pixels\" into a scale factor.\n @location(7) capHeight: f32,\n // Billboard flag (1.0 = use camera-aligned axes, 0.0 = use authored\n // rightAxis/upAxis). Only the grid-tag emission path sets this to 1.0.\n @location(8) billboard: f32,\n // Per-glyph baseline-relative offset + size in WORLD units. Only used\n // when billboard=1 (the authored origin bakes the offset along the\n // floor-plane basis, which is the wrong direction for camera-aligned\n // text). For non-billboard glyphs these are written too but the shader\n // picks the authored path. World units = atlas-pixel * wScale.\n // .xy = (offsetX, offsetY) from anchor to glyph BL\n // .zw = (width, height) of the glyph quad\n @location(9) glyphOffsetSize: vec4<f32>,\n // Per-instance target cap height in screen pixels. 0 = fall back to\n // the renderer global default (viewportAndTarget.z). Grid bubble\n // glyphs override with a larger value so the bubble stays proportional\n // to the tag at every zoom level.\n @location(10) targetPxOverride: f32,\n};\n\nstruct VsOut {\n @builtin(position) clipPos: vec4<f32>,\n @location(0) uv: vec2<f32>,\n @location(1) color: vec4<f32>,\n};\n\n@vertex\nfn vs_main(in: VsIn, inst: InstIn) -> VsOut {\n // Map corner index to (u, v) in [0, 1] \u2014 the four quad corners.\n // 0 = bottom-left, 1 = bottom-right, 2 = top-left, 3 = top-right.\n let u = f32((in.corner & 1u)); // 0,1,0,1\n let v = f32((in.corner >> 1u) & 1u); // 0,0,1,1\n\n // \u2500\u2500 Screen-space text scaling (projection-agnostic) \u2500\u2500\n // For non-billboard glyphs measure world-Y \u2192 screen pixels (matches the\n // authored upAxis convention). For billboard glyphs measure cameraUp \u2192\n // screen pixels \u2014 that axis ALWAYS spans the full viewport height\n // regardless of view angle, so screen-space scaling stays correct in\n // top-down / ground / oblique views.\n let isBillboard = inst.billboard > 0.5;\n let scaleProbeAxis = select(vec3<f32>(0.0, 1.0, 0.0), camera.cameraUp.xyz, isBillboard);\n let aClip = camera.viewProj * vec4<f32>(inst.anchor, 1.0);\n let bClip = camera.viewProj * vec4<f32>(inst.anchor + scaleProbeAxis, 1.0);\n let aNdc = aClip.xy / max(abs(aClip.w), 1e-4);\n let bNdc = bClip.xy / max(abs(bClip.w), 1e-4);\n let unitYPx = length(bNdc - aNdc) * camera.viewportAndTarget.y * 0.5;\n\n let safeCap = max(inst.capHeight, 1e-4);\n let currentPx = safeCap * unitYPx;\n // Per-instance target overrides the uniform default (used by grid bubble\n // glyphs to render at a larger on-screen size than the inscribed tag).\n let targetPx = select(camera.viewportAndTarget.z, inst.targetPxOverride, inst.targetPxOverride > 0.0);\n // Clamp to (0.02, 1.0]: never grow text beyond authored size; never\n // shrink below ~2%.\n let scale = clamp(\n targetPx / max(currentPx, 1e-2),\n 0.02,\n 1.0,\n );\n\n // \u2500\u2500 Position the glyph quad in world space \u2500\u2500\n // Non-billboard: authored axes (text lies in the floor plane of its\n // annotation \u2014 IFC convention). Billboard: camera-aligned axes (text\n // always faces the camera \u2014 grid-tag convention).\n let authoredLocalOffset = inst.origin - inst.anchor;\n let authoredWorldPos =\n inst.anchor\n + authoredLocalOffset * scale\n + inst.rightAxis * scale * u\n + inst.upAxis * scale * v;\n\n // Billboard: rebuild the quad in screen-aligned camera basis. glyphOffsetSize\n // carries the same 2D atlas-pixel layout the upload computed, just in\n // world units \u2014 re-project onto (cameraRight, cameraUp) so it tracks the\n // viewer's eye in every orientation.\n let bbOffsetX = inst.glyphOffsetSize.x;\n let bbOffsetY = inst.glyphOffsetSize.y;\n let bbWidth = inst.glyphOffsetSize.z;\n let bbHeight = inst.glyphOffsetSize.w;\n let billboardWorldPos =\n inst.anchor\n + (camera.cameraRight.xyz * bbOffsetX + camera.cameraUp.xyz * bbOffsetY) * scale\n + (camera.cameraRight.xyz * bbWidth * u\n + camera.cameraUp.xyz * bbHeight * v) * scale;\n\n let worldPos = select(authoredWorldPos, billboardWorldPos, isBillboard);\n\n // UV: lerp atlas bounds. Note v inverted (atlas top is v=0).\n let uMix = mix(inst.uvBounds.x, inst.uvBounds.z, u);\n let vMix = mix(inst.uvBounds.w, inst.uvBounds.y, v);\n\n var out: VsOut;\n
|
|
9
|
+
export declare const SYMBOLIC_TEXT_WGSL = "\nstruct Camera {\n viewProj: mat4x4<f32>,\n // x = viewport width in physical pixels, y = viewport height\n // z = target glyph cap-height in screen pixels, w = padding\n viewportAndTarget: vec4<f32>,\n // Screen-aligned camera basis (world space). xyz = direction, w = padding.\n // Used by billboarded glyphs (grid tags) so they always face the camera \u2014\n // critical for top-down/ground views where world-up upAxis collapses to\n // zero screen extent and the tag becomes invisible.\n cameraRight: vec4<f32>,\n cameraUp: vec4<f32>,\n};\n\n@group(0) @binding(0) var<uniform> camera: Camera;\n@group(0) @binding(1) var atlasTex: texture_2d<f32>;\n@group(0) @binding(2) var atlasSamp: sampler;\n\n// Per-vertex (corner of the glyph quad).\nstruct VsIn {\n // Bit-packed corner index 0..3. The vertex buffer is just [0u, 1u, 2u, 3u].\n @location(0) corner: u32,\n};\n\n// Per-instance attributes \u2014 one record per glyph.\nstruct InstIn {\n // World-space origin of the glyph (bottom-left, after alignment + rotation).\n @location(1) origin: vec3<f32>,\n // Right axis in world space \u2014 encodes both glyph width and baseline rotation.\n @location(2) rightAxis: vec3<f32>,\n // Up axis in world space \u2014 encodes glyph height and baseline rotation.\n @location(3) upAxis: vec3<f32>,\n // Atlas UV bounds: (u0, v0, u1, v1).\n @location(4) uvBounds: vec4<f32>,\n // Glyph tint (sRGB straight-alpha).\n @location(5) color: vec4<f32>,\n // Shared text-label anchor (every glyph in the same label uses the same\n // anchor). Lets the shader compute one screen-space scale per label and\n // apply it uniformly to every glyph offset so row spacing stays in sync.\n @location(6) anchor: vec3<f32>,\n // Authored cap height in world units. Same value for every glyph in the\n // label; used to convert \"target pixels\" into a scale factor.\n @location(7) capHeight: f32,\n // Billboard flag (1.0 = use camera-aligned axes, 0.0 = use authored\n // rightAxis/upAxis). Only the grid-tag emission path sets this to 1.0.\n @location(8) billboard: f32,\n // Per-glyph baseline-relative offset + size in WORLD units. Only used\n // when billboard=1 (the authored origin bakes the offset along the\n // floor-plane basis, which is the wrong direction for camera-aligned\n // text). For non-billboard glyphs these are written too but the shader\n // picks the authored path. World units = atlas-pixel * wScale.\n // .xy = (offsetX, offsetY) from anchor to glyph BL\n // .zw = (width, height) of the glyph quad\n @location(9) glyphOffsetSize: vec4<f32>,\n // Per-instance target cap height in screen pixels. 0 = fall back to\n // the renderer global default (viewportAndTarget.z). Grid bubble\n // glyphs override with a larger value so the bubble stays proportional\n // to the tag at every zoom level.\n @location(10) targetPxOverride: f32,\n};\n\nstruct VsOut {\n @builtin(position) clipPos: vec4<f32>,\n @location(0) uv: vec2<f32>,\n @location(1) color: vec4<f32>,\n};\n\n@vertex\nfn vs_main(in: VsIn, inst: InstIn) -> VsOut {\n // Map corner index to (u, v) in [0, 1] \u2014 the four quad corners.\n // 0 = bottom-left, 1 = bottom-right, 2 = top-left, 3 = top-right.\n let u = f32((in.corner & 1u)); // 0,1,0,1\n let v = f32((in.corner >> 1u) & 1u); // 0,0,1,1\n\n // \u2500\u2500 Screen-space text scaling (projection-agnostic) \u2500\u2500\n // For non-billboard glyphs measure world-Y \u2192 screen pixels (matches the\n // authored upAxis convention). For billboard glyphs measure cameraUp \u2192\n // screen pixels \u2014 that axis ALWAYS spans the full viewport height\n // regardless of view angle, so screen-space scaling stays correct in\n // top-down / ground / oblique views.\n let isBillboard = inst.billboard > 0.5;\n let scaleProbeAxis = select(vec3<f32>(0.0, 1.0, 0.0), camera.cameraUp.xyz, isBillboard);\n let aClip = camera.viewProj * vec4<f32>(inst.anchor, 1.0);\n let bClip = camera.viewProj * vec4<f32>(inst.anchor + scaleProbeAxis, 1.0);\n let aNdc = aClip.xy / max(abs(aClip.w), 1e-4);\n let bNdc = bClip.xy / max(abs(bClip.w), 1e-4);\n let unitYPx = length(bNdc - aNdc) * camera.viewportAndTarget.y * 0.5;\n\n let safeCap = max(inst.capHeight, 1e-4);\n let currentPx = safeCap * unitYPx;\n // Per-instance target overrides the uniform default (used by grid bubble\n // glyphs to render at a larger on-screen size than the inscribed tag).\n let targetPx = select(camera.viewportAndTarget.z, inst.targetPxOverride, inst.targetPxOverride > 0.0);\n // Clamp to (0.02, 1.0]: never grow text beyond authored size; never\n // shrink below ~2%.\n let scale = clamp(\n targetPx / max(currentPx, 1e-2),\n 0.02,\n 1.0,\n );\n\n // \u2500\u2500 Position the glyph quad in world space \u2500\u2500\n // Non-billboard: authored axes (text lies in the floor plane of its\n // annotation \u2014 IFC convention). Billboard: camera-aligned axes (text\n // always faces the camera \u2014 grid-tag convention).\n let authoredLocalOffset = inst.origin - inst.anchor;\n let authoredWorldPos =\n inst.anchor\n + authoredLocalOffset * scale\n + inst.rightAxis * scale * u\n + inst.upAxis * scale * v;\n\n // Billboard: rebuild the quad in screen-aligned camera basis. glyphOffsetSize\n // carries the same 2D atlas-pixel layout the upload computed, just in\n // world units \u2014 re-project onto (cameraRight, cameraUp) so it tracks the\n // viewer's eye in every orientation.\n let bbOffsetX = inst.glyphOffsetSize.x;\n let bbOffsetY = inst.glyphOffsetSize.y;\n let bbWidth = inst.glyphOffsetSize.z;\n let bbHeight = inst.glyphOffsetSize.w;\n let billboardWorldPos =\n inst.anchor\n + (camera.cameraRight.xyz * bbOffsetX + camera.cameraUp.xyz * bbOffsetY) * scale\n + (camera.cameraRight.xyz * bbWidth * u\n + camera.cameraUp.xyz * bbHeight * v) * scale;\n\n let worldPos = select(authoredWorldPos, billboardWorldPos, isBillboard);\n\n // UV: lerp atlas bounds. Note v inverted (atlas top is v=0).\n let uMix = mix(inst.uvBounds.x, inst.uvBounds.z, u);\n let vMix = mix(inst.uvBounds.w, inst.uvBounds.y, v);\n\n var out: VsOut;\n let clip = camera.viewProj * vec4<f32>(worldPos, 1.0);\n // Reverse-Z decal nudge for text coplanar with model faces (issue #812\n // follow-up: \"30\", \"1.49\" etc. flickering against the terrain). The\n // pipeline-level depthBiasSlopeScale collapses to ~0 for billboard\n // glyphs \u2014 the quad faces the camera, so depth slope across the quad\n // is zero \u2014 leaving only a tiny -4 constant that MSAA jitter beats.\n // Adding a small positive multiple of clip.w raises NDC z by a\n // constant after the w-divide, which under reverse-Z reads as\n // \"slightly closer\" \u2014 same trick the line pipeline uses.\n out.clipPos = vec4<f32>(clip.x, clip.y, clip.z + 5e-5 * clip.w, clip.w);\n out.uv = vec2<f32>(uMix, vMix);\n out.color = inst.color;\n return out;\n}\n\n@fragment\nfn fs_main(in: VsOut) -> @location(0) vec4<f32> {\n let atlas = textureSample(atlasTex, atlasSamp, in.uv);\n // The atlas was rasterised with white glyphs on a transparent background,\n // so atlas.r is the coverage and atlas.a is the alpha. Multiply by the\n // per-glyph tint and premultiply for the standard composite.\n let alpha = atlas.a * in.color.a;\n return vec4<f32>(in.color.rgb * alpha, alpha);\n}\n";
|
|
10
10
|
//# sourceMappingURL=symbolic-overlay.wgsl.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"symbolic-overlay.wgsl.d.ts","sourceRoot":"","sources":["../../src/shaders/symbolic-overlay.wgsl.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,eAAO,MAAM,kBAAkB,+uBA+B9B,CAAC;AAEF,eAAO,MAAM,kBAAkB,
|
|
1
|
+
{"version":3,"file":"symbolic-overlay.wgsl.d.ts","sourceRoot":"","sources":["../../src/shaders/symbolic-overlay.wgsl.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,eAAO,MAAM,kBAAkB,+uBA+B9B,CAAC;AAEF,eAAO,MAAM,kBAAkB,mwOA6J9B,CAAC"}
|
|
@@ -173,7 +173,16 @@ fn vs_main(in: VsIn, inst: InstIn) -> VsOut {
|
|
|
173
173
|
let vMix = mix(inst.uvBounds.w, inst.uvBounds.y, v);
|
|
174
174
|
|
|
175
175
|
var out: VsOut;
|
|
176
|
-
|
|
176
|
+
let clip = camera.viewProj * vec4<f32>(worldPos, 1.0);
|
|
177
|
+
// Reverse-Z decal nudge for text coplanar with model faces (issue #812
|
|
178
|
+
// follow-up: "30", "1.49" etc. flickering against the terrain). The
|
|
179
|
+
// pipeline-level depthBiasSlopeScale collapses to ~0 for billboard
|
|
180
|
+
// glyphs — the quad faces the camera, so depth slope across the quad
|
|
181
|
+
// is zero — leaving only a tiny -4 constant that MSAA jitter beats.
|
|
182
|
+
// Adding a small positive multiple of clip.w raises NDC z by a
|
|
183
|
+
// constant after the w-divide, which under reverse-Z reads as
|
|
184
|
+
// "slightly closer" — same trick the line pipeline uses.
|
|
185
|
+
out.clipPos = vec4<f32>(clip.x, clip.y, clip.z + 5e-5 * clip.w, clip.w);
|
|
177
186
|
out.uv = vec2<f32>(uMix, vMix);
|
|
178
187
|
out.color = inst.color;
|
|
179
188
|
return out;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"symbolic-overlay.wgsl.js","sourceRoot":"","sources":["../../src/shaders/symbolic-overlay.wgsl.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;GAMG;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+B5C,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,UAAU,CAAC
|
|
1
|
+
{"version":3,"file":"symbolic-overlay.wgsl.js","sourceRoot":"","sources":["../../src/shaders/symbolic-overlay.wgsl.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;GAMG;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+B5C,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6J5C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ifc-lite/renderer",
|
|
3
|
-
"version": "1.22.
|
|
3
|
+
"version": "1.22.2",
|
|
4
4
|
"description": "WebGPU renderer for IFC-Lite",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@ifc-lite/geometry": "^1.19.0",
|
|
16
16
|
"@ifc-lite/spatial": "^1.14.5",
|
|
17
|
-
"@ifc-lite/wasm": "^1.19.
|
|
17
|
+
"@ifc-lite/wasm": "^1.19.2"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@webgpu/types": "^0.1.70",
|