better looking grid

This commit is contained in:
wass08
2026-02-09 13:49:05 +09:00
parent 48aa62ec87
commit e9d579d24e
+30 -6
View File
@@ -1,13 +1,13 @@
'use client' 'use client'
import { sceneRegistry } from '@pascal-app/core' import { emitter, type GridEvent, sceneRegistry } from '@pascal-app/core'
import { useViewer } from '@pascal-app/viewer' import { useViewer } from '@pascal-app/viewer'
import { useFrame } from '@react-three/fiber' import { useFrame } from '@react-three/fiber'
import { useMemo, useRef, useState } from 'react' import { useEffect, useMemo, useRef, useState } from 'react'
import { MathUtils, type Mesh } from 'three' import { MathUtils, type Mesh, Vector2 } from 'three'
import { color, float, fract, fwidth, mix, positionLocal } from 'three/tsl' import { color, float, fract, fwidth, mix, positionLocal, uniform } from 'three/tsl'
import { MeshBasicNodeMaterial } from 'three/webgpu' import { MeshBasicNodeMaterial } from 'three/webgpu'
import { useGridEvents } from '@/hooks/use-grid-events' import { useGridEvents } from '@/hooks/use-grid-events'
@@ -20,6 +20,7 @@ export const Grid = ({
sectionColor = '#000000', sectionColor = '#000000',
fadeDistance = 100, fadeDistance = 100,
fadeStrength = 1, fadeStrength = 1,
revealRadius = 10,
}: { }: {
cellSize?: number cellSize?: number
cellThickness?: number cellThickness?: number
@@ -29,11 +30,17 @@ export const Grid = ({
sectionColor?: string sectionColor?: string
fadeDistance?: number fadeDistance?: number
fadeStrength?: number fadeStrength?: number
revealRadius?: number
}) => { }) => {
const cursorPositionRef = useRef(new Vector2(0, 0))
const material = useMemo(() => { const material = useMemo(() => {
// Use xy since plane geometry is in XY space (before rotation) // Use xy since plane geometry is in XY space (before rotation)
const pos = positionLocal.xy const pos = positionLocal.xy
// Cursor position uniform
const cursorPos = uniform(cursorPositionRef.current)
// Grid line function using fwidth for anti-aliasing // Grid line function using fwidth for anti-aliasing
// Returns 1 on grid lines, 0 elsewhere // Returns 1 on grid lines, 0 elsewhere
const getGrid = (size: number, thickness: number) => { const getGrid = (size: number, thickness: number) => {
@@ -65,6 +72,10 @@ export const Grid = ({
const dist = pos.length() const dist = pos.length()
const fade = float(1).sub(dist.div(fadeDistance).min(1)).pow(fadeStrength) const fade = float(1).sub(dist.div(fadeDistance).min(1)).pow(fadeStrength)
// Cursor reveal effect - distance from cursor
const cursorDist = pos.sub(cursorPos).length()
const cursorFade = float(1).sub(cursorDist.div(revealRadius).clamp(0, 1)).smoothstep(0, 1)
// Mix colors based on section grid // Mix colors based on section grid
const gridColor = mix( const gridColor = mix(
color(cellColor), color(cellColor),
@@ -72,8 +83,8 @@ export const Grid = ({
float(sectionThickness).mul(g2).min(1), float(sectionThickness).mul(g2).min(1),
) )
// Combined alpha // Combined alpha with cursor fade
const alpha = g1.add(g2).mul(fade) const alpha = g1.add(g2).mul(fade).mul(cursorFade)
const finalAlpha = mix(alpha.mul(0.75), alpha, g2) const finalAlpha = mix(alpha.mul(0.75), alpha, g2)
return new MeshBasicNodeMaterial({ return new MeshBasicNodeMaterial({
@@ -91,6 +102,7 @@ export const Grid = ({
sectionColor, sectionColor,
fadeDistance, fadeDistance,
fadeStrength, fadeStrength,
revealRadius,
]) ])
const gridRef = useRef<Mesh>(null!) const gridRef = useRef<Mesh>(null!)
@@ -99,6 +111,18 @@ export const Grid = ({
// Use custom raycasting for grid events (independent of mesh events) // Use custom raycasting for grid events (independent of mesh events)
useGridEvents(gridY) useGridEvents(gridY)
// Update cursor position from grid:move events
useEffect(() => {
const onGridMove = (event: GridEvent) => {
cursorPositionRef.current.set(event.position[0], -event.position[2])
}
emitter.on('grid:move', onGridMove)
return () => {
emitter.off('grid:move', onGridMove)
}
}, [])
useFrame((_, delta) => { useFrame((_, delta) => {
const currentLevelId = useViewer.getState().selection.levelId const currentLevelId = useViewer.getState().selection.levelId
let targetY = 0 let targetY = 0