added zone edge fade shader
This commit is contained in:
32
app/src/assets/shaders/edge/edge-fade.frag.glsl
Normal file
32
app/src/assets/shaders/edge/edge-fade.frag.glsl
Normal 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);
|
||||
}
|
||||
7
app/src/assets/shaders/edge/edge-fade.vert.glsl
Normal file
7
app/src/assets/shaders/edge/edge-fade.vert.glsl
Normal 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;
|
||||
}
|
||||
75
app/src/modules/builder/materials/polygonEdgeMaterial.tsx
Normal file
75
app/src/modules/builder/materials/polygonEdgeMaterial.tsx
Normal 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;
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user