跳到主要内容

构建场景

本指南介绍配置 @playcanvas/react 项目并创建简单三维场景,帮助理解核心概念。

最终效果如下:

使用 @playcanvas/react 构建的交互式三维场景。
信息

这里假设已了解 React;新用户可先阅读 React 官方文档。

我们逐步搭建,每一步都有代码和实时示例。

第一个场景​

若尚未安装,请先按安装指南 创建 React 项目。

npm create playcanvas@latest my-first-3d-app -- -f react

先显示一个盒体。场景需要 Application、Scene 和 Camera,才能看到内容。

将 /src/App.tsx 替换为以下代码:

/src/App.tsx
import { Application, Entity } from '@playcanvas/react'
import { Render, Camera } from '@playcanvas/react/components'

const Scene = () => {
return (<>
<Entity name='box'>
<Render type='box'/>
</Entity>
</>)
}

export const App = () => (
<Application>
<Entity name='camera' position={[0, 0, 5]}>
<Camera />
</Entity>
<Scene />
</Application>
)

运行或打开 Demo 标签后,可见中央方形。

代码做了什么?​

Application 初始化 HTML canvas 和渲染上下文。独立 Scene 包含带 Render 的 Entity。

Scene 将待渲染内容组织在一起,虽非强制,但便于管理。Entity 只是具有位置、旋转和缩放的容器,本身无显示;Render 赋予三维渲染能力。

提示

PlayCanvas 采用 ECS,通过向实体添加组件赋予功能。

Camera 挂到实体后,从其位置沿负 Z 渲染。位置设为 [0, 0, 5],与盒体保持距离,可修改观察效果。

添加灯光​

通过 Environment 或 Light 提供光照,类型详见灯光。此处使用自然的环境照明和一盏平行光,后续用来增强落地感。

运行后盒体出现明暗,下面解释新增概念。

加载资源​

useEnvAtlas 从 URL 加载环境图集,再传入 Environment。库还提供不同资源 hooks,帮助管理加载和错误状态。

详情见资源加载。

添加组件​

  • Environment:环境照明。
  • Light:场景灯光。
  • Render:盒体渲染。

即加载环境图集传入 Environment,再添加 Light。

添加交互​

使用 Script 挂载 CameraControls,让鼠标旋转摄像机观察盒体。Camera 还设置清屏颜色和视野角。

也可直接给实体添加事件监听,或通过 Script 定义行为。

使用 Script 组件​

Script 将自定义行为挂到 Entity,接入引擎更新循环,在 React 渲染之外逐帧运行,适合输入和动画。

提示

比每帧重新渲染 React 树更高效,但脚本可能覆盖 Entity props,需要注意。

运行后可用鼠标环绕盒体,更多内容详见脚本编程。

添加三维模型​

将盒体换为真实模型,可使用引擎支持的格式。Fab 提供许多免费模型。

现在应看到 Lamborghini。Render 改为渲染资源,useModel 加载模型并传入。加载期间返回 null,也可替换为加载指示,详见资源加载。

布置场景​

已有摄像机、可环绕模型与环境光,再添加地面和阴影,使用 ShadowCatcher 与 Grid 改善展示。

实时示例​

场景已完整,可加入自己的资源和脚本,详见资源加载。

实时编辑器
const Scene = () => {
  // load the assets
  const { asset: envAtlas } = useEnvAtlas('/assets/environment.png');
  const { asset: lambo } = useModel('/assets/lambo.glb');

  // if the assets haven't loaded, don't render anything
  if (!lambo || !envAtlas) return null;

  return <Entity name='model' >
    <Render type='asset' asset={lambo} />
    <Entity name='directional-light' position={[0, .001, 0]}>
      <Light type='directional' />
    </Entity>
    <Environment envAtlas={envAtlas} showSkybox={false} />
  </Entity>
}

const App = () => {
  return <Application>
    <ShadowCatcher width={5} depth={5} />
    <Entity name='grid' scale={[1000, 1, 1000]}>
      <Script script={GridScript}/>
    </Entity>
    <Entity name='camera' position={[4, 1, 4]}>
      <Camera clearColor='#090707' fov={28} renderSceneColorMap={true} />
      <Script script={CameraControls} enableFly={false}/>
    </Entity>
    <Scene />
  </Application>
}

render(<App />)
结果
Loading...

后续步骤​

掌握基础后,可以开始构建自己的场景,继续通过资源加载指南学习导入和脚本交互。

也可阅读概念指南,了解更多场景技术。