@react-three/fiber 绘制自定义顶点

@react-three/fiber to draw custom vertices

我正在尝试使用@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>
);

我手头的数据也可以做索引,如果那是更好的解决方案。

受到 Custom BufferGeometry in react-three-fiber

评论的启发

我找到了答案:

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>
    );
}

结果如下: