Verwenden von Texturen in THREE.js


70

Ich beginne mit THREE.js und versuche, ein Rechteck mit einer Textur darauf zu zeichnen, das von einer einzelnen Lichtquelle beleuchtet wird. Ich denke, das ist so einfach wie es nur geht (HTML der Kürze halber weggelassen):

function loadScene() {
    var world = document.getElementById('world'),
        WIDTH = 1200,
        HEIGHT = 500,
        VIEW_ANGLE = 45,
        ASPECT = WIDTH / HEIGHT,
        NEAR = 0.1,
        FAR = 10000,

        renderer = new THREE.WebGLRenderer(),
        camera = new THREE.Camera(VIEW_ANGLE, ASPECT, NEAR, FAR),
        scene = new THREE.Scene(),
        texture = THREE.ImageUtils.loadTexture('crate.gif'),
        material = new THREE.MeshBasicMaterial({map: texture}),
        // material = new THREE.MeshPhongMaterial({color: 0xCC0000});
        geometry = new THREE.PlaneGeometry(100, 100),
        mesh = new THREE.Mesh(geometry, material),
        pointLight = new THREE.PointLight(0xFFFFFF);

    camera.position.z = 200;    
    renderer.setSize(WIDTH, HEIGHT);
    scene.addChild(mesh);
    world.appendChild(renderer.domElement);
    pointLight.position.x = 50;
    pointLight.position.y = 50;
    pointLight.position.z = 130;
    scene.addLight(pointLight); 
    renderer.render(scene, camera);
}

Das Problem ist, ich kann nichts sehen. Wenn ich das Material ändere und das kommentierte verwende, erscheint ein Quadrat, wie ich es erwarten würde. Beachten Sie, dass

  • Die Textur ist 256x256, also sind seine Seiten Zweierpotenz
  • Die Funktion wird tatsächlich aufgerufen, wenn der Körper geladen wird. in der Tat funktioniert es mit einem anderen Material.
  • Es funktioniert nicht, selbst wenn ich die Datei von einem Webserver aus bereitstelle. Es handelt sich also nicht um eine domänenübergreifende Richtlinie, die das Laden des Images nicht zulässt.

Was mache ich falsch?

Antworten:


73

Zum Zeitpunkt des Ladens des Bildes hat der Renderer die Szene bereits gezeichnet, daher ist es zu spät. Die Lösung ist zu ändern

texture = THREE.ImageUtils.loadTexture('crate.gif'),

in

texture = THREE.ImageUtils.loadTexture('crate.gif', {}, function() {
    renderer.render(scene);
}),

9
Heutzutage lautet die Antwort: Graben THREE.ImageUtils.loadTexture(was veraltet ist) und THREE.TextureLoader.loadstattdessen verwenden. ImageUtilshat bei mir überhaupt nicht funktioniert, aber TextureLoaderbeim ersten Versuch perfekt funktioniert. Docs: threejs.org/docs/index.html#api/loaders/TextureLoader
ArtOfWarfare

27

Andrea Lösung ist absolut richtig, ich werde nur eine weitere Implementierung schreiben, die auf der gleichen Idee basiert. Wenn Sie sich die Quelle THREE.ImageUtils.loadTexture () angesehen haben, werden Sie feststellen, dass sie das Javascript-Image-Objekt verwendet. Das Ereignis $ (window) .load wird ausgelöst, nachdem alle Bilder geladen wurden! In diesem Fall können wir unsere Szene mit den bereits geladenen Texturen rendern ...

  • CoffeeScript

    $(document).ready ->
    
        material = new THREE.MeshLambertMaterial(map: THREE.ImageUtils.loadTexture("crate.gif"))
    
        sphere   = new THREE.Mesh(new THREE.SphereGeometry(radius, segments, rings), material)
    
        $(window).load ->
            renderer.render scene, camera
    
  • JavaScript

    $(document).ready(function() {
    
        material = new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture("crate.gif") });
    
        sphere = new THREE.Mesh(new THREE.SphereGeometry(radius, segments, rings), material);
    
        $(window).load(function() {
            renderer.render(scene, camera);
        });
    });
    

Vielen Dank...


22

In Version r75 von three.js sollten Sie Folgendes verwenden:

var loader = new THREE.TextureLoader();
loader.load('texture.png', function ( texture ) {
  var geometry = new THREE.SphereGeometry(1000, 20, 20);
  var material = new THREE.MeshBasicMaterial({map: texture, overdraw: 0.5});
  var mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);
});

Gute Antwort! Ich vermute, die API hat sich seit der ursprünglichen Antwort geändert. Ihre Antwort ist funktional! Danke vielmals!
CowWarrior

Sie hätten wahrscheinlich angeben sollen, welche Revision von three.js Sie als neueste bezeichnet haben .
Harsh

6

In Version r82 von Three.js ist TextureLoader das Objekt, das zum Laden einer Textur verwendet werden soll.

Laden einer Textur ( Quellcode , Demo )

Auszug ( test.js ):

var scene = new THREE.Scene();
var ratio = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight,
  0.1, 50);

var renderer = ...

[...]

/**
 * Will be called when load completes.
 * The argument will be the loaded texture.
 */
var onLoad = function (texture) {
  var objGeometry = new THREE.BoxGeometry(20, 20, 20);
  var objMaterial = new THREE.MeshPhongMaterial({
    map: texture,
    shading: THREE.FlatShading
  });

  var mesh = new THREE.Mesh(objGeometry, objMaterial);

  scene.add(mesh);

  var render = function () {
    requestAnimationFrame(render);

    mesh.rotation.x += 0.010;
    mesh.rotation.y += 0.010;

    renderer.render(scene, camera);
  };

  render();
}

// Function called when download progresses
var onProgress = function (xhr) {
  console.log((xhr.loaded / xhr.total * 100) + '% loaded');
};

// Function called when download errors
var onError = function (xhr) {
  console.log('An error happened');
};

var loader = new THREE.TextureLoader();
loader.load('texture.jpg', onLoad, onProgress, onError);

Laden mehrerer Texturen ( Quellcode , Demo )

In diesem Beispiel werden die Texturen in den Konstruktor des Netzes geladen, mehrere Texturen werden mit Promises geladen .

Auszug ( Globe.js ):

Erstellen Sie einen neuen Container, Object3Dindem Sie zwei Maschen im selben Container haben:

var Globe = function (radius, segments) {

  THREE.Object3D.call(this);

  this.name = "Globe";

  var that = this;

  // instantiate a loader
  var loader = new THREE.TextureLoader();

Eine Karte genannt , textureswo jedes Objekt das enthält urleine Textur - Datei und valfür den Wert eines Three.js Speicherung Textur - Objekts.

  // earth textures
  var textures = {
    'map': {
      url: 'relief.jpg',
      val: undefined
    },
    'bumpMap': {
      url: 'elev_bump_4k.jpg',
      val: undefined
    },
    'specularMap': {
      url: 'wateretopo.png',
      val: undefined
    }
  };

Das Array von Versprechungen, für jedes Objekt in der Karte, das als texturesPush ein neues Versprechen im Array bezeichnet wird texturePromises, wird von jedem Versprechen aufgerufen loader.load. Wenn der Wert von entry.valein gültiges THREE.TextureObjekt ist, lösen Sie das Versprechen auf.

  var texturePromises = [], path = './';

  for (var key in textures) {
    texturePromises.push(new Promise((resolve, reject) => {
      var entry = textures[key]
      var url = path + entry.url

      loader.load(url,
        texture => {
          entry.val = texture;
          if (entry.val instanceof THREE.Texture) resolve(entry);
        },
        xhr => {
          console.log(url + ' ' + (xhr.loaded / xhr.total * 100) +
            '% loaded');
        },
        xhr => {
          reject(new Error(xhr +
            'An error occurred loading while loading: ' +
            entry.url));
        }
      );
    }));
  }

Promise.allNimmt das Versprechen-Array texturePromisesals Argument. Dadurch wartet der Browser auf die Lösung aller Versprechen. Wenn dies der Fall ist, können wir die Geometrie und das Material laden.

  // load the geometry and the textures
  Promise.all(texturePromises).then(loadedTextures => {

    var geometry = new THREE.SphereGeometry(radius, segments, segments);
    var material = new THREE.MeshPhongMaterial({
      map: textures.map.val,
      bumpMap: textures.bumpMap.val,
      bumpScale: 0.005,
      specularMap: textures.specularMap.val,
      specular: new THREE.Color('grey')
    });

    var earth = that.earth = new THREE.Mesh(geometry, material);
    that.add(earth);
  });

Für die Wolkenkugel ist nur eine Textur erforderlich:

  // clouds
  loader.load('n_amer_clouds.png', map => {
    var geometry = new THREE.SphereGeometry(radius + .05, segments, segments);
    var material = new THREE.MeshPhongMaterial({
      map: map,
      transparent: true
    });

    var clouds = that.clouds = new THREE.Mesh(geometry, material);
    that.add(clouds);
  });
}

Globe.prototype = Object.create(THREE.Object3D.prototype);
Globe.prototype.constructor = Globe;

1

Ohne Fehler Handeling

//Load background texture
 new THREE.TextureLoader();
loader.load('https://images.pexels.com/photos/1205301/pexels-photo-1205301.jpeg' , function(texture)
            {
             scene.background = texture;  
            });

Mit Fehlerbehandlung

// Function called when download progresses
var onProgress = function (xhr) {
  console.log((xhr.loaded / xhr.total * 100) + '% loaded');
};

// Function called when download errors
var onError = function (error) {
  console.log('An error happened'+error);
};

//Function  called when load completes.
var onLoad = function (texture) {
  var objGeometry = new THREE.BoxGeometry(30, 30, 30);
  var objMaterial = new THREE.MeshPhongMaterial({
    map: texture,
    shading: THREE.FlatShading
  });

  var boxMesh = new THREE.Mesh(objGeometry, objMaterial);
  scene.add(boxMesh);

  var render = function () {
    requestAnimationFrame(render);
    boxMesh.rotation.x += 0.010;
    boxMesh.rotation.y += 0.010;
      sphereMesh.rotation.y += 0.1;
    renderer.render(scene, camera);
  };

  render();
}


//LOAD TEXTURE and on completion apply it on box
var loader = new THREE.TextureLoader();
    loader.load('https://upload.wikimedia.org/wikipedia/commons/thumb/9/97/The_Earth_seen_from_Apollo_17.jpg/1920px-The_Earth_seen_from_Apollo_17.jpg', 
                onLoad, 
                onProgress, 
                onError);

Ergebnis:

Geben Sie hier die Bildbeschreibung ein

https://codepen.io/hiteshsahu/pen/jpGLpq/


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.