鸿蒙开发-实战:用ArkGraphics3D做3D产品展示
这篇文章介绍了如何使用ArkGraphics 3D实现电商产品3D展示功能。主要内容包括: 整体流程:创建3D场景→设置相机→添加光照→加载模型→设置自动旋转→处理用户交互 核心功能实现: 通过Scene.load()创建3D场景 设置相机位置和朝向 添加方向光照明效果 加载glTF格式的3D模型 实现自动旋转功能(约60fps) 支持用户交互:拖动旋转和双指缩放 特色功能: 产品换肤功能(修改材
实战:用 ArkGraphics 3D 做 3D 产品展示
电商 APP 里越来越多地使用 3D 产品展示——用户可以 360 度旋转查看商品,比静态图片更直观。今天我们用 ArkGraphics 3D 来实现一个 3D 产品查看器。
3D产品展示整体流程
下面是3D产品展示的完整工作流程:
3D 产品展示的功能
- 加载 3D 模型:加载商品的 glTF 模型
- 旋转查看:用户可以拖动旋转模型
- 缩放:双指缩放
- 自动旋转:不操作时自动旋转展示
第一步:创建场景和相机
import { Scene, RenderContext, Node, Camera } from '@kit.ArkGraphics3D';
import { common } from '@kit.AbilityKit';
导入需要的模块。
@Entry
@Component
struct ProductViewer {
@State status: string = '加载中...';
@State rotationY: number = 0;
@State scale: number = 1;
private scene: Scene | null = null;
private productNode: Node | null = null;
private camera: Camera | null = null;
private isAutoRotating: boolean = true;
定义状态变量。
async aboutToAppear() {
await this.loadModel();
}
async loadModel() {
try {
// 创建场景
this.scene = await Scene.load();
Scene.load() 创建一个新的 3D 场景。
// 设置相机
this.camera = this.scene.mainCamera;
this.camera.position = { x: 0, y: 1, z: 3 }; // 相机在模型前方 3 米
this.camera.lookAt({ x: 0, y: 0, z: 0 }); // 看向原点
相机放在模型前方 3 米、上方 1 米的位置,看向原点。这样可以俯视模型,看到更好的展示效果。
第二步:设置光照
// 设置光照
let lightNode = this.scene.root.createChild('Light');
lightNode.light.type = 'directional';
lightNode.light.color = { r: 1, g: 1, b: 1 };
lightNode.light.intensity = 1;
lightNode.position = { x: 2, y: 3, z: 1 };
方向光(directional)模拟太阳光,从一个方向均匀照射。你也可以用点光源(point)或聚光灯(spot)来实现不同的光照效果。
第三步:加载 3D 模型
// 加载 3D 模型
let uri = "OhosRawFile://assets/gltf/product.glb";
this.productNode = await this.scene.load(uri, 0, this.scene.root);
OhosRawFile:// 指向项目的 rawfile 文件夹。.glb 是 glTF 的二进制格式,比 .gltf 更紧凑。
// 设置模型属性
this.productNode.position = { x: 0, y: 0, z: 0 };
this.productNode.scale = { x: 1, y: 1, z: 1 };
this.productNode.visible = true;
this.status = '加载成功';
设置模型的位置、缩放、可见性。
第四步:自动旋转
this.startAutoRotation();
} catch (err) {
this.status = `加载失败: ${err}`;
}
}
startAutoRotation() {
// 自动旋转
setInterval(() => {
if (this.isAutoRotating && this.productNode != null) {
this.rotationY += 1;
this.productNode.rotation = {
x: 0,
y: Math.sin(this.rotationY * Math.PI / 180),
z: 0,
w: Math.cos(this.rotationY * Math.PI / 180)
};
}
}, 16); // 约 60fps
}
每 16ms 更新一次旋转角度(约 60fps)。旋转用四元数表示,绕 Y 轴旋转的四元数是 (0, sin(θ/2), 0, cos(θ/2))。
第五步:用户交互
onDrag(deltaX: number, deltaY: number) {
// 用户拖动时停止自动旋转
this.isAutoRotating = false;
if (this.productNode != null) {
this.rotationY += deltaX * 0.5;
this.productNode.rotation = {
x: Math.sin(deltaY * Math.PI / 360),
y: Math.sin(this.rotationY * Math.PI / 180),
z: 0,
w: Math.cos(this.rotationY * Math.PI / 180)
};
}
}
用户拖动时停止自动旋转,根据拖动距离更新旋转角度。
onPinch(scale: number) {
if (this.productNode != null) {
this.scale = Math.max(0.5, Math.min(3, this.scale * scale));
this.productNode.scale = {
x: this.scale,
y: this.scale,
z: this.scale
};
}
}
双指缩放时更新模型大小,限制在 0.5-3 倍之间。
resetView() {
this.rotationY = 0;
this.scale = 1;
this.isAutoRotating = true;
if (this.productNode != null) {
this.productNode.rotation = { x: 0, y: 0, z: 0, w: 1 };
this.productNode.scale = { x: 1, y: 1, z: 1 };
}
}
重置视角。
第六步:换肤功能
changeColor(r: number, g: number, b: number) {
if (this.productNode == null) return;
// 遍历模型的所有材质,修改颜色
let meshCount = this.productNode.getChildCount();
for (let i = 0; i < meshCount; i++) {
let child = this.productNode.getChild(i);
if (child != null && child.material != null) {
child.material.baseColorFactor = { r, g, b, a: 1 };
}
}
}
修改材质的基础颜色(baseColorFactor),可以实现"换色"功能。这在电商 APP 中很常见——同一个商品,用户可以切换不同颜色查看效果。
第七步:页面布局
build() {
Column() {
Text('3D 产品展示')
.fontSize(20)
.margin({ top: 20 })
Text(this.status)
.fontSize(14)
.fontColor('#999999')
.margin({ top: 10 })
// 3D 渲染区域
// 实际项目中,这里会放一个 Scene 组件
// 支持拖动旋转和双指缩放
// 操作提示
Text('拖动旋转 | 双指缩放')
.fontSize(12)
.fontColor('#cccccc')
.margin({ top: 20 })
显示状态和操作提示。
// 控制按钮
Row() {
Button('重置视角')
.margin(10)
.onClick(() => this.resetView())
Button('自动旋转')
.margin(10)
.onClick(() => {
this.isAutoRotating = !this.isAutoRotating;
})
}
.margin({ top: 20 })
添加重置和自动旋转按钮。
// 颜色选择(换肤功能)
Text('选择颜色')
.fontSize(14)
.margin({ top: 20 })
Row() {
Button()
.width(40)
.height(40)
.backgroundColor('#ff4081')
.margin(5)
.onClick(() => this.changeColor(1, 0, 0))
Button()
.width(40)
.height(40)
.backgroundColor('#2196f3')
.margin(5)
.onClick(() => this.changeColor(0, 0.5, 1))
Button()
.width(40)
.height(40)
.backgroundColor('#4caf50')
.margin(5)
.onClick(() => this.changeColor(0, 0.8, 0))
Button()
.width(40)
.height(40)
.backgroundColor('#ff9800')
.margin(5)
.onClick(() => this.changeColor(1, 0.6, 0))
}
.margin({ top: 10 })
}
.width('100%')
.height('100%')
}
添加颜色选择按钮。
aboutToDisappear() {
if (this.scene != null) {
this.scene.destroy();
}
}
}
页面销毁时释放场景资源。
换肤功能实现流程
通过修改材质实现产品换色功能:
实际应用中的优化
1. 模型优化
- 减面:3D 模型的面数越少,加载和渲染越快。电商产品模型一般控制在 10 万面以内
- 压缩纹理:使用压缩纹理格式(如 KTX2),减少内存占用
2. 交互优化
- 惯性旋转:松手后模型继续旋转,逐渐减速
- 边界限制:限制旋转角度,防止模型翻转到看不到的位置
3. 加载优化
- 预加载:APP 启动时就预加载常用模型
- 缓存:加载过的模型缓存到本地
优化方向总结
3D产品展示需要在多个方面进行优化:
小结
3D 产品展示的核心:
Scene.load()创建场景scene.load(uri)加载 glTF 模型- 设置相机位置和光照
- 通过
Node.rotation实现旋转 - 通过
Node.scale实现缩放 - 通过
material.baseColorFactor实现换色
ArkGraphics 3D 提供了完整的 3D 场景管理能力,做产品展示绰绰有余。实际项目中,你需要重点关注模型优化和交互体验。
更多推荐



所有评论(0)