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

如何用Three JS和React-Three-Fibre基于缓冲数组渲染多个Points?

解决React Three Fiber中渲染多个Points的问题

你的代码存在几个关键问题导致无法渲染多个点,下面是具体修正方案:

1. 缓冲数组初始化错误

Float32Array 仅支持一维数组,直接传入二维数组会导致数据解析异常。同时Three.js的颜色值需要归一化到0-1区间(你当前使用的是0-255的RGB值,不符合要求)。

正确的缓冲数组创建方式:

// 位置:扁平化一维数组,每个点占3个元素(x,y,z)
const positions = new Float32Array([0,0,0, 3,3,3, 6,6,6]);
// 颜色:归一化到0-1区间,每个点占3个元素(r,g,b)
const colors = new Float32Array([92/255,123/255,23/255, 123/255,12/255,233/255, 23/255,98/255,198/255]);
// 大小:每个点占1个元素
const sizes = new Float32Array([1,2,3]);

2. 正确传递顶点属性到Points

在React Three Fiber中,需要通过bufferGeometry定义顶点属性,而非直接给Points传props。同时,顶点大小需要额外配置材质才能生效:

import { Points, BufferGeometry, pointsMaterial } from '@react-three/fiber';

// 组件内部代码
return (
  {/* 注意:Points无需包裹在mesh里,mesh用于网格模型渲染 */}
  <Points>
    <bufferGeometry>
      <bufferAttribute
        attach="attributes-position"
        count={3} // 点的总数量
        array={positions}
        itemSize={3} // 每个点的位置数据长度
      />
      <bufferAttribute
        attach="attributes-color"
        count={3}
        array={colors}
        itemSize={3}
      />
      <bufferAttribute
        attach="attributes-size"
        count={3}
        array={sizes}
        itemSize={1}
      />
    </bufferGeometry>
    <pointsMaterial
      vertexColors // 启用顶点颜色
      sizeAttenuation // 开启大小衰减(可选,让远点视觉上更小)
      onBeforeCompile={(shader) => {
        // 让材质读取自定义的顶点大小属性
        shader.vertexShader = `
          attribute float size;
          ${shader.vertexShader}
        `.replace(
          'gl_PointSize = size;',
          'gl_PointSize = size;'
        );
      }}
    />
  </Points>
);

3. 生成100个随机点的完整实现

如果要生成100个随机位置、颜色、大小的点,可通过循环生成扁平化数组:

import { useState, useMemo } from 'react';
import { Canvas, Points, BufferGeometry, pointsMaterial } from '@react-three/fiber';

const RandomPoints = () => {
  const pointCount = 100;
  
  // 用useMemo缓存缓冲数组,避免重复渲染时重新生成数据
  const { positions, colors, sizes } = useMemo(() => {
    const positionsArr = [];
    const colorsArr = [];
    const sizesArr = [];
    
    for (let i = 0; i < pointCount; i++) {
      // 随机位置:范围-10到10
      positionsArr.push(
        Math.random() * 20 - 10,
        Math.random() * 20 - 10,
        Math.random() * 20 - 10
      );
      // 随机颜色:归一化到0-1区间
      colorsArr.push(
        Math.random(),
        Math.random(),
        Math.random()
      );
      // 随机大小:范围1到5
      sizesArr.push(Math.random() * 4 + 1);
    }
    
    return {
      positions: new Float32Array(positionsArr),
      colors: new Float32Array(colorsArr),
      sizes: new Float32Array(sizesArr)
    };
  }, [pointCount]);

  return (
    <Points>
      <bufferGeometry>
        <bufferAttribute
          attach="attributes-position"
          count={pointCount}
          array={positions}
          itemSize={3}
        />
        <bufferAttribute
          attach="attributes-color"
          count={pointCount}
          array={colors}
          itemSize={3}
        />
        <bufferAttribute
          attach="attributes-size"
          count={pointCount}
          array={sizes}
          itemSize={1}
        />
      </bufferGeometry>
      <pointsMaterial
        vertexColors
        sizeAttenuation
        onBeforeCompile={(shader) => {
          shader.vertexShader = `
            attribute float size;
            ${shader.vertexShader}
          `.replace(
            'gl_PointSize = size;',
            'gl_PointSize = size;'
          );
        }}
      />
    </Points>
  );
};

export default function App() {
  return (
    <Canvas camera={{ position: [0, 0, 30] }}>
      <ambientLight />
      <RandomPoints />
    </Canvas>
  );
}

额外注意事项

  • Points是独立的渲染对象,不需要包裹在<mesh>组件内。
  • 使用useMemo缓存缓冲数组可提升性能,避免组件每次渲染都重新生成大量数据。
  • 如果不需要每个点大小不同,可去掉size相关属性,直接设置pointsMaterial的size固定值。

内容的提问来源于stack exchange,提问作者stopbanningmelmao123

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 10:10:34