在运行时更改 Three.js 中加载的 .obj 的纹理 [英] Change texture of loaded .obj in three.js at runtime

查看:63
本文介绍了在运行时更改 Three.js 中加载的 .obj 的纹理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在加载的three.js .obj 上在运行时交换图像纹理.这是直接来自three.js示例的代码,稍作修改:

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:

        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 );

        }

我添加的唯一内容是 newTexture 函数和对作为 myMesh 的网格的引用.这是原始示例 (http://threejs.org/examples/webgl_loader_obj.html).该函数不会引发任何错误,但 .obj 不会更新.我知道我只是在这里遗漏了一些基本的东西..

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..

更新:根据下面的优秀答案,这里是正确的代码,并添加了一些通过输入字段交换纹理的代码:

  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;
      }
    });
  }

推荐答案

这里的问题是 object 变量中有多个子网格.通过只有一个 myMesh 全局变量,您只存储了最后一个子网格.因此,当您尝试使用此全局变量更新纹理时,只有一个网格得到了纹理更新,可能是一个不太明显的隐藏部分.

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.

解决方案是:

  • 存储一个 myMeshes 数组全局变量,并在每次出现时将 myMesh 推入其中.然后在您的 newTexture() 函数中,遍历此数组中的所有项目并更新它们的贴图/材质.
  • 或者,将 object 变量(从 OBJLoader 的回调返回的那个)存储到一个全局变量中.然后在您的 newTexture() 函数中,遍历所有网格,就像它在代码中的完成方式一样(使用 traverse()if 语句),并更新他们的贴图/材质.
  • Store a myMeshes array global variable and push myMesh into it every time there is one. Then in your newTexture() function, iterate through all items in this array and update their maps/materials.
  • Or, store the object variable (the one returned from OBJLoader's callback) into one single global variable. Then in your newTexture() function, iterate through all the meshes like how it is done in the code (using traverse() and if statement), and update their maps/materials.

最后,在代码中的某处调用 newTexture() 也有帮助;)

Lastly, calling newTexture() somewhere in your code would also help ;)

这篇关于在运行时更改 Three.js 中加载的 .obj 的纹理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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