Using textures in THREE.js

前端 未结 6 1839
遇见更好的自我
遇见更好的自我 2020-11-27 03:16

I am starting with THREE.js, and I am trying to draw a rectangle with a texture on it, lit by a single source of light. I think this is as simple as it gets (HTML omitted fo

相关标签:
6条回答
  • 2020-11-27 03:30

    Without Error Handeling

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

    With Error Handling

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

    Result:

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

    0 讨论(0)
  • 2020-11-27 03:34

    In version r75 of three.js, you should use:

    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);
    });
    
    0 讨论(0)
  • 2020-11-27 03:34

    In version r82 of Three.js TextureLoader is the object to use for loading a texture.

    Loading one texture (source code, demo)

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

    Loading multiple textures (source code, demo)

    In this example the textures are loaded inside the constructor of the mesh, multiple texture are loaded using Promises.

    Extract (Globe.js):

    Create a new container using Object3D for having two meshes in the same container:

    var Globe = function (radius, segments) {
    
      THREE.Object3D.call(this);
    
      this.name = "Globe";
    
      var that = this;
    
      // instantiate a loader
      var loader = new THREE.TextureLoader();
    

    A map called textures where every object contains the url of a texture file and val for storing the value of a Three.js texture object.

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

    The array of promises, for each object in the map called textures push a new Promise in the array texturePromises, every Promise will call loader.load. If the value of entry.val is a valid THREE.Texture object, then resolve the promise.

      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.all takes the promise array texturePromises as argument. Doing so makes the browser wait for all the promises to resolve, when they do we can load the geometry and the material.

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

    For the cloud sphere only one texture is necessary:

      // 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;
    
    0 讨论(0)
  • 2020-11-27 03:36

    Andrea solution is absolutely right, I will just write another implementation based on the same idea. If you took a look at the THREE.ImageUtils.loadTexture() source you will find it uses the javascript Image object. The $(window).load event is fired after all Images are loaded ! so at that event we can render our scene with the textures already loaded...

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

    Thanks...

    0 讨论(0)
  • 2020-11-27 03:39

    By the time the image is loaded, the renderer has already drawn the scene, hence it is too late. The solution is to change

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

    into

    texture = THREE.ImageUtils.loadTexture('crate.gif', {}, function() {
        renderer.render(scene);
    }),
    
    0 讨论(0)
  • 2020-11-27 03:41

    Use TextureLoader to load a image as texture and then simply apply that texture to scene background.

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

    Result:

    https://codepen.io/hiteshsahu/pen/jpGLpq?editors=0011

    See the Pen Flat Earth Three.JS by Hitesh Sahu (@hiteshsahu) on CodePen.

    0 讨论(0)
提交回复
热议问题