【问题标题】:Using textures in THREE.js在 THREE.js 中使用纹理
【发布时间】:2011-12-16 16:45:39
【问题描述】:

我从 THREE.js 开始,我正在尝试绘制一个带有纹理的矩形,由单一光源照亮。我认为这很简单(为简洁起见,省略了 HTML):

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

问题是,我什么都看不到。如果我更改材料并使用注释的材料,则会出现一个正方形,如我所料。请注意

  • 纹理是 256x256,所以它的边是 2 的幂
  • 该函数实际上是在body加载时调用的;事实上,它适用于不同的材料。
  • 即使我从网络服务器提供文件也无法正常工作,因此这不是跨域策略不允许加载图像的问题。

我做错了什么?

【问题讨论】:

    标签: javascript three.js


    【解决方案1】:

    在加载图像时,渲染器已经绘制了场景,因此为时已晚。解决办法是改变

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

    进入

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

    【讨论】:

    【解决方案2】:

    Andrea 解决方案是绝对正确的,我将基于相同的想法编写另一个实现。 如果您查看 THREE.ImageUtils.loadTexture() source 您会发现它使用了 javascript Image 对象。 $(window).load 事件在所有图像加载后触发!所以在那个事件中,我们可以使用已经加载的纹理来渲染我们的场景......

    • 咖啡脚本

      $(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);
          });
      });
      

    谢谢...

    【讨论】:

      【解决方案3】:

      在three.js的r75版本中,你应该使用:

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

      【讨论】:

      • 很好的答案!我猜API自原始答案以来发生了变化。你的答案很实用!非常感谢!
      • 您可能应该提供您所指的three.js 的哪个版本是最新的。
      【解决方案4】:

      在 Three.js 的 r82 版本中,TextureLoader 是用于加载纹理的对象。

      加载一个纹理(source code,demo)

      提取(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);
      

      加载多个纹理(source code、demo)

      在本例中,纹理在网格的构造函数中加载,多个纹理使用Promises 加载。

      提取(Globe.js):

      使用Object3D 创建一个新容器,以便在同一个容器中拥有两个网格:

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

      一个名为 textures 的映射,其中每个对象都包含纹理文件的 url 和用于存储 Three.js texture 对象的值的 val。

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

      promise 数组,对于 map 中名为 textures 的每个对象,在数组 texturePromises 中推送一个新的 Promise,每个 Promise 都会调用 loader.load。如果entry.val 的值是一个有效的THREE.Texture 对象,则解析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 将 promise 数组 texturePromises 作为参数。这样做会使浏览器等待所有的 Promise 解析,当它们完成时,我们可以加载几何体和材质。

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

      对于云球,只需要一个纹理:

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

      【讨论】:

        【解决方案5】:

        无错误处理

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

        带有错误处理

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

        结果:

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

        【讨论】:

          【解决方案6】:

          使用 TextureLoader 将图像加载为纹理,然后简单地将纹理应用到场景背景。

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

          结果:

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

          请参阅 CodePen 上 Hitesh Sahu (@hiteshsahu) 的 Pen Flat Earth Three.JS。

          【讨论】:

            猜你喜欢
            • 2017-06-05
            • 2019-07-31
            • 1970-01-01
            • 2017-04-26
            • 2013-06-22
            • 2023-04-09
            • 1970-01-01
            • 2013-06-28
            • 2014-07-11
            相关资源
            最近更新 更多