我是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/