在three.js中使用物理正确的照明进行衰减和距离

时间:2018-08-31 00:39:13

标签: three.js

在three.js中,distance设置与基于物理的照明有关意味着什么?

对于非基于物理的照明,distance设置是灯光影响线性消失的设置。有效地

 lightAffect = 1 - min(1, distanceFromLight / distance)

我不太了解基于物理的照明,但是在我看来,真实的照明没有距离设置,它们仅具有功率输出(流明)和基于大气密度的衰减。 Three.js既有power设置又有decay设置,尽管根本不清楚应将decay设置为什么,因为文档实际上只是说将其设置为{{1} }。

例如,如果我要基于物理的照明,应该为基于物理的2设置distance吗?

PointLight
'use strict';

/* global dat */

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas: canvas});
  renderer.physicallyCorrectLights = true;

  const fov = 45;
  const aspect = 2;  // the canvas default
  const zNear = 0.1;
  const zFar = 100;
  const camera = new THREE.PerspectiveCamera(fov, aspect, zNear, zFar);
  camera.position.set(0, 10, 20);
  camera.lookAt(0, 5, 0);

  const scene = new THREE.Scene();
  scene.background = new THREE.Color('black');

  {
    const planeSize = 40;

    const planeGeo = new THREE.PlaneBufferGeometry(planeSize, planeSize);
    const planeMat = new THREE.MeshPhongMaterial({
      color: '#A86',
      side: THREE.DoubleSide,
    });
    const mesh = new THREE.Mesh(planeGeo, planeMat);
    mesh.rotation.x = Math.PI * -.5;
    scene.add(mesh);
  }  {
    const cubeSize = 4;
    const cubeGeo = new THREE.BoxBufferGeometry(cubeSize, cubeSize, cubeSize);
    const cubeMat = new THREE.MeshPhongMaterial({color: '#8AC'});
    const mesh = new THREE.Mesh(cubeGeo, cubeMat);
    mesh.position.set(cubeSize + 1, cubeSize / 2, 0);
    scene.add(mesh);
  }
  {
    const sphereRadius = 3;
    const sphereWidthDivisions = 32;
    const sphereHeightDivisions = 16;
    const sphereGeo = new THREE.SphereBufferGeometry(sphereRadius, sphereWidthDivisions, sphereHeightDivisions);
    const sphereMat = new THREE.MeshPhongMaterial({color: '#CA8'});
    const mesh = new THREE.Mesh(sphereGeo, sphereMat);
    mesh.position.set(-sphereRadius - 1, sphereRadius + 2, 0);
    scene.add(mesh);
  }

  {
    const color = 0xFFFFFF;
    const intensity = 1;
    const light = new THREE.PointLight(color, intensity);
    light.power = 800;
    light.distance = 20;
    light.position.set(0, 10, 5);
    scene.add(light);
    light.decay = 2;

    const helper = new THREE.PointLightHelper(light);
    scene.add(helper);

    const onChange = () => {
      helper.update();
      render();
    };
    setTimeout(onChange);
    window.onresize = onChange;

    const gui = new dat.GUI();
    gui.add(light, 'distance', 0, 100).onChange(onChange);
    gui.add(light, 'decay', 0, 4).onChange(onChange);
    gui.add(light, 'power', 0, 3000).onChange(onChange);
  }

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

  function render() {
    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }

    renderer.render(scene, camera);
  }
}

main();
html, body {
    margin: 0;
    height: 100%;
}
#c {
    width: 100%;
    height: 100%;
    display: block;
}

1 个答案:

答案 0 :(得分:0)

至少从r95开始,通读three.js资料及其链接的纸张,对于基于物理的光源,距离设置基本上应该为Infinity

在论文中,他们指出了基于物理的灯光会发出无限远的光,但是在3D引擎中当然不好。大多数3D引擎需要计算每个绘制对象的最小灯光数量,因此添加了lightDistance设置,如果灯光比lightDistance更远,它们可以忽略该灯光。问题是,如果他们只是停止使用lightDistance过去的光线,那么它们就会有锋利的边缘,因此他们陷入了崩溃。

three.js从论文中复制了lightDistance和falloff设置,但是three.js不会在灯光远处从计算中剔除灯光,因此似乎没有理由不将distance设置为无穷远AFAICT至少从r95起。