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

这篇具有很好参考价值的文章主要介绍了THREE.JS镜头随鼠标晃动效果。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

THREE.JS镜头随鼠标晃动效果,Three.js,javascript,前端,three.js
为了让动画更灵活并且简单 借助gsap让其具有更多可能,在未来更容易扩充其他动效
gsap Dom跟随鼠标移动 gsap.quickTo()


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

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

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

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

 private mousemove(e: MouseEvent) {
    const x = (e.clientX / innerWidth) * 2 - 1) ;
    const y = ((innerHeight - e.clientY) / innerHeight) * 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增加暂停动画的能力 以及mousemove时记录当前鼠标对相机的位置影响,松开鼠标,相机回去时直接回到mousemove中的位置


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) {
        const x = ((e.clientX / innerWidth) * 2 - 1) / this.amplitude;
        const y =
            (((innerHeight - e.clientY) / innerHeight) * 2 - 1) /
            this.amplitude;
        this.point.set(x, y);
        
        if (this.pause) {
            this.xQuickToTween && this.xQuickToTween.pause();
            this.yQuickToTween && this.yQuickToTween.pause();
        }else {
        	this.xQuickToTween = this.xQuickTo(this.cameraPosition.x + x);
        	this.yQuickToTween = this.yQuickTo(this.cameraPosition.y + y);
        }
    }
}

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);
    }
}

截至目前还有一个问题 ,鼠标松开后第一次移动鼠标 动画会闪一下,他的运动路线实际是鼠标按下的位置到当前鼠标移动的位置,因为mousemove中的quickTo被暂停了 mousemove开始动画是从上次播放的位置开始计算的,因此我们需要在mouseup后的mousemove传入quickTo第二哥参数 start 也就是从哪开始计算,这是松开鼠标后第一次 mousemove ,其他时候就可以穿入undefined让其自行计算。

 mouseMove(e: MouseEvent) {
        // -1  ~  1
        const x = (e.clientX / innerWidth) * 2 - 1;
        const y = ((innerHeight - e.clientY) / innerHeight) * 2 - 1;
        if (this.pause) {
            this.xQuickToTween && this.xQuickToTween.pause();
            this.yQuickToTween && this.yQuickToTween.pause();
            this.point.set(x, y);
        } else {
            this.xQuickToTween = this.xQuickTo(
                this.cameraPosition.x + x,
                Number.isNaN(this.point.x)
                    ? undefined
                    : this.cameraPosition.x + this.point.x
            );
            this.yQuickToTween = this.yQuickTo(
                this.cameraPosition.y + y,
                Number.isNaN(this.point.y)
                    ? undefined
                    : this.cameraPosition.y + this.point.y
            );
            this.point.set(NaN, NaN);
        }
    }

完整代码:

import { Vector2, Vector3 } from "three";
import { gsap } from "gsap";

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

    point = new Vector2();

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

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

    destroyMouseMove = () => {
        this.dom.addEventListener("mousemove", this.selfMouseMove);
    };

    mouseMove(e: MouseEvent) {
        // -1  ~  1
        const x = ((e.clientX / innerWidth) * 2 - 1) * this.amplitude;
        const y = (((innerHeight - e.clientY) / innerHeight) * 2 - 1) * this.amplitude;
        if (this.pause) {
            this.xQuickToTween && this.xQuickToTween.pause();
            this.yQuickToTween && this.yQuickToTween.pause();
            this.point.set(x, y);
        } else {
            this.xQuickToTween = this.xQuickTo(
                this.cameraPosition.x + x,
                Number.isNaN(this.point.x)
                    ? undefined
                    : this.cameraPosition.x + this.point.x
            );
            this.yQuickToTween = this.yQuickTo(
                this.cameraPosition.y + y,
                Number.isNaN(this.point.y)
                    ? undefined
                    : this.cameraPosition.y + this.point.y
            );
            this.point.set(NaN, NaN);
        }
    }
}

export class CameraShake extends Shake {
    constructor(...params: ConstructorParameters<typeof Shake>) {
        super(...params);
        this.dom.addEventListener("mousedown", this.selfMouseDown);
    }

    mouseDown = () => {
        this.pause = true;

        this.dom.addEventListener("mouseup", this.selfMouseUp, {
            once: true,
        });
    };

    selfMouseDown = () => this.mouseDown.call(this);

    mouseUp = () => {
   		 //鼠标按下又抬起未移动 point是NaN不能参与计算 也不需要计算
     	if (Number.isNaN(this.point.x)) return (this.pause = false);
        gsap.to(this.camera.position, {
            x: this.cameraPosition.x + this.point.x,
            y: this.cameraPosition.y + this.point.y,
            z: this.cameraPosition.z,
            duration: 0.5,
            onComplete: () => {
                this.pause = false;
            },
        });
    };

    selfMouseUp = () => this.mouseUp.call(this);

    destroyMouseEvent = () => {
        this.destroyMouseMove();
        this.dom.removeEventListener("mousedown", this.selfMouseDown);
    };
}


gitee仓库:
CameraShake.ts文章来源地址https://www.toymoban.com/news/detail-545941.html

到了这里,关于THREE.JS镜头随鼠标晃动效果的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • three.js 汽车行驶动画效果

    实现原理是使用TWEEN.Tween实现动画效果 使用Promise编写模型的异步加载方法 参数position是汽车初始位置,参数rotation是汽车初始朝向 调用: 第1个参数是汽车初始位置,第2个参数表示汽车初始朝向:西 参数start是行驶起点位置,参数end是行驶终点位置,参数speed是速度 this.mod

    2024年02月05日
    浏览(33)
  • Three.js中的3D文字效果

    对于一些设计网页中经常会出现一些3D的文字效果,本文将利用Three.js实现各种动画WebGL文本输入效果。 示例效果 原文章 通常情况下,文本网格是2D的平面形状,我们所要实现的3D文本形状则是要在2D的平面下,再生成z值形成一个立体的效果。 首先,我们创建一个canvas元素,

    2024年02月02日
    浏览(88)
  • Three.js--》实现图片转3D效果展示

    目录 项目搭建 初始化three.js基础代码 加载图片纹理 设置着色器 今天简单实现一个three.js的小Demo,加强自己对three知识的掌握与学习,只有在项目中才能灵活将所学知识运用起来,话不多说直接开始。 项目搭建 本案例还是借助框架书写three项目,借用vite构建工具搭建vue项目

    2024年02月08日
    浏览(37)
  • three.js实现雷达扫描效果(纹理贴图)

    three.js实现雷达扫描效果(纹理贴图) 图例 步骤 创建两个平面,分别纹理贴图,底图模型.add(光波模型) 关闭材质的深度测试 光波旋转 代码 图片(透明的)

    2024年02月01日
    浏览(33)
  • Three.js--》实现3D汽车展厅效果展示

    目录 项目搭建 初始化three.js基础代码 加载汽车模型 设置展厅效果 设置GUI面板动态控制车身操作 车门操作与车身视角展示 设置手动点击打开关闭车门 设置图片背景 今天简单实现一个three.js的小Demo,加强自己对three知识的掌握与学习,只有在项目中才能灵活将所学知识运用起

    2024年02月09日
    浏览(39)
  • Three 之 three.js (webgl)鼠标/手指通过射线移动物体的简单整理封装

    目录 Three 之 three.js (webgl)鼠标/手指通过射线移动物体的简单整理封装 一、简单介绍 二、实现原理 三、注意事项 四、效果预览 五、案例实现步骤 六、关键代码 Three js 开发的一些知识整理,方便后期遇到类似的问题,能够及时查阅使用。 本节介绍, three.js (webgl) 中,

    2024年02月16日
    浏览(35)
  • Three.js 实现模型材质分解,拆分,拆解效果

    原理:通过修改模型材质的 x,y,z 轴坐标 positon.set( x,y,z) 来实现拆解,分解的效果。 注意:支持模型材质position 修改的材质类型为 type=“Mesh” ,其他类型的材质修改了 position 可能没有实际效果 在上一篇 Three.js加载外部glb,fbx,gltf,obj 模型文件 的文章基础上新增一个 setModelMeshD

    2024年02月11日
    浏览(46)
  • vue 项目使用three.js 实现3D看房效果

    0.前言 该教程能帮助直接写出vue项目的3D看房效果!!! 先上效果图 1.安装依赖 2.vue代码 这里文件名为three.vue 代码非原创,出处 vue3+threejs实现全景看房 (异步加载 BOLLROOM 部件为对原代码的修改) 注意这里的hdr 文件必须要放在assets文件夹中,且要通过import模块的形式导入!

    2024年02月13日
    浏览(34)
  • web上构建3d效果 基于three.js的实例

    web页面上提供3D效果,可以为页面提供不少色彩,H5之后canvas 为webgl提供了基础,使得在web页面使用JS也能写出3D的效果,其中three.js作为封装了图形函数 的框架,为入门提供了方便,效果图如下。   以上是官方例子中其中的三个,没接触过的朋友肯定会觉得很神奇,事实上

    2024年02月05日
    浏览(28)
  • three.js OrbitControls.js 修改配置鼠标行为mouse和手势行为touch

    1. 引入three.js和OrbitControls.js 可以看一下OrbitControls.js源码,方便理解:https://threejs.org/examples/jsm/controls/OrbitControls.js 2. 重新配置鼠标和手势

    2024年02月16日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包