三.js,补间相机和鼠标移动事件 [英] three.js, tween camera and mousemove event

查看:30
本文介绍了三.js,补间相机和鼠标移动事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用three.js

我正在使用补间移动相机,效果很好.然而,在动画结束时,相机跳回其初始位置.

我发现 mousemove 事件导致了这种行为.如何解决此问题并同时保持补间移动和鼠标移动?

我基于这个例子构建了我的three.js;

在渲染函数中声明的鼠标移动

function render() {camera.position.x += ( mouseX - camera.position.x ) * 0.04;camera.position.y += ( - mouseY - camera.position.y ) * 0.04;相机.看(场景.位置);TWEEN.update();renderer.render(场景,相机);}

补间运动

 function setupTween(位置,目标,持续时间){TWEEN.removeAll();new TWEEN.Tween(位置).to(目标,持续时间).easing (TWEEN.Easing.Quadratic.InOut).onUpdate (功能() {//将传入位置复制到相机位置camera.position.copy(位置);}).开始();};

<块引用>

补间函数源码

更新

完整的工作代码:

解决方案

我认为,您应该只在不补间时通过 mousemove 事件更新位置.所以你需要检查它当前是否在补间.

var isTweening = false;新的 TWEEN.Tween (camera.position).to(目标,持续时间).easing (TWEEN.Easing.Quadratic.InOut).onStart(函数(){isTweening = true;}).onComplete(函数(){isTweening = false;}).开始();//在你的渲染循环中函数渲染(){如果 (!isTweening) {camera.position.x += ( mouseX - camera.position.x ) * 0.04;camera.position.y += ( - mouseY - camera.position.y ) * 0.04;}相机.看(场景.位置);TWEEN.update();renderer.render(场景,相机);}

您不需要设置onUpdate 函数并将新位置复制到camera.position.您可以将 camera.position 传递给补间,它就会起作用.

我没有看到示例的链接.现在,我知道使用哪种导航(实际上在很多three.js示例中都使用了).导致您的问题的不是 mousemove 事件,而是这种计算新相机位置的方法(camera.position.x += ( mouseX - camera.position.x ) * 0.04;).因此,我稍微更改了示例的代码,尤其是导航.以下是重要部分:

document.addEventListener('mousemove', onDocumentMouseMove, false );函数 onDocumentMouseMove( 事件 ) {mouseX = (event.movementX * 0.5) ||event.mozMovementX ||event.webkitMovementX ||0;mouseY = (event.movementY * 0.5) ||event.mozMovementY ||event.webkitMovementY ||0;}函数渲染(){if(!isTweening && (mouseX || mouseY)) {//更通用的方法,不只是转换 x 和 y(也许需要改进一下)var upVector = camera.up.clone().transformDirection(camera.matrix);var forwardVector = new THREE.Vector3().subVectors(scene.position, camera.position).normalize();var rightVector = new THREE.Vector3().crossVectors(forwardVector, upVector);camera.translateOnAxis(rightVector, mouseX);camera.translateOnAxis(upVector, -mouseY);鼠标X = 鼠标Y = 0;}相机.看(场景.位置);TWEEN.update();}函数 startTween() {isTweening = false;var target = new THREE.Vector3(getRandomNumber(), getRandomNumber(), getRandomNumber());新 TWEEN.Tween (camera.position.clone()).to(目标,1000).easing (TWEEN.Easing.Quadratic.InOut).onUpdate( 函数() {camera.position.copy(this);}).onStart(函数(){isTweening = true;}).onComplete(函数(){isTweening = false;}).开始();}函数 getRandomNumber() {//得到一个介于 -1000 到 -500 和 500 到 1000 之间的数字返回 ( Math.random() * 500 + 500 ) * ( Math.random() <0.5 ? -1 : 1 );}

您对 TWEEN.onUpdate 的看法是正确的:您需要将新值复制到 camera.position.我之前的方法也有效,但随后 THREE.Vector3 的所有功能都丢失了.直到现在我才意识到这一点.

I'm trying my hands on three.js

I am moving the camera using a tween, and it works quite good. At the end of the animation, however, the camera jumps back to its initial position.

I found out that the mousemove event was causing that behavior. How can i fix this problem and keep both the tween movement and the mouse move?

I have constructed my three.js based on this example;

Mousemove declared inside render function

function render() {

    camera.position.x += ( mouseX - camera.position.x ) * 0.04;
    camera.position.y += ( - mouseY - camera.position.y ) * 0.04;
    camera.lookAt( scene.position );

    TWEEN.update();

    renderer.render( scene, camera );
}

Tween movement

    function setupTween (position, target, duration) {
    TWEEN.removeAll();

    new TWEEN.Tween (position)
            .to (target, duration)
            .easing (TWEEN.Easing.Quadratic.InOut)
            .onUpdate (
                    function() {
                        // copy incoming position into camera position
                        camera.position.copy (position);
                    })
            .start();
};

tween function source

UPDATE

Complete working code:

<script>

    var container,
            i,
            camera,
            scene,
            renderer,
            particles,
            geometry,
            materials = [],
            color,
            sprite,
            size,
            mouseX = 0,
            mouseY = 0,
            isTweening,
            windowHalfX = window.innerWidth / 2,
            windowHalfY = window.innerHeight / 2;

    // +++++ three.js +++++
    // +++++ +++++ +++++ +++++ +++++
    function init() {
        container = document.createElement( 'div' );
        document.body.appendChild( container );
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.5, 2000 );
        camera.position.set (0,0,1900);

        scene = new THREE.Scene();
        scene.fog = new THREE.FogExp2( 0x000000, 0.0005 );
        geometry = new THREE.Geometry();
        var textureLoader = new THREE.TextureLoader();
        for ( i = 0; i < 1000; i ++ ) {
            var vertex = new THREE.Vector3();
            vertex.x = Math.random() * 2000 - 1000;
            vertex.y = Math.random() * 2000 - 1000;
            vertex.z = Math.random() * 2000 - 1000;
            geometry.vertices.push( vertex );
        }




        sprite = textureLoader.load( "circle.png" );
        color  = [0.90, 0.05, 0.8];
        size   = 8.5;
        materials = new THREE.PointsMaterial( { size: size, map: sprite, blending: THREE.AdditiveBlending, depthTest: false, transparent : false } );
        materials.color.setHSL( color[0], color[1], color[2] );
        particles = new THREE.Points( geometry, materials );
        scene.add( particles );


        renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
        renderer.setPixelRatio( window.devicePixelRatio );

        renderer.setSize( window.innerWidth, window.innerHeight );
        container.appendChild( renderer.domElement );

        document.addEventListener( 'mousemove', onDocumentMouseMove, false );
    }
    function onWindowResize() {
        windowHalfX = window.innerWidth / 2;
        windowHalfY = window.innerHeight / 2;
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();

        renderer.setSize( window.innerWidth, window.innerHeight );

    }
    function onDocumentMouseMove( event ) {
        mouseX = event.clientX - windowHalfX;
        mouseY = event.clientY - windowHalfY;
    }

    function animate() {
        requestAnimationFrame( animate );
        render();
    }

    function startTween() {

        isTweening = false;

        var target = new THREE.Vector3(getRandomNumber(), getRandomNumber(), getRandomNumber());

        new TWEEN.Tween (camera.position.clone())
                .to (target, 1000)
                .easing (TWEEN.Easing.Quadratic.InOut)
                .onUpdate( function() {
                    camera.position.copy(this);
                })
                .onStart ( function() {
                    isTweening = true;
                })
                .onComplete ( function() {
                    isTweening = false;
                })
                .start();
    }

    function getRandomNumber() {
        // get a number between -1000 and -500 and 500 and 1000
        return ( Math.random() * 500 + 500 ) * ( Math.random() < 0.5 ? -1 : 1 );
    }

    function render() {

        if(!isTweening && (mouseX || mouseY)) {
            // more a generic approach, not just transforming x and y (maybe it needs to be improved a bit)
            var upVector = camera.up.clone().transformDirection(camera.matrix);
            var forwardVector = new THREE.Vector3().subVectors(scene.position, camera.position).normalize();
            var rightVector = new THREE.Vector3().crossVectors(forwardVector, upVector);

            camera.translateOnAxis(rightVector, mouseX);
            camera.translateOnAxis(upVector, -mouseY);
            mouseX = mouseY = 0;
        }
        camera.lookAt( scene.position );

        TWEEN.update();

        renderer.render( scene, camera );
    }

    init();
    animate();


    setTimeout(function(){
        startTween();
    },2500);

</script>

解决方案

I think, you should only update the position by the mousemove event, when it's not tweening. So you need to check if its currently tweening or not.

var isTweening = false;

new TWEEN.Tween (camera.position)
    .to (target, duration)
    .easing (TWEEN.Easing.Quadratic.InOut)
    .onStart ( function() {
        isTweening = true;
    })
    .onComplete ( function() {
        isTweening = false;
    })
    .start();

// in your render loop
function render() {

    if (!isTweening) {
        camera.position.x += ( mouseX - camera.position.x ) * 0.04;
        camera.position.y += ( - mouseY - camera.position.y ) * 0.04;
    }
    camera.lookAt( scene.position );

    TWEEN.update();

    renderer.render( scene, camera );
}

You don't need to set an onUpdate function and copy the new position to camera.position. You can just pass over camera.position to the tween and it will work.

EDIT:

I didn't see the link to example. Now, I know which kind of navigation is used (which is actually used in a lot of three.js examples). It's not the mousemove event that is causing your problem, it's this kind of calculating the new camera position (camera.position.x += ( mouseX - camera.position.x ) * 0.04;). So, I changed the code of the example a bit, especially the navigation. Here are the important parts:

document.addEventListener( 'mousemove', onDocumentMouseMove, false );

function onDocumentMouseMove( event ) {
    mouseX = (event.movementX * 0.5) || event.mozMovementX || event.webkitMovementX || 0;
    mouseY = (event.movementY * 0.5) || event.mozMovementY || event.webkitMovementY || 0;
}

function render() {

    if(!isTweening && (mouseX || mouseY)) {
        // more a generic approach, not just transforming x and y (maybe it needs to be improved a bit)
        var upVector = camera.up.clone().transformDirection(camera.matrix);
        var forwardVector = new THREE.Vector3().subVectors(scene.position, camera.position).normalize();
        var rightVector = new THREE.Vector3().crossVectors(forwardVector, upVector);

        camera.translateOnAxis(rightVector, mouseX);
        camera.translateOnAxis(upVector, -mouseY);
        mouseX = mouseY = 0;
    }
    camera.lookAt( scene.position );

    TWEEN.update();
}

function startTween() {

    isTweening = false;

    var target = new THREE.Vector3(getRandomNumber(), getRandomNumber(), getRandomNumber());

    new TWEEN.Tween (camera.position.clone())
        .to (target, 1000)
        .easing (TWEEN.Easing.Quadratic.InOut)
        .onUpdate( function() {
            camera.position.copy(this);
        })
        .onStart ( function() {
            isTweening = true;
        })
        .onComplete ( function() {
            isTweening = false;
        })
        .start();
}

function getRandomNumber() {
    // get a number between -1000 and -500 and 500 and 1000
    return ( Math.random() * 500 + 500 ) * ( Math.random() < 0.5 ? -1 : 1 );
}

And you are right about TWEEN.onUpdate: you need to copy the new values to camera.position. My earlier approach do also work, but then all of the functionality of THREE.Vector3 gets lost. I didn't realize that until now.

这篇关于三.js,补间相机和鼠标移动事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆