added zone edge fade shader

This commit is contained in:
2025-09-11 11:04:07 +05:30
parent 521aed3d1e
commit 9f386bef59
4 changed files with 127 additions and 4 deletions

View File

@@ -0,0 +1,32 @@
precision highp float;
varying vec3 vWorldPosition;
uniform vec3 uColor;
uniform float uFadeDistance; // max distance inward from edge
uniform vec2 uEdges[64]; // polygon edges packed as pairs (start, end)
uniform int uEdgeCount;
float pointToSegmentDist(vec2 p, vec2 a, vec2 b) {
vec2 pa = p - a;
vec2 ba = b - a;
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
return length(pa - ba * h);
}
void main() {
vec2 fragXZ = vWorldPosition.xz;
float minDist = 1e6;
for (int i = 0; i < 64; i++) {
if (i >= uEdgeCount) break;
vec2 a = uEdges[i*2 + 0];
vec2 b = uEdges[i*2 + 1];
float d = pointToSegmentDist(fragXZ, a, b);
minDist = min(minDist, d);
}
float alpha = smoothstep(uFadeDistance, 0.0, minDist);
gl_FragColor = vec4(uColor, alpha);
}

View File

@@ -0,0 +1,7 @@
varying vec3 vWorldPosition;
void main() {
vec4 worldPos = modelMatrix * vec4(position, 1.0);
vWorldPosition = worldPos.xyz;
gl_Position = projectionMatrix * viewMatrix * worldPos;
}

View File

@@ -0,0 +1,75 @@
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;

View File

@@ -3,17 +3,24 @@ 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 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 CornerReference from "./cornerReference";
// 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 }) {
const vertexShader = useShaderReader(vertexShaderUrl);
const fragmentShader = useShaderReader(fragmentShaderUrl);
const zoneLayer = zone.points[0].layer;
const { limitFps } = useSceneStore();
const [time, setTime] = useState<number>();
const [time, setTime] = useState<number>(0);
const zoneMaterial = useMemo(() => {
if (!vertexShader || !fragmentShader) return null;
@@ -40,7 +47,9 @@ function ZoneInstance({ zone }: { readonly zone: Zone }) {
if (!zoneMaterial) return null;
return (
<mesh 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} />
{zone.points.map((point, index: number) => {
const nextPoint = zone.points[(index + 1) % zone.points.length];
const prevPoint = zone.points[(index - 1 + zone.points.length) % zone.points.length];
@@ -65,7 +74,7 @@ function ZoneInstance({ zone }: { readonly zone: Zone }) {
</group>
);
})}
</mesh>
</group>
);
}