THREE.JS镜头随鼠标晃动效果

news2024/9/22 21:15:44

请添加图片描述
为了让动画更灵活并且简单 借助gsap让其具有更多可能,在未来更容易扩充其他动效
gsap Dom跟随鼠标移动 gsap.quickTo()


首先要监听鼠标移动,并且将移动的值转换到 -1 和 1 之间 方便处理
 private mousemove(e: MouseEvent) {
    const x = (e.clientX / innerWidth) * 2 - 1;
    const y = (e.clientY / innerHeight) * 2 - 1;
 }

这样将 位置 / 屏幕宽高 将值缩放在 0 和 1之间
然后通过 乘2减1 将其限制在-1 和 1之间

 private mousemove(e: MouseEvent) {
    const x = ((e.clientX / innerWidth) * 2 - 1) * 2 - 1;
    const y = ((e.clientY / innerHeight) * 2 - 1) * 2 - 1;
 }

在three中y轴 上面是1下面是-1 而我们窗口上面是-1 下面是1 所以取y轴剩余的高度让两者行为统一,也就是实现向着鼠标方向

 private mousemove(e: MouseEvent) {
    const x = ((e.clientX / innerWidth) * 2 - 1) * 2 - 1;
    const y = (((innerHeight - e.clientY) / innerHeight) * 2 - 1) * 2 - 1;
 }

如此 我们获取了鼠标移动的增量,将这一向量加在camera的x和y轴即可,这里不能使用+=这样会越来越偏 所以保存相机的原始位置。那么当前鼠标所在相机的位置,应当是原始位置加上鼠标移动的增量
这里就可以使用gsap来控制position变化

private xQuickTo = gsap.quickTo(this.camera.position, "x", {
	        duration: 0.5,
});

上述代码 this.camera.position.x 经过0.5秒后变化到传入值,如:this.xQuickTo(this.cameraPosition.x + x)

class Shake {
	cameraPosition = this.camera.position.clone();
	private xQuickTo = gsap.quickTo(this.camera.position, "x", {
	        duration: 0.5,
	});
	private yQuickTo = gsap.quickTo(this.camera.position, "y", {
	    duration: 0.5,
	});

	private mousemove(e: MouseEvent) {
        const x = ((e.clientX / innerWidth) * 2 - 1) / this.amplitude;
        const y =
            (((innerHeight - e.clientY) / innerHeight) * 2 - 1) /
            this.amplitude;

		this.xQuickTo(this.cameraPosition.x + x).play();
		this.yQuickTo(this.cameraPosition.y + y).play();
    }
	
}

如此 核心逻辑便完成,丰富事件监听并且加入振幅,控制相机移动范围 后完成这个class

export class Shake {
    /** 振幅 鼠标晃动的影响 */
    amplitude = 1;
    cameraPosition = this.camera.position.clone();
    private xQuickTo = gsap.quickTo(this.camera.position, "x", {
        duration: 0.5,
    });
    private yQuickTo = gsap.quickTo(this.camera.position, "y", {
        duration: 0.5,
    });

    constructor(public camera: THREE.Camera, public domElement: HTMLElement) {
        this.domElement.addEventListener("mousemove", this.selfMouseMove);
    }

    private mousemove(e: MouseEvent) {
        const x = ((e.clientX / innerWidth) * 2 - 1) / this.amplitude;
        const y =
            (((innerHeight - e.clientY) / innerHeight) * 2 - 1) /
            this.amplitude;

		this.xQuickTo(this.cameraPosition.x + x)
		this.yQuickTo(this.cameraPosition.y + y)
    }

    private selfMouseMove = (e: MouseEvent) => this.mousemove.call(this, e);

    destroyMouseMove() {
        this.domElement.removeEventListener("mousemove", this.selfMouseMove);
    }
}

接下来可以扩充一下功能, 加入鼠标按下时可以拖拽旋转,鼠标松开后回到原来的位置
为了支持这些功能 需要给shake增加暂停动画的能力


export class Shake {
    pause = false;
    /** 振幅 鼠标晃动的影响 */
    amplitude = 1;
    cameraPosition = this.camera.position.clone();
    xQuickTo = gsap.quickTo(this.camera.position, "x", {
        duration: 0.5,
    });
    yQuickTo = gsap.quickTo(this.camera.position, "y", {
        duration: 0.5,
    });
    private yQuickToTween: gsap.core.Tween | undefined;
    private xQuickToTween: gsap.core.Tween | undefined;
    point = new Vector2();

    constructor(public camera: THREE.Camera, public domElement: HTMLElement) {
        this.domElement.addEventListener("mousemove", this.selfMouseMove);
    }

    private mousemove(e: MouseEvent) {
        if (this.pause) {
            this.xQuickToTween && this.xQuickToTween.pause();
            this.yQuickToTween && this.yQuickToTween.pause();
            return;
        }
        //  -1 ~ 1
        const x = ((e.clientX / innerWidth) * 2 - 1) / this.amplitude;
        const y =
            (((innerHeight - e.clientY) / innerHeight) * 2 - 1) /
            this.amplitude;
        this.point.set(x, y);

        this.xQuickToTween = this.xQuickTo(this.cameraPosition.x + x);
        this.yQuickToTween = this.yQuickTo(this.cameraPosition.y + y);
    }

    private selfMouseMove = (e: MouseEvent) => this.mousemove.call(this, e);

    destroyMouseMove() {
        this.domElement.removeEventListener("mousemove", this.selfMouseMove);
    }
}

export class CameraShake extends Shake {
    constructor(...params: ConstructorParameters<typeof Shake>) {
        super(...params);
        this.domElement.addEventListener("mousedown", this.selfMouseDown);
    }
    
    mousedown() {
        if (this.pause) return;
        this.pause = true;
        document.addEventListener("mouseup", this.selfMouseUp, { once: true });
    }

    mouseup() {
        const { x, y, z } = this.cameraPosition;
        gsap.to(this.camera.position, {
            x: x + this.point.x,
            y: y + this.point.y,
            z,
            duration: 0.8,
            onComplete: () => {
                this.pause = false;
            },
        });
    }

    selfMouseDown = () => this.mousedown.call(this);
    selfMouseUp = () => this.mouseup.call(this);

    destroyMouseEvent() {
        this.destroyMouseMove();
        this.domElement.removeEventListener("mousedown", this.selfMouseDown);
    }
}

ok 上述代码将支持轨道控制器 旋转回来能力


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/735763.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

spring10-配置数据元

他的作用是提高我们程序性能的&#xff1a;我们怎么用呢&#xff01;先创建我们数据源对象&#xff1a;创建初始化对象之后&#xff0c;创建数据源对象之后&#xff0c;会给我们一些初始化资源。 使用完后还给他 &#xff0c;这是一种环保的思想。 常见的数据源&#xff1a;底…

干货-卷起来,企业级web自动化测试实战落地(二)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 WebDriver的基本使…

毫米波雷达 TI IWR1443 测试官方程序(Out Of Box Demo)

IWR1443 windows 文章目录 1、准备工作1.1、mmWave SDK1.2、Code Composer Studio&#xff08;CCS&#xff09;1.3、Uniflash1.4、TI Cloud Agent 2、导入工程3、烧录3.1、先将 IWR1443 调到 Flashing Mode3.2、使用 UniFlash 软件 4、运行GUI4.1、IWR1443 调到 Functional Mo…

【计算机组成与体系结构Ⅰ】实验0 Logisim 入门实验

一、实验目的 1&#xff1a;掌握加减法器工作原理。 2&#xff1a;能够设计出一个n位加减法器。 3&#xff1a;熟悉Logisim软件使用。 二、实验环境 &#xff08;1&#xff09;Logisim 2.7.1 &#xff08;2&#xff09;Microsoft Windows 10 三、实验内容 1&#xff1a;设…

FastAPI中如何正确理解和使用:async和await

1 缘起 项目需要, 技术选型使用FastAPI。 开发过程中,遇到需要异步操作的场景, 查阅相关FastAPI异步信息的过程中,发现了async和await组合技, 通过阅读官方文档和实际测试,发现,async和await并不是传统意义上的异步(如线程池异步执行任务), async和await的融合技是应…

SEGA: Semantic Guided Attention on Visual Prototype for Few-Shot Learning

方法比较简单&#xff0c;利用语义改进prototype&#xff0c;能促进性提升

如何系统学习分布式?

关键词&#xff1a;想要走存储/数据库方向的话&#xff0c;具体路线是啥&#xff1f;重点需要掌握精通哪些知识&#xff1f; 回答 那我简单说一下走存储/数据库这块的学习路线吧。 目前做存储比较热门的是分布式存储方向&#xff0c;有NoSQL的也有关系型数据库的&#xff0c…

21.DAC数模转换

1.STM32 DAC介绍&#xff1a; DAC(Digital to analog converter)即数字模拟转换器&#xff0c;它可以将数字信号转换为模拟信号。 DAC主要特性&#xff1a; 2个DAC转换器&#xff0c;每个转换器对应1个输出通道&#xff1b;8位或者12位单调输出&#xff1b;12位模式下数据左…

Coggle 30 Days of ML(23年7月)任务五:XGBoost训练与预测

Coggle 30 Days of ML&#xff08;23年7月&#xff09;任务五&#xff1a;XGBoost训练与预测 任务五&#xff1a;使用TFIDF特征和XGBoost完成训练和预测 说明&#xff1a;在这个任务中&#xff0c;你需要使用TFIDF特征和XGBoost算法完成训练和预测&#xff0c;进一步提升文本…

Matlab数学建模实战——(Lokta-Volterra掠食者-猎物方程)

1.题目 问题1 该数学建模的第一问和第二问主要是用Matlab求解微分方程组&#xff0c;直接编程即可。 求解 Step1改写 y(1)ry(2)f Step2得y的导数 y(1).2y(1)-ay(1)*y(2)y(2).-y(2)a*y(1)*y(2) Step3编程 clear; a0.01; F(t,y)[2*y(1)-a*y(1)*y(2);-y(2)a*y(1)*y(2)]; […

【Mac】Mac 通过路径找到对应的文件夹

mac 的快捷键 复制文件夹或文件全路径 命令&#xff1a;command Option C 跳转文件夹或文件 命令&#xff1a;command shift G 其他待补充

hexo #02 基本操作

本篇主要步骤 1、创建博客 1、创建博客 使用 $ hexo new [layout] <title>命令创建一篇新的博客。 PS hexo> npx hexo new post "test" Debugger attached. Debugger attached. INFO Validating config INFO Created: D:\hexo\source\_posts\test.md Wa…

MySQL表单查询以及多表查询

1.单表查询 CREATE TABLE emp ( empno int(4) NOT NULL, ename varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, job varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, mgr int(4) NULL DEFAULT NULL, hi…

基于51单片机的羽毛球计分器设计

功能&#xff1a; 本实例是基于51单片机的羽毛球计分器&#xff0c;主要硬件由51单片机最小系统&#xff0c;LCD1602液晶屏电路&#xff0c;按键电路构成。 1.本设计选用LCD1602液晶屏作为显示器件&#xff0c;用于记录两队的分数。 2.按照设计的功能模块共选用8个按键&#xf…

【软件测试】Git查看commit的提交历史(详细)一点即通...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 查看提交历史 在提…

【MATLAB第53期】基于MATLAB的TSK模糊神经网络时间序列预测模型,含短期预测未来功能

【MATLAB第53期】基于MATLAB的TSK模糊神经网络时间序列预测模型&#xff0c;含短期预测未来功能 一、效果展示 二、数据设置 数据采用一列数据滑动窗口设置为5 &#xff0c;可自行设置70%训练30%测试预测未来值为10 &#xff0c;可自行设置&#xff0c;控制10以内 三、模型…

zabbix proxy的配置及zabbix实现高可用(监控 windows,java应用,SNMP等)

目录 zabbix proxy 分布式代理服务器部署zabbix proxy 代理服务器部署 Zabbix 高可用集群Zabbix 监控 Windows 系统Zabbix 监控 java 应用Zabbix 监控 SNMP zabbix proxy 分布式代理服务器 zabbix 分布式代理服务器&#xff0c;可以代替zabbix server 采集性能和可用性数据。z…

C++的范围for语句详解 附易错实例

&#x1f4af; 博客内容&#xff1a;C读取一行内个数不定的整数的方式 &#x1f600; 作  者&#xff1a;陈大大陈 &#x1f680; 个人简介&#xff1a;一个正在努力学技术的准前端&#xff0c;专注基础和实战分享 &#xff0c;欢迎私信&#xff01; &#x1f496; 欢迎大家&…

匿名管道的使用示例

目录 整体框架 通信步骤 创建管道 ​编辑创建子进程&关闭相应的fd ​编辑 进程间通信 父子进程通信之间四种场景 实现父亲读&#xff0c;孩子写的进程间通信 管道通信的使用场景样例实现 整体框架 通信步骤 创建管道 pipe的参数为输出型参数&#xff0c;返回读写端…

从小白到大神之路之学习运维第55天--------shell脚本实例应用

第三阶段基础 时 间&#xff1a;2023年7月7日 参加人&#xff1a;全班人员 内 容&#xff1a; shell实例 目录 shell脚本应用&#xff1a; 一、shell脚本 二、环境变量的基本使用 三、条件测试 shell脚本应用&#xff1a; 一、shell脚本 1、shell脚本的作用shell解…