grid
This commit is contained in:
@@ -9,8 +9,9 @@ import {
|
||||
} from "@pascal-app/core";
|
||||
import { Viewer } from "@pascal-app/viewer";
|
||||
import { Stats } from "@react-three/drei";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useEffect, useMemo, useRef } from "react";
|
||||
import { Mesh } from "three";
|
||||
import { color, float, fract, fwidth, mix, positionLocal } from "three/tsl";
|
||||
import { MeshBasicNodeMaterial } from "three/webgpu";
|
||||
|
||||
export default function Editor() {
|
||||
@@ -20,11 +21,101 @@ export default function Editor() {
|
||||
<Viewer>
|
||||
<Selector />
|
||||
<Stats />
|
||||
<Grid cellColor="#666" sectionColor="#999" fadeDistance={30} />
|
||||
</Viewer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const Grid = ({
|
||||
cellSize = 0.5,
|
||||
cellThickness = 0.5,
|
||||
cellColor = "#888888",
|
||||
sectionSize = 1,
|
||||
sectionThickness = 1,
|
||||
sectionColor = "#000000",
|
||||
fadeDistance = 100,
|
||||
fadeStrength = 1,
|
||||
}: {
|
||||
cellSize?: number;
|
||||
cellThickness?: number;
|
||||
cellColor?: string;
|
||||
sectionSize?: number;
|
||||
sectionThickness?: number;
|
||||
sectionColor?: string;
|
||||
fadeDistance?: number;
|
||||
fadeStrength?: number;
|
||||
}) => {
|
||||
const material = useMemo(() => {
|
||||
// Use xy since plane geometry is in XY space (before rotation)
|
||||
const pos = positionLocal.xy;
|
||||
|
||||
// Grid line function using fwidth for anti-aliasing
|
||||
// Returns 1 on grid lines, 0 elsewhere
|
||||
const getGrid = (size: number, thickness: number) => {
|
||||
const r = pos.div(size);
|
||||
const fw = fwidth(r);
|
||||
// Distance to nearest grid line for each axis
|
||||
const grid = fract(r.sub(0.5)).sub(0.5).abs();
|
||||
// Anti-aliased step: divide by fwidth and clamp
|
||||
const lineX = float(1).sub(
|
||||
grid.x
|
||||
.div(fw.x)
|
||||
.add(1 - thickness)
|
||||
.min(1)
|
||||
);
|
||||
const lineY = float(1).sub(
|
||||
grid.y
|
||||
.div(fw.y)
|
||||
.add(1 - thickness)
|
||||
.min(1)
|
||||
);
|
||||
// Combine both axes - max gives us lines in both directions
|
||||
return lineX.max(lineY);
|
||||
};
|
||||
|
||||
const g1 = getGrid(cellSize, cellThickness);
|
||||
const g2 = getGrid(sectionSize, sectionThickness);
|
||||
|
||||
// Distance fade from center
|
||||
const dist = pos.length();
|
||||
const fade = float(1).sub(dist.div(fadeDistance).min(1)).pow(fadeStrength);
|
||||
|
||||
// Mix colors based on section grid
|
||||
const gridColor = mix(
|
||||
color(cellColor),
|
||||
color(sectionColor),
|
||||
float(sectionThickness).mul(g2).min(1)
|
||||
);
|
||||
|
||||
// Combined alpha
|
||||
const alpha = g1.add(g2).mul(fade);
|
||||
const finalAlpha = mix(alpha.mul(0.75), alpha, g2);
|
||||
|
||||
return new MeshBasicNodeMaterial({
|
||||
transparent: true,
|
||||
colorNode: gridColor,
|
||||
opacityNode: finalAlpha,
|
||||
depthWrite: false,
|
||||
});
|
||||
}, [
|
||||
cellSize,
|
||||
cellThickness,
|
||||
cellColor,
|
||||
sectionSize,
|
||||
sectionThickness,
|
||||
sectionColor,
|
||||
fadeDistance,
|
||||
fadeStrength,
|
||||
]);
|
||||
|
||||
return (
|
||||
<mesh rotation-x={-Math.PI / 2} material={material}>
|
||||
<planeGeometry args={[fadeDistance * 2, fadeDistance * 2]} />
|
||||
</mesh>
|
||||
);
|
||||
};
|
||||
|
||||
const Selector = () => {
|
||||
const selectedItemId = useRef<ItemNode["id"]>(null);
|
||||
const itemSelectedAt = useRef<number>(0);
|
||||
|
||||
Reference in New Issue
Block a user