You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 09:53:11