【问题标题】:decay and distance with physically correct lighting in three.jsThree.js 中物理正确光照的衰减和距离
【发布时间】:2018-08-31 00:39:12
【问题描述】:

three.js 中的distance 设置与基于物理的光照相关是什么意思?

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

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

我不太了解基于物理的照明,但在我看来,真正的灯光没有距离设置,它们只有功率输出(流明)和基于大气密度的衰减。 Three.js 有一个 power 设置和一个 decay 设置,尽管完全不清楚应该将 decay 设置为什么,因为文档实际上只是说将其设置为 2

如果我想要基于物理的照明,我应该为基于物理的PointLight 设置distance 什么?

'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;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.2/dat.gui.min.js"></script>
<canvas id="c"></canvas>

【问题讨论】:

  • 不是答案:距离单位通常以米为单位。有关 distance 在您的情况下如何影响照明的说明,请参阅 bsdfs.glsl 中的内联 cmets。
  • 阅读linked paper page 32 这显然是一种黑客行为。 distance 设置主要在那里,因此 3D 引擎可以知道光线何时超出范围并且不必被视为贡献,因此可以忽略。不过,它并没有真正提供任何关于如何设置它的指导。我听起来基本上是“由艺术家决定”,尽管我想你可以计算出无限距离的光何时低于某个阈值并将距离设置为该阈值或略高。
  • 也就是说,如果我正确理解了three.js,three.js 不会进行任何灯光管理。场景中的所有灯光都会影响具有受该类型灯光影响的材质的所有对象。因此,distance 始终可以设置为 Infinity 或某个较大的数字,因为将其设置得更小没有意义,因为它不会被剔除?
  • distance 设置为零与基本灯光的无穷大相同。对于物理上正确的灯光,您必须阅读源代码以了解其后果。

标签: three.js


【解决方案1】:

阅读 three.js 源代码和它所链接的论文,至少从 r95 开始,距离设置基本上应该是 Infinity,用于基于物理的灯光。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-19
    • 1970-01-01
    • 1970-01-01
    • 2016-03-07
    • 1970-01-01
    • 2017-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多