相机跟随之轨道控制器

本文介绍了一个基于Three.js的轨道控制器实现,通过长按鼠标进行视角旋转、滚轮缩放和平移。控制器的核心是球坐标系,通过调整水平、竖直角度和半径来控制相机位置。文章提供了代码示例,并提出了未来改进的TODO列表,包括处理正交相机和触摸事件。
摘要由CSDN通过智能技术生成

效果

长按鼠标右键,旋转视角。
757ccc13dead023f4ee7e4e0715d6ed0.gif

鼠标滚轮,缩放视角。
b88b38f8dc76aebac13c5d13f0ce6830.gif

长按鼠标中键,平移视角。
a6b102c337d2262238514e4c78c42c2d.gif

如果你对这个模型感觉很熟悉,你肯定没看错,这是 threejs 中的 examples

https://threejs.org/examples/#webgl_animation_keyframes

dd8514dd1096b01484c357006e087162.jpeg

咱们就是从中借鉴(CCVV)出的代码,在抄的时候,感受其中的思路与思想,本文的重点就是分享其中的要领与精髓。

在此,感谢开源者们与模型作者等人的贡献。 4609e4ffe395fc69ac3d8f9406053c96.png

实现

思路

实现思路就是个球。


风在动还是树在动?长按鼠标,手指在动,模型也跟着动?

不,是心在动!

实际上是相机在动!

5e04e3433c0f5bef615771d5a3dda0ec.gif

此控制器叫做 OrbitControls , Orbit 是轨道的意思,轨道控制器的作用是让相机在一定的轨道上运行,就像是卫星环绕地球的轨道一样!

这个轨迹就是个球!!!相机就在这个球上做运动!

8e2f567b5d5f247dde42afc40a72d6fe.gif

如何让相机对着目标一直拍摄呢?简单地用 lookAt 就行喽!

scope.object.lookAt(scope.target);

球坐标系

既然原理思路是个球,自然用球坐标系去算相机的位置。
944a60867a577f3add6990e20f06a127.jpeg

此处加一个文章链接,讲述坐标系的那些事情:https://mp.weixin.qq.com/s/3vut2vfoQG6OH4OtMtZGsg

确定球坐标需要以下几点,而这些点正好对应了操作。

  • theta 水平方向角度,对应相机左右移动

  • phi 竖直角度,对应相机上下移动

  • radius 半径,对应相机与目标点的距离

  • target 圆心坐标,对应观察点的位置修改

此处直接贴上球坐标系的代码。assets\src\math\Spherical.ts

/**
 * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
 *
 * The polar angle (phi) is measured from the positive y-axis. The positive y-axis is up.
 * The azimuthal angle (theta) is measured from the positive z-axis.
 */

import { IVec3Like, math } from "cc";


class Spherical {
    radius: number = 1
    phi: number = 0
    theta: number = 0

    constructor(radius = 1, phi = 0, theta = 0) {

        this.radius = radius;
        this.phi = phi; // polar angle
        this.theta = theta; // azimuthal angle

        return this;

    }

    set(radius, phi, theta) {

        this.radius = radius;
        this.phi = phi;
        this.theta = theta;

        return this;

    }

    copy(other) {

        this.radius = other.radius;
        this.phi = other.phi;
        this.theta = other.theta;

        return this;

    }

    // restrict phi to be between EPS and PI-EPS
    makeSafe() {

        const EPS = 0.000001;
        this.phi = Math.max(EPS, Math.min(Math.PI - EPS, this.phi));

        return this;

    }

    setFromVector3(v) {

        return this.setFromCartesianCoords(v.x, v.y, v.z);

    }

    setFromCartesianCoords(x, y, z) {

        this.radius = Math.sqrt(x * x + y * y + z * z);

        if (this.radius === 0) {

            this.theta = 0;
            this.phi = 0;

        } else {

            this.theta = Math.atan2(x, z);
            this.phi = Math.acos(math.clamp(y / this.radius, - 1, 1));

        }

        return this;

    }

    clone() {
        return new Spherical().copy(this);
    }

    toVec3(out: IVec3Like) {
        const phi = this.phi;
        const radius = this.radius;
        const theta = this.theta;

        const sinPhiRadius = Math.sin(phi) * radius;
        out.x = sinPhiRadius * Math.sin(theta);
        out.y = Math.cos(phi) * radius;
        out.z = sinPhiRadius * Math.cos(theta);
        return this;

    }

}

export { Spherical };

再贴上同步相机的核心代码,具体逻辑可以参考下面的注释。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值