optimized zone material
This commit is contained in:
@@ -44,7 +44,7 @@ function FloorInstance({ floor }: { readonly floor: Floor }) {
|
|||||||
textureTileScale?: [number, number];
|
textureTileScale?: [number, number];
|
||||||
}
|
}
|
||||||
> = {
|
> = {
|
||||||
"Default Material": { map: savedTheme === "dark" ? texturePathDark : texturePath, },
|
"Default Material": { map: savedTheme === "dark" ? texturePathDark : texturePath },
|
||||||
"Material 1": { map: material1 },
|
"Material 1": { map: material1 },
|
||||||
"Material 2": {
|
"Material 2": {
|
||||||
map: material2Map,
|
map: material2Map,
|
||||||
@@ -111,30 +111,17 @@ function FloorInstance({ floor }: { readonly floor: Floor }) {
|
|||||||
|
|
||||||
const textureMaterialMap = [
|
const textureMaterialMap = [
|
||||||
{
|
{
|
||||||
textures: [
|
textures: [topTexture, topNormalTexture, topRoughnessTexture, topMetalicTexture],
|
||||||
topTexture,
|
|
||||||
topNormalTexture,
|
|
||||||
topRoughnessTexture,
|
|
||||||
topMetalicTexture,
|
|
||||||
],
|
|
||||||
materialKey: floor.topMaterial,
|
materialKey: floor.topMaterial,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
textures: [
|
textures: [sideTexture, sideNormalTexture, sideRoughnessTexture, sideMetalicTexture],
|
||||||
sideTexture,
|
|
||||||
sideNormalTexture,
|
|
||||||
sideRoughnessTexture,
|
|
||||||
sideMetalicTexture,
|
|
||||||
],
|
|
||||||
materialKey: floor.sideMaterial,
|
materialKey: floor.sideMaterial,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
textureMaterialMap.forEach(({ textures, materialKey }) => {
|
textureMaterialMap.forEach(({ textures, materialKey }) => {
|
||||||
const tileScale = materials[materialKey]?.textureTileScale ?? [
|
const tileScale = materials[materialKey]?.textureTileScale ?? [textureScale, textureScale];
|
||||||
textureScale,
|
|
||||||
textureScale,
|
|
||||||
];
|
|
||||||
|
|
||||||
textures.forEach((tex, idx) => {
|
textures.forEach((tex, idx) => {
|
||||||
if (!tex) return;
|
if (!tex) return;
|
||||||
@@ -166,11 +153,7 @@ function FloorInstance({ floor }: { readonly floor: Floor }) {
|
|||||||
geometry={geometry}
|
geometry={geometry}
|
||||||
name={`Floor-${floor.floorUuid}`}
|
name={`Floor-${floor.floorUuid}`}
|
||||||
rotation={[Math.PI / 2, 0, 0]}
|
rotation={[Math.PI / 2, 0, 0]}
|
||||||
position={[
|
position={[shapeData?.center[0] ?? 0, !floor.isBeveled ? floor.floorDepth - 0.1 : floor.floorDepth - 0.2, shapeData?.center[1] ?? 0]}
|
||||||
shapeData?.center[0] ?? 0,
|
|
||||||
!floor.isBeveled ? floor.floorDepth - 0.1 : floor.floorDepth - 0.2,
|
|
||||||
shapeData?.center[1] ?? 0,
|
|
||||||
]}
|
|
||||||
userData={floor}
|
userData={floor}
|
||||||
onDoubleClick={(e) => {
|
onDoubleClick={(e) => {
|
||||||
if (!toggleView && activeModule === "builder") {
|
if (!toggleView && activeModule === "builder") {
|
||||||
|
|||||||
59
app/src/modules/builder/materials/planeMaterial.tsx
Normal file
59
app/src/modules/builder/materials/planeMaterial.tsx
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
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 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 zone3Vertex from "../../../assets/shaders/zone/zone3.vert.glsl";
|
||||||
|
import zone3Fragment from "../../../assets/shaders/zone/zone3.frag.glsl";
|
||||||
|
|
||||||
|
type PlaneMaterialProps = {
|
||||||
|
color: string;
|
||||||
|
variant?: "zone1" | "zone2" | "zone3";
|
||||||
|
};
|
||||||
|
|
||||||
|
function PlaneMaterial({ color, variant = "zone1", ...props }: Readonly<PlaneMaterialProps>) {
|
||||||
|
const { limitFps } = useSceneStore();
|
||||||
|
const materialRef = useRef<ShaderMaterial | null>(null);
|
||||||
|
|
||||||
|
const vertexShaderUrl = variant === "zone1" ? zone1Vertex : variant === "zone2" ? zone2Vertex : variant === "zone3" ? zone3Vertex : zone1Vertex;
|
||||||
|
|
||||||
|
const fragmentShaderUrl = variant === "zone1" ? zone1Fragment : variant === "zone2" ? zone2Fragment : variant === "zone3" ? zone3Fragment : zone1Fragment;
|
||||||
|
|
||||||
|
const vertexShader = useShaderReader(vertexShaderUrl);
|
||||||
|
const fragmentShader = useShaderReader(fragmentShaderUrl);
|
||||||
|
|
||||||
|
const material = useMemo(() => {
|
||||||
|
if (!vertexShader || !fragmentShader) return null;
|
||||||
|
|
||||||
|
return new ShaderMaterial({
|
||||||
|
side: DoubleSide,
|
||||||
|
vertexShader,
|
||||||
|
fragmentShader,
|
||||||
|
uniforms: {
|
||||||
|
uOuterColor: { value: new Color(color) },
|
||||||
|
uTime: { value: 0 },
|
||||||
|
},
|
||||||
|
transparent: true,
|
||||||
|
depthWrite: false,
|
||||||
|
...props,
|
||||||
|
});
|
||||||
|
}, [color, vertexShader, fragmentShader]);
|
||||||
|
|
||||||
|
useFrame(({ clock }) => {
|
||||||
|
if (materialRef.current && !limitFps) {
|
||||||
|
materialRef.current.uniforms.uTime.value = clock.getElapsedTime();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!material) return null;
|
||||||
|
return <primitive object={material} ref={materialRef} attach="material" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PlaneMaterial;
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
import { useMemo } from "react";
|
|
||||||
import { Color, DoubleSide, ShaderMaterial, Shape, ShapeGeometry, Vector3 } from "three";
|
|
||||||
import useShaderReader from "../../../utils/scene/useShaderReader";
|
|
||||||
|
|
||||||
import vertexShaderUrl from "../../../assets/shaders/edge/edge-fade.vert.glsl";
|
|
||||||
import fragmentShaderUrl from "../../../assets/shaders/edge/edge-fade.frag.glsl";
|
|
||||||
|
|
||||||
type PolygonEdgeMaterialProps = {
|
|
||||||
points: { position: [number, number, number] }[];
|
|
||||||
positionY: number;
|
|
||||||
color: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
function PolygonEdgeMaterial({ points, positionY, color }: Readonly<PolygonEdgeMaterialProps>) {
|
|
||||||
const vertexShader = useShaderReader(vertexShaderUrl);
|
|
||||||
const fragmentShader = useShaderReader(fragmentShaderUrl);
|
|
||||||
|
|
||||||
const geometry = useMemo(() => {
|
|
||||||
if (points.length < 3) return null;
|
|
||||||
|
|
||||||
const shape = new Shape();
|
|
||||||
points.forEach((p, i) => {
|
|
||||||
const v = new Vector3(...p.position);
|
|
||||||
if (i === 0) shape.moveTo(v.x, v.z);
|
|
||||||
else shape.lineTo(v.x, v.z);
|
|
||||||
});
|
|
||||||
shape.closePath();
|
|
||||||
|
|
||||||
return new ShapeGeometry(shape);
|
|
||||||
}, [points]);
|
|
||||||
|
|
||||||
const edges = useMemo(() => {
|
|
||||||
return points.map((p, i) => {
|
|
||||||
const next = points[(i + 1) % points.length];
|
|
||||||
return [new Vector3(...p.position), new Vector3(...next.position)];
|
|
||||||
});
|
|
||||||
}, [points]);
|
|
||||||
|
|
||||||
const material = useMemo(() => {
|
|
||||||
if (!vertexShader || !fragmentShader) return null;
|
|
||||||
|
|
||||||
const edgeArray: number[] = [];
|
|
||||||
edges.forEach(([a, b]) => {
|
|
||||||
edgeArray.push(a.x, a.z, b.x, b.z);
|
|
||||||
});
|
|
||||||
|
|
||||||
return new ShaderMaterial({
|
|
||||||
side: DoubleSide,
|
|
||||||
vertexShader,
|
|
||||||
fragmentShader,
|
|
||||||
uniforms: {
|
|
||||||
uColor: { value: new Color(color) },
|
|
||||||
uFadeDistance: { value: 2.0 },
|
|
||||||
uEdges: { value: edgeArray },
|
|
||||||
uEdgeCount: { value: edges.length },
|
|
||||||
},
|
|
||||||
transparent: true,
|
|
||||||
depthWrite: false,
|
|
||||||
depthTest: true,
|
|
||||||
polygonOffset: true,
|
|
||||||
polygonOffsetFactor: -10,
|
|
||||||
polygonOffsetUnits: -10,
|
|
||||||
});
|
|
||||||
}, [color, vertexShader, fragmentShader, edges]);
|
|
||||||
|
|
||||||
if (!geometry || !material) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<mesh geometry={geometry} position={[0, positionY, 0]} rotation={[Math.PI / 2, 0, 0]}>
|
|
||||||
<primitive object={material} attach="material" />
|
|
||||||
</mesh>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PolygonEdgeMaterial;
|
|
||||||
69
app/src/modules/builder/materials/polygonMaterial.tsx
Normal file
69
app/src/modules/builder/materials/polygonMaterial.tsx
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
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";
|
||||||
|
|
||||||
|
type PolygonMaterialProps = {
|
||||||
|
points: { position: [number, number, number] }[];
|
||||||
|
color: string;
|
||||||
|
fadeDistance?: number;
|
||||||
|
variant?: "edge" | "none";
|
||||||
|
};
|
||||||
|
|
||||||
|
function PolygonMaterial({ points, color, fadeDistance = 2.0, variant = "edge", ...props }: Readonly<PolygonMaterialProps>) {
|
||||||
|
const vertexShader = useShaderReader(edgeVertex);
|
||||||
|
const fragmentShader = useShaderReader(edgeFragment);
|
||||||
|
|
||||||
|
const edges = useMemo(() => {
|
||||||
|
return points.map((p, i) => {
|
||||||
|
const next = points[(i + 1) % points.length];
|
||||||
|
return [new Vector3(...p.position), new Vector3(...next.position)];
|
||||||
|
});
|
||||||
|
}, [points]);
|
||||||
|
|
||||||
|
const edgeMaterial = useMemo(() => {
|
||||||
|
if (!vertexShader || !fragmentShader || variant !== "edge") return null;
|
||||||
|
|
||||||
|
const edgeArray: number[] = [];
|
||||||
|
edges.forEach(([a, b]) => {
|
||||||
|
edgeArray.push(a.x, a.z, b.x, b.z);
|
||||||
|
});
|
||||||
|
|
||||||
|
return new ShaderMaterial({
|
||||||
|
side: DoubleSide,
|
||||||
|
vertexShader,
|
||||||
|
fragmentShader,
|
||||||
|
uniforms: {
|
||||||
|
uColor: { value: new Color(color) },
|
||||||
|
uFadeDistance: { value: fadeDistance },
|
||||||
|
uEdges: { value: edgeArray },
|
||||||
|
uEdgeCount: { value: edges.length },
|
||||||
|
},
|
||||||
|
transparent: true,
|
||||||
|
depthWrite: false,
|
||||||
|
depthTest: true,
|
||||||
|
polygonOffset: true,
|
||||||
|
polygonOffsetFactor: -10,
|
||||||
|
polygonOffsetUnits: -10,
|
||||||
|
...props,
|
||||||
|
});
|
||||||
|
}, [color, fadeDistance, vertexShader, fragmentShader, edges]);
|
||||||
|
|
||||||
|
const basicMaterial = useMemo(() => {
|
||||||
|
if (variant !== "none") return null;
|
||||||
|
return new MeshStandardMaterial({
|
||||||
|
color: new Color(color),
|
||||||
|
side: DoubleSide,
|
||||||
|
transparent: true,
|
||||||
|
});
|
||||||
|
}, [color]);
|
||||||
|
|
||||||
|
if (variant === "none" && basicMaterial) return <primitive object={basicMaterial} attach="material" />;
|
||||||
|
if (variant === "edge" && edgeMaterial) return <primitive object={edgeMaterial} attach="material" />;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PolygonMaterial;
|
||||||
@@ -1,54 +1,34 @@
|
|||||||
import { useMemo, useState } from "react";
|
import { useMemo } from "react";
|
||||||
import { Color, DoubleSide, ShaderMaterial, Vector3 } from "three";
|
import { Extrude } from "@react-three/drei";
|
||||||
import { useFrame } from "@react-three/fiber";
|
import { Shape, Vector2, Vector3 } from "three";
|
||||||
import { useSceneStore } from "../../../../../store/scene/useSceneStore";
|
|
||||||
import useShaderReader from "../../../../../utils/scene/useShaderReader";
|
|
||||||
import CornerReference from "./cornerReference";
|
import CornerReference from "./cornerReference";
|
||||||
import PolygonEdgeMaterial from "../../../materials/polygonEdgeMaterial";
|
import PlaneMaterial from "../../../materials/planeMaterial";
|
||||||
|
import PolygonMaterial from "../../../materials/polygonMaterial";
|
||||||
import vertexShaderUrl from "../../../../../assets/shaders/zone/zone1.vert.glsl";
|
|
||||||
import fragmentShaderUrl from "../../../../../assets/shaders/zone/zone1.frag.glsl";
|
|
||||||
|
|
||||||
// import vertexShaderUrl from "../../../../../assets/shaders/zone/zone2.vert.glsl";
|
|
||||||
// import fragmentShaderUrl from "../../../../../assets/shaders/zone/zone2.frag.glsl";
|
|
||||||
|
|
||||||
// import vertexShaderUrl from "../../../../../assets/shaders/zone/zone2.vert.glsl";
|
|
||||||
// import fragmentShaderUrl from "../../../../../assets/shaders/zone/zone2.frag.glsl";
|
|
||||||
|
|
||||||
function ZoneInstance({ zone }: { readonly zone: Zone }) {
|
function ZoneInstance({ zone }: { readonly zone: Zone }) {
|
||||||
const vertexShader = useShaderReader(vertexShaderUrl);
|
|
||||||
const fragmentShader = useShaderReader(fragmentShaderUrl);
|
|
||||||
const zoneLayer = zone.points[0].layer;
|
const zoneLayer = zone.points[0].layer;
|
||||||
const { limitFps } = useSceneStore();
|
|
||||||
const [time, setTime] = useState<number>(0);
|
|
||||||
|
|
||||||
const zoneMaterial = useMemo(() => {
|
const points2D = useMemo(() => {
|
||||||
if (!vertexShader || !fragmentShader) return null;
|
return zone.points.map((p) => new Vector2(parseFloat(p.position[0].toFixed(2)), parseFloat(p.position[2].toFixed(2))));
|
||||||
|
}, [zone]);
|
||||||
|
|
||||||
return new ShaderMaterial({
|
const shape = useMemo(() => {
|
||||||
side: DoubleSide,
|
const shape = new Shape();
|
||||||
vertexShader,
|
shape.moveTo(points2D[0].x, points2D[0].y);
|
||||||
fragmentShader,
|
for (let i = 1; i < points2D.length; i++) {
|
||||||
uniforms: {
|
shape.lineTo(points2D[i].x, points2D[i].y);
|
||||||
uOuterColor: { value: new Color(zone.zoneColor) },
|
|
||||||
uTime: { value: time },
|
|
||||||
},
|
|
||||||
transparent: true,
|
|
||||||
depthWrite: false,
|
|
||||||
});
|
|
||||||
}, [zone.zoneColor, time]);
|
|
||||||
|
|
||||||
useFrame(({ clock }) => {
|
|
||||||
if (!limitFps) {
|
|
||||||
setTime(clock.getElapsedTime());
|
|
||||||
}
|
}
|
||||||
});
|
shape.lineTo(points2D[0].x, points2D[0].y);
|
||||||
|
return shape;
|
||||||
|
}, [points2D]);
|
||||||
|
|
||||||
if (!zoneMaterial) return null;
|
if (!shape) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group name={`Zone-${zone.zoneUuid}`} userData={zone}>
|
<group name={`Zone-${zone.zoneUuid}`} userData={zone}>
|
||||||
<PolygonEdgeMaterial points={zone.points} positionY={(zoneLayer - 1) * zone.zoneHeight} color={zone.zoneColor} />
|
<Extrude args={[shape, { depth: 0, bevelEnabled: false }]} rotation={[Math.PI / 2, 0, 0]}>
|
||||||
|
<PolygonMaterial points={zone.points} color={zone.zoneColor} variant="edge" />
|
||||||
|
</Extrude>
|
||||||
|
|
||||||
{zone.points.map((point, index: number) => {
|
{zone.points.map((point, index: number) => {
|
||||||
const nextPoint = zone.points[(index + 1) % zone.points.length];
|
const nextPoint = zone.points[(index + 1) % zone.points.length];
|
||||||
@@ -67,7 +47,7 @@ function ZoneInstance({ zone }: { readonly zone: Zone }) {
|
|||||||
<group key={index}>
|
<group key={index}>
|
||||||
<mesh position={midpoint} rotation={[0, -angle, 0]}>
|
<mesh position={midpoint} rotation={[0, -angle, 0]}>
|
||||||
<planeGeometry args={[planeWidth, planeHeight]} />
|
<planeGeometry args={[planeWidth, planeHeight]} />
|
||||||
<primitive object={zoneMaterial.clone()} attach="material" />
|
<PlaneMaterial color={zone.zoneColor} variant="zone1" />
|
||||||
</mesh>
|
</mesh>
|
||||||
|
|
||||||
<CornerReference showTop={false} showBottom={false} point={point} prevPoint={prevPoint} nextPoint={nextPoint} zone={zone} cornerThickness={0.25} />
|
<CornerReference showTop={false} showBottom={false} point={point} prevPoint={prevPoint} nextPoint={nextPoint} zone={zone} cornerThickness={0.25} />
|
||||||
|
|||||||
Reference in New Issue
Block a user