@crystaldesign/real-time-viewer-next 26.11.0-beta.22 → 26.11.0-beta.24
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/build/esm/{DeckCutoutSubsystem-76dfe828.js → DeckCutoutSubsystem-4369a7a2.js} +1 -1
- package/build/esm/{SunLensflare-e4ab3f81.js → SunLensflare-6d65fd17.js} +58 -58
- package/build/esm/{WaterSurface-93383fdf.js → WaterSurface-95b630aa.js} +1 -1
- package/build/esm/{index-920dd901.js → index-fa3c5a24.js} +180 -151
- package/build/esm/index.js +1 -1
- package/build/types/real-time-viewer-next/src/core/SceneRenderer.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/environment/EnvironmentSunLensflare.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/environment/SunLensflare.d.ts +17 -5
- package/build/types/real-time-viewer-next/src/core/environment/SunLensflare.d.ts.map +1 -1
- package/build/types/real-time-viewer-next/src/core/meshBVH.d.ts +4 -4
- package/build/types/real-time-viewer-next/src/utils/collisionTargets.d.ts +13 -10
- package/build/types/real-time-viewer-next/src/utils/collisionTargets.d.ts.map +1 -1
- package/build/umd/114.real-time-viewer-next.umd.min.js +1 -1
- package/build/umd/real-time-viewer-next.umd.min.js +1 -1
- package/build/umd/report.html +1 -1
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { p as parseElementKey, u as useRTVStore, b as bootPhase, D as DECK_COLLAR_LOAD_ID } from './index-
|
|
1
|
+
import { p as parseElementKey, u as useRTVStore, b as bootPhase, D as DECK_COLLAR_LOAD_ID } from './index-fa3c5a24.js';
|
|
2
2
|
import { useMemo, useRef, useEffect, useState, useCallback } from 'react';
|
|
3
3
|
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
|
|
4
4
|
import _defineProperty from '@babel/runtime/helpers/defineProperty';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
|
|
2
|
-
import './index-
|
|
2
|
+
import { f as flushPendingBVH, e as collectCollisionTargets } from './index-fa3c5a24.js';
|
|
3
3
|
import { useMemo, useEffect, useRef } from 'react';
|
|
4
4
|
import { Billboard } from '@react-three/drei';
|
|
5
5
|
import { useThree, useFrame } from '@react-three/fiber';
|
|
@@ -191,23 +191,29 @@ var OCCLUSION_MAX_DISTANCE = 10000;
|
|
|
191
191
|
var OCCLUSION_NEAR = 0.1;
|
|
192
192
|
/** Approximate angular radius for visibility sampling around the sun center ray. */
|
|
193
193
|
var OCCLUSION_SAMPLE_RADIUS = 0.018;
|
|
194
|
-
/**
|
|
195
|
-
|
|
194
|
+
/**
|
|
195
|
+
* Temporal response toward LESS visibility (higher = faster, 1 = instant). Asymmetric on purpose:
|
|
196
|
+
* a light source winks out the moment something blocks it, so the fade-out has to feel immediate,
|
|
197
|
+
* while the partial-occlusion gradations still get a little smoothing against tap noise.
|
|
198
|
+
*/
|
|
199
|
+
var OCCLUSION_HIDE_LERP = 0.55;
|
|
200
|
+
/**
|
|
201
|
+
* Temporal response toward MORE visibility. Slower than {@link OCCLUSION_HIDE_LERP}: the flare
|
|
202
|
+
* re-emerging along a geometry edge eases in instead of popping/flickering with every tap that
|
|
203
|
+
* clears.
|
|
204
|
+
*/
|
|
205
|
+
var OCCLUSION_REVEAL_LERP = 0.2;
|
|
206
|
+
/** Temporal response of the anchor centroid shift — jitter matters more than speed here. */
|
|
207
|
+
var OCCLUSION_CENTROID_LERP = 0.2;
|
|
196
208
|
/** Tiny alpha threshold to fully hide flare when effectively occluded. */
|
|
197
209
|
var OCCLUSION_MIN_VISIBLE_ALPHA = 0.01;
|
|
198
210
|
/**
|
|
199
211
|
* Run the 9-tap occlusion kernel only every Nth frame. Visibility is already
|
|
200
|
-
* temporally smoothed (see {@link
|
|
201
|
-
* cadence is visually indistinguishable from per-frame sampling —
|
|
202
|
-
* raycast cost by ~3x.
|
|
212
|
+
* temporally smoothed (see {@link OCCLUSION_HIDE_LERP} / {@link OCCLUSION_REVEAL_LERP}),
|
|
213
|
+
* so a 3-frame cadence is visually indistinguishable from per-frame sampling —
|
|
214
|
+
* but cuts the raycast cost by ~3x.
|
|
203
215
|
*/
|
|
204
216
|
var OCCLUSION_SAMPLE_INTERVAL = 3;
|
|
205
|
-
/**
|
|
206
|
-
* How many frames an occluder list is reused before being rebuilt. The scene
|
|
207
|
-
* graph rarely changes between frames, so walking it every frame just to
|
|
208
|
-
* collect raycastable meshes is wasted work.
|
|
209
|
-
*/
|
|
210
|
-
var OCCLUDER_LIST_REBUILD_INTERVAL = 12;
|
|
211
217
|
/**
|
|
212
218
|
* How much the flare anchor shifts toward the visible side of the sun disc.
|
|
213
219
|
* 0 = disabled, 1 = full centroid shift.
|
|
@@ -228,6 +234,11 @@ var OCCLUSION_SAMPLE_OFFSETS = [[0, 0, 2], [1, 0, 1], [-1, 0, 1], [0, 1, 1], [0,
|
|
|
228
234
|
* Does **not** use `three/examples/jsm/objects/Lensflare.js`: that helper reads the framebuffer for
|
|
229
235
|
* occlusion (`copyFramebufferToTexture`), which fails or zeroes alpha when the scene is drawn through
|
|
230
236
|
* pmndrs `EffectComposer` / multisampled targets.
|
|
237
|
+
*
|
|
238
|
+
* Occlusion taps run against `collectCollisionTargets` (article + BVH decor) — the same scoped set
|
|
239
|
+
* the camera-collision probe uses, and for the same reason: raycasting the whole scene puts every
|
|
240
|
+
* blocked ray on three.js' O(triangles) `Mesh.raycast`, which stalls weak CPUs exactly while the
|
|
241
|
+
* sun sits behind geometry. Visual aids, drag previews and the sky shells drop out with it.
|
|
231
242
|
*/
|
|
232
243
|
function SunLensflare(_ref) {
|
|
233
244
|
var sunDirection = _ref.sunDirection,
|
|
@@ -238,7 +249,9 @@ function SunLensflare(_ref) {
|
|
|
238
249
|
_ref$sizeScale = _ref.sizeScale,
|
|
239
250
|
sizeScale = _ref$sizeScale === void 0 ? 1.0 : _ref$sizeScale,
|
|
240
251
|
_ref$occlusionEnabled = _ref.occlusionEnabled,
|
|
241
|
-
occlusionEnabled = _ref$occlusionEnabled === void 0 ? true : _ref$occlusionEnabled
|
|
252
|
+
occlusionEnabled = _ref$occlusionEnabled === void 0 ? true : _ref$occlusionEnabled,
|
|
253
|
+
_ref$occludersRevisio = _ref.occludersRevision,
|
|
254
|
+
occludersRevision = _ref$occludersRevisio === void 0 ? 0 : _ref$occludersRevisio;
|
|
242
255
|
var scene = useThree(function (s) {
|
|
243
256
|
return s.scene;
|
|
244
257
|
});
|
|
@@ -290,16 +303,23 @@ function SunLensflare(_ref) {
|
|
|
290
303
|
var sunAnchorPos = useMemo(function () {
|
|
291
304
|
return new Vector3();
|
|
292
305
|
}, []);
|
|
306
|
+
// near/far never change, and `firstHitOnly` (three-mesh-bvh) makes every mesh with a
|
|
307
|
+
// `boundsTree` report at most one hit — the taps ask a boolean, so any hit past the
|
|
308
|
+
// first is wasted work.
|
|
293
309
|
var raycaster = useMemo(function () {
|
|
294
|
-
|
|
310
|
+
var r = new Raycaster();
|
|
311
|
+
r.near = OCCLUSION_NEAR;
|
|
312
|
+
r.far = OCCLUSION_MAX_DISTANCE;
|
|
313
|
+
r.firstHitOnly = true;
|
|
314
|
+
return r;
|
|
295
315
|
}, []);
|
|
296
316
|
var hitBufferRef = useRef([]);
|
|
297
317
|
var smoothedVisibilityRef = useRef(1);
|
|
298
318
|
var smoothedCentroidXRef = useRef(0);
|
|
299
319
|
var smoothedCentroidYRef = useRef(0);
|
|
300
320
|
var frameCounterRef = useRef(0);
|
|
301
|
-
var
|
|
302
|
-
var
|
|
321
|
+
var occludersRef = useRef([]);
|
|
322
|
+
var occludersBuiltForRef = useRef(null);
|
|
303
323
|
var flareR = Math.max(10, FLARE_FORWARD_DISTANCE * distanceScale);
|
|
304
324
|
// Chromatic per-ghost tint composed with the overall flare colour.
|
|
305
325
|
var elementTints = useMemo(function () {
|
|
@@ -334,7 +354,14 @@ function SunLensflare(_ref) {
|
|
|
334
354
|
var frame = frameCounterRef.current++;
|
|
335
355
|
var shouldSample = inFront && frame % OCCLUSION_SAMPLE_INTERVAL === 0;
|
|
336
356
|
if (shouldSample) {
|
|
337
|
-
|
|
357
|
+
if (occludersBuiltForRef.current !== occludersRevision) {
|
|
358
|
+
occludersBuiltForRef.current = occludersRevision;
|
|
359
|
+
// Build queued BVHs first: a `boundsTree` is what marks decor collidable, and the
|
|
360
|
+
// article's trees keep the taps below off the O(triangles) raycast path.
|
|
361
|
+
flushPendingBVH();
|
|
362
|
+
occludersRef.current = collectCollisionTargets(scene).meshes;
|
|
363
|
+
}
|
|
364
|
+
var occluders = occludersRef.current;
|
|
338
365
|
var totalWeight = 0;
|
|
339
366
|
var visibleWeight = 0;
|
|
340
367
|
var weightedVisibleX = 0;
|
|
@@ -346,15 +373,17 @@ function SunLensflare(_ref) {
|
|
|
346
373
|
oy = _OCCLUSION_SAMPLE_OFF[1],
|
|
347
374
|
w = _OCCLUSION_SAMPLE_OFF[2];
|
|
348
375
|
sampleDirScratch.copy(sunDirNormalized).addScaledVector(rightScratch, ox * OCCLUSION_SAMPLE_RADIUS).addScaledVector(upScratch, oy * OCCLUSION_SAMPLE_RADIUS).normalize();
|
|
349
|
-
raycaster.near = OCCLUSION_NEAR;
|
|
350
|
-
raycaster.far = OCCLUSION_MAX_DISTANCE;
|
|
351
376
|
raycaster.set(cameraWorldPos, sampleDirScratch);
|
|
352
377
|
var hits = hitBufferRef.current;
|
|
353
|
-
|
|
354
|
-
//
|
|
355
|
-
//
|
|
356
|
-
|
|
357
|
-
|
|
378
|
+
var blocked = false;
|
|
379
|
+
// Any hit answers the tap — stop at the first blocking mesh instead of collecting
|
|
380
|
+
// (and sorting) every intersection along the whole ray.
|
|
381
|
+
for (var m = 0; m < occluders.length && !blocked; m++) {
|
|
382
|
+
hits.length = 0;
|
|
383
|
+
raycaster.intersectObject(occluders[m], false, hits);
|
|
384
|
+
blocked = hits.length > 0;
|
|
385
|
+
}
|
|
386
|
+
var visible = blocked ? 0 : 1;
|
|
358
387
|
totalWeight += w;
|
|
359
388
|
visibleWeight += visible * w;
|
|
360
389
|
weightedVisibleX += ox * visible * w;
|
|
@@ -366,13 +395,14 @@ function SunLensflare(_ref) {
|
|
|
366
395
|
var targetCentroidX = visibleWeight > 1e-4 ? weightedVisibleX / visibleWeight : 0;
|
|
367
396
|
var targetCentroidY = visibleWeight > 1e-4 ? weightedVisibleY / visibleWeight : 0;
|
|
368
397
|
var prevVis = smoothedVisibilityRef.current;
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
398
|
+
var visibilityLerp = targetVisibility < prevVis ? OCCLUSION_HIDE_LERP : OCCLUSION_REVEAL_LERP;
|
|
399
|
+
smoothedVisibilityRef.current = Math.min(1, Math.max(0, prevVis + (targetVisibility - prevVis) * visibilityLerp));
|
|
400
|
+
smoothedCentroidXRef.current += (targetCentroidX - smoothedCentroidXRef.current) * OCCLUSION_CENTROID_LERP;
|
|
401
|
+
smoothedCentroidYRef.current += (targetCentroidY - smoothedCentroidYRef.current) * OCCLUSION_CENTROID_LERP;
|
|
372
402
|
} else if (!inFront) {
|
|
373
403
|
// Sun behind camera: decay toward zero so we don't hold stale visibility
|
|
374
404
|
// when the user spins around.
|
|
375
|
-
smoothedVisibilityRef.current *= 1 -
|
|
405
|
+
smoothedVisibilityRef.current *= 1 - OCCLUSION_HIDE_LERP;
|
|
376
406
|
}
|
|
377
407
|
|
|
378
408
|
// Shift anchor toward the visible side of the sun disc so left/right occlusion
|
|
@@ -450,34 +480,4 @@ function viewZInFront(viewZ) {
|
|
|
450
480
|
return viewZ < 0;
|
|
451
481
|
}
|
|
452
482
|
|
|
453
|
-
/**
|
|
454
|
-
* Collect a flat list of meshes worth raycasting against for sun occlusion.
|
|
455
|
-
* The result is cached for {@link OCCLUDER_LIST_REBUILD_INTERVAL} frames so a
|
|
456
|
-
* static scene only walks the graph occasionally. Excludes:
|
|
457
|
-
* - the lensflare's own root (avoids self-hits)
|
|
458
|
-
* - invisible objects
|
|
459
|
-
* - `userData.lensflare === 'no-occlusion'` opt-outs
|
|
460
|
-
* - `InstancedMesh` (scattered trees) — per-instance raycasts are O(N)
|
|
461
|
-
* and these are decorative, not real occluders for the sun disc
|
|
462
|
-
* - `SkinnedMesh` — skin-bound raycasts force skeleton matrix work
|
|
463
|
-
*/
|
|
464
|
-
function getOccluders(scene, flareRoot, listRef, ageRef) {
|
|
465
|
-
ageRef.current += 1;
|
|
466
|
-
if (ageRef.current < OCCLUDER_LIST_REBUILD_INTERVAL && listRef.current.length > 0) {
|
|
467
|
-
return listRef.current;
|
|
468
|
-
}
|
|
469
|
-
ageRef.current = 0;
|
|
470
|
-
var list = listRef.current;
|
|
471
|
-
list.length = 0;
|
|
472
|
-
scene.traverseVisible(function (object) {
|
|
473
|
-
if (flareRoot.getObjectById(object.id) !== undefined) return;
|
|
474
|
-
if (object.userData.lensflare === 'no-occlusion') return;
|
|
475
|
-
var anyObj = object;
|
|
476
|
-
if (anyObj.isInstancedMesh === true) return;
|
|
477
|
-
if (anyObj.isSkinnedMesh === true) return;
|
|
478
|
-
if (anyObj.isMesh === true) list.push(object);
|
|
479
|
-
});
|
|
480
|
-
return list;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
483
|
export { SunLensflare };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { w as withRenderTarget, s as setCausticReceiversSuspended, a as waterUniforms, d as disableWaterUniforms, u as useRTVStore, F as FRAME_ORDER, c as sunAnglesToDirection, l as lightingSunTowardDirection } from './index-
|
|
1
|
+
import { w as withRenderTarget, s as setCausticReceiversSuspended, a as waterUniforms, d as disableWaterUniforms, u as useRTVStore, F as FRAME_ORDER, c as sunAnglesToDirection, l as lightingSunTowardDirection } from './index-fa3c5a24.js';
|
|
2
2
|
import { useRef, useMemo, useEffect, useCallback } from 'react';
|
|
3
3
|
import { useThree, useFrame } from '@react-three/fiber';
|
|
4
4
|
import { Vector3, WebGLRenderTarget, HalfFloatType, RGBAFormat, LinearFilter, OrthographicCamera, ShaderMaterial, DoubleSide, MeshStandardMaterial, Box3, NoToneMapping, Frustum, Matrix4, Vector4, Vector2, Plane, Scene, Mesh, PlaneGeometry, ClampToEdgeWrapping, UnsignedByteType, MeshBasicMaterial, Color } from 'three';
|