围绕它自己的 y 轴旋转 Collada 模型 [英] Rotate a Collada model around its own y-axis

查看:32
本文介绍了围绕它自己的 y 轴旋转 Collada 模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的 Three.js 场景,其中包含飞机上的 3D Homer Simpson.我希望能够使用鼠标在他自己的 y 轴上旋转他.

I have a simple three.js scene that contains a 3D Homer Simpson, on a plane. I want to be able to spin him around on his own y-axis, using the mouse.

下面的代码几乎就在那里.这是我从这里那里和我自己的一些东西拼凑起来的.问题是我无法让他绕着他的 y 轴旋转,而这个 y 轴会直接穿过他的核心,就在中间.

The following code is almost there. It's bit I've cobbled together from here and there and my own bits. The problem is that I am just not able to get spin him around his y-axis, one that would be running right through his core, right in the middle.

在包含的代码中,如果我使用框架作为参考,他会转一圈.它的周长(在这个例子中只是偶然)大约是他所站立的飞机的大小.

In the included code, if I use the frame as a reference, he spins around in a circle. The circumference of which (and just by chance in this example) is about the size of the plane he's standing on.

如果我移除框架并使用模型旋转,那么他几乎会绕着他的 y 轴旋转——除了 I 轴刚好指向他的一边.

If I remove the frame and instead rotate using the model, then he almost spins around on his y-axis -- except that the I axis is just to his side.

我正在使用以下模型.事实上,我希望他旋转的方式就是他在 3D 仓库示例中的方式.如果您点击 3D 视图 并旋转他,您就会看到我想要实现的目标.

I am using the following model. In fact, the way I want him to spin is the way he does in the 3D Warehouse example. If you click on 3D View and spin him, you'll see what I am trying to achieve.

// nasty globals, but this is just a sandbox.
var camera;
var frame;
var loader = new THREE.ColladaLoader();
var model;
var plane;
var renderer;
var scene;

var mouseX = 0;
var mouseXOnMouseDown = 0;
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var windowHalfX = 800 / 2;

loader.load('Homer/models/body.dae', function(collada) {
    model = collada.scene;

    model.position.x = 0;
    model.position.y = 0;
    model.position.z = 100;

    model.rotation.x = - Math.PI / 2;       // stand Homer upright and facing the camera.

    init();
    animate();
});

function init()
{
    renderer = new THREE.WebGLRenderer();
    renderer.setSize(800, 800);

    document.body.appendChild(renderer.domElement);

    camera = new THREE.PerspectiveCamera(45, 1, 100, 10000);

    camera.position.x = 50;
    camera.position.y = 120;
    camera.position.z = 600;

    scene = new THREE.Scene();
    scene.add(model);

    // Do I need a frame of reference to get Homer to spin on his own Y-axis instead of the scene's?
    frame = new THREE.Object3D();
    frame.add(model);
    scene.add(frame);

    plane = new THREE.Mesh( new THREE.PlaneGeometry( 400, 400 ), new THREE.MeshBasicMaterial( { color: 0xe0e0e0 } ) );
    plane.geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
    scene.add( plane );

    var light = new THREE.SpotLight();
    light.position.set(200, 500, 4000);
    scene.add(light);

    renderer.render(scene, camera);

    // Spin Homer around when moving the mouse around
    document.addEventListener( 'mousedown', onDocumentMouseDown, false );
    document.addEventListener( 'touchstart', onDocumentTouchStart, false );
    document.addEventListener( 'touchmove', onDocumentTouchMove, false );
}


function onDocumentMouseDown( event ) {
    event.preventDefault();
    document.addEventListener( 'mousemove', onDocumentMouseMove, false );
    document.addEventListener( 'mouseup', onDocumentMouseUp, false );
    document.addEventListener( 'mouseout', onDocumentMouseOut, false );

    mouseXOnMouseDown = event.clientX - windowHalfX;
    targetRotationOnMouseDown = targetRotation;
}

function onDocumentMouseMove() {
    mouseX = event.clientX - windowHalfX;
    targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;
}

function onDocumentMouseUp() {
    document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
    document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
    document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}

function onDocumentMouseOut() {
    document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
    document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
    document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}

function onDocumentTouchStart( event ) {
    if ( event.touches.length === 1 ) {
        event.preventDefault();
        mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
        targetRotationOnMouseDown = targetRotation;
    }
}

function onDocumentTouchMove( event ) {
    if ( event.touches.length === 1 ) {
        event.preventDefault();
        mouseX = event.touches[ 0 ].pageX - windowHalfX;
        targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
    }
}

// Spin Homer around the Y-Axis
function animate() {
    requestAnimationFrame( animate );

    // When we add the frame, he spins in a circle, about the size of the plane (that's spin size if coincidence)
    frame.rotation.y += ( targetRotation - frame.rotation.y ) * 0.03;

    // If we remove the frame from the scene, and use this line instead, Homer spins around the y-axis.
    // But, the y-axis is along the outside of his leg and arm, not through his vertical center, which is what I want.
    // model.rotation.z += ( targetRotation - model.rotation.z ) * 0.03;
    renderer.render( scene, camera );
}

推荐答案

这很棘手.问题是荷马的几何学让他站在他的本地坐标系中,右脚靠近原点.

This is tricky. The problem is that Homer's geometry has him standing in his local coordinate system with his right foot next to the origin.

在这种情况下你通常会做的是调用

What you would normallly do in a case like this is call

geometry.applyMatrix( new THREE.Matrix4().makeTranslation( -distance, 0, 0 ) );

并沿局部 x 轴平移几何图形.这将使荷马成为中心,你就完成了.

and translate the geometry along the local x-axis. That would center Homer, and you'd be done.

如果你能弄清楚 Collada 数据结构,你就可以做到.

If you can figure out the Collada data structure, you can do that.

另一个解决方案是这个技巧:(1) 使您的模型成为父对象的子对象,(2) 使父对象成为另一个对象的子对象,(3) 然后将父对象偏移一定距离:

Another solution is this trick: (1) make your model a child of a parent, (2) make the parent a child of another object, (3) and then offset the parent by some distance:

在您的 init() 函数中,执行此操作

In your init() function, do this

scene = new THREE.Scene();

renderer = new THREE.WebGLRenderer();
renderer.setSize(800, 800);
document.body.appendChild( renderer.domElement );

camera = new THREE.PerspectiveCamera( 45, 1, 100, 10000 );
camera.position.x = 50;
camera.position.y = 120;
camera.position.z = 600;
scene.add( camera ); // don't forget this

scene.add( new THREE.AxisHelper() ); // frame of reference

// //////////////////////////////////////////////////
// trick to accommodate geometry offset
object = new THREE.Object3D();
scene.add( object );

parent = new THREE.Object3D();
parent.position.x = -39;
object.add( parent );

parent.add( model );
// //////////////////////////////////////////////////

然后在您的 animate() 函数中:

And then in your animate() function:

object.rotation.y += ( targetRotation - object.rotation.y ) * 0.03;

这篇关于围绕它自己的 y 轴旋转 Collada 模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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