如何在Threejs中旋转路径

时间:2019-01-18 16:27:52

标签: three.js

我是three.js的新手,我想让对象沿椭圆曲线移动,但是用ellipse.rotation.y旋转椭圆后,对象将不再沿路径移动,对象仍将移动使用原始路径,那么如何解决此问题? 我正在使用此站点中的代码来模拟我的问题

http://jsfiddle.net/w9914420/krw8nwLn/14/

// GLOBALS - ALLOCATE THESE OUTSIDE OF THE RENDER LOOP - CHANGED
var cubes = [], marker, spline;
var matrix = new THREE.Matrix4();
var up = new THREE.Vector3( 0, 1, 0 );
var axis = new THREE.Vector3( );
var pt, radians, axis, tangent, path;

// the getPoint starting variable - !important - You get me ;)
var t = 0;

//This function generates the cube and chooses a random color for it 
//on intial load.

function getCube(){
    // cube mats and cube
    var mats = [];
    for (var i = 0; i < 6; i ++) {
        mats.push(new THREE.MeshBasicMaterial({color:Math.random()*0xffffff}));
    }

    var cube = new THREE.Mesh(
        new THREE.CubeGeometry(2, 2, 2),
        new THREE.MeshFaceMaterial( mats )
    );

    return cube
}

// Ellipse class, which extends the virtual base class Curve
function Ellipse( xRadius, yRadius ) {

        THREE.Curve.call( this );

        // add radius as a property
        this.xRadius = xRadius;
        this.yRadius = yRadius;

}

Ellipse.prototype = Object.create( THREE.Curve.prototype );
Ellipse.prototype.constructor = Ellipse;

// define the getPoint function for the subClass
Ellipse.prototype.getPoint = function ( t ) {

    var radians = 2 * Math.PI * t;

    return new THREE.Vector3( this.xRadius * Math.cos( radians ),
                              this.yRadius * Math.sin( radians ),
                              0 );

};

//

var mesh, renderer, scene, camera, controls;


function init() {

    // renderer
    renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );

    // scene
    scene = new THREE.Scene();

    // camera
    camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
    camera.position.set( 20, 20, 20 );

    // controls
    controls = new THREE.OrbitControls( camera, renderer.domElement );
    controls.addEventListener( 'change', render ); // use if there is no animation loop
    controls.minDistance = 10;
    controls.maxDistance = 50;

    // light
    var light = new THREE.PointLight( 0xffffff, 0.7 );
    camera.add( light );
    scene.add( camera ); // add to scene only because the camera  has a child

    // axes
    scene.add( new THREE.AxisHelper( 20 ) );


    ////////////////////////////////////////
    //      Create the cube               //
    ////////////////////////////////////////

    marker = getCube();
    marker.position.set(0,0,0);
    scene.add(marker);


    ////////////////////////////////////////
    //      Create an Extruded shape      //
    ////////////////////////////////////////

    // path
    path = new Ellipse( 5, 10 );

    // params
    var pathSegments = 64;
    var tubeRadius = 0.5;
    var radiusSegments = 16;
    var closed = true;

    var geometry = new THREE.TubeBufferGeometry( path, pathSegments, tubeRadius, radiusSegments, closed );

    // material
    var material = new THREE.MeshPhongMaterial( {
        color: 0x0080ff, 
    } );

    // mesh
    mesh = new THREE.Mesh( geometry, material );
    scene.add( mesh );

    //////////////////////////////////////////////////////////////////////////
    //       Create the path which is based on our shape above              //
    //////////////////////////////////////////////////////////////////////////

    //Please note that this red ellipse was only created has a guide so that I could  be certain that the square is true to the tangent and positioning.

    // Ellipse class, which extends the virtual base class Curve
        var curve = new THREE.EllipseCurve(
            0,  0,            // ax, aY
            6, 11,           // xRadius, yRadius
            0,  2 * Math.PI,  // aStartAngle, aEndAngle
            false,            // aClockwise
            0                 // aRotation
        );

        //defines the amount of points the path will have
        var path2 = new THREE.Path( curve.getPoints( 100 ) );
         geometrycirc = path2.createPointsGeometry( 100 );
        var materialcirc = new THREE.LineBasicMaterial( {
            color : 0xff0000
        } );

        // Create the final object to add to the scene
        var ellipse = new THREE.Line( geometrycirc, materialcirc );
        ellipse.position.set(0,0,0);
        scene.add( ellipse );

}

function animate() {
    requestAnimationFrame(animate);

    render();
}


function render() {

        // set the marker position
        pt = path.getPoint( t );

        // set the marker position
        marker.position.set( pt.x, pt.y, pt.z );

        // get the tangent to the curve
        tangent = path.getTangent( t ).normalize();

        // calculate the axis to rotate around
        axis.crossVectors( up, tangent ).normalize();

        // calcluate the angle between the up vector and the tangent
        radians = Math.acos( up.dot( tangent ) );

        // set the quaternion
        marker.quaternion.setFromAxisAngle( axis, radians );

        t = (t >= 1) ? 0 : t += 0.002;

        renderer.render( scene, camera );

}

init();
animate();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/100/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

1 个答案:

答案 0 :(得分:1)

实现所需目标的最简单方法是,不将管(mesh)和路径跟踪对象(marker)添加到场景中,而是将其添加到{{1 }}。
因此,ellipsemarkermesh的子代,应用于ellipse的转换被“继承”到ellipsemarker

mesh
scene.add(marker);

scene.add(mesh );

请参见示例,我将建议的更改应用于您的原始代码:

ellipse.add(mesh);
ellipse.add(marker);
scene.add(ellipse);
// GLOBALS - ALLOCATE THESE OUTSIDE OF THE RENDER LOOP - CHANGED
var cubes = [], marker, spline;
var matrix = new THREE.Matrix4();
var up = new THREE.Vector3( 0, 1, 0 );
var axis = new THREE.Vector3( );
var pt, radians, axis, tangent, path;

var ellipse;

// the getPoint starting variable - !important - You get me ;)
var t = 0;

//This function generates the cube and chooses a random color for it 
//on intial load.

function getCube(){
    // cube mats and cube
    var mats = [];
    for (var i = 0; i < 6; i ++) {
        mats.push(new THREE.MeshBasicMaterial({color:Math.random()*0xffffff}));
    }

    var cube = new THREE.Mesh(
        new THREE.CubeGeometry(2, 2, 2),
        new THREE.MeshFaceMaterial( mats )
    );

    return cube
}

// Ellipse class, which extends the virtual base class Curve
function Ellipse( xRadius, yRadius ) {

        THREE.Curve.call( this );

        // add radius as a property
        this.xRadius = xRadius;
        this.yRadius = yRadius;
}

Ellipse.prototype = Object.create( THREE.Curve.prototype );
Ellipse.prototype.constructor = Ellipse;

// define the getPoint function for the subClass
Ellipse.prototype.getPoint = function ( t ) {

    var radians = 2 * Math.PI * t;

    return new THREE.Vector3( this.xRadius * Math.cos( radians ),
                              this.yRadius * Math.sin( radians ),
                              0 );
};

var mesh, renderer, scene, camera, controls;

function init() {

    // renderer
    renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );

    // scene
    scene = new THREE.Scene();

    // camera
    camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
    camera.position.set( 20, 20, 20 );

    // controls
    controls = new THREE.OrbitControls( camera, renderer.domElement );
    controls.addEventListener( 'change', render ); // use if there is no animation loop
    controls.minDistance = 10;
    controls.maxDistance = 50;

    // light
    var light = new THREE.PointLight( 0xffffff, 0.7 );
    camera.add( light );
    scene.add( camera ); // add to scene only because the camera  has a child

    // axes
    scene.add( new THREE.AxisHelper( 20 ) );

    ////////////////////////////////////////
    //      Create the cube               //
    ////////////////////////////////////////

    marker = getCube();
    marker.position.set(0,0,0);
    //scene.add(marker);


    ////////////////////////////////////////
    //      Create an Extruded shape      //
    ////////////////////////////////////////

    // path
    path = new Ellipse( 5, 10 );

    // params
    var pathSegments = 64;
    var tubeRadius = 0.5;
    var radiusSegments = 16;
    var closed = true;

    var geometry = new THREE.TubeBufferGeometry( path, pathSegments, tubeRadius, radiusSegments, closed );

    // material
    var material = new THREE.MeshPhongMaterial( {
        color: 0x0080ff, 
    } );

    // mesh
    mesh = new THREE.Mesh( geometry, material );
    scene.add( mesh );

    //////////////////////////////////////////////////////////////////////////
    //       Create the path which is based on our shape above              //
    //////////////////////////////////////////////////////////////////////////

    //Please note that this red ellipse was only created has a guide so that I could  be certain that the square is true to the tangent and positioning.

    // Ellipse class, which extends the virtual base class Curve
    var curve = new THREE.EllipseCurve(
        0,  0,            // ax, aY
        6, 11,           // xRadius, yRadius
        0,  2 * Math.PI,  // aStartAngle, aEndAngle
        false,            // aClockwise
        0                 // aRotation
    );
  

    //defines the amount of points the path will have
    var path2 = new THREE.Path( curve.getPoints( 100 ) );
      geometrycirc = path2.createPointsGeometry( 100 );
    var materialcirc = new THREE.LineBasicMaterial( {
        color : 0xff0000
    } );
      

    // Create the final object to add to the scene
    ellipse = new THREE.Line( geometrycirc, materialcirc );
    ellipse.position.set(0,0,0);

    ellipse.add(mesh);
    ellipse.add(marker);
    scene.add( ellipse );
    window.onresize = resize;
}

function animate() {
    ellipse.rotation.y += Math.PI / 200
    requestAnimationFrame(animate);
    render();
}

function render() {

    // set the marker position
    pt = path.getPoint( t );

    // set the marker position
    marker.position.set( pt.x, pt.y, pt.z );

    // get the tangent to the curve
    tangent = path.getTangent( t ).normalize();

    // calculate the axis to rotate around
    axis.crossVectors( up, tangent ).normalize();

    // calcluate the angle between the up vector and the tangent
    radians = Math.acos( up.dot( tangent ) );

    // set the quaternion
    marker.quaternion.setFromAxisAngle( axis, radians );

    t = (t >= 1) ? 0 : t += 0.002;

    renderer.render( scene, camera );
}

function resize() {    
    var aspect = window.innerWidth / window.innerHeight;
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = aspect;
    camera.updateProjectionMatrix();
}

init();
animate();

相关问题