在运行时更改three.js中加载的.obj的纹理

Bri*_*ero 13 javascript 3d webgl three.js

我试图在运行时在加载的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 );

        }
Run Code Online (Sandbox Code Playgroud)

我添加的唯一内容是newTexture函数和对myMesh的网格引用.这是最初的例子(http://threejs.org/examples/webgl_loader_obj.html).该函数不会抛出任何错误,但.obj不会更新.我知道我在这里缺少一些基本的东西..

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

  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;
      }
    });
  }
Run Code Online (Sandbox Code Playgroud)

ske*_*ogy 11

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

解决方案是:

  • 存储一个myMeshes数组全局变量,并myMesh在每次变量时将其推入.然后在您的newTexture()函数中,遍历此数组中的所有项并更新其地图/材质.
  • 或者,将object变量(从OBJLoader回调中返回的变量)存储到一个单一的全局变量中.然后在您的newTexture()函数中,迭代所有网格,如在代码中完成它(使用traverse()if声明),并更新它们的地图/材料.

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