首页/新闻资讯/正文详情

《HarmonyOS 7 ArkGraphics 3D 空间设计开发实战》05:Camera控制、手势映射与空间浏览交互【鸿蒙心迹】

发布时间:2026/9/27 1:49:04 来源:云帆数科 栏目:资讯中心
《HarmonyOS 7 ArkGraphics 3D 空间设计开发实战》05:Camera控制、手势映射与空间浏览交互【鸿蒙心迹】
手指拖动200像素相机为什么不是在世界里移动200个单位前言前面四篇3D 房间已经能看了有家具、有材质、有灯光。但只能从一个固定视角看用户没法自己转一转、看一看。这一篇开始做交互单指拖动转视角双指缩放双指平移。看起来是很常见的手势但做起来有个很容易绕晕的问题ArkUI 手势给的是二维屏幕坐标像素单位。Camera 在三维世界里工作单位是世界坐标。手指拖动 200 像素不是相机在世界里移动 200 个单位——中间需要一层映射。很多人刚开始做的时候直接把手势 delta 加到相机位置上结果就是手指动一点相机飞出去十万八千里或者手指拖半天相机纹丝不动。这一篇就解决这个问题怎么把二维手势输入映射成三维空间里的相机旋转、缩放和平移。一、先搞清楚手势给的是什么相机需要的是什么先把两边的输入输出列清楚来源给的是什么单位ArkUI 手势手指在屏幕上移动了多少像素屏幕像素x, yCamera 需要的绕 Y 轴转了多少度Yaw、绕 X 轴转了多少度Pitch、离目标点多远Distance角度、世界单位这两个东西量纲都不一样不能直接加。需要一个转换系数屏幕上拖多少像素对应转多少度。举个例子如果用户手指在屏幕上从左到右拖满整个屏幕宽度比如 1080 像素我们希望相机正好绕 Y 轴转 360 度。那转换系数就是 360 / 1080 0.333 度每像素。也就是说手指拖 100 像素相机就转 33.3 度。这个系数不是固定的可以根据手感调整。有人喜欢灵敏一点有人喜欢稳一点。二、写一个 CameraController封装视角逻辑先写 CameraController把相机的状态和操作都封装进去import{scene}fromkit.ArkGraphics3DKit;exportclassCameraController{// 相机状态privateyaw:number0;// 绕Y轴旋转角度privatepitch:number-30;// 绕X轴俯仰角度privatedistance:number8;// 离目标点的距离privatetarget:{x:number,y:number,z:number}{x:0,y:0.5,z:0};// 观察目标点// 手势灵敏度privaterotateSensitivity:number0.3;// 每像素对应多少度privatezoomSensitivity:number0.01;// 每像素对应缩放多少privatecameraNode:scene.Node|nullnull;constructor(privatescene:scene.Scene){}/** * 初始化相机 */setupCamera():void{this.cameraNodethis.scene.createNode(MainCamera);constcamerathis.cameraNode.createComponent(scene.NodeComponentType.CAMERA)asscene.Camera;// 更新相机位置this.updateCameraTransform();this.scene.getRoot().addChild(this.cameraNode);console.info(CameraController: camera ready);}/** * 根据当前状态计算相机位置 */privateupdateCameraTransform():void{if(!this.cameraNode)return;// 球坐标转直角坐标根据yaw、pitch、distance算相机位置constradYawthis.yaw*Math.PI/180;constradPitchthis.pitch*Math.PI/180;constxthis.target.xthis.distance*Math.sin(radYaw)*Math.cos(radPitch);constythis.target.ythis.distance*Math.sin(radPitch);constzthis.target.zthis.distance*Math.cos(radYaw)*Math.cos(radPitch);this.cameraNode.position{x,y,z};// 相机始终看向目标点constcamerathis.cameraNode.getComponent(scene.NodeComponentType.CAMERA)asscene.Camera;camera.lookAtthis.target;}/** * 旋转视角单指拖动 */rotate(deltaX:number,deltaY:number):void{// deltaX 控制左右旋转yawthis.yawdeltaX*this.rotateSensitivity;// deltaY 控制上下俯仰pitchthis.pitchdeltaY*this.rotateSensitivity;// 限制俯仰角度不要转到天上或地下this.pitchMath.max(-80,Math.min(80,this.pitch));this.updateCameraTransform();}/** * 缩放双指捏合 */zoom(delta:number):void{this.distance-delta*this.zoomSensitivity;// 限制距离不要太近也不要太远this.distanceMath.max(2,Math.min(20,this.distance));this.updateCameraTransform();}}核心逻辑就在 updateCameraTransform() 里用 yaw左右角度、pitch俯仰角度、distance距离这三个参数算出相机在空间里的位置然后让相机看向目标点。这就是轨道相机Orbit Camera的基本模型相机绕着一个目标点转不是相机自己乱飞。三、把 ArkUI 手势接到 CameraController 上CameraController 写好了接下来接 ArkUI 的手势EntryComponentstruct SpaceRoomPage{privatecameraCtrl:CameraController|nullnull;build(){Stack(){scene.SceneView({scene:undefined}).width(100%).height(100%).gesture(// 单指拖动旋转PanGesture().onActionUpdate((event:GestureEvent){this.cameraCtrl?.rotate(event.offsetX,event.offsetY);})).gesture(// 双指捏合缩放PinchGesture().onActionUpdate((event:GestureEvent){// 双指距离变化来控制缩放this.cameraCtrl?.zoom(event.scale*10);}))}.width(100%).height(100%)}}这里有个坑PanGesture 的 event.offsetX 是本次手势开始到现在的总偏移不是每次回调的增量。也就是说手指从左边拖到右边拖了 500 像素第一次回调 offsetX 是 10第二次是 30第三次是 60……不是每次给你这次动了多少而是从手势开始到现在累计动了多少。所以正确的做法是记录上一次的位置每次算增量privatelastX:number0;privatelastY:number0;// onActionStart 的时候记录初始位置.onActionStart((){this.lastX0;this.lastY0;}).onActionUpdate((event:GestureEvent){// 本次增量 本次总偏移 - 上次总偏移constdeltaXevent.offsetX-this.lastX;constdeltaYevent.offsetY-this.lastY;this.cameraCtrl?.rotate(deltaX,deltaY);// 更新上次位置this.lastXevent.offsetX;this.lastYevent.offsetY;})这个坑特别常见。我第一次做的时候直接把 event.offsetX 加进去结果就是手指刚拖一下相机瞬间就转了 180 度因为 offsetX 是从手势开始累计的不是增量。四、加边界限制不要让相机穿墙开放的 3D 场景相机是可以随便跑的。但我们这个是房间内部相机不能穿墙不能转到房间外面去。两个限制俯仰角不要太极端不要转到天花板上面或者地板下面距离不要太近不要贴到家具里面刚才代码里已经加了// 限制俯仰角度在 -80 到 80 度之间this.pitchMath.max(-80,Math.min(80,this.pitch));// 限制距离在 2 到 20 之间this.distanceMath.max(2,Math.min(20,this.distance));这样用户再怎么拖相机也不会飞到离谱的位置。五、几个最容易踩的交互坑把这一篇遇到的坑总结一下坑现象解决办法手势坐标直接当世界坐标手指动一点相机飞出去加灵敏度系数像素转角度PanGesture 用了累计偏移不是增量刚开始拖一下相机转半圈记录上次位置每次算增量没有俯仰角限制相机转到天上或者地下pitch 限制在 -80 到 80 度没有距离限制缩放太近贴到模型里太远看不到distance 限制在 2 到 20拖动方向反了手指向右拖场景向左转deltaX 正负号调整一下手势太灵敏或者太迟钝手感不对调整 rotateSensitivity 参数这些问题都不是技术上做不到是手感调优。3D 交互的难点从来不是能不能转而是转起来是不是自然。总结第五篇的核心就一句话二维手势和三维相机之间必须有一层映射。ArkUI 手势给的是屏幕像素相机需要的是角度和距离不能直接加用轨道相机模型yaw左右转、pitch上下俯仰、distance距离三个参数控制相机PanGesture 给的是累计偏移要自己算每次的增量加边界限制俯仰角、距离都要有上下限不然相机乱飞灵敏度参数根据手感调没有标准答案SpaceRoom 现在用户可以自己转着看了。下一篇做更有意思的交互用户点一下沙发能选中它、移动它、删除它——也就是 3D 拾取。

相关推荐

通达信动静指标原理与实操校准指南
通达信动静指标原理与实操校准指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 1:49:04

车载以太网休眠唤醒验证:Kvaser Arcus三种部署形态与TC10实践
车载以太网休眠唤醒验证:Kvaser Arcus三种部署形态与TC10实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 1:48:52

Chrome被劫持修复指南:从原理到清理2024导航劫持木马完整方案
Chrome被劫持修复指南:从原理到清理2024导航劫持木马完整方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 1:48:52

树莓派5双2.5G网口扩展实战:PCIE Switch实现NVMe与网卡共存
树莓派5双2.5G网口扩展实战:PCIE Switch实现NVMe与网卡共存

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 2:34:58

25个真正可用的SVG图标网站推荐(开发者实测)
25个真正可用的SVG图标网站推荐(开发者实测)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 2:34:58

内存测试核心:Shmoo图与RMT分析原理及工程实践
内存测试核心:Shmoo图与RMT分析原理及工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 2:34:52

全志T113-S3 RGB屏移植避坑指南:从设备树到LVGL触摸校准
全志T113-S3 RGB屏移植避坑指南:从设备树到LVGL触摸校准

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 2:34:52

C++小游戏实战:从猜数字到丧尸生存,串联高频语法考点
C++小游戏实战:从猜数字到丧尸生存,串联高频语法考点

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 2:34:45

3步搞定wordpressnginx伪静态保姆级建站教程
3步搞定wordpressnginx伪静态保姆级建站教程

3步搞定wordpressnginx伪静态保姆级建站教程 自己不会代码,却想搭个像样的网站?别慌,很多创业团队负责人都卡在第一步。这篇保姆级建站教程,专为小白设计,让你避开坑,快速上线。 为什么伪静态是SEO命门… · 2026/9/27 2:34:45

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码