added dissolve material

This commit is contained in:
2025-09-16 09:53:19 +05:30
parent f9311ee296
commit b0b71b3db5
5 changed files with 155 additions and 35 deletions

20
app/package-lock.json generated
View File

@@ -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",

View File

@@ -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",

View File

@@ -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 <CSM baseMaterial={baseMaterial} vertexShader={vertexShader} fragmentShader={fragmentShader} uniforms={uniforms.current} toneMapped={false} transparent />;
}

View File

@@ -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<string, string> = {
'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<THREE.Group<THREE.Object3DEventMap>>
matRef: React.Ref<THREE.Group<THREE.Object3DEventMap>>;
}
export function MaterialModel({ materialId, materialType, matRef, ...props }: Readonly<ModelProps>) {
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 (
<group uuid={materialId} ref={matRef} {...props} dispose={null}>
<primitive
object={cloned}
scale={[0.4, 0.4, 0.4]}
/>
<primitive object={cloned} scale={[0.4, 0.4, 0.4]} />
{/* <mesh scale={[0.2, 0.2, 0.2]} geometry={(cloned.children[0] as THREE.Mesh).geometry}>
<DissolveMaterial baseMaterial={mat.clone()} color="blue"/>
</mesh> */}
</group>
);
}
Object.values(modelPaths).forEach((path) => {
useGLTF.preload(path);
});
});

View File

@@ -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<Line>;
/** 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<Wall>;
@@ -144,10 +136,10 @@ export type Walls = Array<Wall>;
export type RefWalls = React.MutableRefObject<Walls>;
// 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<Array<{ coordinates: Array<{ position: THREE.Vector3; uuid: string }>; layer: number; }>>;
export type RefRooms = React.MutableRefObject<Array<{ coordinates: Array<{ position: THREE.Vector3; uuid: string }>; layer: number }>>;
// Reference for lines, supporting React-based state changes
export type RefLines = React.MutableRefObject<Lines>;
@@ -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<CSM>;
export type RefCSMHelper = React.MutableRefObject<CSMHelper>;