grid
This commit is contained in:
@@ -9,8 +9,9 @@ import {
|
|||||||
} from "@pascal-app/core";
|
} from "@pascal-app/core";
|
||||||
import { Viewer } from "@pascal-app/viewer";
|
import { Viewer } from "@pascal-app/viewer";
|
||||||
import { Stats } from "@react-three/drei";
|
import { Stats } from "@react-three/drei";
|
||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useMemo, useRef } from "react";
|
||||||
import { Mesh } from "three";
|
import { Mesh } from "three";
|
||||||
|
import { color, float, fract, fwidth, mix, positionLocal } from "three/tsl";
|
||||||
import { MeshBasicNodeMaterial } from "three/webgpu";
|
import { MeshBasicNodeMaterial } from "three/webgpu";
|
||||||
|
|
||||||
export default function Editor() {
|
export default function Editor() {
|
||||||
@@ -20,11 +21,101 @@ export default function Editor() {
|
|||||||
<Viewer>
|
<Viewer>
|
||||||
<Selector />
|
<Selector />
|
||||||
<Stats />
|
<Stats />
|
||||||
|
<Grid cellColor="#666" sectionColor="#999" fadeDistance={30} />
|
||||||
</Viewer>
|
</Viewer>
|
||||||
</div>
|
</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 Selector = () => {
|
||||||
const selectedItemId = useRef<ItemNode["id"]>(null);
|
const selectedItemId = useRef<ItemNode["id"]>(null);
|
||||||
const itemSelectedAt = useRef<number>(0);
|
const itemSelectedAt = useRef<number>(0);
|
||||||
|
|||||||
Reference in New Issue
Block a user