javascript 在运行时更改 Three.js 中加载的 .obj 的纹理
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18324936/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Change texture of loaded .obj in three.js at runtime
提问by Brian LoCicero
I'm trying to swap image texture at runtime on a loaded three.js .obj. Here's the code straight from three.js examples with slight modification:
我试图在加载的three.js .obj 上在运行时交换图像纹理。这是直接来自three.js示例的代码,稍作修改:
var container, stats;
var camera, scene, renderer;
var mouseX = 0, mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.z = 100;
//scene
scene = new THREE.Scene();
var ambient = new THREE.AmbientLight( 0x101030 );
scene.add( ambient );
var directionalLight = new THREE.DirectionalLight( 0xffeedd );
directionalLight.position.set( 0, 0, 1 );
scene.add( directionalLight );
//manager
var manager = new THREE.LoadingManager();
manager.onProgress = function ( item, loaded, total ) {
console.log( item, loaded, total );
};
//model
var loader = new THREE.OBJLoader( manager );
loader.load( 'obj/female02/female02.obj', function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
//create a global var to reference later when changing textures
myMesh = child;
//apply texture
myMesh.material.map = THREE.ImageUtils.loadTexture( 'textures/ash_uvgrid01.jpg');
myMesh.material.needsUpdate = true;
}
} );
object.position.y = - 80;
scene.add( object );
} );
//render
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
window.addEventListener( 'resize', onWindowResize, false );
}
function newTexture() {
myMesh.material.map = THREE.ImageUtils.loadTexture( 'textures/land_ocean_ice_cloud_2048.jpg');
myMesh.material.needsUpdate = true;
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
mouseX = ( event.clientX - windowHalfX ) / 2;
mouseY = ( event.clientY - windowHalfY ) / 2;
}
//animate
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
camera.position.x += ( mouseX - camera.position.x ) * .05;
camera.position.y += ( - mouseY - camera.position.y ) * .05;
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
The only thing I added was the newTexture function and a reference to the mesh as myMesh. Here's the original example (http://threejs.org/examples/webgl_loader_obj.html). The function doesn't throw any errors but the .obj does not update. I know I'm just missing something fundamental here..
我唯一添加的是 newTexture 函数和作为 myMesh 的网格引用。这是原始示例 ( http://threejs.org/examples/webgl_loader_obj.html)。该函数不会引发任何错误,但 .obj 不会更新。我知道我只是在这里遗漏了一些基本的东西..
Update: Per the excellent answer below, here's the correct code with some additions to swap texture via an input field:
更新:根据下面的优秀答案,这里是正确的代码,其中添加了一些通过输入字段交换纹理的内容:
var container, stats;
var camera, scene, renderer;
var mouseX = 0, mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
var globalObject;
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.z = 100;
//scene
scene = new THREE.Scene();
var ambient = new THREE.AmbientLight( 0x101030 );
scene.add( ambient );
var directionalLight = new THREE.DirectionalLight( 0xffeedd );
directionalLight.position.set( 0, 0, 1 );
scene.add( directionalLight );
//manager
var manager = new THREE.LoadingManager();
manager.onProgress = function (item, loaded, total) {
console.log( item, loaded, total );
};
//model
var loader = new THREE.OBJLoader( manager );
loader.load( 'obj/female02/female02.obj', function (object) {
//store global reference to .obj
globalObject = object;
object.traverse( function (child) {
if ( child instanceof THREE.Mesh ) {
child.material.map = THREE.ImageUtils.loadTexture( 'textures/grid.jpg');
child.material.needsUpdate = true;
}
});
object.position.y = - 80;
scene.add( object );
});
//render
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
mouseX = ( event.clientX - windowHalfX ) / 2;
mouseY = ( event.clientY - windowHalfY ) / 2;
}
//animate
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
camera.position.x += ( mouseX - camera.position.x ) * .05;
camera.position.y += ( - mouseY - camera.position.y ) * .05;
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
function newTexture() {
var newTexturePath = "textures/" + document.getElementById("texture").value + "";
globalObject.traverse( function ( child ) {
if (child instanceof THREE.Mesh) {
//create a global var to reference later when changing textures
child;
//apply texture
child.material.map = THREE.ImageUtils.loadTexture(newTexturePath);
child.material.needsUpdate = true;
}
});
}
采纳答案by skeelogy
The problem here is that there are multiple child meshes in the object
variable. By having only one myMesh
global variable, you are storing only the last child mesh. Thus when you try to update the texture using this global variable, only one of the meshes gets a texture update, probably a small hidden part that is not clearly visible.
这里的问题是object
变量中有多个子网格。通过只有一个myMesh
全局变量,您只存储了最后一个子网格。因此,当您尝试使用此全局变量更新纹理时,只有一个网格会获得纹理更新,可能是一个不太明显的隐藏小部分。
The solution would be to either:
解决方案是:
- Store a
myMeshes
array global variable and pushmyMesh
into it every time there is one. Then in yournewTexture()
function, iterate through all items in this array and update their maps/materials. - Or, store the
object
variable (the one returned fromOBJLoader
's callback) into one single global variable. Then in yournewTexture()
function, iterate through all the meshes like how it is done in the code (usingtraverse()
andif
statement), and update their maps/materials.
- 存储一个
myMeshes
数组全局变量并myMesh
在每次有一个时将其推入。然后在您的newTexture()
函数中,遍历此数组中的所有项目并更新它们的贴图/材质。 - 或者,将
object
变量(从OBJLoader
的回调返回的变量)存储到一个全局变量中。然后在您的newTexture()
函数中,迭代所有网格,就像它在代码中的完成方式(使用traverse()
和if
语句),并更新它们的贴图/材质。
Lastly, calling newTexture() somewhere in your code would also help ;)
最后,在代码中的某处调用 newTexture() 也会有所帮助;)