bufferGeometry 和阴影 react-three-fiber

bufferGeometry and shadow react-three-fiber

我正在尝试让我自己的 bufferGeometry 在 react-three-fiber 中工作,但我只是没有得到任何阴影。我想我对我的 bufferGeometry 的顶点、法线甚至 uv 都做得很好。我还尝试为面添加索引,但出于某种原因,这也弄乱了我的几何形状。

如果我在场景中放置一个小测试框,它会投射阴影。只有我的 bufferGeometry 似乎不起作用。

代码如下:

//MyGeometry.js -- it is stripe of quadrilaterals

import * as THREE from 'three'
import {useMemo} from 'react'

export default function MyGeometry({ position, L, W, res }) {

    const [vertices, faces, normals, uvs] = useMemo( () => 
    {
        const arr = [];
        const facesArr = [];
        const normsArr = [];
        const uvArr = []
        const triangle_pairs = Math.floor(L/res);
        const upper_left_corner = [
            position[0] - W/2,
            position[1] - L/2,
            position[2]
        ];

        for(let i=0; i<triangle_pairs; i++) {

            //v0
            const v0x = upper_left_corner[0] + Math.random()*(res/3);
            const v0y = upper_left_corner[1] + i*res + Math.random()*(res/3);
            const v0z = upper_left_corner[2] + Math.random()*(res/3);
            const v0 = new THREE.Vector3(v0x, v0y, v0z); //for computing normals
            //v1
            const v1x = upper_left_corner[0] + W + Math.random()*(res/3);
            const v1y = upper_left_corner[1] + i*res + Math.random()*(res/3);
            const v1z = upper_left_corner[2] + Math.random()*(res/3);
            const v1 = new THREE.Vector3(v1x, v1y, v1z); //for computing normals
            //v2
            const v2x = upper_left_corner[0] + Math.random()*(res/3);
            const v2y = upper_left_corner[1] + (i+1)*res + Math.random()*(res/3);
            const v2z = upper_left_corner[2] + Math.random()*(res/3);
            const v2 = new THREE.Vector3(v2x, v2y, v2z); //for computing normals
            //v3
            const v3x = upper_left_corner[0] + W + Math.random()*(res/3);
            const v3y = upper_left_corner[1] + (i+1)*res + Math.random()*(res/3);
            const v3z = upper_left_corner[2] + Math.random()*(res/3);
            const v3 = new THREE.Vector3(v3x, v3y, v3z); //for computing normals


            //UPPER triangle - 0,1,2

            //positions

            arr.push(v0x, v0y, v0z, v1x, v1y, v1z, v2x, v2y, v2z);

            //face, or indices

            facesArr.push(2*i, 2*i+1, 2*i+2);

            //normals

            const s21 = new THREE.Vector3();
            s21.copy(v2).sub(v1);
            const s01 = new THREE.Vector3();
            s01.copy(v0).sub(v1);
            const n1 = new THREE.Vector3();
            n1.copy(s21).cross(s01).normalize();
            normsArr.push(n1.x, n1.y, n1.z);
            normsArr.push(n1.x, n1.y, n1.z);
            normsArr.push(n1.x, n1.y, n1.z);

            //uvs
            uvArr.push(0,0, 1,0, 0,1)

            //LOWER triangle - 2,1,3
            
            //positions

            arr.push(v2x, v2y, v2z, v1x, v1y, v1z, v3x, v3y, v3z);

            //face, or indices

            facesArr.push(2*i+2, 2*i+1, 2*i+3);

            //normals

            const s31 = new THREE.Vector3();
            s31.copy(v3).sub(v1);
            const n2 = new THREE.Vector3();
            n2.copy(s31).cross(s21).normalize();
            normsArr.push(n2.x, n2.y, n2.z);
            normsArr.push(n2.x, n2.y, n2.z);
            normsArr.push(n2.x, n2.y, n2.z);

            //uvs
            uvArr.push(0,1, 1,0, 1,1);

        }        

        const vertices = new Float32Array(arr);
        const faces = new Uint16Array(facesArr);
        const normals = new Float32Array(normsArr);
        const uvs = new Float32Array(uvs);

        return [vertices, faces, normals, uvs];

    } 
    , []);

    return (
      <mesh castShadow={true} receiveShadow={true} position={position}>

        <bufferGeometry 
            attach="geometry"
        >
            <bufferAttribute
                attachObject={["attributes", "position"]}
                count={vertices.length / 3}
                array={vertices}
                itemSize={3}
            />

            <bufferAttribute
                attachObject={["attributes", "normal"]}
                count={normals.length / 3}
                array={normals}
                itemSize={3}
            />

            <bufferAttribute
                attachObject={["attributes", "uv"]}
                count={uvs.length / 2}
                array={uvs}
                itemSize={2}
            />
            
            //faces - for some reason if i uncomment this my geometry gets messed up
            {/* <bufferAttribute
                attach="index"
                count={faces.length}
                array={faces}
                itemSize={1}
            /> */}

        </bufferGeometry>

        <meshPhongMaterial attach="material" color="blue" />

      </mesh>
    )
}

然后在此处渲染

//Main.js

import { useRef, useState, useEffect } from 'react'
import { Canvas, useFrame, useThree } from 'react-three-fiber'
import { Box } from '@react-three/drei'
import MyCamera from '../three/MyCamera'
import MyGeometry from '../three/MyGeometry'


export default function Main() { 

  return (
    <div className="canvasContainer">
    <Canvas 
      linear = "true"
      frameloop="demand" 
      shadows = "true"
      shadowMap
    >
      <MyCamera position={[0, 5, 30]} infLimit={-200} supLimit ={200} />
      <ambientLight intensity={1}/>
      <mesh receiveShadow castShadow position={[0,0,0]}>
        <planeBufferGeometry attach="geometry" args={[1000, 1000]} />
        <meshStandardMaterial attach="material" color="gray" />
      </mesh>
      <MyGeometry position={[0, 0, 0]} L={10} W={5} res={10} />
    </Canvas>
    </div>
  )
}

原来我解决了这个问题:

  1. 创建网格时我真的很愚蠢。我忘记了 Canvas 对象中的 y 轴是翻转的,所以我的法线都乱七八糟。
  2. 灯光 中有一个阴影相机 属性 必须包含将渲染阴影的区域。我对此一无所知,还不得不稍微改变一下:

我在 MyCamera 对象中有一盏灯 我删除了它,而是在主要功能组件中创建了一个灯,为了访问这个阴影相机的东西,我必须在 useMemo 中命令性地创建它,并在 Canvas:

export default function Main() { 

  const dirLight = useMemo(()=>{
  
    const light = new THREE.DirectionalLight('white');
    light.castShadow=true;
    //Set up shadow properties for the light
    light.shadow.mapSize.width = 10240 // default
    light.shadow.mapSize.height = 10240 // default
    light.shadow.camera.near = 0.1 // default
    light.shadow.camera.far = 5000 // default
    light.shadow.camera.top = -100 // default
    light.shadow.camera.right = 100 // default
    light.shadow.camera.left = -100 // default
    light.shadow.camera.bottom = 100 // default
    return light
  
  },[])

  return (
    <div className="canvasContainer">
    <Canvas 
      linear = "true"
      frameloop="demand" 
      shadows = "true"
      shadowMap
    >
      
      <MyCamera position={[0, 0, 30]} infLimit={-1000} supLimit ={0} />
      
      <ambientLight intensity={0.2}/>

      <primitive object={dirLight} position={[30, 0, 30]} />
      <primitive object={dirLight.target} position={[0, 0, 0]}  />
      
      <mesh receiveShadow position={[0,0,-2]}>
        <planeBufferGeometry attach="geometry" args={[1000, 1000]} />
        <meshStandardMaterial attach="material" color="gray" />
      </mesh>
      
      <MyGeometry position={[0, 0, 0]} L={400} W={5} res={4} />

    </Canvas>
    </div>
  )
}

然后