added box mateial wrapper

This commit is contained in:
2025-09-11 15:30:11 +05:30
parent f35daf3cf5
commit a9af598ade
16 changed files with 188 additions and 99 deletions

View File

@@ -1,18 +1,16 @@
import * as THREE from "three";
import * as Constants from "../../../types/world/worldConstants";
import { useRef, useState, useEffect, useMemo } from "react";
import { useState, useEffect, useMemo } from "react";
import { useSocketStore, useToolMode } from "../../../store/builder/store";
import { DragControls } from "@react-three/drei";
import { useThree } from "@react-three/fiber";
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
import { useSelectedPoints } from "../../../store/simulation/useSimulationStore";
import { usePointSnapping } from "./helpers/usePointSnapping";
import useShaderReader from "../../../utils/scene/useShaderReader";
import { useParams } from "react-router-dom";
import { useSceneContext } from "../../scene/sceneContext";
import vertexShaderUrl from "../../../assets/shaders/point/point.vert.glsl";
import fragmentShaderUrl from "../../../assets/shaders/point/point.frag.glsl";
import BoxMaterial from "../wrappers/materials/boxMaterial";
import { upsertAisleApi } from "../../../services/factoryBuilder/aisle/upsertAisleApi";
import { deleteAisleApi } from "../../../services/factoryBuilder/aisle/deleteAisleApi";
@@ -30,12 +28,10 @@ import { handleCanvasCursors } from "../../../utils/mouseUtils/handleCanvasCurso
import { calculateAssetTransformationOnWall } from "../wallAsset/Instances/Instance/functions/calculateAssetTransformationOnWall";
function Point({ point }: { readonly point: Point }) {
const materialRef = useRef<THREE.ShaderMaterial>(null);
const vertexShader = useShaderReader(vertexShaderUrl);
const fragmentShader = useShaderReader(fragmentShaderUrl);
const { raycaster, camera, pointer } = useThree();
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const [isHovered, setIsHovered] = useState(false);
const [isDeleteHovered, setIsDeleteHovered] = useState(false);
const [isSelected, setIsSelected] = useState(false);
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
const { socket } = useSocketStore();
@@ -105,35 +101,6 @@ function Point({ point }: { readonly point: Point }) {
}
}
useEffect(() => {
if (materialRef.current && (toolMode === "move" || toolMode === "2D-Delete")) {
let innerColor;
let outerColor;
if (isHovered) {
innerColor = toolMode === "2D-Delete" ? colors.defaultDeleteColor : colors.defaultOuterColor;
outerColor = toolMode === "2D-Delete" ? colors.defaultDeleteColor : colors.defaultOuterColor;
} else {
innerColor = colors.defaultInnerColor;
outerColor = colors.defaultOuterColor;
}
materialRef.current.uniforms.uInnerColor.value.set(innerColor);
materialRef.current.uniforms.uOuterColor.value.set(outerColor);
materialRef.current.uniformsNeedUpdate = true;
} else if (materialRef.current && toolMode !== "move") {
materialRef.current.uniforms.uInnerColor.value.set(colors.defaultInnerColor);
materialRef.current.uniforms.uOuterColor.value.set(colors.defaultOuterColor);
materialRef.current.uniformsNeedUpdate = true;
}
}, [isHovered, colors.defaultInnerColor, colors.defaultOuterColor, colors.defaultDeleteColor, toolMode]);
const uniforms = useMemo(
() => ({
uOuterColor: { value: new THREE.Color(colors.defaultOuterColor) },
uInnerColor: { value: new THREE.Color(colors.defaultInnerColor) },
}),
[colors.defaultInnerColor, colors.defaultOuterColor]
);
const handleDrag = (point: Point) => {
if (toolMode === "move" && isHovered && dragOffset) {
raycaster.setFromCamera(pointer, camera);
@@ -705,8 +672,6 @@ function Point({ point }: { readonly point: Point }) {
}
}, [selectedPoints]);
if (!point || !vertexShader || !fragmentShader) return null;
return (
<>
{!isSelected ? (
@@ -723,25 +688,36 @@ function Point({ point }: { readonly point: Point }) {
onPointerOver={(e) => {
if (!hoveredPoint && selectedPoints.length === 0 && e.buttons === 0 && !e.ctrlKey) {
setHoveredPoint(point);
setIsHovered(true);
if (toolMode === "move") {
setIsHovered(true);
handleCanvasCursors("grab");
} else if (toolMode === "2D-Delete") {
setIsDeleteHovered(true);
}
}
}}
onPointerOut={() => {
if (hoveredPoint) {
handleCanvasCursors("default");
setHoveredPoint(null);
if (!hoveredLine) {
handleCanvasCursors("default");
}
}
setIsHovered(false);
setIsDeleteHovered(false);
}}
userData={point}
>
<boxGeometry args={boxScale} />
<shaderMaterial ref={materialRef} uniforms={uniforms} vertexShader={vertexShader} fragmentShader={fragmentShader} />
<BoxMaterial
variant="box1"
uOuterColor={colors.defaultOuterColor}
uInnerColor={colors.defaultInnerColor}
uDeleteColor={colors.defaultDeleteColor}
isHovered={isHovered}
isDeleteHovered={isDeleteHovered}
/>
</mesh>
</DragControls>
) : (

View File

@@ -1,16 +1,9 @@
import * as THREE from "three";
import { useRef, useMemo } from "react";
import * as Constants from "../../../../types/world/worldConstants";
import useShaderReader from "../../../../utils/scene/useShaderReader";
import vertexShaderUrl from "../../../../assets/shaders/point/point.vert.glsl";
import fragmentShaderUrl from "../../../../assets/shaders/point/point.frag.glsl";
import BoxMaterial from "../../wrappers/materials/boxMaterial";
function ReferencePoint({ point }: { readonly point: Point }) {
const materialRef = useRef<THREE.ShaderMaterial>(null);
const vertexShader = useShaderReader(vertexShaderUrl);
const fragmentShader = useShaderReader(fragmentShaderUrl);
const boxScale: [number, number, number] = Constants.pointConfig.boxScale;
const colors = {
defaultInnerColor: Constants.pointConfig.defaultInnerColor,
@@ -18,14 +11,6 @@ function ReferencePoint({ point }: { readonly point: Point }) {
defaultDeleteColor: Constants.pointConfig.deleteColor,
};
const uniforms = useMemo(
() => ({
uOuterColor: { value: new THREE.Color(colors.defaultOuterColor) },
uInnerColor: { value: new THREE.Color(colors.defaultInnerColor) },
}),
[colors.defaultInnerColor, colors.defaultOuterColor, colors.defaultDeleteColor]
);
if (!point) {
return null;
}
@@ -41,12 +26,12 @@ function ReferencePoint({ point }: { readonly point: Point }) {
pointName = "Zone-Point";
}
if (!point || !vertexShader || !fragmentShader) return null;
if (!point) return null;
return (
<mesh position={new THREE.Vector3(...point.position)} name={pointName} uuid={point.pointUuid} userData={point}>
<boxGeometry args={boxScale} />
<shaderMaterial ref={materialRef} uniforms={uniforms} vertexShader={vertexShader} fragmentShader={fragmentShader} />
<BoxMaterial variant="box1" uOuterColor={colors.defaultOuterColor} uInnerColor={colors.defaultInnerColor} />
</mesh>
);
}

View File

@@ -0,0 +1,107 @@
import { useMemo } from "react";
import * as Constants from "../../../../types/world/worldConstants";
import { Color, DoubleSide, ShaderMaterial, MeshStandardMaterial } from "three";
import useShaderReader from "../../../../utils/scene/useShaderReader";
import edgeVertex from "../../../../assets/shaders/box/box1.vert.glsl";
import edgeFragment from "../../../../assets/shaders/box/box1.frag.glsl";
type BoxMaterialProps = {
color?: string;
transparent?: boolean;
depthWrite?: boolean;
depthTest?: boolean;
opacity?: number;
polygonOffset?: boolean;
polygonOffsetFactor?: number;
polygonOffsetUnits?: number;
variant?: "box1" | "none";
isHovered?: boolean;
} & (
| {
variant?: "none";
}
| {
variant: "box1";
uOuterColor?: string;
uInnerColor?: string;
uDeleteColor?: string;
isDeleteHovered?: boolean;
}
);
function BoxMaterial({
color = "white",
transparent = false,
depthWrite = true,
depthTest = true,
opacity = 1,
polygonOffset = false,
polygonOffsetFactor,
polygonOffsetUnits,
variant = "none",
isHovered = false,
...rest
}: Readonly<BoxMaterialProps>) {
const vertexShader = useShaderReader(edgeVertex);
const fragmentShader = useShaderReader(edgeFragment);
const box1Props = variant === "box1" ? (rest as { uOuterColor?: string; uInnerColor?: string; uDeleteColor: string; isDeleteHovered?: boolean }) : null;
const uOuterColor = box1Props?.uOuterColor ?? Constants.pointConfig.defaultOuterColor;
const uInnerColor = box1Props?.uInnerColor ?? Constants.pointConfig.defaultInnerColor;
const uDeleteColor = box1Props?.uDeleteColor ?? Constants.pointConfig.deleteColor;
const isDeleteHovered = box1Props?.isDeleteHovered ?? false;
const finalOuterColor = isDeleteHovered ? uDeleteColor : uOuterColor;
const finalInnerColor = isDeleteHovered ? uDeleteColor : isHovered ? uOuterColor : uInnerColor;
const finalColor = isDeleteHovered ? uDeleteColor : color;
const polygonOffsetProps = polygonOffset
? {
polygonOffsetFactor: polygonOffsetFactor ?? -1,
polygonOffsetUnits: polygonOffsetUnits ?? -1,
}
: {};
const basicMaterial = useMemo(() => {
if (variant !== "none") return null;
return new MeshStandardMaterial({
color: new Color(finalColor),
side: DoubleSide,
transparent,
depthWrite,
depthTest,
polygonOffset,
...polygonOffsetProps,
opacity,
});
}, [finalColor, transparent, depthWrite, depthTest, polygonOffset, polygonOffsetProps, opacity, variant]);
const boxMaterial1 = useMemo(() => {
if (!vertexShader || !fragmentShader || variant !== "box1") return null;
return new ShaderMaterial({
side: DoubleSide,
vertexShader,
fragmentShader,
uniforms: {
uOuterColor: { value: new Color(finalOuterColor) },
uInnerColor: { value: new Color(finalInnerColor) },
},
transparent,
depthWrite,
depthTest,
polygonOffset,
...polygonOffsetProps,
opacity,
});
}, [finalOuterColor, finalInnerColor, vertexShader, fragmentShader, transparent, depthWrite, depthTest, polygonOffset, polygonOffsetProps, opacity, variant]);
if (variant === "none" && basicMaterial) return <primitive object={basicMaterial} attach="material" />;
if (variant === "box1" && boxMaterial1) return <primitive object={boxMaterial1} attach="material" />;
return null;
}
export default BoxMaterial;

View File

@@ -4,18 +4,18 @@ import { useFrame } from "@react-three/fiber";
import { useSceneStore } from "../../../../store/scene/useSceneStore";
import useShaderReader from "../../../../utils/scene/useShaderReader";
import zone1Vertex from "../../../../assets/shaders/zone/zone1.vert.glsl";
import zone1Fragment from "../../../../assets/shaders/zone/zone1.frag.glsl";
import plane1Vertex from "../../../../assets/shaders/plane/plane1.vert.glsl";
import plane1Fragment from "../../../../assets/shaders/plane/plane1.frag.glsl";
import zone2Vertex from "../../../../assets/shaders/zone/zone2.vert.glsl";
import zone2Fragment from "../../../../assets/shaders/zone/zone2.frag.glsl";
import plane2Vertex from "../../../../assets/shaders/plane/plane2.vert.glsl";
import plane2Fragment from "../../../../assets/shaders/plane/plane2.frag.glsl";
import zone3Vertex from "../../../../assets/shaders/zone/zone3.vert.glsl";
import zone3Fragment from "../../../../assets/shaders/zone/zone3.frag.glsl";
import plane3Vertex from "../../../../assets/shaders/plane/plane3.vert.glsl";
import plane3Fragment from "../../../../assets/shaders/plane/plane3.frag.glsl";
type PlaneMaterialProps = {
color?: string;
variant?: "zone1" | "zone2" | "zone3";
variant?: "plane1" | "plane2" | "plane3";
transparent?: boolean;
opacity?: number;
depthWrite?: boolean;
@@ -27,11 +27,11 @@ type PlaneMaterialProps = {
function PlaneMaterial({
color = "white",
variant = "zone1",
variant = "plane1",
transparent = false,
opacity = 1,
depthWrite,
depthTest,
depthWrite = true,
depthTest = true,
polygonOffset = false,
polygonOffsetFactor,
polygonOffsetUnits,
@@ -39,13 +39,20 @@ function PlaneMaterial({
const { limitFps } = useSceneStore();
const materialRef = useRef<ShaderMaterial | null>(null);
const vertexShaderUrl = variant === "zone1" ? zone1Vertex : variant === "zone2" ? zone2Vertex : variant === "zone3" ? zone3Vertex : zone1Vertex;
const vertexShaderUrl = variant === "plane1" ? plane1Vertex : variant === "plane2" ? plane2Vertex : variant === "plane3" ? plane3Vertex : plane1Vertex;
const fragmentShaderUrl = variant === "zone1" ? zone1Fragment : variant === "zone2" ? zone2Fragment : variant === "zone3" ? zone3Fragment : zone1Fragment;
const fragmentShaderUrl = variant === "plane1" ? plane1Fragment : variant === "plane2" ? plane2Fragment : variant === "plane3" ? plane3Fragment : plane1Fragment;
const vertexShader = useShaderReader(vertexShaderUrl);
const fragmentShader = useShaderReader(fragmentShaderUrl);
const polygonOffsetProps = polygonOffset
? {
polygonOffsetFactor: polygonOffsetFactor ?? -1,
polygonOffsetUnits: polygonOffsetUnits ?? -1,
}
: {};
const material = useMemo(() => {
if (!vertexShader || !fragmentShader) return null;
@@ -62,8 +69,7 @@ function PlaneMaterial({
depthWrite,
depthTest,
polygonOffset,
polygonOffsetFactor,
polygonOffsetUnits,
...polygonOffsetProps,
});
}, [color, vertexShader, fragmentShader, transparent, opacity, depthWrite, depthTest, polygonOffset, polygonOffsetFactor, polygonOffsetUnits]);

View File

@@ -2,8 +2,8 @@ import { useMemo } from "react";
import { Color, DoubleSide, ShaderMaterial, Vector3, MeshStandardMaterial } from "three";
import useShaderReader from "../../../../utils/scene/useShaderReader";
import edgeVertex from "../../../../assets/shaders/edge/edge-fade.vert.glsl";
import edgeFragment from "../../../../assets/shaders/edge/edge-fade.frag.glsl";
import edgeVertex from "../../../../assets/shaders/polygon/edge-fade1.vert.glsl";
import edgeFragment from "../../../../assets/shaders/polygon/edge-fade1.frag.glsl";
type PolygonMaterialProps = {
points: { position: [number, number, number] }[];
@@ -15,26 +15,36 @@ type PolygonMaterialProps = {
polygonOffset?: boolean;
polygonOffsetFactor?: number;
polygonOffsetUnits?: number;
fadeDistance?: number;
variant?: "edge" | "none";
};
} & (
| {
variant?: "none";
}
| {
variant: "edge";
fadeDistance?: number;
}
);
function PolygonMaterial({
points,
color = "white",
transparent = false,
depthWrite,
depthTest,
depthWrite = true,
depthTest = true,
opacity = 1,
polygonOffset = false,
polygonOffsetFactor,
polygonOffsetUnits,
fadeDistance = 2.0,
variant = "none",
...rest
}: Readonly<PolygonMaterialProps>) {
const vertexShader = useShaderReader(edgeVertex);
const fragmentShader = useShaderReader(edgeFragment);
const edgeProps = variant === "edge" ? (rest as { fadeDistance?: number }) : null;
const fadeDistance = edgeProps?.fadeDistance ?? 2.0;
const edges = useMemo(() => {
return points.map((p, i) => {
const next = points[(i + 1) % points.length];
@@ -42,6 +52,27 @@ function PolygonMaterial({
});
}, [points]);
const polygonOffsetProps = polygonOffset
? {
polygonOffsetFactor: polygonOffsetFactor ?? -1,
polygonOffsetUnits: polygonOffsetUnits ?? -1,
}
: {};
const basicMaterial = useMemo(() => {
if (variant !== "none") return null;
return new MeshStandardMaterial({
color: new Color(color),
side: DoubleSide,
transparent,
depthWrite,
depthTest,
polygonOffset,
...polygonOffsetProps,
opacity,
});
}, [color, transparent, depthWrite, depthTest, polygonOffset, polygonOffsetProps, opacity, variant]);
const edgeMaterial = useMemo(() => {
if (!vertexShader || !fragmentShader || variant !== "edge") return null;
@@ -64,26 +95,10 @@ function PolygonMaterial({
depthWrite,
depthTest,
polygonOffset,
polygonOffsetFactor,
polygonOffsetUnits,
...polygonOffsetProps,
opacity,
});
}, [color, fadeDistance, vertexShader, fragmentShader, edges]);
const basicMaterial = useMemo(() => {
if (variant !== "none") return null;
return new MeshStandardMaterial({
color: new Color(color),
side: DoubleSide,
transparent,
depthWrite,
depthTest,
polygonOffset,
polygonOffsetFactor,
polygonOffsetUnits,
opacity,
});
}, [color]);
}, [color, fadeDistance, vertexShader, fragmentShader, edges, transparent, depthWrite, depthTest, polygonOffset, polygonOffsetProps, opacity, variant]);
if (variant === "none" && basicMaterial) return <primitive object={basicMaterial} attach="material" />;
if (variant === "edge" && edgeMaterial) return <primitive object={edgeMaterial} attach="material" />;

View File

@@ -40,10 +40,10 @@ function ZoneInstance({ zone }: { readonly zone: Zone }) {
<group key={index}>
<mesh position={midpoint} rotation={[0, -angle, 0]}>
<planeGeometry args={[planeWidth, planeHeight]} />
<PlaneMaterial transparent depthWrite={false} depthTest={true} color={zone.zoneColor} variant="zone1" />
<PlaneMaterial transparent depthWrite={false} depthTest={true} color={zone.zoneColor} variant="plane1" />
</mesh>
<ZoneCornerReference showTop showBottom point={point} prevPoint={prevPoint} nextPoint={nextPoint} zone={zone} cornerThickness={0.25} />
<ZoneCornerReference showTop={false} showBottom={false} point={point} prevPoint={prevPoint} nextPoint={nextPoint} zone={zone} cornerThickness={0.25} />
</group>
);
})}