@equinor/videx-3d 3.0.0 → 3.2.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.
package/dist/sdk.js CHANGED
@@ -1,2 +1,2 @@
1
- import { $ as e, $t as t, A as n, At as r, Bt as i, C as a, Cn as o, Ct as s, D as c, Dn as l, Dt as u, E as d, En as f, Et as p, F as m, Ft as h, Gt as g, H as _, Ht as v, It as y, J as b, Jt as x, Kt as S, Lt as C, M as w, Mt as T, N as E, Nt as D, O, Ot as k, P as A, Pt as j, Q as M, Qt as N, Rt as P, S as F, Sn as I, St as L, T as R, Tn as z, Tt as B, Ut as V, Vt as H, Wt as U, X as W, Xt as G, Y as K, Yt as q, Z as J, Zt as Y, _ as X, _n as Z, _t as Q, an as $, at as ee, b as te, bn as ne, bt as re, c as ie, cn as ae, ct as oe, d as se, dn as ce, dt as le, en as ue, et as de, f as fe, fn as pe, ft as me, g as he, gn as ge, gt as _e, h as ve, hn as ye, ht as be, in as xe, it as Se, j as Ce, jt as we, k as Te, kt as Ee, l as De, ln as Oe, lt as ke, m as Ae, mn as je, mt as Me, n as Ne, nn as Pe, nt as Fe, on as Ie, ot as Le, p as Re, pn as ze, pt as Be, q as Ve, qt as He, rn as Ue, rt as We, s as Ge, sn as Ke, st as qe, t as Je, tn as Ye, tt as Xe, u as Ze, un as Qe, ut as $e, v as et, vn as tt, vt as nt, w as rt, wn as it, wt as at, x as ot, xn as st, xt as ct, y as lt, yn as ut, yt as dt, zt as ft } from "./chunk-DKAquGKk.js";
2
- export { Ce as CRS, _ as CameraManager, l as DataLoader, B as Delatin, rt as DepthReadMaterial, f as GeneratorRegistry, ae as PI, Oe as PI2, Qe as PI4, ce as PI8, b as PlanarGeometry, K as PlanarLineGeometry, W as PlanarPointGeometry, J as PlanarPolygonGeometry, pe as TAU, Ne as TubeMaterial, ie as Typed2DArray, m as WellboreManager, D as addVec2, j as addVec3, h as angleVec3, y as asVec2, Me as buildMaskedGridPlane, r as calculateFrenetFrames, De as calculateHashValue, I as calculateWellSegments, je as clamp, Q as computePlanarXZUv, X as computeSurfaceNormalsRG, nt as computeUpwardNormals, C as copyVec3, he as createConfig, et as createElevationTexture, ct as createFenceGeometry, dt as createIndexedGeometry, lt as createNormalTexture, Le as createOceanBox, qe as createOceanBoxFromPolygon, oe as createOceanBoxFromSurface, ke as createOceanEllipseBox, $e as createOceanPlane, te as createPackedNormalTexture, p as createTubeGeometries, u as createTubeGeometry, P as crossVec3, R as degreesToRadians, ft as directionVec2, i as directionVec3, H as distanceVec2, v as distanceVec3, V as dotVec2, U as dotVec3, ze as edgeOfRectangle, ot as elevationMapNormalsToRGBA, ut as extractBoundaryLoops, d as feetToMeters, be as floodFillExternalHoles, we as getCurvePositions, o as getFormationMarkers, fe as getObjectByCustomProperty, L as getProjectedTrajectory, w as getProjectionDefFromUtmZone, T as getSplineCurve, s as getTrajectory, M as getTypedArrayFromBuffer, e as getTypedArrayType, E as getUtmZoneFromLatLng, g as getVec2, S as getVec3, it as getWellboreFormations, Te as idToHexColor, ye as inverseLerp, He as lengthVec2, x as lengthVec3, ge as lerp, z as mergeFormationIntervals, k as mergeGeometries, q as mixVec2, G as mixVec3, Re as multiply, Ae as negate, Y as negateVec2, N as negateVec3, t as normalizeVec2, ue as normalizeVec3, c as normalizedDeviceToScreen, de as packAttribute, Xe as packBufferGeometries, Fe as packBufferGeometry, We as packBufferGeometryLike, ve as parseIrapbin, n as randomColor, a as readDepth, me as refineInteriorEdges, Z as remap, re as rotateGeometryY, Ye as rotateVec3, _e as sampleValidGrid, Pe as scaleVec2, Ue as scaleVec3, O as screenToNormalizedDevice, xe as setVec2, $ as setVec3, at as simplifyCurve2D, ne as smoothBoundaryLoops, st as snapBoundaryToOutline, Ie as subVec2, Ke as subVec3, Be as subdivideGeometry, Ze as titleCase, Ee as toBufferGeometry, Ge as toFloat32Array, tt as toRGB, se as toSegments, F as triangleNormal, Ve as triangulateGrid, le as triangulateGridDelaunay, Se as unpackBufferGeometries, ee as unpackBufferGeometry, Je as uvMaterial, A as wgs84Def };
1
+ import { $ as e, $t as t, A as n, At as r, Bt as i, C as a, Cn as o, Ct as s, D as c, Dn as l, Dt as u, E as d, En as f, Et as p, F as m, Ft as h, Gt as g, H as _, Ht as v, It as y, J as b, Jt as x, Kt as S, Lt as C, M as w, Mt as T, N as E, Nt as D, O, On as k, Ot as A, P as j, Pt as M, Q as N, Qt as P, Rt as F, S as I, Sn as L, St as R, T as z, Tn as B, Tt as V, Ut as H, Vt as U, Wt as W, X as G, Xt as K, Y as q, Yt as J, Z as Y, Zt as X, _ as Z, _n as Q, _t as $, an as ee, at as te, b as ne, bn as re, bt as ie, c as ae, cn as oe, ct as se, d as ce, dn as le, dt as ue, en as de, et as fe, f as pe, fn as me, ft as he, g as ge, gn as _e, gt as ve, h as ye, hn as be, ht as xe, in as Se, it as Ce, j as we, jt as Te, k as Ee, kt as De, l as Oe, ln as ke, lt as Ae, m as je, mn as Me, mt as Ne, n as Pe, nn as Fe, nt as Ie, on as Le, ot as Re, p as ze, pn as Be, pt as Ve, q as He, qt as Ue, rn as We, rt as Ge, s as Ke, sn as qe, st as Je, t as Ye, tn as Xe, tt as Ze, u as Qe, un as $e, ut as et, v as tt, vn as nt, vt as rt, w as it, wn as at, wt as ot, x as st, xn as ct, xt as lt, y as ut, yn as dt, yt as ft, zt as pt } from "./chunk-r8Ybij6M.js";
2
+ export { we as CRS, _ as CameraManager, k as DataLoader, V as Delatin, it as DepthReadMaterial, l as GeneratorRegistry, ke as PI, $e as PI2, le as PI4, me as PI8, b as PlanarGeometry, q as PlanarLineGeometry, G as PlanarPointGeometry, Y as PlanarPolygonGeometry, Be as TAU, Pe as TubeMaterial, ae as Typed2DArray, m as WellboreManager, D as addVec2, M as addVec3, h as angleVec3, y as asVec2, Ne as buildMaskedGridPlane, r as calculateFrenetFrames, Oe as calculateHashValue, o as calculateWellSegments, be as clamp, $ as computePlanarXZUv, Z as computeSurfaceNormalsRG, rt as computeUpwardNormals, C as copyVec3, ge as createConfig, tt as createElevationTexture, lt as createFenceGeometry, ft as createIndexedGeometry, ut as createNormalTexture, Re as createOceanBox, Je as createOceanBoxFromPolygon, se as createOceanBoxFromSurface, Ae as createOceanEllipseBox, et as createOceanPlane, ne as createPackedNormalTexture, p as createTubeGeometries, u as createTubeGeometry, F as crossVec3, z as degreesToRadians, pt as directionVec2, i as directionVec3, U as distanceToBounds, v as distanceVec2, H as distanceVec3, W as dotVec2, g as dotVec3, Me as edgeOfRectangle, st as elevationMapNormalsToRGBA, re as extractBoundaryLoops, d as feetToMeters, xe as floodFillExternalHoles, Te as getCurvePositions, at as getFormationMarkers, pe as getObjectByCustomProperty, R as getProjectedTrajectory, w as getProjectionDefFromUtmZone, T as getSplineCurve, s as getTrajectory, N as getTypedArrayFromBuffer, e as getTypedArrayType, E as getUtmZoneFromLatLng, S as getVec2, Ue as getVec3, B as getWellboreFormations, Ee as idToHexColor, _e as inverseLerp, x as lengthVec2, J as lengthVec3, Q as lerp, f as mergeFormationIntervals, A as mergeGeometries, K as mixVec2, X as mixVec3, ze as multiply, je as negate, P as negateVec2, t as negateVec3, de as normalizeVec2, Xe as normalizeVec3, c as normalizedDeviceToScreen, fe as packAttribute, Ze as packBufferGeometries, Ie as packBufferGeometry, Ge as packBufferGeometryLike, ye as parseIrapbin, n as randomColor, a as readDepth, he as refineInteriorEdges, nt as remap, ie as rotateGeometryY, Fe as rotateVec3, ve as sampleValidGrid, We as scaleVec2, Se as scaleVec3, O as screenToNormalizedDevice, ee as setVec2, Le as setVec3, ot as simplifyCurve2D, ct as smoothBoundaryLoops, L as snapBoundaryToOutline, qe as subVec2, oe as subVec3, Ve as subdivideGeometry, Qe as titleCase, De as toBufferGeometry, Ke as toFloat32Array, dt as toRGB, ce as toSegments, I as triangleNormal, He as triangulateGrid, ue as triangulateGridDelaunay, Ce as unpackBufferGeometries, te as unpackBufferGeometry, Ye as uvMaterial, j as wgs84Def };
@@ -0,0 +1,274 @@
1
+ // Procedural (texture-free) normal-detail helpers.
2
+ //
3
+ // Pure functions - no uniforms, no varyings - so any material can reuse them by
4
+ // supplying its own inputs and controls. Include this file in a FRAGMENT shader
5
+ // (it relies on screen-space derivatives, dFdx/dFdy).
6
+ //
7
+ // Dependencies the consuming material must provide when calling perturbNormalHeight:
8
+ // - normal : the shading normal to perturb, in VIEW space
9
+ // - viewPos : the surface position in VIEW space (e.g. -vViewPosition)
10
+ // - height : a scalar height field sampled at this fragment (produced by the
11
+ // pnGranular / pnGrain / pnScratches helpers below, summed); the caller
12
+ // scales it to taste (its "strength"/bump amount) and may fade it by
13
+ // distance
14
+ // And when sampling a pattern height (pnGranular / pnGrain / pnScratches):
15
+ // - uv : a 2D coordinate ALREADY scaled by the caller's frequency. The
16
+ // caller owns the units (world distance, normalized, radius-based,
17
+ // ...) and which axis maps to uv.y (the grain/stretch axis).
18
+ // - octaves : fbm octave count for pnGranular / pnGrain (1..N). pnScratches is
19
+ // segment-based and takes NO octave count.
20
+ // - periodX : if > 0, the noise tiles seamlessly every `periodX` cells in x (pass
21
+ // the number of cells around a circumference to remove the wrap seam
22
+ // on a closed cylinder; pass 0 to disable). Tiling is exact for
23
+ // granular and for grain/scratches at angle 0.
24
+ // The patterns return scalar heights; combine several by summing (optionally weighted)
25
+ // and feed the result to perturbNormalHeight.
26
+ //
27
+ // "width" of the features is controlled by the caller's frequency/anisotropy/angle
28
+ // folded into uv; "height" of the bump is the caller-owned scalar passed to
29
+ // perturbNormalHeight. No CPU data or vertex attributes are required beyond whatever
30
+ // the material already uses to build its uv.
31
+
32
+ // Lattice wrap period (cells). The value-noise lattice (and the scratch seed grid) repeat
33
+ // every PN_WRAP cells per axis, so a caller that reduces a very large sample coordinate
34
+ // into [0, PN_WRAP) - to keep floor()/fract() float-precise at oilfield scale, where
35
+ // metres-along-trajectory x frequency reaches ~1e5 and fract() quantises into visible
36
+ // banding - still tiles SEAMLESSLY at the wrap. Large enough (4096 cells) that the repeat
37
+ // is invisible for fine detail; a no-op (mod = identity) for the small coords normal use
38
+ // produces.
39
+ #define PN_WRAP 4096.0
40
+
41
+ // Precision-robust 2D->1D hash (Dave Hoskins). fract() is applied BEFORE any multiply/
42
+ // dot so the working values stay in [0,1) - this survives the large sample coordinates
43
+ // that occur at oilfield scale (a pattern sampled by metres-along-trajectory times a
44
+ // frequency reaches ~1e5+), where the older fract(p*c) + dot(p, p) form overflowed
45
+ // float32 precision so fract() returned near-constant values and the noise collapsed /
46
+ // stretched with distance down the well.
47
+ float pnHash2(vec2 p) {
48
+ vec3 p3 = fract(vec3(p.xyx) * 0.1031);
49
+ p3 += dot(p3, p3.yzx + 33.33);
50
+ return fract((p3.x + p3.y) * p3.z);
51
+ }
52
+
53
+ // 2D value noise (smoothstep-interpolated).
54
+ float pnValueNoise2(vec2 p) {
55
+ vec2 i = floor(p);
56
+ vec2 f = fract(p);
57
+ f = f * f * (3.0 - 2.0 * f);
58
+ // Wrap the integer lattice at PN_WRAP so the noise tiles seamlessly when a caller reduces
59
+ // a huge coordinate into [0, PN_WRAP) (identity for the small coords normal use produces).
60
+ vec2 i0 = mod(i, PN_WRAP);
61
+ vec2 i1 = mod(i + 1.0, PN_WRAP);
62
+ float a = pnHash2(i0);
63
+ float b = pnHash2(vec2(i1.x, i0.y));
64
+ float c = pnHash2(vec2(i0.x, i1.y));
65
+ float d = pnHash2(i1);
66
+ return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
67
+ }
68
+
69
+ // Fractional Brownian motion with a dynamic (uniform-driven) octave count. The loop
70
+ // bound is a compile-time constant (GLSL requirement); `octaves` clamps it at runtime.
71
+ float pnFbm2(vec2 p, int octaves) {
72
+ float sum = 0.0;
73
+ float amp = 0.5;
74
+ float norm = 0.0;
75
+ for(int o = 0; o < 8; o++) {
76
+ if(o >= octaves)
77
+ break;
78
+ sum += amp * pnValueNoise2(p);
79
+ norm += amp;
80
+ p *= 2.02;
81
+ amp *= 0.5;
82
+ }
83
+ return norm > 0.0 ? sum / norm : 0.0;
84
+ }
85
+
86
+ // Tiling value noise: the integer lattice wraps at `periodX` cells in x, so a pattern
87
+ // sampled over exactly `periodX` units in x is seamless (used to wrap around a
88
+ // cylinder's circumference). y is not tiled.
89
+ float pnValueNoise2Tiled(vec2 p, float periodX) {
90
+ vec2 i = floor(p);
91
+ vec2 f = fract(p);
92
+ f = f * f * (3.0 - 2.0 * f);
93
+ float x0 = mod(i.x, periodX);
94
+ float x1 = mod(i.x + 1.0, periodX);
95
+ float y0 = mod(i.y, PN_WRAP);
96
+ float y1 = mod(i.y + 1.0, PN_WRAP);
97
+ float a = pnHash2(vec2(x0, y0));
98
+ float b = pnHash2(vec2(x1, y0));
99
+ float c = pnHash2(vec2(x0, y1));
100
+ float d = pnHash2(vec2(x1, y1));
101
+ return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
102
+ }
103
+
104
+ // fbm on the x-tiling noise; lacunarity 2.0 so every octave's period stays integer.
105
+ float pnFbm2Tiled(vec2 p, float periodX, int octaves) {
106
+ float sum = 0.0;
107
+ float amp = 0.5;
108
+ float norm = 0.0;
109
+ float per = max(periodX, 1.0);
110
+ for(int o = 0; o < 8; o++) {
111
+ if(o >= octaves)
112
+ break;
113
+ sum += amp * pnValueNoise2Tiled(p, per);
114
+ norm += amp;
115
+ p *= 2.0;
116
+ per *= 2.0;
117
+ amp *= 0.5;
118
+ }
119
+ return norm > 0.0 ? sum / norm : 0.0;
120
+ }
121
+
122
+ // fbm that tiles in x when periodX > 0, else plain (non-tiling) fbm.
123
+ float pnFbm2Auto(vec2 p, int octaves, float periodX) {
124
+ return periodX > 0.5 ? pnFbm2Tiled(p, periodX, octaves) : pnFbm2(p, octaves);
125
+ }
126
+
127
+ // GRANULAR: isotropic value-noise bumps; `anisotropy` (0..1) stretches the cells along
128
+ // uv.y. Signed height. periodX > 0 tiles x (e.g. a circumference).
129
+ float pnGranular(vec2 uv, float anisotropy, int octaves, float periodX) {
130
+ vec2 p = vec2(uv.x, uv.y * mix(1.0, 0.04, anisotropy));
131
+ return pnFbm2Auto(p, octaves, periodX) - 0.5;
132
+ }
133
+
134
+ // BRUSHED: a directional fine grain - thin parallel ridges running at `angle` (radians;
135
+ // 0 = along uv.y). `sharpness` (0..1) thins the ridges (their "width"); `uniformity`
136
+ // (0..1) blends from an irregular grain to perfectly regular flutes. Positive height.
137
+ // Tiling is exact only for angle == 0; other angles degrade gracefully (a faint seam).
138
+ float pnGrain(vec2 uv, float angle, float sharpness, float uniformity, int octaves, float periodX) {
139
+ float ca = cos(angle), sa = sin(angle);
140
+ vec2 r = vec2(uv.x * ca - uv.y * sa, uv.x * sa + uv.y * ca);
141
+ float tile = abs(angle) < 1e-3 ? periodX : 0.0;
142
+ float n = pnFbm2Auto(vec2(r.x, r.y * 0.06), octaves, tile);
143
+ // Irregular grain (fbm-smooth, so it has no cusp to alias); `sharpness` thins the ridges.
144
+ float irregular = pow(1.0 - abs(2.0 * n - 1.0), mix(2.0, 8.0, clamp(sharpness, 0.0, 1.0)));
145
+ // Regular flutes: footprint-anti-aliased evenly-spaced ridges (period 1 in r.x). A
146
+ // smoothstep whose transition is never narrower than the pixel footprint (fwidth)
147
+ // keeps the ridge crisp up close WITHOUT the sharp cusp of the old (1-|sin|)^pow form
148
+ // - that cusp under-sampled the normal and shimmered even close up - and naturally
149
+ // band-limits into a flat tone once a flute drops below a pixel far away. `sharpness`
150
+ // sets the ridge width.
151
+ float dCentre = abs(r.x - floor(r.x + 0.5)); // 0 at a flute centre .. 0.5 between
152
+ float hw = mix(0.35, 0.05, clamp(sharpness, 0.0, 1.0));
153
+ float aaw = max(fwidth(r.x), 1e-4);
154
+ float regular = 1.0 - smoothstep(hw - aaw, hw + aaw, dCentre);
155
+ // Once a flute period approaches the pixel footprint (fwidth ~ 0.5, i.e. the sine is
156
+ // near screen-Nyquist at the grazing sides of the shell), flatten the flutes toward
157
+ // their duty-cycle mean (~2*hw). Without this the ridge stays a smooth-but-undersampled
158
+ // sine there and still shimmers even though the edges are footprint-AA'd.
159
+ regular = mix(regular, 2.0 * hw, smoothstep(0.3, 0.5, aaw));
160
+ return mix(irregular, regular, clamp(uniformity, 0.0, 1.0));
161
+ }
162
+
163
+ // SCRATCHES: sparse, thin grooves crossing at varied angles/lengths - a cell/segment
164
+ // field rather than parallel lanes, so it reads like real scuffing. `density` (0..1) =
165
+ // fraction of seed cells that carry a scratch; `angle` = orientation bias and `wander`
166
+ // (0..1) widens the spread of directions around it (0 = all parallel, 1 = fully random);
167
+ // `lengthScale` (>0) scales each groove's length; `halfWidth` sets the groove width in
168
+ // sample (uv) units - pass (world-width x frequency) to get a FREQUENCY-INDEPENDENT width
169
+ // so lowering the frequency lengthens/thins-out the scratches without widening them. Two
170
+ // families are summed by pnScratches:
171
+ // a fine layer (short/medium scratches) plus a coarse layer (fewer, much longer ones).
172
+ // Each groove is analytically anti-aliased (edge widened to the pixel footprint).
173
+ // Negative height.
174
+
175
+ // One scratch "family": line segments seeded on an integer grid at the coordinate scale
176
+ // of `r`. Each present cell (gated by `density`) spawns a groove with a random midpoint,
177
+ // direction (biased toward `angle`, spread by `wander`), half-length, width and depth. A
178
+ // 3x3 neighbourhood is scanned so segments crossing in from adjacent cells are caught;
179
+ // half-length is capped below the search radius so grooves stay unbroken. `seed`
180
+ // decorrelates layers; x wraps at `periodX` cells (when angle ~ 0) for a seamless
181
+ // circumference seam.
182
+ float pnScratchLayer(vec2 r, float angle, float density, float lengthScale, float halfWidth, float wander, float periodX, float seed) {
183
+ float aaw = max(length(fwidth(r)), 1e-4);
184
+ vec2 cell = floor(r);
185
+ float acc = 0.0;
186
+ bool tile = periodX > 0.5 && abs(angle) < 1e-3;
187
+ for(int j = -1; j <= 1; j++) {
188
+ for(int i = -1; i <= 1; i++) {
189
+ vec2 c = cell + vec2(float(i), float(j));
190
+ vec2 h = mod(c, PN_WRAP); // keep hash coords small/precise + seamless at the axial wrap
191
+ if(tile)
192
+ // max() keeps the divisor provably non-zero: callers that disable tiling pass
193
+ // periodX = 0.0, and some backends (ANGLE/D3D) constant-fold the mod() division
194
+ // inside this branch BEFORE dead-code elimination and warn "X4008: floating
195
+ // point division by zero". Only reached when tile (periodX > 0.5), so this is a
196
+ // no-op at runtime.
197
+ h.x = mod(c.x, max(periodX, 1.0)); // seamless wrap around the circumference
198
+ h += seed;
199
+ if(pnHash2(h + 3.1) > density)
200
+ continue; // sparsity
201
+ vec2 mid = c + vec2(pnHash2(h + 7.3), pnHash2(h + 13.7));
202
+ float a = angle + (pnHash2(h + 21.1) - 0.5) * 3.14159265 * clamp(wander, 0.0, 1.0);
203
+ vec2 d = vec2(cos(a), sin(a));
204
+ vec2 perp = vec2(-d.y, d.x);
205
+ float hl = clamp(mix(0.1, 0.55, pnHash2(h + 29.3)) * max(lengthScale, 0.05), 0.03, 0.92);
206
+ float w = halfWidth * mix(0.7, 1.3, pnHash2(h + 41.7)); // world-scaled half-width (freq-independent)
207
+ float rStr = mix(0.3, 1.0, pnHash2(h + 37.7)); // random depth/brightness
208
+ float bend = (pnHash2(h + 51.9) - 0.5) * 0.7; // shallow curvature so lines aren't dead straight
209
+ vec2 pr = r - mid;
210
+ float t = clamp(dot(pr, d), -hl, hl); // nearest point on the straight axis
211
+ float u = t / max(hl, 1e-3);
212
+ vec2 foot = d * t + perp * (bend * u * u * hl); // bow the centre-line across its length
213
+ float dist = length(pr - foot);
214
+ acc = max(acc, (1.0 - smoothstep(w - aaw, w + aaw, dist)) * rStr);
215
+ }
216
+ }
217
+ return acc;
218
+ }
219
+
220
+ float pnScratches(vec2 uv, float angle, float density, float lengthScale, float halfWidth, float wander, float periodX, float coarseWeight) {
221
+ float ca = cos(angle), sa = sin(angle);
222
+ vec2 r = vec2(uv.x * ca - uv.y * sa, uv.x * sa + uv.y * ca);
223
+
224
+ // Fine family: many short/medium scratches at the caller's frequency.
225
+ float fine = pnScratchLayer(r, angle, density, lengthScale, halfWidth, wander, periodX, 0.0);
226
+
227
+ // Coarse family: a few much longer grooves, seeded on a ~3x larger grid (bigger cells
228
+ // => longer scratches within the same 3x3 search). x is rescaled to an INTEGER period
229
+ // so the circumference seam stays seamless; y (never tiled) is just divided down. The
230
+ // half-width is scaled by the same factor so the coarse grooves keep the SAME world
231
+ // width as the fine ones (longer, not fatter). It is the most repetition-prone / "big"
232
+ // family AND doubles the per-fragment cost, so `coarseWeight` lets the caller drop it
233
+ // entirely (pass 0 - the whole 3x3 loop is then skipped): the branch is expected to be
234
+ // driven by a uniform (e.g. a quality knob) so it stays divergence-free.
235
+ float coarse = 0.0;
236
+ if(coarseWeight > 0.0) {
237
+ float coarsePeriod = max(floor(periodX / 3.0 + 0.5), 1.0);
238
+ float scale = coarsePeriod / max(periodX, 1.0);
239
+ vec2 rc = vec2(r.x * scale, r.y / 3.0);
240
+ coarse = pnScratchLayer(rc, angle, density * 0.5, lengthScale, halfWidth * scale, wander, coarsePeriod, 7.0) * coarseWeight;
241
+ }
242
+
243
+ return -max(fine, coarse);
244
+ }
245
+
246
+ // Footprint anti-aliasing factor (1 near .. 0 sub-pixel). Fades a pattern out as its
247
+ // finest octave shrinks toward a pixel - with distance or at grazing angles - so the
248
+ // high-frequency detail never becomes a shimmering/aliasing signal. `uv` is the
249
+ // (frequency-scaled) sample coordinate; `octaves` is the fbm octave count. Must be
250
+ // called under uniform control flow (uses screen-space derivatives).
251
+ float pnFootprintFade(vec2 uv, int octaves) {
252
+ // cells per pixel of the sample coordinate (mildly boosted for finer octaves). Fade
253
+ // BEFORE the Nyquist limit: a cell must stay >~2 px to sample cleanly, so start fading
254
+ // around 2.5 px/cell and reach zero by ~1 px/cell. (A looser threshold left the pattern
255
+ // near full strength at ~1 cell/pixel, so it stippled/aliased on thin, minified faces
256
+ // such as the end caps and slice faces.)
257
+ float cellsPerPixel = max(fwidth(uv.x), fwidth(uv.y)) * (1.0 + 0.5 * float(octaves - 1));
258
+ return 1.0 - smoothstep(0.4, 1.0, cellsPerPixel);
259
+ }
260
+
261
+ // Perturb a view-space normal by a scalar height field using the screen-space surface
262
+ // gradient (Mikkelsen) - no tangent/bitangent attributes needed. `height` must be the
263
+ // value sampled at THIS fragment; its screen-space derivatives give the slope.
264
+ vec3 perturbNormalHeight(vec3 normal, vec3 viewPos, float height) {
265
+ vec3 sx = dFdx(viewPos);
266
+ vec3 sy = dFdy(viewPos);
267
+ float hx = dFdx(height);
268
+ float hy = dFdy(height);
269
+ vec3 r1 = cross(sy, normal);
270
+ vec3 r2 = cross(normal, sx);
271
+ float det = dot(sx, r1);
272
+ vec3 grad = sign(det) * (hx * r1 + hy * r2);
273
+ return normalize(abs(det) * normal - grad);
274
+ }
@@ -0,0 +1,37 @@
1
+ import { ReactNode } from 'react';
2
+ import { BoundsShape } from '../../sdk';
3
+ /**
4
+ * Bounds props
5
+ * @expand
6
+ */
7
+ export type BoundsProps = BoundsShape & {
8
+ children?: ReactNode;
9
+ };
10
+ /**
11
+ * A generic provider of the {@link DistanceContext}, so the {@link Distance} component
12
+ * (and anything else reading the context) can be used for ANY object — not just
13
+ * wellbores. Supply a bounding `sphere`, `box` or a single `position` and `Bounds`
14
+ * publishes the camera's distance to it each frame, measured in this component's local
15
+ * space and divided by `camera.zoom` (matching {@link WellboreBounds}, so `Distance`'s
16
+ * `min`/`max` behave identically).
17
+ *
18
+ * If more than one shape is provided the precedence is `sphere` > `box` > `position`.
19
+ * With none, the distance stays `Infinity` (so distance-gated children remain hidden).
20
+ *
21
+ * @example
22
+ * <Bounds sphere={{ center: [0, 0, 0], radius: 5 }}>
23
+ * <Distance min={0} max={50}>
24
+ * <mesh>
25
+ * <sphereGeometry />
26
+ * <meshStandardMaterial color="red" />
27
+ * </mesh>
28
+ * </Distance>
29
+ * </Bounds>
30
+ *
31
+ * @see {@link Distance}
32
+ * @see {@link DistanceContext}
33
+ * @see {@link WellboreBounds}
34
+ *
35
+ * @group Components
36
+ */
37
+ export declare const Bounds: ({ sphere, box, position, children }: BoundsProps) => import("react/jsx-runtime").JSX.Element;
@@ -10,23 +10,34 @@ export type DistanceProps = {
10
10
  children: ReactNode;
11
11
  };
12
12
  /**
13
- * The Distance component can be used to conditionally render other components.
13
+ * The Distance component can be used to conditionally render (or, with `onDemand`,
14
+ * mount/unmount) child components based on the camera's distance to a bounds — for
15
+ * example to swap geometry level-of-detail. It reads the {@link DistanceContext}, which a
16
+ * parent must provide: use the generic {@link Bounds} for any object, or
17
+ * {@link WellboreBounds} for a wellbore.
14
18
  *
15
19
  * @example
16
- * <Wellbore id={wellboreId}>
17
- * { // DistanceContext provider }
18
- * <WellboreBounds id={wellboreId}>
19
- * <BasicTrajectory />
20
- * <Distance min={0} max={2000}>
21
- * <TubeTrajectory />
22
- * </Distance>
23
- * </WellboreBounds>
24
- * </Wellbore>
20
+ * <Bounds sphere={{ center: [0, 0, 0], radius: 5 }}>
21
+ * <Distance min={0} max={50}>
22
+ * <mesh>
23
+ * <sphereGeometry />
24
+ * <meshStandardMaterial color="red" />
25
+ * </mesh>
26
+ * </Distance>
27
+ * <Distance min={50} max={Infinity}>
28
+ * <mesh>
29
+ * <boxGeometry />
30
+ * <meshStandardMaterial color="blue" />
31
+ * </mesh>
32
+ * </Distance>
33
+ * </Bounds>
25
34
  *
26
35
  * @remarks
27
- * This component depends on a `DistanceContext` being provided by a parent component.
36
+ * This component depends on a `DistanceContext` being provided by a parent component
37
+ * (e.g. {@link Bounds} or {@link WellboreBounds}).
28
38
  *
29
39
  * @see [Storybook](/videx-3d/?path=/docs/components-misc-distance--docs)
40
+ * @see {@link Bounds}
30
41
  * @see {@link DistanceContext}
31
42
  * @see {@link WellboreBounds}
32
43
  *
@@ -1,2 +1,3 @@
1
+ export * from './Bounds';
1
2
  export * from './Distance';
2
3
  export * from './DistanceContext';
@@ -1,5 +1,137 @@
1
1
  import { MeshStandardMaterial, MeshStandardMaterialParameters, Uniform, WebGLProgramParametersWithUniforms } from 'three';
2
+ /**
3
+ * Parameters accepted by {@link CasingMaterial}. A `MeshStandardMaterial` at heart, so
4
+ * it takes the familiar PBR knobs (`color`, `roughness`, `metalness`, `emissive`,
5
+ * `envMap`, `envMapIntensity`, ...) plus the casing texture-UV units and the grouped
6
+ * {@link CasingEffects | effects} below.
7
+ *
8
+ * @expand
9
+ */
10
+ export type CasingMaterialParameters = MeshStandardMaterialParameters & {
11
+ /** UV units for the base `map` (and the aoMap/lightMap/emissiveMap/metalnessMap/
12
+ * roughnessMap group): `'normalized'` = 0..1 around/along, `'world'` = object-space
13
+ * distance (arc length x trajectory distance) so `texture.repeat` becomes a density
14
+ * that stays consistent across sections of different radius and length. Default
15
+ * `'normalized'`. */
16
+ mapUvUnits?: 'normalized' | 'world';
17
+ /** UV units for `normalMap` / `bumpMap`, independent of `mapUvUnits`. Default
18
+ * `'normalized'`. */
19
+ normalMapUvUnits?: 'normalized' | 'world';
20
+ /** Grouped casing stylization effects (silhouette outline, section edge shading,
21
+ * procedural weathering, per-section variation and micro-normal surface detail).
22
+ * Every sub-effect is optional and independent; omitted ones fall back to their
23
+ * defaults (mostly off). */
24
+ effects?: CasingEffects;
25
+ };
26
+ /**
27
+ * Composable casing stylization effects for {@link CasingMaterial}. Every field is
28
+ * optional and independent; the procedural surface-detail layers (`granular`,
29
+ * `brushed`, `scratches`) simply sum. Strengths default to 0 (off) unless noted.
30
+ * @expand
31
+ */
32
+ export type CasingEffects = {
33
+ /** View-space silhouette darkening that outlines each shell, helping nested strings
34
+ * read apart (especially under slicing / auto-slice). */
35
+ silhouette?: {
36
+ /** 0-1 strength (0 = off). Default 0. */
37
+ strength?: number;
38
+ /** Exponent tightening the rim toward the edge (higher = tighter). Default 3. */
39
+ power?: number;
40
+ };
41
+ /** Darkening at each section's own top/bottom edges. */
42
+ edgeShading?: {
43
+ /** 0-1 strength (0 = off). Default 0. */
44
+ strength?: number;
45
+ /** Distance in metres the darkening reaches from each edge, independent of section
46
+ * length. Default 0.2. */
47
+ width?: number;
48
+ };
49
+ /** Procedural wear/tear/spill (no textures), pinned in world space. */
50
+ weathering?: {
51
+ /** 0-1 strength (0 = off). Default 0. */
52
+ strength?: number;
53
+ /** Noise frequency in cells per real-world metre (lower = larger, sparser smears).
54
+ * Default 1.5. */
55
+ scale?: number;
56
+ /** 0-1 per-material multiplier (1 = full wear, 0 = none) so a preset such as the
57
+ * matte shoe can resist the weathering. Default 1. */
58
+ resistance?: number;
59
+ };
60
+ /** 0-1 per-section wear variation so adjacent telescoping strings read apart by
61
+ * looking differently worn rather than by a colour/value ramp. Default 0. */
62
+ sectionVariation?: number;
63
+ /** 0-1 performance vs. quality of the procedural surface detail (a fill-rate knob;
64
+ * off-effects always cost nothing regardless). Lower = cheaper: fewer weathering fbm
65
+ * octaves (2 at 0 .. 4 at 1) and the coarse/long scratch family only runs at >= 0.66.
66
+ * 1 = full-detail reference. Default 0.6. */
67
+ detailQuality?: number;
68
+ /** Isotropic value-noise bumps. */
69
+ granular?: {
70
+ /** 0-1 strength (0 = off). Default 0. */
71
+ strength?: number;
72
+ /** Cells per world (object-distance) unit. Default 2. */
73
+ frequency?: number;
74
+ /** 1-5 fbm octaves. Default 3. */
75
+ octaves?: number;
76
+ /** 0-1 stretch of the cells along the trajectory axis. Default 0. */
77
+ anisotropy?: number;
78
+ };
79
+ /** Directional fine grain (many thin parallel ridges). */
80
+ brushed?: {
81
+ /** 0-1 strength (0 = off). Default 0. */
82
+ strength?: number;
83
+ /** Cells per world (object-distance) unit. Default 2. */
84
+ frequency?: number;
85
+ /** 1-5 fbm octaves. Default 3. */
86
+ octaves?: number;
87
+ /** Grain direction in radians (0 = along the trajectory axis; non-zero angles
88
+ * reintroduce a faint seam on a full shell). Default 0. */
89
+ angle?: number;
90
+ /** 0-1 line thinness. Default 0.5. */
91
+ sharpness?: number;
92
+ /** 0-1 blend from an irregular grain (0) to regular, evenly-spaced flutes (1).
93
+ * Default 0. */
94
+ uniformity?: number;
95
+ };
96
+ /** Sparse, hair-thin surface scuffs that glint under changing light (their relief is
97
+ * kept very shallow - visibility comes from a localized polish, not depth). */
98
+ scratches?: {
99
+ /** 0-1 strength (0 = off). Default 0. */
100
+ strength?: number;
101
+ /** Cells per world (object-distance) unit. Default 10. */
102
+ frequency?: number;
103
+ /** Scratch direction in radians (0 = along the trajectory axis). Default 0. */
104
+ angle?: number;
105
+ /** 0-1 how many scratches survive. Default 0.4. */
106
+ density?: number;
107
+ /** Average scratch length multiplier (>0). Default 0.6. */
108
+ length?: number;
109
+ /** 0-1 how much the scratch direction drifts. Default 1. */
110
+ wander?: number;
111
+ /** 0-1 groove width, frequency-independent (world-scaled, hair/needle-thin:
112
+ * ~0.02..0.12mm half-width). Default 0.15. */
113
+ width?: number;
114
+ };
115
+ };
116
+ /**
117
+ * Physically-based (PBR) material for `Casings` / `CasingSection`. A
118
+ * `MeshStandardMaterial` at its core - so casings pick up real image-based
119
+ * reflections from the scene `environment`, exactly matching neighbouring
120
+ * `CompletionTools` - with the casing-specific stylization (procedural weathering,
121
+ * granular/brushed/scratch micro-normal detail, silhouette darkening and edge shading)
122
+ * spliced into its shaders via `onBeforeCompile`, and the slicing/vertex
123
+ * transform driven by the same custom attributes as the picking material.
124
+ *
125
+ * OIT-capable via {@link makeOitCompatible} so casings participate in the
126
+ * `OITRenderPass` hybrid pipeline (a no-op in the default render loop).
127
+ */
2
128
  export declare class CasingMaterial extends MeshStandardMaterial {
129
+ isCasingMaterial: boolean;
130
+ private _weathering;
131
+ private _wearResistance;
132
+ private _wellLength;
133
+ /** Custom uniforms bound into the patched program in `onBeforeCompile` and
134
+ * shared by reference with the OIT variants so per-frame updates propagate. */
3
135
  uniforms: {
4
136
  sizeMultiplier: Uniform<number>;
5
137
  radius: Uniform<number>;
@@ -7,8 +139,40 @@ export declare class CasingMaterial extends MeshStandardMaterial {
7
139
  sliceOffset: Uniform<number>;
8
140
  sliceAngle: Uniform<number>;
9
141
  autoSlicePosition: Uniform<boolean>;
142
+ sectionVariation: Uniform<number>;
143
+ silhouette: Uniform<number>;
144
+ silhouettePower: Uniform<number>;
145
+ edgeShading: Uniform<number>;
146
+ edgeShadingWidth: Uniform<number>;
147
+ sectionIndex: Uniform<number>;
148
+ detailFadeNear: Uniform<number>;
149
+ detailFadeFar: Uniform<number>;
150
+ detailQuality: Uniform<number>;
151
+ schematic: Uniform<number>;
152
+ mapUvWorld: Uniform<number>;
153
+ normalMapUvWorld: Uniform<number>;
154
+ wellLength: Uniform<number>;
155
+ granularStrength: Uniform<number>;
156
+ granularFrequency: Uniform<number>;
157
+ granularOctaves: Uniform<number>;
158
+ granularAnisotropy: Uniform<number>;
159
+ brushedStrength: Uniform<number>;
160
+ brushedFrequency: Uniform<number>;
161
+ brushedOctaves: Uniform<number>;
162
+ brushedAngle: Uniform<number>;
163
+ brushedSharpness: Uniform<number>;
164
+ brushedUniformity: Uniform<number>;
165
+ scratchStrength: Uniform<number>;
166
+ scratchFrequency: Uniform<number>;
167
+ scratchAngle: Uniform<number>;
168
+ scratchDensity: Uniform<number>;
169
+ scratchLength: Uniform<number>;
170
+ scratchWander: Uniform<number>;
171
+ scratchWidth: Uniform<number>;
172
+ weathering: Uniform<number>;
173
+ weatheringScale: Uniform<number>;
10
174
  };
11
- constructor(params?: MeshStandardMaterialParameters);
175
+ constructor(parameters?: CasingMaterialParameters);
12
176
  get sizeMultiplier(): number;
13
177
  set sizeMultiplier(v: number);
14
178
  get radius(): number;
@@ -21,5 +185,69 @@ export declare class CasingMaterial extends MeshStandardMaterial {
21
185
  set sliceAngle(v: number);
22
186
  get autoSlicePosition(): boolean;
23
187
  set autoSlicePosition(v: boolean);
188
+ /** 0-1 strength of the per-section wear variation: how much each section's
189
+ * procedural wear is offset (seed) and scaled (amount) by its index, so adjacent
190
+ * telescoping strings read apart by looking differently worn rather than by a
191
+ * colour/value ramp. */
192
+ get sectionVariation(): number;
193
+ set sectionVariation(v: number);
194
+ /** 0-1 strength of the view-space silhouette darkening (outlines each shell). */
195
+ get silhouette(): number;
196
+ set silhouette(v: number);
197
+ /** Exponent tightening the silhouette rim toward the edge (higher = tighter). Default 3. */
198
+ get silhouettePower(): number;
199
+ set silhouettePower(v: number);
200
+ /** 0-1 strength of the edge shading (darkening at each section's own top/bottom edges). */
201
+ get edgeShading(): number;
202
+ set edgeShading(v: number);
203
+ /** Distance in metres the edge shading reaches from each section edge. Default 0.2. */
204
+ get edgeShadingWidth(): number;
205
+ set edgeShadingWidth(v: number);
206
+ /** Index of this section within the wellbore's casing stack, used to seed the
207
+ * per-section variation of the stylization effects. */
208
+ get sectionIndex(): number;
209
+ set sectionIndex(v: number);
210
+ /** 0-1 performance vs. quality of the procedural surface detail (fill-rate knob).
211
+ * Lower = cheaper (fewer weathering fbm octaves; the coarse scratch family only runs
212
+ * at >= 0.66); 1 = full-detail reference. */
213
+ get detailQuality(): number;
214
+ set detailQuality(v: number);
215
+ /** Unlit "schematic" shading mode: flat material `color` + `silhouette` outline only,
216
+ * with all lighting/env, textures and realism detail ignored. Set by the `Casings`
217
+ * component's `schematic` prop; the slice is locked separately (component side). */
218
+ get schematic(): boolean;
219
+ set schematic(v: boolean);
220
+ /** 0-1 strength of the procedural wear/tear/spill surface detail (no textures). The
221
+ * effective amount is scaled per-material by {@link wearResistance}. */
222
+ get weathering(): number;
223
+ set weathering(v: number);
224
+ /** 0-1 per-material wear multiplier (1 = full wear, 0 = none). Lets material presets
225
+ * (e.g. the matte shoe) resist the procedural weathering the component applies
226
+ * globally via {@link weathering}. */
227
+ get wearResistance(): number;
228
+ set wearResistance(v: number);
229
+ /** Weathering noise frequency in cells per real-world metre (lower = larger,
230
+ * sparser smears). */
231
+ get weatheringScale(): number;
232
+ set weatheringScale(v: number);
233
+ /** Real-world total length (metres) of the whole wellbore trajectory. Uploaded as a
234
+ * uniform and used by the vertex shader to derive each section's physical length
235
+ * (`vSectionLength`) and the along-axis coordinate (`casingAxial`). The weathering is
236
+ * pinned in world space (via `vWorldPos`) and does not use it. */
237
+ get wellLength(): number;
238
+ set wellLength(v: number);
239
+ /** UV units for the base `map` group. `'world'` uses object-space distance so
240
+ * `texture.repeat` is a radius/length-consistent density. */
241
+ get mapUvUnits(): 'normalized' | 'world';
242
+ set mapUvUnits(v: 'normalized' | 'world');
243
+ /** UV units for `normalMap` / `bumpMap`, independent of {@link mapUvUnits}. */
244
+ get normalMapUvUnits(): 'normalized' | 'world';
245
+ set normalMapUvUnits(v: 'normalized' | 'world');
246
+ /** Grouped casing stylization effects (silhouette, edge shading, weathering,
247
+ * per-section variation and the granular/brushed/scratch micro-normal layers).
248
+ * Reading returns the current settings reconstructed from the uniforms. Assigning
249
+ * applies the whole group at once - omitted sub-effects reset to their defaults. */
250
+ get effects(): CasingEffects;
251
+ set effects(v: CasingEffects | undefined);
24
252
  onBeforeCompile(parameters: WebGLProgramParametersWithUniforms): void;
25
253
  }
@@ -1,4 +1,5 @@
1
1
  import { PointerEvents } from '../../../main';
2
+ import { CasingEffects } from './CasingMaterial';
2
3
  import { CasingSectionMaterialOptions } from './Casings';
3
4
  import { CasingSectionType } from './casings-defs';
4
5
  type CasingSectionProps = {
@@ -11,6 +12,10 @@ type CasingSectionProps = {
11
12
  autoSlicePosition?: boolean;
12
13
  opacity?: number;
13
14
  renderOrder?: number;
15
+ effects?: CasingEffects;
16
+ wellLength?: number;
17
+ sectionIndex?: number;
18
+ schematic?: boolean;
14
19
  } & PointerEvents;
15
- export declare const CasingSection: ({ section, materialOptions, radialSegments, sizeMultiplier, sliceAngle, sliceOffset, autoSlicePosition, opacity, renderOrder, onPointerClick, onPointerEnter, onPointerLeave, onPointerMove, }: CasingSectionProps) => import("react/jsx-runtime").JSX.Element;
20
+ export declare const CasingSection: ({ section, materialOptions, radialSegments, sizeMultiplier, sliceAngle, sliceOffset, autoSlicePosition, opacity, renderOrder, effects, wellLength, sectionIndex, schematic, onPointerClick, onPointerEnter, onPointerLeave, onPointerMove, }: CasingSectionProps) => import("react/jsx-runtime").JSX.Element;
16
21
  export {};