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>
)
}
原来我解决了这个问题:
- 创建网格时我真的很愚蠢。我忘记了 Canvas 对象中的 y 轴是翻转的,所以我的法线都乱七八糟。
- 灯光 中有一个阴影相机 属性 必须包含将渲染阴影的区域。我对此一无所知,还不得不稍微改变一下:
我在 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>
)
}
然后
我正在尝试让我自己的 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>
)
}
原来我解决了这个问题:
- 创建网格时我真的很愚蠢。我忘记了 Canvas 对象中的 y 轴是翻转的,所以我的法线都乱七八糟。
- 灯光 中有一个阴影相机 属性 必须包含将渲染阴影的区域。我对此一无所知,还不得不稍微改变一下:
我在 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>
)
}
然后