我是Unity开发人员,尝试学习Three.js。
我遇到的许多问题中的一个听起来很简单,但这对我来说还是很痛苦的。

我要做的就是在Three.js应用程序中导入3D徽标并为其设置动画。
该徽标由4个不重叠的不同网格(elem1至elem4)组成。
它已导出为FBX,然后使用在线转换器转换为GLTF。
导入,调整大小甚至更改其材质都没问题。

我的问题是:如何引用整个对象及其4个元素,以便在我的«animate»函数中对其进行动画处理(我的意思是在我的主渲染循环中)?
我唯一能做的就是在加载器回调中创建第二个«animate»函数,这对我来说有点奇怪。
我找不到在应用程序的主要范围内引用它们的方法。

转储我的GLTF导入将给出此层次结构(这些称为“节点”,对吗?):

AuxScene [Scene]
    *no-name* [Object3D]
        elem1 [Mesh]
        elem2 [Mesh]
        elem3 [Mesh]
        elem4 [Mesh]


这是我的代码,清除了不必要的内容:

'use strict';

// CANVAS AND RENDERER
const canvas = document.querySelector('#myCanvas');
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setSize( window.innerWidth, window.innerHeight );

// SCENE AND BACKGROUND
var scene = new THREE.Scene();
const loader = new THREE.TextureLoader();
scene.background = loader.load( 'images/background.jpg');

// CAMERA
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.z = 100;

// MATERIALS
var material = new THREE.MeshNormalMaterial ();


// ---------------------------------- LOGO IMPORTATION
var gltfLoader = new THREE.GLTFLoader();
var root;
var elem1, elem2, elem3, elem4;

gltfLoader.load('gltf/logo.gltf', function(gltf)  {
  root = gltf.scene;
  root.rotation.x = Math.PI / 2;
  scene.add(root);

  root.traverse( function( child ) {
    if ( child instanceof THREE.Mesh ) { child.material = material; }
  } );

  elem1 = root.getObjectByName('element1');
  elem2 = root.getObjectByName('element2');
  elem3 = root.getObjectByName('element3');
  elem4 = root.getObjectByName('element4');

  console.log(dumpObject(root).join('\n'));

  // logo animations
  var speed = 0.0005;
  var turnsBeforeStop = 4;
  requestAnimationFrame( animate2 );

  function animate2( time ) {
    root.rotation.z = Math.sin (time * 0.0005) * 0.5;
    root.rotation.x = Math.PI/3 + Math.sin(time * 0.0003) * 0.5;

    if(elem1.rotation.y < Math.PI * turnsBeforeStop){
      elem1.rotation.y = time * speed*2;
      elem2.rotation.z = time * speed*2;
      elem3.rotation.y = time * -speed;
      elem4.rotation.z = time * -speed*2;
    }
    requestAnimationFrame( animate2 );
  }
});
// ------------------------------------------------------------ END LOGO


renderer.render( scene, camera );
requestAnimationFrame( animate );

// ANIMATION MAIN LOOP
function animate( time ) {
  /*
        This is where I would like to access my logo (as a whole, and also its separate parts).
        But root.rotation or elem1.rotation won't work here and give me this error :
        TypeError: undefined is not an object (evaluating 'elem1.rotation')
  */
  renderer.render( scene, camera );
  requestAnimationFrame( animate );
}


// OBJECT DUMPING
function dumpObject(obj, lines = [], isLast = true, prefix = '              ') {
  const localPrefix = isLast ? '└─' : '├─';
  lines.push(`${prefix}${prefix ? localPrefix : ''}${obj.name || '*no-name*'} [${obj.type}]`);
  const newPrefix = prefix + (isLast ? '  ' : '│ ');
  const lastNdx = obj.children.length - 1;
  obj.children.forEach((child, ndx) => {
    const isLast = ndx === lastNdx;
    dumpObject(child, lines, isLast, newPrefix);
  });
  return lines;
}



感谢任何帮助。

最佳答案

问题是您尝试在为值(glTF模型)赋值之前访问root。请注意,GLTFLoader.load()是异步的。因此,设置为onLoad()root回调不会立即被调用,但是会产生一定程度的延迟。

有几种方法可以解决此问题。如果root不是undefined,则可以签入动画循环。它看起来像这样:

function animate( time ) {
    requestAnimationFrame( animate );

    if ( root ) {

        // do something with root

    }

    renderer.render( scene, camera );

}


或者,您可以在onLoad()完成后开始制作动画。在这种情况下,代码如下所示:

'use strict';

// CANVAS AND RENDERER
const canvas = document.querySelector('#myCanvas');
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setSize( window.innerWidth, window.innerHeight );

// SCENE AND BACKGROUND
var scene = new THREE.Scene();
const loader = new THREE.TextureLoader();
scene.background = loader.load( 'images/background.jpg');

// CAMERA
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.z = 100;

// MATERIALS
var material = new THREE.MeshNormalMaterial ();


// ---------------------------------- LOGO IMPORTATION
var gltfLoader = new THREE.GLTFLoader();
var root;
var elem1, elem2, elem3, elem4;

gltfLoader.load('gltf/logo.gltf', function(gltf)  {
  root = gltf.scene;
  root.rotation.x = Math.PI / 2;
  scene.add(root);

  root.traverse( function( child ) {
    if ( child instanceof THREE.Mesh ) { child.material = material; }
  } );

  animate(); // start animating

});
// ------------------------------------------------------------ END LOGO



// ANIMATION MAIN LOOP
function animate() {
    requestAnimationFrame( animate );
    // do something with root
    renderer.render( scene, camera );
}


// OBJECT DUMPING
function dumpObject(obj, lines = [], isLast = true, prefix = '              ') {
  const localPrefix = isLast ? '└─' : '├─';
  lines.push(`${prefix}${prefix ? localPrefix : ''}${obj.name || '*no-name*'} [${obj.type}]`);
  const newPrefix = prefix + (isLast ? '  ' : '│ ');
  const lastNdx = obj.children.length - 1;
  obj.children.forEach((child, ndx) => {
    const isLast = ndx === lastNdx;
    dumpObject(child, lines, isLast, newPrefix);
  });
  return lines;
}

关于javascript - 在主渲染循环中访问GLTF导入的部分(对不起的话,很抱歉),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58164834/

10-09 22:19