made a wrapper for extrude polygons for code optimization

This commit is contained in:
2025-09-11 14:33:41 +05:30
parent 6091031b9d
commit f35daf3cf5
10 changed files with 258 additions and 219 deletions

View File

@@ -1,9 +1,10 @@
import { useMemo } from "react";
import { DoubleSide, Shape, Vector2 } from "three";
import { Extrude, Html } from "@react-three/drei";
import { DoubleSide, Vector2 } from "three";
import { Html } from "@react-three/drei";
import * as Constants from "../../../../../types/world/worldConstants";
import getCenteroidPoint from "../../../functions/getCenteroid";
import getArea from "../../../functions/getArea";
import ExtrudePolygon from "../../../wrappers/geomentry/extrudePolygon";
function Floor2DInstance({ floor }: { readonly floor: Floor }) {
const savedTheme: string | null = localStorage.getItem("theme");
@@ -12,16 +13,6 @@ function Floor2DInstance({ floor }: { readonly floor: Floor }) {
return floor.points.map((p) => new Vector2(parseFloat(p.position[0].toFixed(2)), parseFloat(p.position[2].toFixed(2))));
}, [floor]);
const shape = useMemo(() => {
const shape = new Shape();
shape.moveTo(points2D[0].x, points2D[0].y);
for (let i = 1; i < points2D.length; i++) {
shape.lineTo(points2D[i].x, points2D[i].y);
}
shape.lineTo(points2D[0].x, points2D[0].y);
return shape;
}, [points2D]);
const area = useMemo(() => getArea(points2D), [points2D]);
const centroid: [number, number, number] = useMemo(() => {
@@ -31,23 +22,13 @@ function Floor2DInstance({ floor }: { readonly floor: Floor }) {
return [center.x, Constants.floorConfig.height + 0.01, center.y] as [number, number, number];
}, [points2D]);
if (!shape) return null;
const formattedArea = `${area.toFixed(2)}`;
return (
<>
<mesh castShadow receiveShadow name={`Floor-2D-${floor.floorUuid}`} rotation={[Math.PI / 2, 0, 0]} position={[0, 0, 0]} userData={floor}>
<Extrude name={`Floor-${floor.floorUuid}`} args={[shape, { depth: Constants.floorConfig.height }]} userData={floor}>
<meshBasicMaterial
color={savedTheme === "dark" ? Constants.lineConfig.floorColor : Constants.lineConfig.floorColor}
side={DoubleSide}
transparent
opacity={0.4}
depthWrite={false}
/>
</Extrude>
</mesh>
<ExtrudePolygon castShadow receiveShadow name={`Floor-2D-${floor.floorUuid}`} points={floor.points} options={{ depth: 0, bevelEnabled: false }} userData={floor}>
<meshBasicMaterial color={savedTheme === "dark" ? Constants.lineConfig.floorColor : Constants.lineConfig.floorColor} side={DoubleSide} transparent opacity={0.4} depthWrite={false} />
</ExtrudePolygon>
<Html key={floor.floorUuid} position={centroid} wrapperClass="distance-text-wrapper" className="distance-text" zIndexRange={[1, 0]} prepend center sprite>
<div className="distance area">

View File

@@ -1,5 +1,4 @@
import { useMemo } from "react";
import { Shape, Vector2, DoubleSide, TextureLoader, RepeatWrapping, SRGBColorSpace, NoColorSpace, ExtrudeGeometry } from "three";
import { DoubleSide, TextureLoader, RepeatWrapping, SRGBColorSpace, NoColorSpace } from "three";
import { useLoader } from "@react-three/fiber";
import useModuleStore from "../../../../../store/ui/useModuleStore";
import { useBuilderStore } from "../../../../../store/builder/useBuilderStore";
@@ -27,6 +26,7 @@ import material4Map from "../../../../../assets/textures/floor/tex3/metal_plate_
import material4RoughnessMap from "../../../../../assets/textures/floor/tex3/metal_plate_rough_1k.png";
import material4MetalicMap from "../../../../../assets/textures/floor/tex3/metal_plate_metal_1k.png";
import material4NormalMap from "../../../../../assets/textures/floor/tex3/metal_plate_nor_gl_1k.png";
import ExtrudePolygon from "../../../wrappers/geomentry/extrudePolygon";
function FloorInstance({ floor }: { readonly floor: Floor }) {
const { toggleView } = useToggleView();
@@ -68,24 +68,6 @@ function FloorInstance({ floor }: { readonly floor: Floor }) {
},
};
const shapeData = useMemo(() => {
const points = floor.points.map((p) => new Vector2(p.position[0], p.position[2]));
if (points.length < 3) return null;
const centroidX = points.reduce((sum, p) => sum + p.x, 0) / points.length;
const centroidY = points.reduce((sum, p) => sum + p.y, 0) / points.length;
const relativePoints = points.map((p) => new Vector2(p.x - centroidX, p.y - centroidY));
const shape = new Shape();
shape.moveTo(relativePoints[0].x, relativePoints[0].y);
for (let i = 1; i < relativePoints.length; i++) {
shape.lineTo(relativePoints[i].x, relativePoints[i].y);
}
return { shape, center: [centroidX, centroidY] };
}, [floor]);
const textureScale = Constants.floorConfig.textureScale;
function getMaterialMaps(material: any, defaultMap: any) {
@@ -132,28 +114,23 @@ function FloorInstance({ floor }: { readonly floor: Floor }) {
});
});
const geometry = useMemo(() => {
if (!shapeData) return null;
return new ExtrudeGeometry(shapeData.shape, {
depth: !floor.isBeveled ? floor.floorDepth : floor.floorDepth - 0.1,
bevelEnabled: floor.isBeveled,
bevelSegments: floor.bevelStrength,
bevelOffset: -0.1,
bevelSize: 0.1,
bevelThickness: 0.1,
});
}, [shapeData, floor]);
if (!geometry) return null;
const extrudeOptions = {
depth: !floor.isBeveled ? floor.floorDepth : floor.floorDepth - 0.1,
bevelEnabled: floor.isBeveled,
bevelSegments: floor.bevelStrength,
bevelOffset: -0.1,
bevelSize: 0.1,
bevelThickness: 0.1,
};
return (
<mesh
<ExtrudePolygon
castShadow
receiveShadow
geometry={geometry}
points={floor.points}
options={extrudeOptions}
name={`Floor-${floor.floorUuid}`}
rotation={[Math.PI / 2, 0, 0]}
position={[shapeData?.center[0] ?? 0, !floor.isBeveled ? floor.floorDepth - 0.1 : floor.floorDepth - 0.2, shapeData?.center[1] ?? 0]}
position={[0, !floor.isBeveled ? floor.floorDepth - 0.1 : floor.floorDepth - 0.2, 0]}
userData={floor}
onDoubleClick={(e) => {
if (!toggleView && activeModule === "builder") {
@@ -170,7 +147,7 @@ function FloorInstance({ floor }: { readonly floor: Floor }) {
}
}}
>
<meshPhysicalMaterial
<meshStandardMaterial
attach="material-0"
color={Constants.floorConfig.defaultColor}
map={topTexture}
@@ -196,7 +173,7 @@ function FloorInstance({ floor }: { readonly floor: Floor }) {
{floor.decals.map((decal) => (
<DecalInstance parent={floor} key={decal.decalUuid} decal={decal} />
))}
</mesh>
</ExtrudePolygon>
);
}

View File

@@ -1,19 +1,19 @@
import * as THREE from 'three';
import { Base } from '@react-three/csg';
import { useMemo, useRef, useState } from 'react';
import { MeshDiscardMaterial } from '@react-three/drei';
import { useFrame, useThree } from '@react-three/fiber';
import useModuleStore from '../../../../../store/ui/useModuleStore';
import { useSceneContext } from '../../../../scene/sceneContext';
import { useWallClassification } from './helpers/useWallClassification';
import { useToggleView, useWallVisibility } from '../../../../../store/builder/store';
import { useBuilderStore } from '../../../../../store/builder/useBuilderStore';
import * as Constants from '../../../../../types/world/worldConstants';
import * as THREE from "three";
import { Base } from "@react-three/csg";
import { useMemo, useRef, useState } from "react";
import { MeshDiscardMaterial } from "@react-three/drei";
import { useFrame, useThree } from "@react-three/fiber";
import useModuleStore from "../../../../../store/ui/useModuleStore";
import { useSceneContext } from "../../../../scene/sceneContext";
import { useWallClassification } from "./helpers/useWallClassification";
import { useToggleView, useWallVisibility } from "../../../../../store/builder/store";
import { useBuilderStore } from "../../../../../store/builder/useBuilderStore";
import * as Constants from "../../../../../types/world/worldConstants";
import DecalInstance from '../../../Decal/decalInstance/decalInstance';
import DecalInstance from "../../../Decal/decalInstance/decalInstance";
import defaultMaterial from '../../../../../assets/textures/floor/wall-tex.png';
import material1 from '../../../../../assets/textures/floor/factory wall texture.jpg';
import defaultMaterial from "../../../../../assets/textures/floor/wall-tex.png";
import material1 from "../../../../../assets/textures/floor/factory wall texture.jpg";
function Wall({ wall }: { readonly wall: Wall }) {
const { wallStore, wallAssetStore } = useSceneContext();
@@ -66,19 +66,19 @@ function Wall({ wall }: { readonly wall: Wall }) {
const materials = useMemo(() => {
return [
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide, visible: visible, clipShadows: true }), // Left
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide, visible: visible, clipShadows: true }), // Right
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide, visible: visible, clipShadows: true }), // Top
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide, visible: visible, clipShadows: true }), // Bottom
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide, visible: visible, clipShadows: true }), // Left
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide, visible: visible, clipShadows: true }), // Right
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide, visible: visible, clipShadows: true }), // Top
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide, visible: visible, clipShadows: true }), // Bottom
new THREE.MeshStandardMaterial({
color: Constants.wallConfig.defaultColor,
side: THREE.DoubleSide,
map: wall.insideMaterial === 'Default Material' ? defaultWallTexture : material1WallTexture,
map: wall.insideMaterial === "Default Material" ? defaultWallTexture : material1WallTexture,
}),
new THREE.MeshStandardMaterial({
color: Constants.wallConfig.defaultColor,
side: THREE.DoubleSide,
map: wall.outsideMaterial === 'Default Material' ? defaultWallTexture : material1WallTexture,
map: wall.outsideMaterial === "Default Material" ? defaultWallTexture : material1WallTexture,
}),
];
}, [defaultWallTexture, material1WallTexture, wall, visible]);
@@ -96,7 +96,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
meshRef.current.getWorldDirection(v);
camera.getWorldDirection(u);
if (!u || !v) return;
nextVisible = (2 * v.dot(u)) <= 0.1;
nextVisible = 2 * v.dot(u) <= 0.1;
}
if (prevVisibleRef.current !== nextVisible) {
@@ -104,19 +104,13 @@ function Wall({ wall }: { readonly wall: Wall }) {
setVisible(nextVisible);
assets.forEach((asset) => {
setVisibility(asset.modelUuid, nextVisible);
})
});
}
});
return (
<mesh
castShadow
receiveShadow
name={`Wall-${wall.wallUuid}`}
key={wall.wallUuid}
userData={wall}
>
{(assets.length > 0 || (walls[0].wallUuid === wall.wallUuid && wallAssets.length > 0)) ?
<mesh castShadow receiveShadow name={`Wall-${wall.wallUuid}`} key={wall.wallUuid} userData={wall}>
{assets.length > 0 || (walls[0].wallUuid === wall.wallUuid && wallAssets.length > 0) ? (
<Base
name={`BaseWall${wall.wallUuid}`}
castShadow
@@ -131,21 +125,13 @@ function Wall({ wall }: { readonly wall: Wall }) {
<primitive key={index} visible={visible} object={material} attach={`material-${index}`} />
))}
</Base>
:
<mesh
castShadow
receiveShadow
ref={meshRef}
geometry={geometry}
position={[centerX, centerY, centerZ]}
rotation={[0, -angle, 0]}
userData={wall}
>
) : (
<mesh castShadow receiveShadow ref={meshRef} geometry={geometry} position={[centerX, centerY, centerZ]} rotation={[0, -angle, 0]} userData={wall}>
{materials.map((material, index) => (
<primitive key={index} visible={visible} object={material} attach={`material-${index}`} />
))}
</mesh>
}
)}
<mesh
castShadow
receiveShadow
@@ -155,7 +141,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
userData={wall}
name={`WallReference_${wall.wallUuid}`}
onDoubleClick={(e) => {
if (visible && !toggleView && activeModule === 'builder') {
if (visible && !toggleView && activeModule === "builder") {
if (e.object.userData.wallUuid) {
e.stopPropagation();
setSelectedWall(e.object);
@@ -179,4 +165,4 @@ function Wall({ wall }: { readonly wall: Wall }) {
);
}
export default Wall;
export default Wall;

View File

@@ -1,6 +1,6 @@
import React, { useEffect, useMemo } from "react";
import { DoubleSide, RepeatWrapping, Shape, SRGBColorSpace, TextureLoader, Vector2, Vector3 } from "three";
import { Html, Extrude } from "@react-three/drei";
import { DoubleSide, RepeatWrapping, SRGBColorSpace, TextureLoader, Vector2, Vector3 } from "three";
import { Html } from "@react-three/drei";
import { useLoader } from "@react-three/fiber";
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
import { useSceneContext } from "../../../scene/sceneContext";
@@ -16,6 +16,7 @@ import texturePathDark from "../../../../assets/textures/floor/black.png";
import useModuleStore from "../../../../store/ui/useModuleStore";
import getCenteroidPoint from "../../functions/getCenteroid";
import getArea from "../../functions/getArea";
import ExtrudePolygon from "../../wrappers/geomentry/extrudePolygon";
function WallInstances() {
const { wallStore } = useSceneContext();
@@ -135,25 +136,10 @@ function Floor3D({ room }: { readonly room: Point[] }) {
floorTexture.repeat.set(textureScale, textureScale);
floorTexture.colorSpace = SRGBColorSpace;
const shape = useMemo(() => {
const shape = new Shape();
const points = room.map((p) => new Vector2(p.position[0], p.position[2]));
if (points.length < 3) return null;
shape.moveTo(points[0].x, points[0].y);
points.forEach((pt) => {
shape.lineTo(pt.x, pt.y);
});
return shape;
}, [room]);
if (!shape) return null;
return (
<mesh name="Wall-Floor" rotation={[Math.PI / 2, 0, 0]}>
<Extrude receiveShadow castShadow name="Wall-Floor" args={[shape, { depth: Constants.floorConfig.height, bevelEnabled: false }]} position={[0, 0, 0]}>
<meshStandardMaterial color={Constants.floorConfig.defaultColor} map={floorTexture} side={DoubleSide} />
</Extrude>
</mesh>
<ExtrudePolygon points={room} receiveShadow castShadow name="Wall-Floor" options={{ depth: Constants.floorConfig.height, bevelEnabled: false }}>
<meshStandardMaterial color={Constants.floorConfig.defaultColor} map={floorTexture} side={DoubleSide} />
</ExtrudePolygon>
);
}
@@ -164,16 +150,6 @@ function Floor2D({ room }: { readonly room: Point[] }) {
return room.map((p) => new Vector2(parseFloat(p.position[0].toFixed(2)), parseFloat(p.position[2].toFixed(2))));
}, [room]);
const shape = useMemo(() => {
const shape = new Shape();
shape.moveTo(points2D[0].x, points2D[0].y);
for (let i = 1; i < points2D.length; i++) {
shape.lineTo(points2D[i].x, points2D[i].y);
}
shape.lineTo(points2D[0].x, points2D[0].y);
return shape;
}, [points2D]);
const area = useMemo(() => getArea(points2D), [points2D]);
const centroid: [number, number, number] = useMemo(() => {
@@ -183,17 +159,13 @@ function Floor2D({ room }: { readonly room: Point[] }) {
return [center.x, Constants.floorConfig.height + 0.01, center.y] as [number, number, number];
}, [points2D]);
if (!shape) return null;
const formattedArea = `${area.toFixed(2)}`;
return (
<>
<mesh castShadow receiveShadow name="Wall-Floor" rotation={[Math.PI / 2, 0, 0]}>
<Extrude receiveShadow castShadow name="Wall-Floor" args={[shape, { depth: Constants.floorConfig.height }]} position={[0, 0, 0]}>
<meshBasicMaterial color={savedTheme === "dark" ? Constants.lineConfig.wallColor : Constants.lineConfig.wallColor} side={DoubleSide} transparent opacity={0.4} depthWrite={false} />
</Extrude>
</mesh>
<ExtrudePolygon points={room} receiveShadow castShadow name="Wall-Floor" options={{ depth: 0, bevelEnabled: false }}>
<meshBasicMaterial color={savedTheme === "dark" ? Constants.lineConfig.wallColor : Constants.lineConfig.wallColor} side={DoubleSide} transparent opacity={0.4} depthWrite={false} />
</ExtrudePolygon>
<Html position={centroid} wrapperClass="distance-text-wrapper" className="distance-text" zIndexRange={[1, 0]} prepend center sprite>
<div className="distance area">({formattedArea})</div>

View File

@@ -0,0 +1,97 @@
import { useMemo, ReactNode } from "react";
import { ExtrudeGeometryOptions, Shape, Vector2, Vector3, Euler } from "three";
import { Extrude } from "@react-three/drei";
import { ThreeEvent } from "@react-three/fiber";
function ExtrudePolygon({
name,
points,
options,
userData,
children,
castShadow,
receiveShadow,
position = [0, 0, 0],
rotation = [Math.PI / 2, 0, 0],
onClick,
onContextMenu,
onDoubleClick,
onPointerUp,
onPointerDown,
onPointerOver,
onPointerOut,
onPointerEnter,
onPointerLeave,
onPointerMove,
onPointerMissed,
onPointerCancel,
onWheel,
}: Readonly<{
name?: string;
options?: ExtrudeGeometryOptions;
userData?: Record<string, any>;
points: Point[];
children?: ReactNode;
castShadow?: boolean;
receiveShadow?: boolean;
position?: [number, number, number] | Vector3;
rotation?: [number, number, number] | Euler;
onClick?: (event: ThreeEvent<MouseEvent>) => void;
onContextMenu?: (event: ThreeEvent<MouseEvent>) => void;
onDoubleClick?: (event: ThreeEvent<MouseEvent>) => void;
onPointerUp?: (event: ThreeEvent<PointerEvent>) => void;
onPointerDown?: (event: ThreeEvent<PointerEvent>) => void;
onPointerOver?: (event: ThreeEvent<PointerEvent>) => void;
onPointerOut?: (event: ThreeEvent<PointerEvent>) => void;
onPointerEnter?: (event: ThreeEvent<PointerEvent>) => void;
onPointerLeave?: (event: ThreeEvent<PointerEvent>) => void;
onPointerMove?: (event: ThreeEvent<PointerEvent>) => void;
onPointerMissed?: (event: MouseEvent) => void;
onPointerCancel?: (event: ThreeEvent<PointerEvent>) => void;
onWheel?: (event: ThreeEvent<WheelEvent>) => void;
}>) {
const points2D = useMemo(() => {
return points.map((p) => new Vector2(parseFloat(p.position[0].toFixed(2)), parseFloat(p.position[2].toFixed(2))));
}, [points]);
const shape = useMemo(() => {
const shape = new Shape();
shape.moveTo(points2D[0].x, points2D[0].y);
for (let i = 1; i < points2D.length; i++) {
shape.lineTo(points2D[i].x, points2D[i].y);
}
shape.closePath();
return shape;
}, [points2D]);
if (!shape) return null;
return (
<Extrude
name={name}
args={[shape, options]}
position={position}
rotation={rotation}
userData={userData}
castShadow={castShadow}
receiveShadow={receiveShadow}
onClick={onClick}
onContextMenu={onContextMenu}
onDoubleClick={onDoubleClick}
onPointerUp={onPointerUp}
onPointerDown={onPointerDown}
onPointerOver={onPointerOver}
onPointerOut={onPointerOut}
onPointerEnter={onPointerEnter}
onPointerLeave={onPointerLeave}
onPointerMove={onPointerMove}
onPointerMissed={onPointerMissed}
onPointerCancel={onPointerCancel}
onWheel={onWheel}
>
{children}
</Extrude>
);
}
export default ExtrudePolygon;

View File

@@ -1,24 +1,41 @@
import { useMemo, useRef } from "react";
import { Color, DoubleSide, ShaderMaterial } from "three";
import { useFrame } from "@react-three/fiber";
import { useSceneStore } from "../../../store/scene/useSceneStore";
import useShaderReader from "../../../utils/scene/useShaderReader";
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 zone1Vertex from "../../../../assets/shaders/zone/zone1.vert.glsl";
import zone1Fragment from "../../../../assets/shaders/zone/zone1.frag.glsl";
import zone2Vertex from "../../../assets/shaders/zone/zone2.vert.glsl";
import zone2Fragment from "../../../assets/shaders/zone/zone2.frag.glsl";
import zone2Vertex from "../../../../assets/shaders/zone/zone2.vert.glsl";
import zone2Fragment from "../../../../assets/shaders/zone/zone2.frag.glsl";
import zone3Vertex from "../../../assets/shaders/zone/zone3.vert.glsl";
import zone3Fragment from "../../../assets/shaders/zone/zone3.frag.glsl";
import zone3Vertex from "../../../../assets/shaders/zone/zone3.vert.glsl";
import zone3Fragment from "../../../../assets/shaders/zone/zone3.frag.glsl";
type PlaneMaterialProps = {
color: string;
color?: string;
variant?: "zone1" | "zone2" | "zone3";
transparent?: boolean;
opacity?: number;
depthWrite?: boolean;
depthTest?: boolean;
polygonOffset?: boolean;
polygonOffsetFactor?: number;
polygonOffsetUnits?: number;
};
function PlaneMaterial({ color, variant = "zone1", ...props }: Readonly<PlaneMaterialProps>) {
function PlaneMaterial({
color = "white",
variant = "zone1",
transparent = false,
opacity = 1,
depthWrite,
depthTest,
polygonOffset = false,
polygonOffsetFactor,
polygonOffsetUnits,
}: Readonly<PlaneMaterialProps>) {
const { limitFps } = useSceneStore();
const materialRef = useRef<ShaderMaterial | null>(null);
@@ -40,11 +57,15 @@ function PlaneMaterial({ color, variant = "zone1", ...props }: Readonly<PlaneMat
uOuterColor: { value: new Color(color) },
uTime: { value: 0 },
},
transparent: true,
depthWrite: false,
...props,
transparent,
opacity,
depthWrite,
depthTest,
polygonOffset,
polygonOffsetFactor,
polygonOffsetUnits,
});
}, [color, vertexShader, fragmentShader]);
}, [color, vertexShader, fragmentShader, transparent, opacity, depthWrite, depthTest, polygonOffset, polygonOffsetFactor, polygonOffsetUnits]);
useFrame(({ clock }) => {
if (materialRef.current && !limitFps) {

View File

@@ -1,18 +1,37 @@
import { useMemo } from "react";
import { Color, DoubleSide, ShaderMaterial, Vector3, MeshStandardMaterial } from "three";
import useShaderReader from "../../../utils/scene/useShaderReader";
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/edge/edge-fade.vert.glsl";
import edgeFragment from "../../../../assets/shaders/edge/edge-fade.frag.glsl";
type PolygonMaterialProps = {
points: { position: [number, number, number] }[];
color: string;
color?: string;
transparent?: boolean;
depthWrite?: boolean;
depthTest?: boolean;
opacity?: number;
polygonOffset?: boolean;
polygonOffsetFactor?: number;
polygonOffsetUnits?: number;
fadeDistance?: number;
variant?: "edge" | "none";
};
function PolygonMaterial({ points, color, fadeDistance = 2.0, variant = "edge", ...props }: Readonly<PolygonMaterialProps>) {
function PolygonMaterial({
points,
color = "white",
transparent = false,
depthWrite,
depthTest,
opacity = 1,
polygonOffset = false,
polygonOffsetFactor,
polygonOffsetUnits,
fadeDistance = 2.0,
variant = "none",
}: Readonly<PolygonMaterialProps>) {
const vertexShader = useShaderReader(edgeVertex);
const fragmentShader = useShaderReader(edgeFragment);
@@ -41,13 +60,13 @@ function PolygonMaterial({ points, color, fadeDistance = 2.0, variant = "edge",
uEdges: { value: edgeArray },
uEdgeCount: { value: edges.length },
},
transparent: true,
depthWrite: false,
depthTest: true,
polygonOffset: true,
polygonOffsetFactor: -10,
polygonOffsetUnits: -10,
...props,
transparent,
depthWrite,
depthTest,
polygonOffset,
polygonOffsetFactor,
polygonOffsetUnits,
opacity,
});
}, [color, fadeDistance, vertexShader, fragmentShader, edges]);
@@ -56,7 +75,13 @@ function PolygonMaterial({ points, color, fadeDistance = 2.0, variant = "edge",
return new MeshStandardMaterial({
color: new Color(color),
side: DoubleSide,
transparent: true,
transparent,
depthWrite,
depthTest,
polygonOffset,
polygonOffsetFactor,
polygonOffsetUnits,
opacity,
});
}, [color]);

View File

@@ -1,6 +1,7 @@
import { useMemo } from "react";
import { DoubleSide, Shape, Vector2 } from "three";
import { Extrude, Html } from "@react-three/drei";
import { DoubleSide, Vector2 } from "three";
import { Html } from "@react-three/drei";
import ExtrudePolygon from "../../../wrappers/geomentry/extrudePolygon";
import * as Constants from "../../../../../types/world/worldConstants";
import getCenteroid from "../../../functions/getCenteroid";
import getArea from "../../../functions/getArea";
@@ -12,16 +13,6 @@ function Zone2DInstance({ zone }: { readonly zone: Zone }) {
return zone.points.map((p) => new Vector2(parseFloat(p.position[0].toFixed(2)), parseFloat(p.position[2].toFixed(2))));
}, [zone]);
const shape = useMemo(() => {
const shape = new Shape();
shape.moveTo(points2D[0].x, points2D[0].y);
for (let i = 1; i < points2D.length; i++) {
shape.lineTo(points2D[i].x, points2D[i].y);
}
shape.lineTo(points2D[0].x, points2D[0].y);
return shape;
}, [points2D]);
const area = useMemo(() => getArea(points2D), [points2D]);
const centroid: [number, number, number] = useMemo(() => {
@@ -31,17 +22,13 @@ function Zone2DInstance({ zone }: { readonly zone: Zone }) {
return [center.x, Constants.floorConfig.height + 0.01, center.y] as [number, number, number];
}, [points2D]);
if (!shape) return null;
const formattedArea = `${area.toFixed(2)}`;
return (
<>
<mesh castShadow receiveShadow name={`Zone-2D-${zone.zoneUuid}`} rotation={[Math.PI / 2, 0, 0]} position={[0, 0, 0]} userData={zone}>
<Extrude name={`Zone-${zone.zoneUuid}`} args={[shape, { depth: Constants.floorConfig.height }]} userData={zone}>
<meshBasicMaterial color={savedTheme === "dark" ? Constants.lineConfig.zoneColor : Constants.lineConfig.zoneColor} side={DoubleSide} transparent opacity={0.4} depthWrite={false} />
</Extrude>
</mesh>
<ExtrudePolygon points={zone.points} options={{ depth: 0, bevelEnabled: false }} castShadow receiveShadow name={`Zone-2D-${zone.zoneUuid}`} userData={zone}>
<meshBasicMaterial color={savedTheme === "dark" ? Constants.lineConfig.zoneColor : Constants.lineConfig.zoneColor} side={DoubleSide} transparent opacity={0.4} depthWrite={false} />
</ExtrudePolygon>
<Html key={zone.zoneUuid} position={centroid} wrapperClass="distance-text-wrapper" className="distance-text" zIndexRange={[1, 0]} prepend center sprite>
<div className="distance area">

View File

@@ -1,7 +1,7 @@
import { Vector3 } from "three";
import { RoundedBox } from "@react-three/drei";
function CornerReference({
function ZoneCornerReference({
point,
prevPoint,
nextPoint,
@@ -77,4 +77,4 @@ function CornerReference({
);
}
export default CornerReference;
export default ZoneCornerReference;

View File

@@ -1,34 +1,27 @@
import { useMemo } from "react";
import { Extrude } from "@react-three/drei";
import { Shape, Vector2, Vector3 } from "three";
import CornerReference from "./cornerReference";
import PlaneMaterial from "../../../materials/planeMaterial";
import PolygonMaterial from "../../../materials/polygonMaterial";
import { Vector3 } from "three";
import ZoneCornerReference from "./zoneCornerReference";
import ExtrudePolygon from "../../../wrappers/geomentry/extrudePolygon";
import PlaneMaterial from "../../../wrappers/materials/planeMaterial";
import PolygonMaterial from "../../../wrappers/materials/polygonMaterial";
function ZoneInstance({ zone }: { readonly zone: Zone }) {
const zoneLayer = zone.points[0].layer;
const points2D = useMemo(() => {
return zone.points.map((p) => new Vector2(parseFloat(p.position[0].toFixed(2)), parseFloat(p.position[2].toFixed(2))));
}, [zone]);
const shape = useMemo(() => {
const shape = new Shape();
shape.moveTo(points2D[0].x, points2D[0].y);
for (let i = 1; i < points2D.length; i++) {
shape.lineTo(points2D[i].x, points2D[i].y);
}
shape.lineTo(points2D[0].x, points2D[0].y);
return shape;
}, [points2D]);
if (!shape) return null;
return (
<group name={`Zone-${zone.zoneUuid}`} userData={zone}>
<Extrude args={[shape, { depth: 0, bevelEnabled: false }]} rotation={[Math.PI / 2, 0, 0]}>
<PolygonMaterial points={zone.points} color={zone.zoneColor} variant="edge" />
</Extrude>
<ExtrudePolygon options={{ depth: 0, bevelEnabled: false }} points={zone.points}>
<PolygonMaterial
transparent
depthWrite={false}
depthTest={true}
polygonOffset
polygonOffsetFactor={-10}
polygonOffsetUnits={-10}
points={zone.points}
color={zone.zoneColor}
variant="edge"
/>
</ExtrudePolygon>
{zone.points.map((point, index: number) => {
const nextPoint = zone.points[(index + 1) % zone.points.length];
@@ -47,10 +40,10 @@ function ZoneInstance({ zone }: { readonly zone: Zone }) {
<group key={index}>
<mesh position={midpoint} rotation={[0, -angle, 0]}>
<planeGeometry args={[planeWidth, planeHeight]} />
<PlaneMaterial color={zone.zoneColor} variant="zone1" />
<PlaneMaterial transparent depthWrite={false} depthTest={true} color={zone.zoneColor} variant="zone1" />
</mesh>
<CornerReference showTop={false} showBottom={false} point={point} prevPoint={prevPoint} nextPoint={nextPoint} zone={zone} cornerThickness={0.25} />
<ZoneCornerReference showTop showBottom point={point} prevPoint={prevPoint} nextPoint={nextPoint} zone={zone} cornerThickness={0.25} />
</group>
);
})}