web-dev-qa-db-ja.com

THREE.jsでテクスチャを使用する

私は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の累乗です
  • この関数は、ボディがロードされるときに実際に呼び出されます。実際、それは異なる素材で動作します。
  • ウェブサーバーからファイルを提供しても機能しないため、クロスドメインポリシーが画像の読み込みを許可しないという問題はありません。

私は何を間違っていますか?

69
Andrea

画像がロードされるまでに、レンダラーはすでにシーンを描画しているため、手遅れです。解決策は変更することです

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

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

アンドレアのソリューションは絶対に正しいです、私は同じアイデアに基づいて別の実装を書くだけです。 THREE.ImageUtils.loadTexture() source を見ると、javascript Imageオブジェクトを使用していることがわかります。 $(window).loadイベントは、すべての画像が読み込まれた後に発生します!そのイベントでは、既にロードされたテクスチャでシーンをレンダリングできます...

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

ありがとう...

27
Mustafah

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);
});
20
Sky Yip

Three.jsのバージョンr82では、 TextureLoader はテクスチャのロードに使用するオブジェクトです。

1つのテクスチャの読み込み( ソースコードデモ

抽出( 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);

複数のテクスチャの読み込み( ソースコードデモ

この例では、テクスチャはメッシュのコンストラクタ内にロードされ、複数のテクスチャは Promises を使用してロードされます。

抽出( Globe.js ):

Object3Dを使用して、同じコンテナ内に2つのメッシュを持つ新しいコンテナを作成します。

var Globe = function (radius, segments) {

  THREE.Object3D.call(this);

  this.name = "Globe";

  var that = this;

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

すべてのオブジェクトにテクスチャファイルのtexturesとThree.js texture オブジェクトの値を格納するurlが含まれる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
    }
  };

texturesというマップ内の各オブジェクトのPromiseの配列。新しいPromiseを配列texturePromisesにプッシュすると、すべての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は、約束配列texturePromisesを引数として取ります。そうすることで、すべての約束が解決するのをブラウザが待機します。約束が解決したら、ジオメトリとマテリアルをロードできます。

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

雲球の場合、必要なテクスチャは1つだけです。

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

エラー処理なし

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

結果:

enter image description here

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

0
Hitesh Sahu