This commit is contained in:
wass08
2026-01-15 13:03:41 +09:00
parent c0626662a8
commit fbd050ad73
+92 -1
View File
@@ -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);