THREE.js: Имитация MeshBasicMaterial, позволяя разноцветные огни

Я делаю игру типа "Подземелье" с использованием three.js. Я использовал MeshBasicMaterial, чтобы все было "правильно", чтобы подземелье постоянно было видно. Однако я хотел добавить "бонусные" огни, проходящие под дверными проемами или прорезями в стене, чтобы создать атмосферу. Но свет не отображается на BasicMaterial, поэтому я переключился на Фонг, чтобы проверить свет на моем полу. Теперь мой пол черный! Скорее всего, потому что нет глобального света.

Есть ли способ имитировать свойства MeshBasicMaterial, позволяя разноцветные источники света? Темница закрыта со всех четырех сторон, поэтому я представляю, что если поместить очень большой глобальный свет, то повсюду отбрасывают тени или перекрывают цвета на земле.

Не основной фокус моего вопроса, но дополнительно: как сделать так, чтобы свет останавливался стенами, а не просто проходил сквозь них? Стены - это всего лишь 1x1x1 3d сетчатые кубы, порожденные картографической системой.

С MeshBasicMaterial

С MeshPhongMaterial

С MeshPhongMaterial

1 ответ

Решение

Как только вы переключитесь на MeshPhongMaterial Материал становится затененным. Вы можете установить некоторые параметры, чтобы он был ближе к MeshBasicMaterial, но вы по-прежнему будете получать градиентное освещение, которое в любом случае вы действительно ищете для своего "бонусного" освещения. В приведенном ниже коде я установил shininess свойство до 0, что устраняет эффект жесткого света затенения Фонга.

Чтобы свет не проникал через ваши стены, вам нужно применить отбрасывание теней. Это действительно очень просто в THREE.js, и в Интернете есть множество статей, описывающих, как это сделать, поэтому я не буду повторять здесь что-либо подобное. Но, как вы можете видеть на моем простом примере, вам нужно настроить свои сетки для приведения и получения теней (castShadows / receiveShadows соответственно), и включите ваш свет, чтобы также castShadows).

var renderer, scene, camera, controls, stats;

var WIDTH = window.innerWidth,
  HEIGHT = window.innerHeight,
  FOV = 70,
  NEAR = 1,
  FAR = 1000;

function populateScene() {
  var cfgeo = new THREE.PlaneBufferGeometry(100, 100),
    lwallgeo = new THREE.PlaneBufferGeometry(20, 20),
    rwallgeo = new THREE.PlaneBufferGeometry(50, 20),
    farwallgeo = new THREE.PlaneBufferGeometry(50, 20),
    bumpgeo = new THREE.PlaneBufferGeometry(10, 10);

  var mat = new THREE.MeshPhongMaterial({
    color: 0xcccccc,
    emissive: new THREE.Color(0x0c0c0c),
    shininess: 0,
    side: THREE.DoubleSide
  });

  var ceiling = new THREE.Mesh(cfgeo, mat),
    floor = new THREE.Mesh(cfgeo, mat),
    lwall = new THREE.Mesh(lwallgeo, mat),
    rwall = new THREE.Mesh(rwallgeo, mat),
    farwall = new THREE.Mesh(farwallgeo, mat),
    bump1 = new THREE.Mesh(bumpgeo, mat),
    bump2 = new THREE.Mesh(bumpgeo, mat);
  ceiling.castShadow = true;
  ceiling.receiveShadow = true;
  floor.castShadow = true;
  floor.receiveShadow = true;
  lwall.castShadow = true;
  lwall.receiveShadow = true;
  rwall.castShadow = true;
  rwall.receiveShadow = true;
  farwall.castShadow = true;
  farwall.receiveShadow = true;
  bump1.castShadow = true;
  bump1.receiveShadow = true;
  bump2.castShadow = true;
  bump2.receiveShadow = true;

  ceiling.position.y = 10;
  ceiling.rotation.x = Math.PI / 2;
  floor.position.y = -10;
  floor.rotation.x = Math.PI / -2;
  lwall.rotation.y = Math.PI / 2;
  lwall.position.x = -10;
  rwall.rotation.y = Math.PI / -2;
  rwall.position.x = 10;
  rwall.position.y = 2;
  farwall.position.z = -20;
  bump1.rotation.y = Math.PI / -2;
  bump2.rotation.y = Math.PI / -2;
  bump1.position.set(10, -10, -15);
  bump2.position.set(10, -10, 5);

  scene.add(ceiling);
  scene.add(floor);
  scene.add(lwall);
  scene.add(rwall);
  scene.add(farwall);
  scene.add(bump1);
  scene.add(bump2);

  var bonus = new THREE.SpotLight(0xcccc00, 0.5);
  bonus.position.set(15, -7, -5);
  bonus.castShadow = true;
  bonus.distance = 20;
  var tgt = new THREE.Object3D();
  tgt.position.set(0, -10, -10);
  bonus.target = tgt;
  scene.add(bonus);
  scene.add(tgt);
}

function init() {
  document.body.style.backgroundColor = "slateGray";

  renderer = new THREE.WebGLRenderer({
    antialias: true,
    alpha: true
  });
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap;

  document.body.appendChild(renderer.domElement);
  document.body.style.overflow = "hidden";
  document.body.style.margin = "0";
  document.body.style.padding = "0";

  scene = new THREE.Scene();

  camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
  camera.position.z = 15;
  scene.add(camera);

  controls = new THREE.TrackballControls(camera, renderer.domElement);
  controls.dynamicDampingFactor = 0.5;
  controls.rotateSpeed = 3;

  var light = new THREE.PointLight(0xffffff, 1, Infinity);
  camera.add(light);

  stats = new Stats();
  stats.domElement.style.position = 'absolute';
  stats.domElement.style.top = '0';
  document.body.appendChild(stats.domElement);

  resize();
  window.onresize = resize;

  populateScene();

  animate();
}

function resize() {
  WIDTH = window.innerWidth;
  HEIGHT = window.innerHeight;
  if (renderer && camera && controls) {
    renderer.setSize(WIDTH, HEIGHT);
    camera.aspect = WIDTH / HEIGHT;
    camera.updateProjectionMatrix();
    controls.handleResize();
  }
}

function render() {
  renderer.render(scene, camera);
}

function animate() {
  requestAnimationFrame(animate);
  render();
  controls.update();
  stats.update();
}

function threeReady() {
  init();
}

(function() {
  function addScript(url, callback) {
    callback = callback || function() {};
    var script = document.createElement("script");
    script.addEventListener("load", callback);
    script.setAttribute("src", url);
    document.head.appendChild(script);
  }

  addScript("https://threejs.org/build/three.js", function() {
    addScript("https://threejs.org/examples/js/controls/TrackballControls.js", function() {
      addScript("https://threejs.org/examples/js/libs/stats.min.js", function() {
        threeReady();
      })
    })
  })
})();

Другие вопросы по тегам