From b0b71b3db5a3d484397db5cf75c19bc9088bea1c Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 16 Sep 2025 09:53:19 +0530 Subject: [PATCH] added dissolve material --- app/package-lock.json | 20 ++++ app/package.json | 1 + .../wrappers/materials/dissolveMaterial.tsx | 108 ++++++++++++++++++ .../instances/material/materialModel.tsx | 40 ++++--- app/src/types/world/worldTypes.d.ts | 21 +--- 5 files changed, 155 insertions(+), 35 deletions(-) create mode 100644 app/src/modules/builder/wrappers/materials/dissolveMaterial.tsx 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