【问题标题】:@react-three/fiber to draw custom vertices@react-three/fiber 绘制自定义顶点
【发布时间】:2026-01-16 20:50:01
【问题描述】:

我正在尝试使用 @react-three/fiber 在 bufferGeometry 上绘制自定义网格。我看到无数教程教如何绘制点、球体、框、线。但是我不知道如何绘制自定义网格,并且很难阅读 three.js 文档,因为我使用的是具有不同语法的 react。有人能帮我吗?我只想做两个或更多三角形之类的事情:

const vertices = [ 
    0.0, 0.0, 0.0,
    1.0, 0.0, 0.0,
    0.0, 0.0, 1.0,

    1.0, 0.0, 0.0,
    0.0, 0.0, 1.0,
    1.0, 0.0, 1.0,

    ...
];

return (
    <mesh>
      <bufferGeometry ???>
        <bufferAttribute ??? />
      </bufferGeometry>
      <meshLambertMaterial attach="material" color="hotpink" />
    </mesh>
);

如果这是一个更好的解决方案,我的数据也可以做索引。

【问题讨论】:

    标签: react-three-fiber


    【解决方案1】:

    灵感来自Custom BufferGeometry in react-three-fiber的cmets

    我找到了答案:

    const vertices = new Float32Array([
      0.0, 0.0,  0.0,
      1.0, 0.0,  0.0,
      0.0, 1.0,  0.0,
        
      1.0, 0.0,  0.0,
      1.0, 1.0,  0.0,
      0.0, 1.0,  0.0
    ]);
    
    return (
      <mesh>
        <bufferGeometry>
          <bufferAttribute
            attachObject={["attributes", "position"]}
            array={vertices}
            itemSize={3}
            count={6}
          />
        </bufferGeometry>
        <meshStandardMaterial attach="material" color="hotpink" flatShading={true} />
      </mesh>
    )
    

    我注意到,three.js 仅在法线(来自著名的右手定则)指向屏幕外时才显示表面。因此,以下将不会显示

    const vertices = new Float32Array([
      0.0, 0.0,  0.0,
      0.0, 1.0,  0.0,
      1.0, 0.0,  0.0,
        
      1.0, 0.0,  0.0,
      0.0, 1.0,  0.0,
      1.0, 1.0,  0.0
    ]);
    

    更高级的使用需要自定义着色器。制服和属性允许用户传入对象的颜色(制服)或顶点的颜色(属性)。但是,需要更多的包来做用 glsl 编写的自定义着色器。 下面是一个使用属性传递颜色,同时使用变量插入颜色的示例。

    /**
     * Documentation: https://threejs.org/docs/#api/en/renderers/webgl/WebGLProgram
     * 
     * default vertex attributes provided by Geometry and BufferGeometry
     * attribute vec3 position;
     * attribute vec3 normal;
     * attribute vec2 uv;
     */
    
    import React from 'react';
    import { extend } from "@react-three/fiber";
    import { shaderMaterial } from '@react-three/drei';
    import * as THREE from 'three';
    import glsl from 'babel-plugin-glsl/macro';
    
    export default function Square() {
        const vertices = new Float32Array([
          0.0, 0.0,  0.0,
          1.0, 0.0,  0.0,
          0.0, 1.0,  0.0,
            
          1.0, 0.0,  0.0,
          1.0, 1.0,  0.0,
          0.0, 1.0,  0.0
        ]);
    
        const colors = new Float32Array([
          1.0, 0.0, 0.0,
          0.0, 1.0, 0.0,
          0.0, 0.0, 1.0,
    
          1.0, 0.0, 0.0,
          0.0, 1.0, 0.0,
          0.0, 0.0, 1.0,
        ]);
    
        // shaderMaterial's name must be <Something>ShaderMaterial
        // use extend below to add it to shader component
        // The component's first letter need to be uppercase when defined but lowercase when called.
        const SquareShaderMaterial = shaderMaterial(
            // Uniform -> Allow to pass data in object level from react component to glsl
            {
                uColor: new THREE.Color(0.0, 0.0, 1.0)
            },
            // Vertex Shader -> Corner points of polygons
            glsl`
                attribute vec3 color;
                varying lowp vec3 vColor;
                void main() {
                    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
                    vColor = color;
                }
            `,
            // Fragment Shader -> Color the polygon surface
            glsl`
                uniform vec3 uColor;
                varying lowp vec3 vColor;
                void main() {
                    gl_FragColor = vec4(vColor, 1.0); // modify to uColor if using uniform
                }
            `
        );
          
        extend({ SquareShaderMaterial });
        
        return (
          <mesh>
            <bufferGeometry>
              <bufferAttribute
                attachObject={["attributes", "position"]}
                array={vertices}
                itemSize={3}
                count={6}
              />
              <bufferAttribute
                attachObject={["attributes", "color"]}
                array={colors}
                itemSize={3}
                count={6}
              />
            </bufferGeometry>
            <squareShaderMaterial uColor="hotpink"/>
            
          </mesh>
        );
    }
    

    结果如下:

    【讨论】: