Files
Dwinzo_Demo/app/src/modules/builder/wrappers/materials/polygonMaterial.tsx

95 lines
2.9 KiB
TypeScript

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;
transparent?: boolean;
depthWrite?: boolean;
depthTest?: boolean;
opacity?: number;
polygonOffset?: boolean;
polygonOffsetFactor?: number;
polygonOffsetUnits?: number;
fadeDistance?: number;
variant?: "edge" | "none";
};
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);
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,
depthWrite,
depthTest,
polygonOffset,
polygonOffsetFactor,
polygonOffsetUnits,
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]);
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;