optimized zone material
This commit is contained in:
@@ -44,7 +44,7 @@ function FloorInstance({ floor }: { readonly floor: Floor }) {
|
||||
textureTileScale?: [number, number];
|
||||
}
|
||||
> = {
|
||||
"Default Material": { map: savedTheme === "dark" ? texturePathDark : texturePath, },
|
||||
"Default Material": { map: savedTheme === "dark" ? texturePathDark : texturePath },
|
||||
"Material 1": { map: material1 },
|
||||
"Material 2": {
|
||||
map: material2Map,
|
||||
@@ -111,30 +111,17 @@ function FloorInstance({ floor }: { readonly floor: Floor }) {
|
||||
|
||||
const textureMaterialMap = [
|
||||
{
|
||||
textures: [
|
||||
topTexture,
|
||||
topNormalTexture,
|
||||
topRoughnessTexture,
|
||||
topMetalicTexture,
|
||||
],
|
||||
textures: [topTexture, topNormalTexture, topRoughnessTexture, topMetalicTexture],
|
||||
materialKey: floor.topMaterial,
|
||||
},
|
||||
{
|
||||
textures: [
|
||||
sideTexture,
|
||||
sideNormalTexture,
|
||||
sideRoughnessTexture,
|
||||
sideMetalicTexture,
|
||||
],
|
||||
textures: [sideTexture, sideNormalTexture, sideRoughnessTexture, sideMetalicTexture],
|
||||
materialKey: floor.sideMaterial,
|
||||
},
|
||||
];
|
||||
|
||||
textureMaterialMap.forEach(({ textures, materialKey }) => {
|
||||
const tileScale = materials[materialKey]?.textureTileScale ?? [
|
||||
textureScale,
|
||||
textureScale,
|
||||
];
|
||||
const tileScale = materials[materialKey]?.textureTileScale ?? [textureScale, textureScale];
|
||||
|
||||
textures.forEach((tex, idx) => {
|
||||
if (!tex) return;
|
||||
@@ -166,11 +153,7 @@ function FloorInstance({ floor }: { readonly floor: Floor }) {
|
||||
geometry={geometry}
|
||||
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={[shapeData?.center[0] ?? 0, !floor.isBeveled ? floor.floorDepth - 0.1 : floor.floorDepth - 0.2, shapeData?.center[1] ?? 0]}
|
||||
userData={floor}
|
||||
onDoubleClick={(e) => {
|
||||
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 { Color, DoubleSide, ShaderMaterial, Vector3 } from "three";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import { useSceneStore } from "../../../../../store/scene/useSceneStore";
|
||||
import useShaderReader from "../../../../../utils/scene/useShaderReader";
|
||||
import { useMemo } from "react";
|
||||
import { Extrude } from "@react-three/drei";
|
||||
import { Shape, Vector2, Vector3 } from "three";
|
||||
import CornerReference from "./cornerReference";
|
||||
import PolygonEdgeMaterial from "../../../materials/polygonEdgeMaterial";
|
||||
|
||||
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";
|
||||
import PlaneMaterial from "../../../materials/planeMaterial";
|
||||
import PolygonMaterial from "../../../materials/polygonMaterial";
|
||||
|
||||
function ZoneInstance({ zone }: { readonly zone: Zone }) {
|
||||
const vertexShader = useShaderReader(vertexShaderUrl);
|
||||
const fragmentShader = useShaderReader(fragmentShaderUrl);
|
||||
const zoneLayer = zone.points[0].layer;
|
||||
const { limitFps } = useSceneStore();
|
||||
const [time, setTime] = useState<number>(0);
|
||||
|
||||
const zoneMaterial = useMemo(() => {
|
||||
if (!vertexShader || !fragmentShader) return null;
|
||||
const points2D = useMemo(() => {
|
||||
return zone.points.map((p) => new Vector2(parseFloat(p.position[0].toFixed(2)), parseFloat(p.position[2].toFixed(2))));
|
||||
}, [zone]);
|
||||
|
||||
return new ShaderMaterial({
|
||||
side: DoubleSide,
|
||||
vertexShader,
|
||||
fragmentShader,
|
||||
uniforms: {
|
||||
uOuterColor: { value: new Color(zone.zoneColor) },
|
||||
uTime: { value: time },
|
||||
},
|
||||
transparent: true,
|
||||
depthWrite: false,
|
||||
});
|
||||
}, [zone.zoneColor, time]);
|
||||
|
||||
useFrame(({ clock }) => {
|
||||
if (!limitFps) {
|
||||
setTime(clock.getElapsedTime());
|
||||
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 (!zoneMaterial) return null;
|
||||
if (!shape) return null;
|
||||
|
||||
return (
|
||||
<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) => {
|
||||
const nextPoint = zone.points[(index + 1) % zone.points.length];
|
||||
@@ -67,7 +47,7 @@ function ZoneInstance({ zone }: { readonly zone: Zone }) {
|
||||
<group key={index}>
|
||||
<mesh position={midpoint} rotation={[0, -angle, 0]}>
|
||||
<planeGeometry args={[planeWidth, planeHeight]} />
|
||||
<primitive object={zoneMaterial.clone()} attach="material" />
|
||||
<PlaneMaterial color={zone.zoneColor} variant="zone1" />
|
||||
</mesh>
|
||||
|
||||
<CornerReference showTop={false} showBottom={false} point={point} prevPoint={prevPoint} nextPoint={nextPoint} zone={zone} cornerThickness={0.25} />
|
||||
|
||||
Reference in New Issue
Block a user