资讯详情

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

发布时间:2026/9/27 1:49:13

500+
企业客户服务经验
120+
行业领域内容覆盖
3000+
原创页面设计沉淀
98%
客户满意度

《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 拾取。
热门专题

继续阅读更多专题内容

围绕企业服务、数字化转型与官网运营的常青话题,持续输出深度内容

企业官网建设指南 企业托管服务模式 财税政策与解读 企业数字化转型 官网SEO与获客 网站安全与运维
配套服务

读完这篇文章,了解更多服务

从整站搭建到SEO布局,17项核心服务助您打造高转化的企业官网

01

企业托管整站搭建

从信息架构到栏目预留,搭建可生长的企业站点骨架,每个页面独立原创设计。...

了解详情
02

规整可信网页设计

雪地靴温暖风原创设计,金属铜线条贯穿全页,拒绝通用模板与AI流水线。...

了解详情
03

企业服务SEO布局

关键词体系与语义化结构,从建站源头为搜索排名而生。...

了解详情
04

业务预约咨询表单

多场景表单与线索收集体系,把访问流量转化为可追踪的销售线索。...

了解详情
05

企业服务站点运维

安全巡检、数据备份与内容更新支持,全年守护网站稳定运行。...

了解详情
06

全终端商务适配

电脑、平板、手机一致呈现,移动端体验与转化同样出色。...

了解详情
需要专业建议?

让专业顾问为您解读行业趋势

关于企业官网建设、SEO获客与数字化转型的任何疑问,欢迎一对一咨询我们的专业顾问。