HarmonyOS APP《画伴梦工厂》开发第15篇:3D 模型渲染入门——@kit.ArkGraphics3D 初探
第2.7篇:3D 模型渲染入门——@kit.ArkGraphics3D 初探
难度:⭐⭐⭐ 高级
前置知识:2.5 视频播放器集成
涉及源文件:products/default/src/main/ets/pages/ModelViewerPage.ets

前言
在"画伴梦工厂"的绘画转动画流程中,3D 模型展示是一个重要的视觉环节。HarmonyOS 提供了 @kit.ArkGraphics3D 图形能力集,让开发者可以轻松加载 glTF/GLB 格式的 3D 模型,并在应用中渲染出精美的 3D 场景。
本篇将首次探索 ArkGraphics3D 的核心概念——Scene(场景)、Camera(相机)、Light(灯光)、Node(节点),并一步步实现从 glTF 文件加载到 3D 场景渲染的完整流程。
1. ArkGraphics3D 核心概念
在动手编码之前,先理清四个核心概念:
| 概念 | 说明 | 类比 |
|---|---|---|
| Scene(场景) | 3D 世界的容器,管理所有节点、相机、灯光 | 一个舞台 |
| Camera(相机) | 定义观察者的位置、视角范围、远近裁剪面 | 摄影师的眼睛 |
| Light(灯光) | 为场景提供光照,决定了物体的明暗和立体感 | 舞台灯光 |
| Node(节点) | 场景中的基本元素,可以是模型、空节点等 | 舞台上的演员 |
它们的关系是:Scene 包含 Camera、Light、Node,Camera 决定用户看到什么,Light 决定物体看起来什么样,Node 承载具体的模型数据。
2. 导入 ArkGraphics3D 模块
首先从 @kit.ArkGraphics3D 中导入需要的类型:
import {
Camera, Color, Light, LightType, Node,
Quaternion, RenderContext, RenderParameters,
Scene, SceneNodeParameters, SceneResourceFactory
} from '@kit.ArkGraphics3D';
这些类型涵盖了 3D 场景渲染的核心要素。注意 SceneResourceFactory 是用于创建相机和灯光的工厂类,Quaternion 用于处理旋转(下篇文章会详细展开)。
3. 加载 GLB 模型:Scene.load + importScene
加载一个标准 glTF/GLB 模型需要两步:
第一步:从 rawfile 资源加载源场景(sourceScene),此时模型数据位于 sourceScene 中。
第二步:创建一个新的空场景(scene),然后通过 importScene 将 sourceScene 中的模型节点导入到目标场景中。
private async loadGlbModel(): Promise<void> {
try {
this.status = '正在加载普通 GLB 模型';
// 从 rawfile 加载源场景
const sourceScene: Scene = await Scene.load($rawfile('assets/gltf/car.glb'));
// 创建空场景
const scene: Scene = await Scene.load();
// 将源场景中的模型导入到新场景的根节点下
const previewRoot: Node = scene.importScene('PreviewModel', sourceScene, scene.root);
previewRoot.visible = true;
// 设置模型位置和缩放
previewRoot.position.x = 0;
previewRoot.position.y = 0;
previewRoot.position.z = 0;
previewRoot.scale.x = 1;
previewRoot.scale.y = 1;
previewRoot.scale.z = 1;
// 配置相机和灯光
await this.setupDebugView(scene);
// 保存引用
this.activeScene = scene;
this.modelRoot = previewRoot;
// 应用初始旋转
this.applyModelRotation();
// 配置 SceneOptions 供 Component3D 使用
const options: SceneOptions = {
scene: scene,
modelType: ModelType.SURFACE
};
this.sceneOptions = options;
this.status = '普通 GLB 模型加载成功';
} catch (error) {
this.status = '普通 GLB 加载失败: ' + this.getErrorMessage(error as Error);
}
}
关键细节:
Scene.load()无参数调用创建一个空场景;Scene.load($rawfile(...))从 rawfile 加载包含模型的场景。scene.importScene(name, sourceScene, parentNode)将 sourceScene 中的完整节点树导入到当前场景,挂载到指定父节点下。ModelType.SURFACE表示使用表面渲染模式(相对于点云、线框等)。
4. 设置相机和灯光:SceneResourceFactory
通过 scene.getResourceFactory() 获取工厂实例,然后创建 Camera 和 Light。
4.1 创建 Camera
private async setupDebugView(scene: Scene): Promise<void> {
const factory: SceneResourceFactory = scene.getResourceFactory();
// 创建相机
const cameraParams: SceneNodeParameters = { name: 'DebugCamera' };
const camera: Camera = await factory.createCamera(cameraParams);
const clearColor: Color = {
r: 0.94,
g: 0.96,
b: 1,
a: 1 // 浅蓝灰色背景
};
camera.enabled = true;
camera.fov = Math.PI / 4; // 45° 视场角
camera.nearPlane = 0.1; // 近裁剪面 0.1
camera.farPlane = 1000; // 远裁剪面 1000
camera.clearColor = clearColor; // 背景色
camera.position.x = 0;
camera.position.y = 1.2; // 略微仰视
camera.position.z = 5; // 相机在 Z 轴正方向
this.debugCamera = camera;
// ... 创建灯光
}
Camera 关键属性解析:
| 属性 | 值 | 说明 |
|---|---|---|
fov |
Math.PI / 4 |
垂直视场角 45°,数值越大视野越宽 |
nearPlane |
0.1 |
近裁剪面,小于此距离的物体不可见 |
farPlane |
1000 |
远裁剪面,超出此距离的物体不可见 |
clearColor |
Color |
渲染前的背景清除颜色 |
position |
(0, 1.2, 5) |
相机在世界空间中的位置 |
clearColor 在这里设为浅蓝灰色 (0.94, 0.96, 1.0),给场景一个柔和的背景色。
4.2 创建 DIRECTIONAL 光源
// 创建平行光
const lightParams: SceneNodeParameters = { name: 'DebugLight' };
const light: Light = await factory.createLight(lightParams, LightType.DIRECTIONAL);
const lightColor: Color = {
r: 1,
g: 1,
b: 1,
a: 1 // 纯白光
};
light.enabled = true;
light.intensity = 8; // 光照强度
light.color = lightColor;
light.position.x = 0;
light.position.y = 3; // 从上方照射
light.position.z = 4;
this.debugLight = light;
}
Light 关键属性解析:
| 属性 | 值 | 说明 |
|---|---|---|
LightType.DIRECTIONAL |
平行光 | 模拟太阳光,所有光线平行 |
intensity |
8 |
光照强度,值越大越亮 |
color |
(1,1,1,1) |
纯白色 |
position |
(0, 3, 4) |
光源位置(对平行光而言是方向参考) |
平行光(DIRECTIONAL)的特点是光线方向一致、没有衰减,适合作为主光源照亮整个场景。
5. Component3D 渲染 3D 场景
模型加载完成后,通过 SceneOptions 配置场景,然后使用 Component3D 组件进行渲染:
// 构建 SceneOptions
const options: SceneOptions = {
scene: scene,
modelType: ModelType.SURFACE
};
this.sceneOptions = options;
在 UI 中使用 Component3D:
// @Builder
// private RenderPanel() {
// Stack() {
// if (this.sceneOptions !== null) {
// Component3D(this.sceneOptions)
// .width('100%')
// .height('100%')
// } else {
// Column() {
// LoadingProgress().width(36).height(36)
// Text(this.status).fontSize(14)
// }
// }
// }
// .width('90%').height(360).backgroundColor('#10131F')
// .borderRadius(18).clip(true)
// }
Component3D 是 ArkGraphics3D 提供的 ArkUI 组件,传入 SceneOptions 即可渲染 3D 场景。加载过程中可以用 LoadingProgress 显示等待状态。
6. requestRenderFrame 主动触发渲染
当模型旋转或场景发生变化时,需要主动请求渲染帧更新:
private requestRenderFrame(): void {
if (this.activeScene === null) {
return;
}
const params: RenderParameters = {
alwaysRender: true
};
this.activeScene.renderFrame(params);
}
RenderParameters 中的 alwaysRender: true 表示即使场景没有变化也强制渲染,确保每次更新都能立即呈现。
7. 模型文件与路径
private readonly modelPath: string = 'assets/gltf/car.glb';
private readonly gsModelUri: string = 'OhosRawFile://assets/gltf/car.glb';
modelPath:rawfile 中的相对路径。gsModelUri:OhosRawFile://协议 URI,专用于访问 rawfile 资源。
模型文件 car.glb 位于 entry/src/main/resources/rawfile/assets/gltf/ 目录下。
8. 完整流程总结
┌─────────────────────────────────────────────────┐
│ 加载流程总览 │
├─────────────────────────────────────────────────┤
│ │
│ Scene.load($rawfile) │
│ │ │
│ ▼ │
│ sourceScene(含模型数据) │
│ │ │
│ Scene.load() → 空 scene │
│ │ │
│ scene.importScene('Preview', sourceScene, root) │
│ │ │
│ ▼ │
│ previewRoot(模型节点) │
│ │ │
│ setupDebugView(scene) │
│ │ │
│ ├── factory.createCamera() │
│ └── factory.createLight(DIRECTIONAL) │
│ │ │
│ ▼ │
│ SceneOptions { scene, ModelType.SURFACE } │
│ │ │
│ ▼ │
│ Component3D(options) → 渲染 3D 场景 │
│ │
└─────────────────────────────────────────────────┘
小结
本篇我们完成了以下工作:
- 理解了 Scene / Camera / Light / Node 四者的角色与关系。
- 使用
Scene.load()加载 glTF 模型,并通过importScene导入场景。 - 使用
SceneResourceFactory创建 Camera 并配置fov、nearPlane、farPlane、clearColor、position。 - 使用
SceneResourceFactory创建 DIRECTIONAL 平行光 并配置intensity、color、position。 - 通过
SceneOptions+Component3D在 ArkUI 中渲染 3D 场景。 - 使用
renderFrame主动触发渲染更新。
这是 ArkGraphics3D 的入门基础,下篇将继续在本篇基础上实现手势拖拽旋转模型,让 3D 模型"动"起来。
下一篇预告:第2.8篇:手势交互——拖拽旋转 3D 模型
更多推荐

所有评论(0)