Canvas组件是你进入three.js的入口

Canvas组件是你开始定义你的React Three Fiber的场景的起点。

import React from 'react'
import { Canvas } from '@react-three/fiber'

const App = () => (
  <Canvas>
    <pointLight position={[10, 10, 10]} />
    <mesh>
      <sphereGeometry />
      <meshStandardMaterial color="hotpink" />
    </mesh>
  </Canvas>
)

Render Props 渲染属性

Canvas 画布

PROP

DESCRIPTION

DEFAULT

children

Threejs的JSX元素或者常规的组件元素

gl

传递给默认渲染器或者你自定义的渲染器的参数。

也可以接收一个同步执行的回调,比如 gl={canvas => new Renderer({ canvas })}

{}

camera

给默认的相机传递参数,或者是你自己的THREE.Camera

{ fov: 75, near: 0.1, far: 1000, position: [0, 0, 5] }

scene

给默认的场景传递参数,或者你自己的THREE.Scene

{}

shadows

给gl.shadowMap传递参数,如果想要设置PCFsoft也可以直接设置成true,或者也可以设置成'basic'、'percentage'、'soft'、'variance'其中一个

false

raycaster

给默认的raycaster传递参数

{}

frameloop

渲染模式:always, demand,never

always

resize

处理缩放的配置,可以看react-useMeasure的选项

{scroll:true, debounce:{scroll:50, resize:0}}

orthographic

创建一个orthographic相机

false

dpr

Pixel-ratio像素比设置,使用window.devicePixelRatio,或者自动使用[min,max]

[1,2]

legacy

在threejs r139及更新的版本中启用THREE.ColorManagement.legacyMode

false

linear

关闭自动sRGB编码和ganma矫正

false

events

事件管理配置,用函数或者状态

import { events } from '@react-three/fiber'

eventSource

事件订阅到哪个html元素

React.MutableRefObject<HTMLElement> , gl.domElement.parentNode

eventPrefix

被注入到canvas相关指针事件中x/y数据的前缀

offset

flat

是否使用THREE.NoToneMapping来替代THREE.ACESFilmicToneMapping

false

onCreated

在canvas元素渲染之后执行的回调(但是还没有committed)

(state) => {}

onPointerMissed

当鼠标或者其他指针类型的是被点击canvas区域但是没有点击到任何物体时触发

( event ) => {}

Render Default 渲染默认设置

Canvas使用createRoot方法来创建一个半透明的THREE.WebGLRenderer,创建的时候用的是下面这些参数:

antialias=true

alpha=true

powerPreference="high-performance"

同时设置了以下的属性:

outputEncoding = THREE.sRGBEncoding

toneMapping = THREE.ACESFilmicToneMapping

同时会同步创建以下的场景设置:

一个THREE.Perspective相机

如果orthographic设置为true的话,会创建一个THREE.Orthographic相机,即正交投影相机

如果shadows设置为true的话,会创建THREE.PCFSoftShadowMap

一个THREE.Scene(包含所有JSX渲染的内容)和一个THREE.Raycaster

在最近版本的 Three.js 中,THREE.ColorManagement.legacy 会被设置为 false,以便根据渲染器配置的颜色空间自动转换颜色。R3F 将处理纹理编码转换。在最近版本的 Three.js 中,为了根据渲染器配置的颜色空间自动转换颜色,THREE.ColorManagement.legacy 会被设置为 false。R3F 将负责处理纹理编码转换。关于这个问题可以查看这篇资料https://threejs.org/docs/#manual/en/introduction/Color-management.

Custom Canvas 自定义Canvas元素

R3F(three-react-fiber简称)可以渲染到根节点,类似于react-dom和所有其他React渲染器的工作方式。在自定义Canvas元素的情况下,如果您不需要,你可以删减掉react-dom(约40kb),react-use-measure(约3kb)以及pointer-events(约7kb)(否则需要显式导入事件并将其添加到配置中)。

根节点具有与Canvas相同的选项和属性,但你需要负责调整其大小。它需要一个的DOM <canvas>对象,用来渲染的目标。

CreateRoot

创建一个canvas对象最为根元素,来渲染JSX元素。

import * as THREE from 'three'
import { extend, createRoot, events } from '@react-three/fiber'

// Register the THREE namespace as native JSX elements.
// See below for notes on tree-shaking
extend(THREE)

// Create a react root
const root = createRoot(document.querySelector('canvas'))

// Configure the root, inject events optionally, set camera, etc
root.configure({ events, camera: { position: [0, 0, 50] } })

// createRoot by design is not responsive, you have to take care of resize yourself
window.addEventListener('resize', () => {
  root.configure({ size: { width: window.innerWidth, height: window.innerHeight } })
})

// Trigger resize
window.dispatchEvent(new Event('resize'))

// Render entry point
root.render(<App />)

// Unmount and dispose of memory
// root.unmount()

Tree-shaking 树摇 代码优化

从版本8开始,底层的调和器不再自动引入THREE命名空间。

这使得能够进行细粒度的目录分类,也可以通过extend API进行树摇。

import { extend, createRoot } from '@react-three/fiber'
import { Mesh, BoxGeometry, MeshStandardMaterial } from 'three'

extend({ Mesh, BoxGeometry, MeshStandardMaterial })

createRoot(canvas).render(
  <>
    <mesh>
      <boxGeometry />
      <meshStandardMaterial />
    </mesh>
  </>,
)

有一个官方的babel插件,可以帮你自动的处理这些工作

// In:

import { createRoot } from '@react-three/fiber'

createRoot(canvasNode).render(
  <mesh>
    <boxGeometry />
    <meshStandardMaterial />
  </mesh>,
)

// Out:

import { createRoot, extend } from '@react-three/fiber'
import { Mesh as _Mesh, BoxGeometry as _BoxGeometry, MeshStandardMaterial as _MeshStandardMaterial } from 'three'

extend({
  Mesh: _Mesh,
  BoxGeometry: _BoxGeometry,
  MeshStandardMaterial: _MeshStandardMaterial,
})

createRoot(canvasNode).render(
  <mesh>
    <boxGeometry />
    <meshStandardMaterial />
  </mesh>,
)