three.js学习笔记 1.基础概念

146 阅读3分钟

场景Scene

import * as Three from 'three'

const scene = new Three.Scene()

容纳了一切3d资源 包括物体、光源、摄像机等

网格Mesh

三点确定一个平面 常用若干拼接起来的三角形描述物体的表面 这就是网格
一个网格就是three.js里的一个3d物体
mesh具有位置、旋转、缩放等功能 但它只是一个基础框架
真正渲染的物体还需要几何体Geometry材质Material的支持

const geometry = new THREE.BoxGeometry(1,1,1)
const material = new THREE.MeshBasicMaterial({color:'red'})

const mesh = new THREE.Mesh(geometry, material)

几何体Geometry

geometry决定了mesh的形状(平面) 也包括法线以参与光照信息
three.js中预设了立方体 三角形 圆锥等形状 参考文档

const geometry = new THREE.BoxGeometry(1,1,1)

这就新建了一个立方体geometry
还可以使用BufferGeometry自定义几何体

材质Material

material决定了mesh看起来怎么样 与光的阴影和反射有关系
three.js中预设了许多材质 参考文档

const material = new THREE.MeshBasicMaterial({color:'red'})

创建一个基础的材质 不参与光照计算

纹理Texture

纹理可以让材质拥有图像的外观

const texture = new THREE.TextureLoader().load('/textures/wood.jpg');

const material = new THREE.MeshStandardMaterial({
  map: texture
});

加载第三方资源

使用three.js内置的Loader可以加载3d资源 参考文档 导入.glb或其他3d模型文件可以获取一个mesh的全部信息
.glb / .gltf文件使用GLTFLoader即可

光源

让物体有阴影和反光 只有材质受光照影响的时候才需要

摄像机

分为透视摄像机和正交投影摄像机
参考视频更清晰

透视摄像机

近大远小 类似人眼 image.png

正交投影摄像机

按某个方向垂直投影 类似三视图 image.png

react-three-fiber

这个库允许我们在react中便捷地配置three.js

// react-three-fiber
<Canvas>
  <mesh>
    <boxGeometry />
    <meshStandardMaterial />
  </mesh>
</Canvas>

// three.js
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000)

const renderer = new THREE.WebGLRenderer()
renderer.setSize(width, height)
document.querySelector('#canvas-container').appendChild(renderer.domElement)

const mesh = new THREE.Mesh()
mesh.geometry = new THREE.BoxGeometry()
mesh.material = new THREE.MeshStandardMaterial()

scene.add(mesh)

function animate() {
  requestAnimationFrame(animate)
  renderer.render(scene, camera)
}

animate()

这两种写法是完全等价的 react-three-fiber只是允许我们用jsx的方式配置动画 并会根据props自动更新、组件销毁时自动释放资源

layers

three.js具有图层的概念
一个图层使用0-31的数字标识 一个对象可以被分配至一个或多个图层
可以为摄像机设置图层 它会只拍摄该图层的内容
@react-three/fiber中 一般只支持用单个数字设置图层 多图层需要直接使用three中的Layers对象

世界坐标

mesh、光源等3D对象嵌套时 其position时相对其父元素的坐标
获取其世界坐标

const meshRef = useRef<Mesh>(null)

      <mesh castShadow ref={meshRef}>
        <boxGeometry></boxGeometry>
        <meshPhysicalMaterial color={'red'} />
      </mesh>
// 世界坐标
const worldPosition = meshRef.current.getWorldPosition(new Vector3())

getWorldPosition来自Object3D类型(即任何一个3d对象都有此函数)
getWorldPosition会将结果写在参数1 并将其作为返回值 这是为了变量的复用 避免频繁创建和销毁 还有两个函数可以进行坐标转换: localToWorld worldToLocal localToWorld将一个相对当前对象的坐标转化为世界坐标 也会把结果写入参数1中并返回
如果不想修改原对象 需要创建其复制作为参数

      const someVector = new Vector3(1, 1, 1)
      meshRef.current.worldToLocal(someVector.clone())

worldToLocal类似

测试和学习

fanethedivine.github.io/test-three/… 提供了多个参数的调整和实时反馈 image.png