Статьи

WebGL с Three.js – Урок 6

Сегодня мы продолжаем наши уроки WebGL для тех, кто изучает его и хочет расширить свои знания. В сегодняшнем уроке мы рассмотрим процесс загрузки готовых трехмерных объектов. Существует множество веб-сайтов, на которых вы можете загрузить эти модели, и, кроме того, если у вас есть редактор трехмерных объектов (например, 3D Max, Maya или даже Blender), вы можете создавать свои собственные модели. Существует также множество форматов файлов трехмерных объектов, таких как obj, collada (dae), obj, mtl, stl, vrml и так далее. Большинство из них могут быть загружены в ваши сцены three.js с помощью специальных загрузчиков. И сегодня мы рассмотрим, как загружать трехмерные модели, используя различные загрузчики.

Live Demo 1
Live Demo 2
Live Demo 3
Live Demo 4

OBJ

Чтобы загрузить объектные файлы (.obj), мы можем использовать OBJLoader.js. Использовать эту библиотеку довольно просто, но, прежде всего, нам нужно присоединить библиотеку (в разделе, где мы связываем все другие необходимые скрипты):

<script src="js/three.min.js"></script>
<script src="js/OBJLoader.js"></script>
<script src="js/THREEx.WindowResize.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/stats.min.js"></script>
<script src="js/script1.js"></script>

Теперь давайте подготовим общий скелет (из всех наших демонстраций):

var lesson6 = {
  scene: null,
  camera: null,
  renderer: null,
  container: null,
  controls: null,
  clock: null,
  stats: null,

  init: function() { // Initialization

    // create main scene
    this.scene = new THREE.Scene();
    this.scene.fog = new THREE.FogExp2(0xcce0ff, 0.0003);

    var SCREEN_WIDTH = window.innerWidth,
        SCREEN_HEIGHT = window.innerHeight;

    // prepare camera
    var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 1, FAR = 2000;
    this.camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
    this.scene.add(this.camera);
    this.camera.position.set(0, 100, 300);
    this.camera.lookAt(new THREE.Vector3(0,0,0));

    // prepare renderer
    this.renderer = new THREE.WebGLRenderer({ antialias:true });
    this.renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
    this.renderer.setClearColor(this.scene.fog.color);
    this.renderer.shadowMapEnabled = true;
    this.renderer.shadowMapSoft = true;

    // prepare container
    this.container = document.createElement('div');
    document.body.appendChild(this.container);
    this.container.appendChild(this.renderer.domElement);

    // events
    THREEx.WindowResize(this.renderer, this.camera);

    // prepare controls (OrbitControls)
    this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
    this.controls.target = new THREE.Vector3(0, 0, 0);
    this.controls.maxDistance = 2000;

    // prepare clock
    this.clock = new THREE.Clock();

    // prepare stats
    this.stats = new Stats();
    this.stats.domElement.style.position = 'absolute';
    this.stats.domElement.style.left = '50px';
    this.stats.domElement.style.bottom = '50px';
    this.stats.domElement.style.zIndex = 1;
    this.container.appendChild( this.stats.domElement );

    // add spot light
    var spLight = new THREE.SpotLight(0xffffff, 1.75, 2000, Math.PI / 3);
    spLight.castShadow = true;
    spLight.position.set(-100, 300, -50);
    this.scene.add(spLight);

    // add simple ground
    var ground = new THREE.Mesh( new THREE.PlaneGeometry(200, 200, 10, 10), new THREE.MeshLambertMaterial({color:0x999999}) );
    ground.receiveShadow = true;
    ground.position.set(0, 0, 0);
    ground.rotation.x = -Math.PI / 2;
    this.scene.add(ground);

    // load a model
    this.loadModel();
  },
  loadModel: function() {

    ......
  }
};

// Animate the scene
function animate() {
  requestAnimationFrame(animate);
  render();
  update();
}

// Update controls and stats
function update() {
  lesson6.controls.update(lesson6.clock.getDelta());
  lesson6.stats.update();
}

// Render the scene
function render() {
  if (lesson6.renderer) {
    lesson6.renderer.render(lesson6.scene, lesson6.camera);
  }
}

// Initialize lesson on page load
function initializeLesson() {
  lesson6.init();
  animate();
}

if (window.addEventListener)
  window.addEventListener('load', initializeLesson, false);
else if (window.attachEvent)
  window.attachEvent('onload', initializeLesson);
else window.onload = initializeLesson;

Этот код создает пустую сцену с камерой, статистикой управления рендерингом и освещением. Обратите внимание на пустую функцию «loadModel» — мы будем размещать здесь разные коды для загрузки моделей разных форматов. Наш первый формат — «obj». Посмотрите на следующую реализацию:

// prepare loader and load the model
var oLoader = new THREE.OBJLoader();
oLoader.load('models/chair.obj', function(object, materials) {

  // var material = new THREE.MeshFaceMaterial(materials);
  var material2 = new THREE.MeshLambertMaterial({ color: 0xa65e00 });

  object.traverse( function(child) {
    if (child instanceof THREE.Mesh) {

      // apply custom material
      child.material = material2;

      // enable casting shadows
      child.castShadow = true;
      child.receiveShadow = true;
    }
  });

  object.position.x = 0;
  object.position.y = 0;
  object.position.z = 0;
  object.scale.set(1, 1, 1);
  lesson6.scene.add(object);
});

Сначала мы создали новый экземпляр THREE.OBJLoader, а затем — загружаем файл модели ‘chair.obj’. Чтобы применить пользовательский материал, мы просмотрели его дочерние элементы и применили подготовленный материал2 (THREE.MeshLambertMaterial). Мы также применили отбрасывание и получение теней. В конце — мы устанавливаем положение объекта и устанавливаем значение масштаба.

MTL

Короче говоря, это дополнение к ранее описанному формату OBJ. Потому что MTL — это файл, который описывает материалы файла OBJ. Для загрузки файлов OBJ с поддержкой MTL мы можем использовать другой загрузчик: OBJMTLLoader. Чтобы его использовать, не забудьте включить необходимые библиотеки:

<script src="js/MTLLoader.js"></script>
<script src="js/OBJMTLLoader.js"></script>

Теперь добавьте следующий код в нашу функцию loadModel:

// prepare loader and load the model
var oLoader = new THREE.OBJMTLLoader();
oLoader.load('models/castle.obj', 'models/castle.mtl', function(object) {

  object.position.x = -200;
  object.position.y = 0;
  object.position.z = 100;
  object.scale.set(0.1, 0.1, 0.1);
  lesson6.scene.add(object);
});

Как видите, функция загрузки принимает больше параметров — мы можем указать наш файл ‘mtl’ материалами. Этот метод позволяет нам загружать модель (obj) с текстурами!

DAE

Файлы Collada (dae) также популярны среди 3d дизайнеров. Этот формат также поддерживает текстуры. Чтобы загрузить этот формат, мы можем использовать другой загрузчик: ColladaLoader. Чтобы использовать его, не забудьте включить необходимые библиотеки:

<script src="js/ColladaLoader.js"></script>

Теперь добавьте следующий код в нашу функцию loadModel:

// prepare loader and load the model
var oLoader = new THREE.ColladaLoader();
oLoader.load('models/mlc.dae', function(collada) {

  var object = collada.scene;
  var skin = collada.skins[0];

  object.rotation.x = -Math.PI / 2;
  object.rotation.z = Math.PI / 2;
  object.position.x = -50;
  object.position.y = -100;
  object.position.z = 0;
  object.scale.set(0.025, 0.025, 0.025);
  object.updateMatrix();
  lesson6.scene.add(object);
});

JSON

Этот формат изначально поддерживается Three.js. Он также поддерживает пользовательские материалы (с текстурами), которые описаны в файле json. Чтобы загрузить этот формат, мы можем использовать другой загрузчик: JSONLoader:

// prepare loader and load the model
var oLoader = new THREE.JSONLoader();
oLoader.load('models/palm.js', function(geometry, materials) {

  // get original materials
  var material = new THREE.MeshFaceMaterial(materials);

  var mesh = new THREE.Mesh(geometry, material);

  mesh.position.x = -50;
  mesh.position.y = -80;
  mesh.position.z = 0;
  mesh.scale.set(10, 10, 10);
  lesson6.scene.add(mesh);
});
Live Demo 1
Live Demo 2
Live Demo 3
Live Demo 4