手指在屏幕滑动时可以控制摄像机360度的绕着一个节点旋转?

最近想实现一下如下图功能。摄像机盯着一个节点,当你手指在屏幕滑动的时候,摄像机会按照你滑动的方向来旋转。

从论坛里抄了一些作业

 const rotateAround = (center: Vec3, axis: Vec3, angle: number, isLimit: boolean = false) => {
        let pos: Vec3 = this.node.position;// 当前节点就是摄像机
        let rot: Quat = Quat.fromAxisAngle(new Quat, axis, angle);
        let dir: Vec3 = Vec3.subtract(new Vec3, this.node.position, center);
        Vec3.transformQuat(dir, dir, rot);
        this.curOffset = new Vec3(dir);
        Vec3.add(pos, center, dir);

        var myrot = this.node.rotation;
        Quat.multiply(myrot, rot, myrot);
        if (isLimit) {
          let eulerAngle = new Vec3;
          myrot.getEulerAngles(eulerAngle);
          if (eulerAngle.x < -70 || eulerAngle.x > 70)
            return;
        }
        this.node.rotation = myrot;
      }
      //targetNode 是目标的节点
      rotateAround(this.targetNode.position, new Vec3(0, -1, 0), delta.x / 300);
      rotateAround(this.targetNode.position, Vec3.RIGHT, delta.y / 300, true) 

但是如果你旋转的角度越大,这个手指滑动的方向就偏移的越离谱。我感觉x,y分量分别绕旋转UP和RIGHT轴旋转是不对的。如果摄像机视角已经被旋转到了从头顶往下看或者从底部往上看的时候。手指滑动就已经错乱的厉害了。求个指导方法。哎,四元数真是太难了。

1赞

我贴个场景编辑里Alt+鼠标左键的Orbit效果代码给你参考:

// Orbit 操作模式
class OrbitMode extends ModeBase {
    private _rotateSpeed = 0.006;
    public async enter() {
        const node = this._cameraCtrl.node;
        node.getWorldPosition(this._curPos);
        node.getWorldRotation(this._curRot);

        this._cameraCtrl.view = MVec3.distance(this._curPos, this._cameraCtrl.sceneViewCenter);
        this._cameraCtrl.emit('camera-move-mode', CameraMoveMode.ORBIT);
        cce.Engine.enterState(cce.NeedAnimState.CAMERA_ORBIT);
    }

    public async exit() {
        cce.Engine.exitState(cce.NeedAnimState.CAMERA_ORBIT);
    }

    onMouseDown(event: ISceneMouseEvent): boolean {
        return false;
    }

    onMouseMove(event: ISceneMouseEvent): boolean {
        if (!event.leftButton) {
            return true;
        }

        const dx = event.moveDeltaX;
        const dy = event.moveDeltaY;

        const rot = this._curRot;
        const euler = cc.v3();
        MQuat.rotateX(rot, rot, -dy * this._rotateSpeed);
        MQuat.rotateAround(rot, rot, Vec3.UNIT_Y, -dx * this._rotateSpeed);
        MQuat.toEuler(euler, rot);
        MQuat.fromEuler(rot, euler.x, euler.y, 0); // clear rotate of z
        const offset = cc.v3(0, 0, 1);
        MVec3.transformQuat(offset, offset, rot);
        MVec3.normalize(offset, offset);
        MVec3.multiplyScalar(offset, offset, this._cameraCtrl.viewDist);
        MVec3.add(this._curPos, this._cameraCtrl.sceneViewCenter, offset);
        this._cameraCtrl.node.setWorldPosition(this._curPos);
        // this.node.setRotation(rot);
        const up = cc.v3(0, 1, 0);
        MVec3.transformQuat(up, up, rot);
        MVec3.normalize(up, up);
        this._cameraCtrl.node.lookAt(this._cameraCtrl.sceneViewCenter, up);
        this._cameraCtrl.updateGrid();

        return false;
    }

    onMouseUp(event: ISceneMouseEvent) {
        return false;
    }
}

export { OrbitMode };

MQuat和MVec3就是Quat和Vec3

2赞

好哎。稍微修改了一下就可以用啦。接下来附上完整的代码

  _curPos = new Vec3;
  _curRot = new Quat;
  onTouchMove(event: EventTouch) {

    this.node.getWorldPosition(this._curPos);
    this.node.getWorldRotation(this._curRot);
    const delta = event.getDelta();
    const dx = delta.x / 300;  //dx,dy的数值越大则旋转的越快
    const dy = delta.y / 300;
    const rot = new Quat(this._curRot);
    const euler = new Vec3();
    Quat.rotateX(rot, rot, dy);
    Quat.rotateAround(rot, rot, Vec3.UNIT_Y, -dx);
    Quat.toEuler(euler, rot);
    Quat.fromEuler(rot, euler.x, euler.y, 0); // clear rotate of z


    const offset = new Vec3(0, 0, 1);
    Vec3.transformQuat(offset, offset, rot);
    Vec3.normalize(offset, offset);
    Vec3.multiplyScalar(offset, offset, 10); //数字10表示当前距离摄像机距离目标物体的直线距离

    //this.targetNode 是希望绕着旋转的节点  this.node 就是摄像机自己
    Vec3.add(this._curPos, this.targetNode.worldPosition, offset);
    this.node.setWorldPosition(this._curPos);

    const up = new Vec3(0, 1, 0);
    Vec3.transformQuat(up, up, rot);
    Vec3.normalize(up, up);
    this.node.lookAt(this.targetNode.worldPosition, up);
  }

4赞