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

70 lines
2.4 KiB
TypeScript
Raw Normal View History

2025-09-11 11:58:12 +05:30
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;