Trip1eLift
Trip1eLift

Reputation: 163

@react-three/fiber to draw custom vertices

I am trying to draw a custom mesh on bufferGeometry using @react-three/fiber. I saw countless tutorials teaching how to draw points, spheres, boxes, lines. But I couldn't figure out how to draw a custom mesh, and it's hard to read three.js documentation because I am using react which has a different syntax. Can someone help me? I just want to do something like two or more triangle:

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

The data I have can also do indices if that's a better solution.

Upvotes: 4

Views: 5184

Answers (2)

Astro Bear
Astro Bear

Reputation: 71

In the latest version it's a bit different:

const vertices = new Float32Array( [
    -1.0, -1.0,  1.0,
    1.0, -1.0,  1.0,
    1.0,  1.0,  1.0,

    1.0,  1.0,  1.0,
    -1.0,  1.0,  1.0,
    -1.0, -1.0,  1.0
  ] );
  return (
    <mesh>
      <bufferGeometry attach="geometry">
        <bufferAttribute attach="attributes-position" array={vertices} itemSize={3} count={6} />
      </bufferGeometry>
      <meshBasicMaterial attach="material" color="hotpink" />
    </mesh>
  );

Upvotes: 2

Trip1eLift
Trip1eLift

Reputation: 163

So inspired by the comments from Custom BufferGeometry in react-three-fiber

I found the answer:

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

I notice that three.js only displays the surface when the normal (from the famous right-hand rule) is pointing out of the screen. Therefore, the following will not be displayed:

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

A custom shader is needed for more advanced usage. Uniforms and attributes allow user to pass in color for the object (uniform) or color for vertex (attribute). However, more package is needed to do custom shader written in glsl. The following is an example of using attributes to pass color while using varying to interpolate color.

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

The result is the following:

React three fiber custom shader 101

Upvotes: 1

Related Questions