@neurodyn/react-room-viewer 0.0.22 → 0.0.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/dist/index.js +167 -112
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import { Swiper, SwiperSlide } from "swiper/react";
|
|
|
19
19
|
import { TransformComponent, TransformWrapper } from "react-zoom-pan-pinch";
|
|
20
20
|
import { Clone, DragControls, Environment, Html, useGLTF, useProgress, useTexture } from "@react-three/drei";
|
|
21
21
|
import { Canvas, useFrame, useLoader, useThree } from "@react-three/fiber";
|
|
22
|
-
import { ACESFilmicToneMapping, Box3, BufferGeometry, CanvasTexture, ClampToEdgeWrapping, Color, DataTexture, DoubleSide, Float32BufferAttribute, LinearFilter, LoadingManager, MathUtils, Matrix4, Mesh, MeshBasicMaterial,
|
|
22
|
+
import { ACESFilmicToneMapping, Box3, BufferGeometry, CanvasTexture, ClampToEdgeWrapping, Color, DataTexture, DoubleSide, Float32BufferAttribute, LinearFilter, LoadingManager, MathUtils, Matrix4, Mesh, MeshBasicMaterial, PerspectiveCamera, Plane, Quaternion, RGBAFormat, RedFormat, SRGBColorSpace, Scene, TextureLoader, Vector2, Vector3, WebGLRenderTarget } from "three";
|
|
23
23
|
import { MeshoptDecoder } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
|
24
24
|
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
25
25
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
@@ -5409,6 +5409,10 @@ var __webpack_modules__ = {
|
|
|
5409
5409
|
color: var(--v-text-dark);
|
|
5410
5410
|
}
|
|
5411
5411
|
|
|
5412
|
+
.data-\\[variant\\=destructive\\]\\:\\[\\&_svg\\:not\\(\\[class\\*\\=text-\\]\\)\\]\\:text-inherit[data-variant="destructive"] svg:not([class*="text-"]) {
|
|
5413
|
+
color: inherit;
|
|
5414
|
+
}
|
|
5415
|
+
|
|
5412
5416
|
.\\[\\&_tr\\]\\:border-b tr {
|
|
5413
5417
|
border-bottom-style: var(--tw-border-style);
|
|
5414
5418
|
border-bottom-width: 1px;
|
|
@@ -7795,7 +7799,7 @@ const RESOURCE_TYPE_PROFILES = {
|
|
|
7795
7799
|
chrome: 'immersive-room',
|
|
7796
7800
|
presentation: 'immersive-panels',
|
|
7797
7801
|
manipulation: 'panel-group',
|
|
7798
|
-
|
|
7802
|
+
productNameSource: 'collection',
|
|
7799
7803
|
catalogTitle: 'wall-panel',
|
|
7800
7804
|
introduction: 'focus-resource',
|
|
7801
7805
|
identity: 'modelled-resource',
|
|
@@ -7815,7 +7819,7 @@ const RESOURCE_TYPE_PROFILES = {
|
|
|
7815
7819
|
chrome: 'framed-scene',
|
|
7816
7820
|
presentation: 'framed-default',
|
|
7817
7821
|
manipulation: 'single-resource',
|
|
7818
|
-
|
|
7822
|
+
productNameSource: 'material',
|
|
7819
7823
|
catalogTitle: 'title',
|
|
7820
7824
|
introduction: null,
|
|
7821
7825
|
identity: 'textured-resource',
|
|
@@ -7832,7 +7836,7 @@ const RESOURCE_TYPE_PROFILES = {
|
|
|
7832
7836
|
chrome: 'immersive-room',
|
|
7833
7837
|
presentation: 'immersive-default',
|
|
7834
7838
|
manipulation: 'drag-with-rotation-handle',
|
|
7835
|
-
|
|
7839
|
+
productNameSource: 'collection',
|
|
7836
7840
|
catalogTitle: 'rugs',
|
|
7837
7841
|
introduction: null,
|
|
7838
7842
|
identity: 'modelled-resource',
|
|
@@ -7849,7 +7853,7 @@ const RESOURCE_TYPE_PROFILES = {
|
|
|
7849
7853
|
chrome: 'immersive-room',
|
|
7850
7854
|
presentation: 'immersive-default',
|
|
7851
7855
|
manipulation: 'rotate-on-floor',
|
|
7852
|
-
|
|
7856
|
+
productNameSource: 'collection',
|
|
7853
7857
|
catalogTitle: 'flooring',
|
|
7854
7858
|
introduction: null,
|
|
7855
7859
|
identity: 'modelled-resource',
|
|
@@ -8807,13 +8811,7 @@ function getListingKey(object) {
|
|
|
8807
8811
|
return object.kit?.uuid ?? object.uuid ?? object.tinuuid ?? '';
|
|
8808
8812
|
}
|
|
8809
8813
|
function getSizedDesignKey(object) {
|
|
8810
|
-
|
|
8811
|
-
const name = object.name?.trim();
|
|
8812
|
-
const sizeSuffix = meta ? ` — ${meta.size}` : null;
|
|
8813
|
-
if (name && sizeSuffix && name.endsWith(sizeSuffix)) {
|
|
8814
|
-
const designName = name.slice(0, -sizeSuffix.length).trim();
|
|
8815
|
-
if (designName) return `rug-name:${designName}`;
|
|
8816
|
-
}
|
|
8814
|
+
if (object.kit?.uuid) return object.kit.uuid;
|
|
8817
8815
|
return `object:${getListingKey(object)}`;
|
|
8818
8816
|
}
|
|
8819
8817
|
const PRODUCT_COMPOSITION_ANSWERS = {
|
|
@@ -8835,16 +8833,13 @@ const PRODUCT_COMPOSITION_ANSWERS = {
|
|
|
8835
8833
|
};
|
|
8836
8834
|
const MATERIAL_ROLE_ANSWERS = {
|
|
8837
8835
|
'product-identity': {
|
|
8838
|
-
catalogsEveryMaterial: true
|
|
8839
|
-
namesProduct: true
|
|
8836
|
+
catalogsEveryMaterial: true
|
|
8840
8837
|
},
|
|
8841
8838
|
finish: {
|
|
8842
|
-
catalogsEveryMaterial: false
|
|
8843
|
-
namesProduct: false
|
|
8839
|
+
catalogsEveryMaterial: false
|
|
8844
8840
|
},
|
|
8845
8841
|
placeholder: {
|
|
8846
|
-
catalogsEveryMaterial: false
|
|
8847
|
-
namesProduct: false
|
|
8842
|
+
catalogsEveryMaterial: false
|
|
8848
8843
|
}
|
|
8849
8844
|
};
|
|
8850
8845
|
function resolveProductCompositionAnswers(type) {
|
|
@@ -8869,8 +8864,7 @@ function resolveResourceIdentityAnswers(type) {
|
|
|
8869
8864
|
return RESOURCE_IDENTITY_ANSWERS[resolveResourceProfile(type).identity];
|
|
8870
8865
|
}
|
|
8871
8866
|
function getResourceProductName(type, object, material, fallback = '') {
|
|
8872
|
-
|
|
8873
|
-
return namesProduct ? material?.name ?? object?.name ?? object?.kit?.name ?? fallback : object?.kit?.name ?? object?.name ?? material?.name ?? fallback;
|
|
8867
|
+
return 'material' === resolveResourceProfile(type).productNameSource ? material?.name ?? object?.name ?? object?.kit?.name ?? fallback : object?.kit?.name?.trim() || object?.name?.trim() || material?.name?.trim() || fallback;
|
|
8874
8868
|
}
|
|
8875
8869
|
function getMaterialId(material) {
|
|
8876
8870
|
return material.hid ?? '';
|
|
@@ -8982,13 +8976,14 @@ function useRoomViewerMaterialCatalog({ includeEmbeddedObject = false } = {}) {
|
|
|
8982
8976
|
const { requiresMaterialModel } = resolveResourceIdentityAnswers(type);
|
|
8983
8977
|
const { getCollapseKey } = resolveProductCompositionAnswers(type);
|
|
8984
8978
|
const { catalogsEveryMaterial } = resolveMaterialRoleAnswers(type);
|
|
8985
|
-
const {
|
|
8979
|
+
const { composition, productNameSource } = resolveResourceProfile(type);
|
|
8986
8980
|
const fetchedObjects = (0, __rspack_external_react.useMemo)(()=>data?.pages.flatMap((page)=>page.objs ?? []) ?? [], [
|
|
8987
8981
|
data
|
|
8988
8982
|
]);
|
|
8989
|
-
const unresolvedObjects = (0, __rspack_external_react.useMemo)(()=>'
|
|
8990
|
-
|
|
8991
|
-
|
|
8983
|
+
const unresolvedObjects = (0, __rspack_external_react.useMemo)(()=>'material' === productNameSource ? [] : fetchedObjects.filter((object)=>object.tinuuid && (!object.kit?.uuid || !object.kit.name?.trim()) && (!requiresMaterialModel || object.materials?.[0]?.native?.glbUrl)), [
|
|
8984
|
+
fetchedObjects,
|
|
8985
|
+
productNameSource,
|
|
8986
|
+
requiresMaterialModel
|
|
8992
8987
|
]);
|
|
8993
8988
|
const collectionQueries = useQueries({
|
|
8994
8989
|
queries: unresolvedObjects.map((object)=>({
|
|
@@ -9015,7 +9010,10 @@ function useRoomViewerMaterialCatalog({ includeEmbeddedObject = false } = {}) {
|
|
|
9015
9010
|
return [
|
|
9016
9011
|
{
|
|
9017
9012
|
...object,
|
|
9018
|
-
kit: query?.data?.kit
|
|
9013
|
+
kit: query?.data?.kit ? {
|
|
9014
|
+
...object.kit,
|
|
9015
|
+
...query.data.kit
|
|
9016
|
+
} : object.kit
|
|
9019
9017
|
}
|
|
9020
9018
|
];
|
|
9021
9019
|
});
|
|
@@ -9043,17 +9041,16 @@ function useRoomViewerMaterialCatalog({ includeEmbeddedObject = false } = {}) {
|
|
|
9043
9041
|
return catalogMaterials?.map((material)=>{
|
|
9044
9042
|
const materialId = getMaterialId(material);
|
|
9045
9043
|
if (!materialId || !object.tinuuid) return null;
|
|
9044
|
+
const productName = getResourceProductName(type, object, material, name);
|
|
9046
9045
|
return {
|
|
9047
9046
|
materialId,
|
|
9048
|
-
|
|
9049
|
-
productName: getResourceProductName(type, object, material, name),
|
|
9047
|
+
productName,
|
|
9050
9048
|
material,
|
|
9051
9049
|
tinuuid: object.tinuuid
|
|
9052
9050
|
};
|
|
9053
9051
|
}).filter((item)=>null !== item) ?? [];
|
|
9054
9052
|
}), [
|
|
9055
9053
|
catalogsEveryMaterial,
|
|
9056
|
-
catalogLabel,
|
|
9057
9054
|
composition,
|
|
9058
9055
|
objects,
|
|
9059
9056
|
type,
|
|
@@ -14676,7 +14673,7 @@ function dropdown_menu_DropdownMenuItem({ className, inset, variant = 'default',
|
|
|
14676
14673
|
"data-slot": "dropdown-menu-item",
|
|
14677
14674
|
"data-inset": inset,
|
|
14678
14675
|
"data-variant": variant,
|
|
14679
|
-
className: utils_cn('relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden hover:bg-background-base focus:bg-background-base data-[highlighted]:bg-background-base data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:hover:bg-destructive/10 data-[highlighted][data-variant=destructive]:bg-destructive/10 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg:not([class*=text-])]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0', inset && 'pl-8', className),
|
|
14676
|
+
className: utils_cn('relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden hover:bg-background-base focus:bg-background-base data-[highlighted]:bg-background-base data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:hover:bg-destructive/10 data-[highlighted][data-variant=destructive]:bg-destructive/10 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg:not([class*=text-])]:text-muted-foreground data-[variant=destructive]:[&_svg:not([class*=text-])]:text-inherit [&_svg]:pointer-events-none [&_svg]:shrink-0', inset && 'pl-8', className),
|
|
14680
14677
|
...props
|
|
14681
14678
|
});
|
|
14682
14679
|
}
|
|
@@ -15345,6 +15342,106 @@ function useFlooringRotation(enabled, isPointerOnSurface, roomId) {
|
|
|
15345
15342
|
setRotation
|
|
15346
15343
|
]);
|
|
15347
15344
|
}
|
|
15345
|
+
const MASK_EDGE_START = 0.4;
|
|
15346
|
+
const MASK_EDGE_END = 0.7;
|
|
15347
|
+
const MASK_DISCARD_ALPHA = 0.001;
|
|
15348
|
+
const UPSCALE = 2;
|
|
15349
|
+
const BLUR_SIGMA = 3;
|
|
15350
|
+
const BLUR_RADIUS = 9;
|
|
15351
|
+
const plane_visibility_mask_kernel = new Float32Array(2 * BLUR_RADIUS + 1);
|
|
15352
|
+
let kernelSum = 0;
|
|
15353
|
+
for(let offset = -BLUR_RADIUS; offset <= BLUR_RADIUS; offset++){
|
|
15354
|
+
const weight = Math.exp(-offset * offset / (2 * BLUR_SIGMA * BLUR_SIGMA));
|
|
15355
|
+
plane_visibility_mask_kernel[offset + BLUR_RADIUS] = weight;
|
|
15356
|
+
kernelSum += weight;
|
|
15357
|
+
}
|
|
15358
|
+
for(let index = 0; index < plane_visibility_mask_kernel.length; index++)plane_visibility_mask_kernel[index] /= kernelSum;
|
|
15359
|
+
function plane_visibility_mask_clamp(value1, max) {
|
|
15360
|
+
return Math.max(0, Math.min(max, value1));
|
|
15361
|
+
}
|
|
15362
|
+
function createPlaneVisibilityMask(map, planeId) {
|
|
15363
|
+
const width = map.width * UPSCALE;
|
|
15364
|
+
const height = map.height * UPSCALE;
|
|
15365
|
+
const upscaled = new Float32Array(width * height);
|
|
15366
|
+
const horizontal = new Float32Array(width * height);
|
|
15367
|
+
const data = new Uint8Array(width * height);
|
|
15368
|
+
let minX = map.width;
|
|
15369
|
+
let minY = map.height;
|
|
15370
|
+
let maxX = -1;
|
|
15371
|
+
let maxY = -1;
|
|
15372
|
+
for(let y = 0; y < map.height; y++)for(let x = 0; x < map.width; x++)if (map.data[y * map.width + x] === planeId) {
|
|
15373
|
+
minX = Math.min(minX, x);
|
|
15374
|
+
minY = Math.min(minY, y);
|
|
15375
|
+
maxX = Math.max(maxX, x);
|
|
15376
|
+
maxY = Math.max(maxY, y);
|
|
15377
|
+
}
|
|
15378
|
+
const margin = BLUR_RADIUS + UPSCALE;
|
|
15379
|
+
const startX = maxX < 0 ? width : Math.max(0, minX * UPSCALE - margin);
|
|
15380
|
+
const startY = maxY < 0 ? height : Math.max(0, minY * UPSCALE - margin);
|
|
15381
|
+
const endX = maxX < 0 ? -1 : Math.min(width - 1, (maxX + 1) * UPSCALE + margin);
|
|
15382
|
+
const endY = maxY < 0 ? -1 : Math.min(height - 1, (maxY + 1) * UPSCALE + margin);
|
|
15383
|
+
for(let y = startY; y <= endY; y++){
|
|
15384
|
+
const sourceY = (y + 0.5) / UPSCALE - 0.5;
|
|
15385
|
+
const sourceY0 = Math.floor(sourceY);
|
|
15386
|
+
const y0 = plane_visibility_mask_clamp(sourceY0, map.height - 1);
|
|
15387
|
+
const y1 = plane_visibility_mask_clamp(sourceY0 + 1, map.height - 1);
|
|
15388
|
+
const fy = sourceY - sourceY0;
|
|
15389
|
+
for(let x = startX; x <= endX; x++){
|
|
15390
|
+
const sourceX = (x + 0.5) / UPSCALE - 0.5;
|
|
15391
|
+
const sourceX0 = Math.floor(sourceX);
|
|
15392
|
+
const x0 = plane_visibility_mask_clamp(sourceX0, map.width - 1);
|
|
15393
|
+
const x1 = plane_visibility_mask_clamp(sourceX0 + 1, map.width - 1);
|
|
15394
|
+
const fx = sourceX - sourceX0;
|
|
15395
|
+
const top = (map.data[y0 * map.width + x0] === planeId ? 1 - fx : 0) + (map.data[y0 * map.width + x1] === planeId ? fx : 0);
|
|
15396
|
+
const bottom = (map.data[y1 * map.width + x0] === planeId ? 1 - fx : 0) + (map.data[y1 * map.width + x1] === planeId ? fx : 0);
|
|
15397
|
+
upscaled[y * width + x] = top * (1 - fy) + bottom * fy;
|
|
15398
|
+
}
|
|
15399
|
+
}
|
|
15400
|
+
for(let y = startY; y <= endY; y++)for(let x = startX; x <= endX; x++){
|
|
15401
|
+
let value1 = 0;
|
|
15402
|
+
for(let offset = -BLUR_RADIUS; offset <= BLUR_RADIUS; offset++)value1 += upscaled[y * width + plane_visibility_mask_clamp(x + offset, width - 1)] * plane_visibility_mask_kernel[offset + BLUR_RADIUS];
|
|
15403
|
+
horizontal[y * width + x] = value1;
|
|
15404
|
+
}
|
|
15405
|
+
for(let y = startY; y <= endY; y++)for(let x = startX; x <= endX; x++){
|
|
15406
|
+
let value1 = 0;
|
|
15407
|
+
for(let offset = -BLUR_RADIUS; offset <= BLUR_RADIUS; offset++)value1 += horizontal[plane_visibility_mask_clamp(y + offset, height - 1) * width + x] * plane_visibility_mask_kernel[offset + BLUR_RADIUS];
|
|
15408
|
+
data[y * width + x] = Math.round(255 * value1);
|
|
15409
|
+
}
|
|
15410
|
+
const texture = new DataTexture(data, width, height, RedFormat);
|
|
15411
|
+
texture.minFilter = LinearFilter;
|
|
15412
|
+
texture.magFilter = LinearFilter;
|
|
15413
|
+
texture.wrapS = ClampToEdgeWrapping;
|
|
15414
|
+
texture.wrapT = ClampToEdgeWrapping;
|
|
15415
|
+
texture.generateMipmaps = false;
|
|
15416
|
+
texture.unpackAlignment = 1;
|
|
15417
|
+
texture.needsUpdate = true;
|
|
15418
|
+
return {
|
|
15419
|
+
data,
|
|
15420
|
+
width,
|
|
15421
|
+
height,
|
|
15422
|
+
texture
|
|
15423
|
+
};
|
|
15424
|
+
}
|
|
15425
|
+
function samplePlaneVisibilityMask(mask, u, v) {
|
|
15426
|
+
if (u < 0 || u > 1 || v < 0 || v > 1) return 0;
|
|
15427
|
+
const x = u * mask.width - 0.5;
|
|
15428
|
+
const y = v * mask.height - 0.5;
|
|
15429
|
+
const sourceX0 = Math.floor(x);
|
|
15430
|
+
const sourceY0 = Math.floor(y);
|
|
15431
|
+
const x0 = plane_visibility_mask_clamp(sourceX0, mask.width - 1);
|
|
15432
|
+
const y0 = plane_visibility_mask_clamp(sourceY0, mask.height - 1);
|
|
15433
|
+
const x1 = plane_visibility_mask_clamp(sourceX0 + 1, mask.width - 1);
|
|
15434
|
+
const y1 = plane_visibility_mask_clamp(sourceY0 + 1, mask.height - 1);
|
|
15435
|
+
const fx = x - Math.floor(x);
|
|
15436
|
+
const fy = y - Math.floor(y);
|
|
15437
|
+
const top = mask.data[y0 * mask.width + x0] * (1 - fx) + mask.data[y0 * mask.width + x1] * fx;
|
|
15438
|
+
const bottom = mask.data[y1 * mask.width + x0] * (1 - fx) + mask.data[y1 * mask.width + x1] * fx;
|
|
15439
|
+
return (top * (1 - fy) + bottom * fy) / 255;
|
|
15440
|
+
}
|
|
15441
|
+
function planeVisibilityAlpha(value1) {
|
|
15442
|
+
const t = plane_visibility_mask_clamp((value1 - MASK_EDGE_START) / (MASK_EDGE_END - MASK_EDGE_START), 1);
|
|
15443
|
+
return t * t * (3 - 2 * t);
|
|
15444
|
+
}
|
|
15348
15445
|
new Set();
|
|
15349
15446
|
function warnOnce(key, message) {}
|
|
15350
15447
|
const RESOURCE_BASE_NORMAL = new Vector3(0, 0, 1);
|
|
@@ -15483,11 +15580,12 @@ function useRoomScenePlacement({ camera, invalidate, pointer, raycaster, roomId,
|
|
|
15483
15580
|
const placementKey = `${roomId}:${[
|
|
15484
15581
|
...surfaces
|
|
15485
15582
|
].sort().join(',')}`;
|
|
15486
|
-
const
|
|
15487
|
-
value:
|
|
15583
|
+
const activeMaskTextureUniform = (0, __rspack_external_react.useMemo)(()=>({
|
|
15584
|
+
value: null
|
|
15488
15585
|
}), []);
|
|
15489
15586
|
const [placementState, dispatchPlacementState] = (0, __rspack_external_react.useReducer)(reduceRoomScenePlacementState, placementKey, createInitialRoomScenePlacementState);
|
|
15490
15587
|
const activePlaneIdRef = (0, __rspack_external_react.useRef)(null);
|
|
15588
|
+
const planeMasksRef = (0, __rspack_external_react.useRef)(new Map());
|
|
15491
15589
|
const planeMapRef = (0, __rspack_external_react.useRef)(new Map());
|
|
15492
15590
|
const pointerDragOffsetRef = (0, __rspack_external_react.useRef)(null);
|
|
15493
15591
|
const isCurrentPlacementKey = placementState.placementKey === placementKey;
|
|
@@ -15520,7 +15618,16 @@ function useRoomScenePlacement({ camera, invalidate, pointer, raycaster, roomId,
|
|
|
15520
15618
|
placementKey
|
|
15521
15619
|
});
|
|
15522
15620
|
decodePlaneIdsDataPng(scene.planeIds.dataPng, scene.planeIds.width, scene.planeIds.height).then((map)=>{
|
|
15523
|
-
if (
|
|
15621
|
+
if (isCancelled) return;
|
|
15622
|
+
const masks = new Map();
|
|
15623
|
+
try {
|
|
15624
|
+
for (const plane of scene.planes)if (surfaces.includes(plane.kind) && plane.id > 0) masks.set(plane.id, createPlaneVisibilityMask(map, plane.id));
|
|
15625
|
+
} catch (error) {
|
|
15626
|
+
masks.forEach((mask)=>mask.texture.dispose());
|
|
15627
|
+
throw error;
|
|
15628
|
+
}
|
|
15629
|
+
planeMasksRef.current = masks;
|
|
15630
|
+
dispatchPlacementState({
|
|
15524
15631
|
type: 'set-plane-id-map',
|
|
15525
15632
|
placementKey,
|
|
15526
15633
|
planeIdMap: map
|
|
@@ -15534,10 +15641,16 @@ function useRoomScenePlacement({ camera, invalidate, pointer, raycaster, roomId,
|
|
|
15534
15641
|
});
|
|
15535
15642
|
return ()=>{
|
|
15536
15643
|
isCancelled = true;
|
|
15644
|
+
planeMasksRef.current.forEach((mask)=>mask.texture.dispose());
|
|
15645
|
+
planeMasksRef.current = new Map();
|
|
15646
|
+
activeMaskTextureUniform.value = null;
|
|
15537
15647
|
};
|
|
15538
15648
|
}, [
|
|
15649
|
+
activeMaskTextureUniform,
|
|
15539
15650
|
placementKey,
|
|
15540
|
-
scene.planeIds
|
|
15651
|
+
scene.planeIds,
|
|
15652
|
+
scene.planes,
|
|
15653
|
+
surfaces
|
|
15541
15654
|
]);
|
|
15542
15655
|
(0, __rspack_external_react.useEffect)(()=>{
|
|
15543
15656
|
dispatchPlacementState({
|
|
@@ -15545,17 +15658,17 @@ function useRoomScenePlacement({ camera, invalidate, pointer, raycaster, roomId,
|
|
|
15545
15658
|
placementKey
|
|
15546
15659
|
});
|
|
15547
15660
|
activePlaneIdRef.current = null;
|
|
15548
|
-
|
|
15661
|
+
activeMaskTextureUniform.value = null;
|
|
15549
15662
|
pointerDragOffsetRef.current = null;
|
|
15550
15663
|
}, [
|
|
15551
|
-
|
|
15664
|
+
activeMaskTextureUniform,
|
|
15552
15665
|
placementKey
|
|
15553
15666
|
]);
|
|
15554
15667
|
const updatePoseFromPlane = (0, __rspack_external_react.useCallback)((mesh, point, pointerDragOffset = null)=>{
|
|
15555
15668
|
const pointerPose = createPoseFromPlane(mesh, point, camera);
|
|
15556
15669
|
const pose = pointerDragOffset ? applyPointerDragOffset(pointerPose, pointerDragOffset) : pointerPose;
|
|
15557
15670
|
activePlaneIdRef.current = pose.activePlaneId;
|
|
15558
|
-
|
|
15671
|
+
activeMaskTextureUniform.value = planeMasksRef.current.get(pose.activePlaneId)?.texture ?? null;
|
|
15559
15672
|
dispatchPlacementState({
|
|
15560
15673
|
type: 'set-resource-pose',
|
|
15561
15674
|
placementKey,
|
|
@@ -15563,7 +15676,7 @@ function useRoomScenePlacement({ camera, invalidate, pointer, raycaster, roomId,
|
|
|
15563
15676
|
});
|
|
15564
15677
|
invalidate();
|
|
15565
15678
|
}, [
|
|
15566
|
-
|
|
15679
|
+
activeMaskTextureUniform,
|
|
15567
15680
|
camera,
|
|
15568
15681
|
invalidate,
|
|
15569
15682
|
placementKey
|
|
@@ -15594,7 +15707,7 @@ function useRoomScenePlacement({ camera, invalidate, pointer, raycaster, roomId,
|
|
|
15594
15707
|
});
|
|
15595
15708
|
if (!pose) return;
|
|
15596
15709
|
activePlaneIdRef.current = pose.activePlaneId;
|
|
15597
|
-
|
|
15710
|
+
activeMaskTextureUniform.value = planeMasksRef.current.get(pose.activePlaneId)?.texture ?? null;
|
|
15598
15711
|
dispatchPlacementState({
|
|
15599
15712
|
type: 'set-resource-pose',
|
|
15600
15713
|
placementKey,
|
|
@@ -15602,7 +15715,7 @@ function useRoomScenePlacement({ camera, invalidate, pointer, raycaster, roomId,
|
|
|
15602
15715
|
});
|
|
15603
15716
|
invalidate();
|
|
15604
15717
|
}, [
|
|
15605
|
-
|
|
15718
|
+
activeMaskTextureUniform,
|
|
15606
15719
|
allowedPlanes,
|
|
15607
15720
|
camera,
|
|
15608
15721
|
invalidate,
|
|
@@ -15636,19 +15749,14 @@ function useRoomScenePlacement({ camera, invalidate, pointer, raycaster, roomId,
|
|
|
15636
15749
|
pointerDragOffsetRef.current = null;
|
|
15637
15750
|
}, []);
|
|
15638
15751
|
const isPointVisible = (0, __rspack_external_react.useCallback)((point)=>{
|
|
15639
|
-
|
|
15752
|
+
const activePlaneId = activePlaneIdRef.current;
|
|
15753
|
+
const mask = null === activePlaneId ? null : planeMasksRef.current.get(activePlaneId);
|
|
15754
|
+
if (!mask) return false;
|
|
15640
15755
|
const projected = point.clone().project(camera);
|
|
15641
|
-
const
|
|
15642
|
-
|
|
15643
|
-
for(let dy = -2; dy <= 2; dy++)for(let dx = -2; dx <= 2; dx++){
|
|
15644
|
-
const px = Math.max(0, Math.min(planeIdMap.width - 1, x + dx));
|
|
15645
|
-
const py = Math.max(0, Math.min(planeIdMap.height - 1, y + dy));
|
|
15646
|
-
if (planeIdMap.data[py * planeIdMap.width + px] === activePlaneIdRef.current) return true;
|
|
15647
|
-
}
|
|
15648
|
-
return false;
|
|
15756
|
+
const value1 = samplePlaneVisibilityMask(mask, (projected.x + 1) * 0.5, (1 - projected.y) * 0.5);
|
|
15757
|
+
return planeVisibilityAlpha(value1) > MASK_DISCARD_ALPHA;
|
|
15649
15758
|
}, [
|
|
15650
|
-
camera
|
|
15651
|
-
planeIdMap
|
|
15759
|
+
camera
|
|
15652
15760
|
]);
|
|
15653
15761
|
const isPointerOnSurface = (0, __rspack_external_react.useCallback)((point)=>{
|
|
15654
15762
|
const id = planeIdMap ? findPlaneIdAtPointer(point, planeIdMap) : null;
|
|
@@ -15659,7 +15767,7 @@ function useRoomScenePlacement({ camera, invalidate, pointer, raycaster, roomId,
|
|
|
15659
15767
|
]);
|
|
15660
15768
|
return {
|
|
15661
15769
|
isPointerOnSurface,
|
|
15662
|
-
|
|
15770
|
+
activeMaskTextureUniform,
|
|
15663
15771
|
isPointVisible,
|
|
15664
15772
|
failure,
|
|
15665
15773
|
handleDrag,
|
|
@@ -15816,16 +15924,10 @@ function createRoomLightingTexture(planeIds, shading, neutral = 128) {
|
|
|
15816
15924
|
const CACHE_KEY = 'neurodyn-room-scene-v5';
|
|
15817
15925
|
const GLSL_DEFINE = 'NEURODYN_ROOM_SCENE_PATCH';
|
|
15818
15926
|
function patchShader(shader, patch, shading) {
|
|
15819
|
-
shader.uniforms.
|
|
15820
|
-
value: patch.planeIdsTexture
|
|
15821
|
-
};
|
|
15927
|
+
shader.uniforms.uMask = patch.activeMaskTextureUniform;
|
|
15822
15928
|
shader.uniforms.uRoomLighting = {
|
|
15823
15929
|
value: patch.lightingTexture
|
|
15824
15930
|
};
|
|
15825
|
-
shader.uniforms.uActiveId = patch.activePlaneIdUniform;
|
|
15826
|
-
shader.uniforms.uPlaneIdsSize = {
|
|
15827
|
-
value: patch.planeIdsSize
|
|
15828
|
-
};
|
|
15829
15931
|
shader.uniforms.uViewport = {
|
|
15830
15932
|
value: patch.viewport
|
|
15831
15933
|
};
|
|
@@ -15833,54 +15935,25 @@ function patchShader(shader, patch, shading) {
|
|
|
15833
15935
|
const inject = `
|
|
15834
15936
|
{
|
|
15835
15937
|
vec2 _neurodynRoomUv = gl_FragCoord.xy / uViewport;
|
|
15836
|
-
float
|
|
15938
|
+
float _neurodynRoomMask = texture2D(uMask, vec2(_neurodynRoomUv.x, 1.0 - _neurodynRoomUv.y)).r;
|
|
15939
|
+
float _neurodynRoomCoverage = smoothstep(${MASK_EDGE_START}, ${MASK_EDGE_END}, _neurodynRoomMask);
|
|
15837
15940
|
|
|
15838
|
-
if (_neurodynRoomCoverage <=
|
|
15941
|
+
if (_neurodynRoomCoverage <= ${MASK_DISCARD_ALPHA}) discard;
|
|
15839
15942
|
|
|
15840
15943
|
${shading ? `
|
|
15841
15944
|
float _neurodynRoomGain = min(texture2D(uRoomLighting, vec2(_neurodynRoomUv.x, 1.0 - _neurodynRoomUv.y)).r * (255.0 / 128.0), ${patch.maxRoomGain.toFixed(3)});
|
|
15842
15945
|
outgoingLight = (outgoingLight - ${emissive}) * _neurodynRoomGain + ${emissive};
|
|
15843
15946
|
` : ''}
|
|
15844
|
-
diffuseColor.a *=
|
|
15947
|
+
diffuseColor.a *= _neurodynRoomCoverage;
|
|
15845
15948
|
}
|
|
15846
15949
|
`;
|
|
15847
15950
|
const fragmentWithUniforms = shader.fragmentShader.replace('#include <common>', `
|
|
15848
15951
|
#include <common>
|
|
15849
15952
|
#ifndef ${GLSL_DEFINE}
|
|
15850
15953
|
#define ${GLSL_DEFINE}
|
|
15851
|
-
uniform sampler2D
|
|
15954
|
+
uniform sampler2D uMask;
|
|
15852
15955
|
uniform sampler2D uRoomLighting;
|
|
15853
|
-
uniform float uActiveId;
|
|
15854
|
-
uniform vec2 uPlaneIdsSize;
|
|
15855
15956
|
uniform vec2 uViewport;
|
|
15856
|
-
|
|
15857
|
-
float neurodynRoomScenePlaneMatch(vec2 uv) {
|
|
15858
|
-
float id = floor(texture2D(uPlaneIds, uv).r * 255.0 + 0.5);
|
|
15859
|
-
return 1.0 - step(0.5, abs(id - uActiveId));
|
|
15860
|
-
}
|
|
15861
|
-
|
|
15862
|
-
// uPlaneIds is a low-res nearest-filtered id map, so its edges are blocky.
|
|
15863
|
-
// A single-texel tent filter isn't wide enough to hide that — it just
|
|
15864
|
-
// softens each block's corner, which reads as a staircase. Supersample
|
|
15865
|
-
// a wider neighbourhood (5x5 taps, 2-texel radius) with Gaussian-like
|
|
15866
|
-
// falloff so the boundary is both denser-sampled and properly blurred.
|
|
15867
|
-
float neurodynRoomScenePlaneCoverage(vec2 uv) {
|
|
15868
|
-
vec2 texel = 1.0 / uPlaneIdsSize;
|
|
15869
|
-
float coverage = 0.0;
|
|
15870
|
-
float totalWeight = 0.0;
|
|
15871
|
-
|
|
15872
|
-
for (int y = -2; y <= 2; y++) {
|
|
15873
|
-
for (int x = -2; x <= 2; x++) {
|
|
15874
|
-
vec2 offset = vec2(float(x), float(y));
|
|
15875
|
-
float weight = 1.0 / (1.0 + dot(offset, offset));
|
|
15876
|
-
|
|
15877
|
-
coverage += neurodynRoomScenePlaneMatch(uv + offset * texel) * weight;
|
|
15878
|
-
totalWeight += weight;
|
|
15879
|
-
}
|
|
15880
|
-
}
|
|
15881
|
-
|
|
15882
|
-
return coverage / totalWeight;
|
|
15883
|
-
}
|
|
15884
15957
|
#endif
|
|
15885
15958
|
`);
|
|
15886
15959
|
if (fragmentWithUniforms.includes('#include <output_fragment>')) {
|
|
@@ -17151,10 +17224,6 @@ function Room() {
|
|
|
17151
17224
|
});
|
|
17152
17225
|
useFlooringRotation('rotate-on-floor' === resolveResourceProfile(type).manipulation, scenePlacement.isPointerOnSurface, room.id);
|
|
17153
17226
|
const viewport = (0, __rspack_external_react.useMemo)(()=>new Vector2(1, 1), []);
|
|
17154
|
-
const planeIdsSize = (0, __rspack_external_react.useMemo)(()=>new Vector2(scene.planeIds.width, scene.planeIds.height), [
|
|
17155
|
-
scene.planeIds.height,
|
|
17156
|
-
scene.planeIds.width
|
|
17157
|
-
]);
|
|
17158
17227
|
const lightingTexture = (0, __rspack_external_react.useMemo)(()=>createRoomLightingTexture(planeIdsTexture, shadingTexture, scene.shading?.neutral), [
|
|
17159
17228
|
planeIdsTexture,
|
|
17160
17229
|
shadingTexture,
|
|
@@ -17164,16 +17233,12 @@ function Room() {
|
|
|
17164
17233
|
lightingTexture
|
|
17165
17234
|
]);
|
|
17166
17235
|
const materialPatch = (0, __rspack_external_react.useMemo)(()=>({
|
|
17167
|
-
planeIdsTexture,
|
|
17168
17236
|
lightingTexture,
|
|
17169
|
-
planeIdsSize,
|
|
17170
17237
|
viewport,
|
|
17171
|
-
|
|
17238
|
+
activeMaskTextureUniform: scenePlacement.activeMaskTextureUniform,
|
|
17172
17239
|
maxRoomGain: MAX_ROOM_GAIN
|
|
17173
17240
|
}), [
|
|
17174
|
-
scenePlacement.
|
|
17175
|
-
planeIdsSize,
|
|
17176
|
-
planeIdsTexture,
|
|
17241
|
+
scenePlacement.activeMaskTextureUniform,
|
|
17177
17242
|
lightingTexture,
|
|
17178
17243
|
viewport
|
|
17179
17244
|
]);
|
|
@@ -17189,16 +17254,6 @@ function Room() {
|
|
|
17189
17254
|
invalidate,
|
|
17190
17255
|
scene.camera.fovYDeg
|
|
17191
17256
|
]);
|
|
17192
|
-
(0, __rspack_external_react.useLayoutEffect)(()=>{
|
|
17193
|
-
planeIdsTexture.minFilter = NearestFilter;
|
|
17194
|
-
planeIdsTexture.magFilter = NearestFilter;
|
|
17195
|
-
planeIdsTexture.wrapS = ClampToEdgeWrapping;
|
|
17196
|
-
planeIdsTexture.wrapT = ClampToEdgeWrapping;
|
|
17197
|
-
planeIdsTexture.generateMipmaps = false;
|
|
17198
|
-
planeIdsTexture.needsUpdate = true;
|
|
17199
|
-
}, [
|
|
17200
|
-
planeIdsTexture
|
|
17201
|
-
]);
|
|
17202
17257
|
(0, __rspack_external_react.useLayoutEffect)(()=>{
|
|
17203
17258
|
gl.getDrawingBufferSize(viewport);
|
|
17204
17259
|
viewport.set(Math.max(1, viewport.x), Math.max(1, viewport.y));
|