HarmonyOS 6.1 空间计算初探:把电商展厅搬进“虚实融合”新世界

系列番外·空间计算篇 。终章发布后,有读者留言:"现在都在聊Vision Pro和空间计算,鸿蒙在这方面有布局吗?能不能把我们这个电商Demo弄成3D的?" 答案是肯定的。HarmonyOS NEXT的ArkUI 3DSpatial Computing Kit 正是为此而生。今天作为系列的第一个番外篇,我们跳出手机屏幕的限制,将电商Demo升级为3D沉浸式购物空间。用户不再只是"刷列表",而是可以走进虚拟展厅,"拿起"商品查看细节,甚至把家具"摆放"在自己家里。全程基于API23,解决3D模型加载、手势交互、虚实锚定三大核心技术点。这是通往下一代操作系统的入场券。


一、前言:为什么电商是空间计算的"杀手级场景"?

回顾我们之前的系列,所有的交互都被局限在6英寸的矩形屏幕里。无论是滑动列表还是点击按钮,本质上都是在操作二维平面上的像素。

空间计算(Spatial Computing)打破了这个界限:

  • 从"看图片"到"看展品":以前的详情页是几张平面图,现在是一个可以720°旋转的3D模型。

  • 从"想象摆放"到"真实预览":买沙发不用凭空想象,直接把虚拟沙发"放"在客厅里,看看尺寸和风格是否合适。

  • 从"手指点击"到"自然交互":用手捏合来缩放商品,用手抛动作来切换视角,就像在现实世界一样自然。

HarmOS 6.1提供了低门槛的3D开发能力。我们不需要学习OpenGL或Unity复杂的Shader语言,直接用熟悉的ArkTS和类Compose的声明式语法就能构建3D场景。今天,我们就来给电商Demo加一个"3D展厅"页面。


二、核心概念辨析(2D UI vs 3D Scene)

很多前端开发者对3D有畏难情绪,其实只要理清这几个核心概念,上手非常快:

概念 2D UI (传统) 3D Scene (空间计算) 类比说明
坐标系 X(横), Y(纵) X(横), Y(纵), **Z(深)**​ 从画纸变成了雕塑台
基本单元 Column, Text, Image Scene, Node3D, Mesh 积木块变成了3D模型
位置 position({x:0, y:0}) position({x:0, y:0, **z:-5**}) Z轴负值表示远离镜头
旋转 rotate({angle: 90}) rotation({x:0, y:1, z:0, angle:90}) 指定绕哪个轴旋转
相机 屏幕即是相机 Camera组件 导演的眼睛,决定看哪里

💡 核心认知:ArkUI 3D的本质是把3D场景当作一个特殊的UI组件来渲染。我们可以在3D场景里嵌套2D的按钮(Overlay),也可以在2D页面里嵌入3D视口。这种混合渲染能力是鸿蒙的独特优势。


三、代码实现:构建3D商品展厅

3.1 环境准备与资源引入

  1. 模型准备 :3D开发离不开模型文件。常用的格式是.glb.gltf。我们可以从Sketchfab等网站下载免费的电商产品模型(如椅子、包包),放入entry/src/main/resources/rawfile/models/目录。

  2. 权限配置 :空间计算可能需要相机权限(用于虚实融合),在module.json5中添加:

    复制代码
    复制代码
    复制代码
    {
      "module": {
        "requestPermissions": [
          { "name": "ohos.permission.CAMERA", "reason": "AR空间锚定需要" }
        ]
      }
    }

3.2 构建3D场景组件

创建entry/src/main/ets/pages/SpatialShowroom.ets。这是我们的核心3D页面。

复制代码
复制代码
复制代码
import { scene } from '@kit.ArkGraphics3D'
import { abilityAccessCtrl } from '@kit.AbilityKit'

@Entry
@Component
struct SpatialShowroom {
  private scene: scene.Scene = null!
  private modelNode: scene.Node3D = null!
  @State rotationY: number = 0 // 控制模型Y轴旋转
  @State scale: number = 1.0 // 控制模型缩放

  aboutToAppear(): void {
    // 请求相机权限(用于AR模式)
    this.requestCameraPermission()
  }

  async requestCameraPermission(): Promise<void> {
    let atManager = abilityAccessCtrl.createAtManager()
    try {
      await atManager.requestPermissionsFromUser(getContext(this), ['ohos.permission.CAMERA'])
    } catch (err) {
      console.error('相机权限申请失败:', err)
    }
  }

  /**
   * 加载3D场景
   */
  onSceneCreated(scene: scene.Scene): void {
    this.scene = scene
    console.log('3D场景加载成功')

    // 1. 设置环境光(让模型更清晰)
    const light = scene.getNode('EnvLight') as scene.Light
    if (light) {
      light.intensity = 20000
    }

    // 2. 加载商品模型(例如一把椅子)
    scene.loadModel({
      path: 'models/chair.glb', // rawfile目录下的路径
      onLoaded: (node: scene.Node3D) => {
        this.modelNode = node
        console.log('模型加载成功:', node.name)
        // 调整模型位置和大小
        node.position = { x: 0, y: -1, z: -5 } // 稍微下移,后退
        node.scale = { x: 0.5, y: 0.5, z: 0.5 } // 缩小一半
      },
      onError: (err: Error) => {
        console.error('模型加载失败:', err)
      }
    })
  }

  build() {
    Stack() {
      // 3D场景视口(铺满全屏)
      SceneView({
        sceneOptions: {
          environment: scene.EnvironmentPreset.STUDIO // 使用工作室光照环境
        },
        onSceneCreated: (scene: scene.Scene) => this.onSceneCreated(scene)
      })
        .width('100%')
        .height('100%')

      // 叠加在3D场景上的2D UI(操作面板)
      Column() {
        // 标题
        Text('3D商品展厅')
          .fontSize(24)
          .fontColor(Color.White)
          .fontWeight(FontWeight.Bold)
          .shadow({ radius: 10, color: Color.Black })
          .margin({ top: 40 })

        Blank()

        // 底部操作栏
        Row() {
          // 旋转按钮
          Button('↻')
            .onClick(() => {
              this.rotationY += 45
              if (this.modelNode) {
                this.modelNode.rotation = { x: 0, y: 1, z: 0, angle: this.rotationY }
              }
            })
            .width(60)
            .height(60)
            .borderRadius(30)
            .backgroundColor('#0A59F7')

          // 缩放控制
          Slider({
            value: this.scale,
            min: 0.5,
            max: 2.0,
            step: 0.1
          })
            .width(150)
            .onChange((value: number) => {
              this.scale = value
              if (this.modelNode) {
                this.modelNode.scale = { x: value, y: value, z: value }
              }
            })

          // AR放置按钮(进阶功能)
          Button('AR')
            .onClick(() => {
              this.enterARMode()
            })
            .width(60)
            .height(60)
            .borderRadius(30)
            .backgroundColor('#4CAF50')
        }
        .width('90%')
        .justifyContent(FlexAlign.SpaceBetween)
        .margin({ bottom: 40 })
      }
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor(Color.Black)
  }

  /**
   * 进入AR放置模式(虚实融合)
   */
  enterARMode(): void {
    if (!this.scene) return
    // 切换到AR环境(需要设备支持,如Mate 60 Pro+)
    this.scene.switchEnvironment(scene.EnvironmentPreset.AR)
    // 提示用户点击地面放置模型
    promptAction.showToast({ message: '请点击地面放置商品' })
    // 监听点击事件,在点击位置放置模型
    this.scene.on('touch', (hitResult: scene.HitResult) => {
      if (hitResult.type === scene.HitType.PLANE) {
        if (this.modelNode) {
          // 将模型移动到点击的平面位置
          this.modelNode.position = hitResult.point
          promptAction.showToast({ message: '商品已放置' })
        }
      }
    })
  }
}

四、踩坑记录(官方文档没写的5个细节)

  1. 模型格式陷阱 :一定要用.glb格式,不要用.obj.fbx.glb是二进制格式,体积小,加载快,且支持PBR材质(金属、粗糙度),鸿蒙对其支持最好。.gltf是JSON格式,加载慢,不推荐。

  2. 坐标系手性 :鸿蒙3D使用的是右手坐标系(Y轴向上),而Unity等引擎常用左手坐标系。导入模型后如果发现上下颠倒,记得在Blender等建模软件中调整坐标轴方向,或者在代码里旋转90度。

  3. 性能瓶颈 :3D渲染非常耗电耗性能。不要在列表页一次性加载多个复杂3D模型。建议只在详情页进入全屏3D模式。同时,务必给模型做**LOD(多层次细节)**处理,远看用低模,近看用高模。

  4. AR模式的设备限制 :目前的EnvironmentPreset.AR主要依赖华为自研的Cyberverse技术,并非所有鸿蒙设备都支持(主要是旗舰机如Mate 60系列、Pura 70系列)。赶稿时如果设备不支持,可以用下面的浏览器模拟方案。

  5. 触摸事件穿透 :3D场景的触摸事件默认会吃掉所有点击,导致后面的2D按钮点不了。需要在SceneView上设置.hitTestBehavior(HitTestMode.None)或者在3D场景里手动转发事件给UI层。

相关推荐
不羁的木木1 天前
HarmonyOS技术精讲-Connectivity Kit:实战——多屏协同与文件快传应用
华为·wpf·harmonyos
ldsweet1 天前
《HarmonyOS技术精讲-Basic Services Kit》划词服务:构建系统级文本选取能力
华为·harmonyos
tyqtyq221 天前
HarmonyOS AI 应用开发实战:简历项目经历改写系统
人工智能·学习·华为·生活·harmonyos
2301_768103491 天前
HarmonyOS趣味相机实战第16篇:实时识别采样、Busy锁与Generation并发治理
harmonyos·arkts·并发控制·camerakit·corevisionkit
xd1855785551 天前
表情包配文-基于鸿蒙的AI表情包配文生成应用开发实践
人工智能·华为·harmonyos·鸿蒙
AD02271 天前
39-设置开关退出就复原-用偏好写队列和回滚状态兜住
harmonyos·arkts·鸿蒙开发
不羁的木木1 天前
HarmonyOS技术精讲-Connectivity Kit:蓝牙基础——经典蓝牙与BLE入门
华为·harmonyos
不羁的木木1 天前
HarmonyOS技术精讲-Connectivity Kit:自动设备发现与一键配网
华为·harmonyos
雪芽蓝域zzs1 天前
HarmonyOS开发 指纹验证和ESDSA加密
华为·harmonyos