Using textures in THREE.js

前端 未结 6 1905
遇见更好的自我
遇见更好的自我 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: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;
    

提交回复
热议问题