-5

我正在尝试用 THREE.JS 制作类似星际争霸的游戏。

我在其 Y 轴上旋转对象以面对新方向,然后更改位置时遇到问题。

并且通过旋转我的意思是动画/所以请停止使用糟糕的lookAt()函数

如果有人告诉我如何补间一些魔法 obj.MatrixRotationY(angle),我将不胜感激,并且我希望从 Vector3 计算出该角度

这是我到目前为止所拥有的:

http://f.cl.ly/items/3J3R0X2q2R1h1J203C1V/drone.jpg

我从 Vector3 中获得了新的位置,如下所示。

// scene
var container;
var camera, scene, renderer;

// intersect with objects in this array
var intersectObjects    = [];

// materials
var material = new THREE.MeshNormalMaterial();
var cristal_texture = new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture("models/JSON/textures/cristal.jpg") });
var destination;

init();
animate();


function init() {

    container = document.createElement( 'div' );
    document.body.appendChild( container );

    camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 15000 );
    camera.rotation.x = - 90 * ( Math.PI / 180 );
    camera.position.set( 800 , 1000 , 0 );

    scene = new THREE.Scene();

    plane = new THREE.Mesh( new THREE.PlaneGeometry( 3000, 3000 ), new THREE.MeshBasicMaterial( { color: 0xe0e0e0 } ) );
    plane.rotation.x = - 90 * ( Math.PI / 180 );
    plane.position.set(0,0,0);
    plane.overdraw = true;
    scene.add( plane );
    intersectObjects.push(plane);

    loader = new THREE.JSONLoader();
    loader.load( "models/JSON/driller.js", function( geometry ) {
        driller = new THREE.Mesh( geometry, material );
        driller.position.set(0,50,0);
        matr = new THREE.Matrix4();     
        driller.matrixAutoUpdate = false;
        driller.geometry.applyMatrix( matr.makeRotationY( 0 ) );
        driller.scale.set(0.5,0.5,0.5);
        scene.add( driller );
    });

    loade = new THREE.JSONLoader();
    loade.load( "models/JSON/cristal.js", function( geometry ) {
        cristal = new THREE.Mesh( geometry, cristal_texture );
        cristal.position.set(-1450,0,1450);
        matre = new THREE.Matrix4();        
        cristal.matrixAutoUpdate = false;
        cristal.geometry.applyMatrix(matre.makeRotationY( 0 ));
        cristal.scale.set(0.5,0.5,0.5);         
        scene.add( cristal );
        intersectObjects.push(plane);
    });

    // lightning properties
    var ambientLight = new THREE.AmbientLight(0xFFFFFF);
    scene.add(ambientLight);
    scene.matrixAutoUpdate = false;

    // render engine
    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.sortObjects = false;
    container.appendChild( renderer.domElement );

    // event listeners
    document.addEventListener('mouseup', onMouseUp, false);


}

function onMouseUp(event) {

    event.preventDefault();        
    x_pos = (event.clientX / window.innerWidth) * 2 - 1;
    y_pos = -(event.clientY / window.innerHeight) * 2 + 1;
    z_pos = 0.5;

    var vector = new THREE.Vector3( x_pos , y_pos , z_pos );

    var projector = new THREE.Projector();
    projector.unprojectVector(vector, camera);
    var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
    var intersects = raycaster.intersectObjects(intersectObjects);

    if (intersects.length > 0) {

        xp = intersects[0].point.x.toFixed(2);
        yp = intersects[0].point.y.toFixed(2);
        zp = intersects[0].point.z.toFixed(2);  
        destination = new THREE.Vector3( xp , 50 , zp );

        var se23k = Math.random() * 4 * 4 ;
        new TWEEN.Tween( driller.rotation ).to( { y: se23k }, 1000 ).easing( TWEEN.Easing.Linear.None).start();

    }

    else {
        console.log('outside boundaries');
    }

};

function update(){  

   camera.lookAt( plane.position );
   renderer.render( scene, camera );
}

function animate() {

    requestAnimationFrame( animate );       
    update();
    render();
}

function render() {
    driller.updateMatrix();
    cristal.updateMatrix();

    TWEEN.update();
    renderer.render( scene, camera );       
}
4

2 回答 2

1

这是一些代码,可以在指向 Z 轴和指向 X 轴之间平滑地旋转船。

在http://youtu.be/jBlDVSBv_m4有一个演示视频

我已经删除了渲染器设置的大部分内容,只专注于四元数 slerping。

以下代码在咖啡脚本中,并使用了S3age中的几个自定义类;我尽可能地评论了他们。如果这有问题,请在评论中提及,我会将其重写为 VanillaJS。

# RequireJS preamble, not important.
define ["util/stage", "game/clock"],
    (Stage, Clock)->
        ###
        # Ship is a constructor.
        # It uses no ctor arguments, but does pass them to Object3D.
        ###
        Ship = (Object3DArgs)->
            # Ship directly extends Object3D
            THREE.Object3D.apply @, arguments
            @build()

            # The critical piece - use the model's quaternion, not its rotation
            @useQuaternion = yes
            @

        # Finish subclassing, by creating a new prototype chain.
        Ship:: = Object.create THREE.Object3D::
        ###
        # Create some geometry, materials, etc. Not important, could be from
        # Collada/JSON/etcLoader
        # Important part is noticing the rotation and position are set relative to
        # the Ship object itself; moving or rotating @ will move/rotate the 
        # geometry inside it implicitly.
        ###
        Ship::build = ->
            geom = new THREE.CylinderGeometry 0, 3, 1.5, 20, 1
            mat = new THREE.MeshLambertMaterial
            @hull = new THREE.Mesh geom, mat
            @hull.scale.set(0.3, 1, 0.1)
            @hull.rotation.set(Math.PI / 2, 0, 0)
            @hull.position.set(0, 0, 0.33)
            @add @hull
            @


        ###
        # An easing function, to go from ticks on a frame counter to some
        # percentage between zero and one, over the course of some time.
        ###
        ease = do ->
            seconds = 4
            d = time = (seconds * 60)
            b = 0.0
            c = 1.0
            #easeInOutQuad from http://www.robertpenner.com/easing/
            (t) ->
                # Constrain `t` between `0` and the animation's duration
                t %= d 
                if ((t /= d/2 ) < 1)
                    c/2*t*t + b
                else
                    -c/2 * ((--t)*(t-2) - 1) + b

        # Y is the axis to rotate through. In this instance, it is the Y axis.
        # In general, it should be the "Up" vertex of the model.
        # You will calculate this when the user clicks.
        y = new THREE.Vector3(0, 1, 0)

        # r0 is the initial direction when the animation starts;
        # that is, the "up" vector at theta=0
        r0 = new THREE.Quaternion()
        r0.setFromAxisAngle(y, 0)

        # r1 is the desired direction. Calculate theta from the dot product of the
        # ship's normal with the vector pointing from the ship to the target (eg
        # target.position - ship.position)
        r1 = new THREE.Quaternion()
        r1.setFromAxisAngle(y, Math.PI / 2)

        ###
        # The update function will get called every physics update.
        # Clock has time, delta, and frame.
        # Frame is number of ticks, time is total time elapsed,
        # delta is time since last update.
        ###
        Ship::update = (clock)->
            # Get the prct between zero and one of how far through
            # the animation the clock is
            prct = ease clock.frame
            # Use the static slerp, storing the result directly
            # in the ship's quaternion.
            THREE.Quaternion.slerp r0, r1, @quaternion, prct

        # A convention in my loader, not important.
        # Creates a S3age, gets the scene, etc.
        play: (selector)->
            stage = new Stage selector
            stage.scene = new THREE.Scene()

            stage.scene.add ship = new Ship()

            # Some lights, controls, an axis.
            stage.scene.add new THREE.AmbientLight 0x404040
            stage.scene.add light = new THREE.PointLight 0xF0F0F0, 1, 100
            light.position.set(20, 30, 50)
            stage.controls = new THREE.Trackball stage.camera, stage.container
            stage.camera.position.set(2, 5, -5)
            stage.scene.add new THREE.AxisHelper(2)
            # Call the update function every time the clock goes tick-tock
            (new Clock()).addEventListener 'tick', (event)->
                clock = event.clock
                ship.update clock
            stage.start()
于 2013-06-25T01:20:18.600 回答
0

实际上,我找到了更快的解决方案;)

        xp = intersects[0].point.x.toFixed(2);
        yp = intersects[0].point.y.toFixed(2);
        zp = intersects[0].point.z.toFixed(2);  
        destination = new THREE.Vector3( xp , yp , zp );

        radians =  Math.atan2( ( driller.position.x - xp) , (driller.position.z - zp));
        radians += 90 * (Math.PI / 180);

        var tween = new TWEEN.Tween(driller.rotation).to({ y : radians },200).easing(TWEEN.Easing.Linear.None).start();
于 2013-06-26T12:24:08.840 回答