2013-08-20 19 views
11

Sto provando a scambiare la texture dell'immagine in fase di esecuzione su un file caricato con tre.js .obj. Ecco il codice direttamente dal Three.js esempi con leggera modifica:Cambia trama di .obj caricato in three.js durante il runtime

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

     } 

L'unica cosa che aggiunto era la funzione newTexture e un riferimento alla maglia come myMesh. Ecco l'esempio originale (http://threejs.org/examples/webgl_loader_obj.html). La funzione non genera errori, ma il file .obj non si aggiorna. So che sto manca solo una cosa fondamentale qui ..

Aggiornamento: Per la risposta eccellente sotto, ecco il codice corretto con alcune aggiunte per scambiare tessitura attraverso un campo di input:

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

Non v'è alcuna necessità di impostare 'child.material.needsUpdate = true;' in questo caso. È impostato per 'loadTexture()'. L'impostazione 'needsUpdate' può causare problemi se il caricamento asincrono delle texture è ritardato. – WestLangley

+0

Grazie per aver aggiornato il codice <3 –

risposta

9

Il problema qui è che esistono più mesh figlio nella variabile object. Con una sola variabile globale myMesh, si sta memorizzando solo l'ultima mesh figlio. Pertanto, quando si tenta di aggiornare la trama utilizzando questa variabile globale, solo una delle mesh ottiene un aggiornamento della trama, probabilmente una piccola parte nascosta che non è chiaramente visibile.

La soluzione sarebbe quella di uno:

  • Conservare una variabile globale myMeshes matrice e spingerlo myMesh in esso ogni volta che c'è uno. Quindi nella tua funzione newTexture(), itera su tutti gli elementi di questo array e aggiorna le loro mappe/materiali.
  • Oppure, memorizzare la variabile object (quella restituita dal callback OBJLoader) in una singola variabile globale. Quindi nella tua funzione newTexture(), itera su tutte le mesh come avviene nel codice (usando la dichiarazione traverse() e if) e aggiorna le loro mappe/materiali.

Infine, chiamando newTexture() da qualche parte nel codice contribuirebbe anche;)

+0

Funziona ora grazie! Ho usato la seconda opzione. E sì, stavo chiamando newTexture() nella console in modo che non fosse chiaro. Ho pubblicato il codice sopra riportato per il beneficio di tutti. –

Problemi correlati