You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化Phaser 3中可旋转地球的点击拖拽交互使其更直观?

解决Phaser 3 3D模型拖拽旋转的直觉交互问题

问题的核心在于直接修改欧拉角时,X轴旋转基于全局坐标系而非模型当前的局部坐标系。当模型绕全局Y轴旋转后,继续用全局X轴旋转会出现不符合直觉的拖拽表现——正确逻辑应该是:鼠标左右拖拽时绕全局Y轴旋转(保持世界上下方向固定),鼠标上下拖拽时绕模型当前的局部X轴旋转(让模型正面区域随鼠标方向移动)。

解决方案:用四元数实现局部坐标系旋转

Phaser的Math.Quaternion可方便处理局部旋转,避开欧拉角的旋转顺序和万向锁问题。具体步骤如下:

  1. 初始化时用四元数维护模型旋转状态(替代直接修改modelRotation)
  2. 在pointermove事件中,将垂直拖拽转换为模型局部X轴旋转,水平拖拽保持为全局Y轴旋转
  3. 将四元数转回匹配Phaser要求的欧拉角,赋值给mesh.modelRotation

代码实现:

首先在场景初始化时定义四元数变量:

// 场景类内部定义
this.modelQuat = new Phaser.Math.Quaternion();

然后替换pointermove中的旋转逻辑:

// pointermove事件回调内
const rotateRate = 0.01; // 按需调整旋转速率

// 水平拖拽:绕全局Y轴执行外在旋转
const yRot = pointer.velocity.x * rotateRate / 800;
const globalYQuat = new Phaser.Math.Quaternion().setFromAxisAngle(new Phaser.Math.Vector3(0,1,0), yRot);

// 垂直拖拽:绕模型当前局部X轴执行内在旋转
const xRot = pointer.velocity.y * rotateRate / 600;
const localXQuat = new Phaser.Math.Quaternion().setFromAxisAngle(new Phaser.Math.Vector3(1,0,0), xRot);

// 先应用局部X旋转,再叠加全局Y旋转(顺序不可颠倒)
Phaser.Math.Quaternion.multiply(this.modelQuat, localXQuat, this.modelQuat);
Phaser.Math.Quaternion.multiply(globalYQuat, this.modelQuat, this.modelQuat);

// 将四元数转换为Phaser要求的ZXY顺序外在欧拉角
const euler = new Phaser.Math.Euler().setFromQuaternion(this.modelQuat, 'ZXY');
mesh.modelRotation.x = euler.x;
mesh.modelRotation.y = euler.y;
mesh.modelRotation.z = euler.z;

逻辑说明

  • 局部X轴旋转:通过四元数乘法顺序,先基于模型当前姿态(局部坐标系)绕X轴旋转,确保鼠标上下拖拽时,模型正面区域始终跟随鼠标方向移动
  • 全局Y轴旋转:绕世界空间Y轴旋转,保持左右拖拽时世界上下方向固定,符合用户对“左右旋转”的直觉
  • 适配Phaser旋转规则:转换欧拉角时指定ZXY顺序,完美匹配modelRotation的外在旋转逻辑

可选优化:限制翻转范围

如果需要避免模型过度翻转(类似Google Earth的限制),可在转换欧拉角后对X轴旋转值做约束:

euler.x = Phaser.Math.Clamp(euler.x, -Math.PI/2, Math.PI/2);

内容的提问来源于stack exchange,提问作者Kylok

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 13:30:00