diff --git a/app/package-lock.json b/app/package-lock.json
index a1bf231..cd88505 100644
--- a/app/package-lock.json
+++ b/app/package-lock.json
@@ -48,6 +48,7 @@
"sass": "^1.78.0",
"socket.io-client": "^4.8.1",
"three": "^0.168.0",
+ "three-custom-shader-material": "^6.3.7",
"three-viewport-gizmo": "^2.2.0",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4",
@@ -20675,6 +20676,25 @@
"three-mesh-bvh": ">=0.6.6"
}
},
+ "node_modules/three-custom-shader-material": {
+ "version": "6.3.7",
+ "resolved": "https://registry.npmjs.org/three-custom-shader-material/-/three-custom-shader-material-6.3.7.tgz",
+ "integrity": "sha512-u+REZFLqjCTFgKrBu9nFomwcmLwGkuz//Hk8NezXBnC1rVb+0knyxsoFisoltQRJLg4CoB0pJda9iYItlX4IuQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@react-three/fiber": ">=8.0",
+ "react": ">=18.0",
+ "three": ">=0.159"
+ },
+ "peerDependenciesMeta": {
+ "@react-three/fiber": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/three-mesh-bvh": {
"version": "0.6.8",
"resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.6.8.tgz",
diff --git a/app/package.json b/app/package.json
index aec1d38..9cee022 100644
--- a/app/package.json
+++ b/app/package.json
@@ -43,6 +43,7 @@
"sass": "^1.78.0",
"socket.io-client": "^4.8.1",
"three": "^0.168.0",
+ "three-custom-shader-material": "^6.3.7",
"three-viewport-gizmo": "^2.2.0",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4",
diff --git a/app/src/modules/builder/wrappers/materials/dissolveMaterial.tsx b/app/src/modules/builder/wrappers/materials/dissolveMaterial.tsx
new file mode 100644
index 0000000..957f045
--- /dev/null
+++ b/app/src/modules/builder/wrappers/materials/dissolveMaterial.tsx
@@ -0,0 +1,108 @@
+import * as React from "react";
+import * as THREE from "three";
+import { easing } from "maath";
+import { useFrame } from "@react-three/fiber";
+import CSM from "three-custom-shader-material";
+
+const vertexShader = `
+ varying vec2 vUv;
+ varying vec3 vPosition;
+ void main() {
+ vUv = uv;
+ vPosition = position;
+ }
+`;
+
+const fragmentShader = `
+ varying vec2 vUv;
+ varying vec3 vPosition;
+ uniform float uThickness;
+ uniform vec3 uColor;
+ uniform float uProgress;
+
+ float hash(vec3 p) {
+ p = fract(p * 0.3183099 + 0.1);
+ p *= 17.0;
+ return fract(p.x * p.y * p.z * (p.x + p.y + p.z));
+ }
+
+ float noise(vec3 x) {
+ vec3 i = floor(x);
+ vec3 f = fract(x);
+ f = f * f * (3.0 - 2.0 * f);
+
+ return mix(
+ mix(mix(hash(i + vec3(0,0,0)), hash(i + vec3(1,0,0)), f.x),
+ mix(hash(i + vec3(0,1,0)), hash(i + vec3(1,1,0)), f.x), f.y),
+ mix(mix(hash(i + vec3(0,0,1)), hash(i + vec3(1,0,1)), f.x),
+ mix(hash(i + vec3(0,1,1)), hash(i + vec3(1,1,1)), f.x), f.y), f.z);
+ }
+
+ void main() {
+ float noiseValue = noise(vPosition * 10.0);
+ float progress = uProgress;
+
+ float visualFade = 1.0 - smoothstep(0.9, 1.0, progress);
+
+ float dissolveProgress = 1.0 - progress;
+
+ float alpha = step(noiseValue, dissolveProgress);
+
+ float border = step(noiseValue, dissolveProgress + uThickness) - alpha;
+ border *= step(0.0, dissolveProgress);
+
+ alpha *= visualFade;
+ border *= visualFade;
+
+ csm_DiffuseColor.rgb = border > 0.0 ? uColor : csm_DiffuseColor.rgb;
+ csm_DiffuseColor.a = alpha + border;
+
+ if (progress >= 1.0) {
+ csm_DiffuseColor.a = 0.0;
+ }
+ }
+`;
+
+interface DissolveMaterialProps {
+ baseMaterial: THREE.ShaderMaterial | THREE.MeshStandardMaterial | THREE.MeshPhysicalMaterial;
+ thickness?: number;
+ color?: string;
+ intensity?: number;
+ duration?: number;
+ fade?: boolean;
+ fadedIn?: () => void;
+ fadedOut?: () => void;
+}
+
+export function DissolveMaterial({ baseMaterial, thickness = 0.1, color = "#0082b2", intensity = 50, duration = 1.2, fade = true, fadedIn, fadedOut }: DissolveMaterialProps) {
+ const uniforms = React.useRef({
+ uThickness: { value: thickness },
+ uColor: { value: new THREE.Color(color).multiplyScalar(intensity) },
+ uProgress: { value: fade ? 1 : 0 },
+ });
+
+ const hasFadedIn = React.useRef(false);
+ const hasFadedOut = React.useRef(false);
+
+ useFrame((_state, delta) => {
+ easing.damp(uniforms.current.uProgress, "value", fade ? 0 : 1, duration, delta);
+
+ const p = uniforms.current.uProgress.value;
+
+ if (p <= 0.01) {
+ if (!hasFadedIn.current) {
+ fadedIn?.();
+ hasFadedIn.current = true;
+ hasFadedOut.current = false;
+ }
+ } else if (p >= 0.99) {
+ if (!hasFadedOut.current) {
+ fadedOut?.();
+ hasFadedOut.current = true;
+ hasFadedIn.current = false;
+ }
+ }
+ });
+
+ return ;
+}
diff --git a/app/src/modules/simulation/materials/instances/material/materialModel.tsx b/app/src/modules/simulation/materials/instances/material/materialModel.tsx
index 5ffb486..a0738c2 100644
--- a/app/src/modules/simulation/materials/instances/material/materialModel.tsx
+++ b/app/src/modules/simulation/materials/instances/material/materialModel.tsx
@@ -1,44 +1,46 @@
-import { useGLTF } from '@react-three/drei'
-import { useMemo } from 'react';
-import * as THREE from 'three';
+import { useGLTF } from "@react-three/drei";
+import { useMemo } from "react";
+import * as THREE from "three";
-import defaultMaterial from '../../../../../assets/gltf-glb/materials/default.glb';
-import material1 from '../../../../../assets/gltf-glb/materials/material1.glb';
-import material2 from '../../../../../assets/gltf-glb/materials/material2.glb';
-import material3 from '../../../../../assets/gltf-glb/materials/material3.glb';
+import defaultMaterial from "../../../../../assets/gltf-glb/materials/default.glb";
+import material1 from "../../../../../assets/gltf-glb/materials/material1.glb";
+import material2 from "../../../../../assets/gltf-glb/materials/material2.glb";
+import material3 from "../../../../../assets/gltf-glb/materials/material3.glb";
+// import { DissolveMaterial } from "../../../../builder/wrappers/materials/dissolveMaterial";
const modelPaths: Record = {
- 'Default material': defaultMaterial,
- 'Material 1': material1,
- 'Material 2': material2,
- 'Material 3': material3,
+ "Default material": defaultMaterial,
+ "Material 1": material1,
+ "Material 2": material2,
+ "Material 3": material3,
};
type ModelType = keyof typeof modelPaths;
-interface ModelProps extends React.ComponentProps<'group'> {
+interface ModelProps extends React.ComponentProps<"group"> {
materialId: string;
materialType: ModelType;
- matRef: React.Ref>
+ matRef: React.Ref>;
}
export function MaterialModel({ materialId, materialType, matRef, ...props }: Readonly) {
- const path = modelPaths[materialType] || modelPaths['Default material'];
+ const path = modelPaths[materialType] || modelPaths["Default material"];
const gltf = useGLTF(path);
const cloned = useMemo(() => gltf?.scene.clone(), [gltf]);
+ // const mat = useMemo(() => (gltf?.scene.clone().children[0] as THREE.Mesh).material as THREE.MeshStandardMaterial, [gltf]);
if (!cloned) return null;
return (
-
+
+ {/*
+
+ */}
);
}
Object.values(modelPaths).forEach((path) => {
useGLTF.preload(path);
-});
\ No newline at end of file
+});
diff --git a/app/src/types/world/worldTypes.d.ts b/app/src/types/world/worldTypes.d.ts
index 6b4552b..19aab08 100644
--- a/app/src/types/world/worldTypes.d.ts
+++ b/app/src/types/world/worldTypes.d.ts
@@ -6,8 +6,6 @@ import { DragControls } from "three/examples/jsm/controls/DragControls";
import { IntersectionEvent } from "@react-three/fiber/dist/declarations/src/core/events";
import { ThreeEvent } from "@react-three/fiber/dist/declarations/src/core/events";
import { RootState } from "@react-three/fiber";
-import { CSM } from "three/examples/jsm/csm/CSM";
-import { CSMHelper } from "three/examples/jsm/csm/CSMHelper";
import { CameraControls } from "@react-three/drei";
/** Core THREE.js and React-Fiber Event Types **/
@@ -129,13 +127,7 @@ export type Lines = Array;
/** Wall and Room Types for 3D Space Management **/
// Defines a wall with its geometry, position, rotation, material, and layer information
-export type Wall = [
- THREE.ExtrudeGeometry,
- [number, number, number],
- [number, number, number],
- string,
- number
-];
+export type Wall = [THREE.ExtrudeGeometry, [number, number, number], [number, number, number], string, number];
// Collection of walls, useful in scene construction
export type Walls = Array;
@@ -144,10 +136,10 @@ export type Walls = Array;
export type RefWalls = React.MutableRefObject;
// Room type, containing coordinates and layer metadata for spatial management
-export type Rooms = Array<{ coordinates: Array<{ position: THREE.Vector3; uuid: string }>; layer: number; }>;
+export type Rooms = Array<{ coordinates: Array<{ position: THREE.Vector3; uuid: string }>; layer: number }>;
// Reference for room objects, enabling updates within React components
-export type RefRooms = React.MutableRefObject; layer: number; }>>;
+export type RefRooms = React.MutableRefObject; layer: number }>>;
// Reference for lines, supporting React-based state changes
export type RefLines = React.MutableRefObject;
@@ -203,13 +195,13 @@ export type FloorItemType = {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
- }
+ };
points?: {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
}[];
- }
+ };
};
// Array of floor items for managing multiple objects on the floor
@@ -256,6 +248,3 @@ export type setRemoveLayerSetState = (layer: number | null) => void;
export type setSelectedWallItemSetState = (item: THREE.Object3D | null) => void;
export type setSelectedFloorItemSetState = (item: THREE.Object3D | null) => void;
export type setSelectedItemsIndexSetState = (index: number | null) => void;
-
-export type RefCSM = React.MutableRefObject;
-export type RefCSMHelper = React.MutableRefObject;
\ No newline at end of file