如何用React Three Fiber实现顶点带圆点的网格效果?
实现带圆点的网格(React Three Fiber)
问题分析
你之前用LineDashedMaterial尝试做虚线网格,但该材质只能生成线段式虚线,无法直接实现目标中的圆点效果。更合适的方式是采用平面几何体+自定义Shader材质,或批量渲染圆点实例,以下是两种可行方案:
方案一:自定义Shader材质(性能最优)
通过Shader在平面上计算并渲染圆点,仅需单个几何体,性能开销低,适合大尺寸网格:
import { Canvas } from '@react-three/fiber'; import * as THREE from 'three'; const DotGrid = () => { // 自定义Shader材质 const dotMaterial = new THREE.ShaderMaterial({ uniforms: { gridSize: { value: new THREE.Vector2(50, 50) }, // 网格整体宽高 dotSize: { value: 0.1 }, // 圆点直径 dotColor: { value: new THREE.Color(0xffffff) }, // 圆点颜色 gap: { value: 1 }, // 圆点间距 }, vertexShader: ` varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `, fragmentShader: ` uniform vec2 gridSize; uniform float dotSize; uniform vec3 dotColor; uniform float gap; varying vec2 vUv; void main() { // 将UV坐标映射为网格坐标 vec2 gridPos = vUv * gridSize / gap; // 计算当前点到最近网格交点的距离 vec2 dist = abs(fract(gridPos - 0.5) - 0.5) * gap; float closestDist = length(dist); // 仅渲染距离小于圆点半径的区域 if (closestDist < dotSize / 2.0) { gl_FragColor = vec4(dotColor, 1.0); } else { discard; } } `, transparent: true, }); return ( <mesh rotation-y={Math.PI / 2} position={[0, 12.5, 0]}> <planeGeometry args={[50, 50]} /> {/* 平面尺寸与gridSize对应 */} <primitive object={dotMaterial} attach="material" /> </mesh> ); }; function App() { return ( <Canvas frameloop="demand" camera={{ position: [75, 1, 0.1], zoom: 15 }}> <DotGrid /> </Canvas> ); } export default App;
参数调整说明
gridSize:控制网格的整体覆盖范围dotSize:调整单个圆点的大小gap:修改圆点之间的间隔距离dotColor:自定义圆点颜色
方案二:InstancedMesh批量渲染(新手友好)
如果对Shader不熟悉,可使用InstancedMesh批量生成圆点实例,性能优于单独创建数百个网格:
import { Canvas, useFrame, useRef } from '@react-three/fiber'; import * as THREE from 'three'; const DotGrid = () => { const gridCount = 50; // 网格行列数 const totalDots = gridCount * gridCount; const meshRef = useRef(); const dummy = new THREE.Object3D(); useFrame(() => { if (!meshRef.current) return; let index = 0; const step = 50 / gridCount; // 每个圆点的间隔步长 const offset = -25 + step / 2; // 网格中心偏移 // 遍历设置每个圆点的位置 for (let x = 0; x < gridCount; x++) { for (let z = 0; z < gridCount; z++) { dummy.position.set(offset + x * step, 12.5, offset + z * step); dummy.updateMatrix(); meshRef.current.setMatrixAt(index, dummy.matrix); index++; } } meshRef.current.instanceMatrix.needsUpdate = true; }); return ( <instancedMesh ref={meshRef} args={[null, null, totalDots]}> <circleGeometry args={[0.05, 16]} /> {/* 圆点的几何形状与精度 */} <meshBasicMaterial color="white" /> </instancedMesh> ); }; function App() { return ( <Canvas frameloop="demand" camera={{ position: [75, 1, 0.1], zoom: 15 }}> <DotGrid /> </Canvas> ); } export default App;
内容的提问来源于stack exchange,提问作者Quicksilver
相关产品推荐
相关产品推荐

