【问题标题】:Understanding physically correct lighting in three.js在 three.js 中理解物理上正确的光照
【发布时间】:2018-09-03 21:46:23
【问题描述】:

我可能误解了一些东西,但是...我正在尝试在 three.js 中使用物理上正确的照明和基于物理的渲染

我做了一个简单的场景。在这种情况下只是一架飞机。我在飞机上方 2 个单位(2 米)处放了一个灯。这架飞机使用MeshStandardMaterialroughness 为 0.9,metalness 为 0。灯的power 设置为 800,如果我理解正确的话,它是 800 流明,相当于一个 60 瓦的灯泡。我设置了renderer.physicallyCorrectLights = true

结果如下:

这个结果看起来一点也不像高出地板 2 米的 60 瓦灯泡。

我是不是做错了什么?

'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;
  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.MeshStandardMaterial({
      color: '#C84',
      side: THREE.DoubleSide,
      roughness: 0.9,
      metalness: 0,
    });
    const mesh = new THREE.Mesh(planeGeo, planeMat);
    mesh.rotation.x = Math.PI * -.5;
    scene.add(mesh);
  }

  {
    const color = 0xFFFFFF;
    const intensity = 1;
    const light = new THREE.PointLight(color, intensity);
    light.power = 800;
    light.decay = 2;
    light.distance = Infinity;
    light.position.set(0, 2, 0);
    scene.add(light);
    
    const helper = new THREE.PointLightHelper(light);
    scene.add(helper);
  }

  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);
  }
  render();
  window.onresize = render;
}

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.min.js"></script>
<canvas id="c"></canvas>

【问题讨论】:

    标签: three.js


    【解决方案1】:

    在拍摄物理场景时,您必须考虑曝光(f-stop)设置。我找不到相机的专用设置来允许这样做(这可能是一个很自然的地方找到它),但渲染器本身有一个曝光设置 -

    您可以在渲染器上使用toneMappingExposure 设置来找到合适的值,例如:

    renderer.toneMappingExposure = Math.pow(0.7, 5.0);  // -> exposure: 0.168
    

    例如,更现实的权力价值:

    light.power = 740;  // GE Lumens @ 60W incandescent 
    

    技术考虑:瓦特不能直接转换为流明,因为不同品牌在相同瓦特数下产​​生不同的流明值;在 60W 白炽灯的情况下,它们实际上可以在 400-1000 流明之间变化(GE 使用 740 左右)。但这是一个侧面.. :)

    'use strict';
    
    /* global dat */
    
    function main() {
      const canvas = document.querySelector('#c');
      const renderer = new THREE.WebGLRenderer({canvas: canvas});
      renderer.physicallyCorrectLights = true;
    
      renderer.toneMappingExposure = Math.pow(0.7, 5.0);
      
      const fov = 45;
      const aspect = 2;
      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.MeshStandardMaterial({
          color: '#C84',
          side: THREE.DoubleSide,
          roughness: 0.9,
          metalness: 0,
        });
        const mesh = new THREE.Mesh(planeGeo, planeMat);
        mesh.rotation.x = Math.PI * -.5;
        scene.add(mesh);
      }
    
      {
        const color = 0xFFFFFF;
        const intensity = 1;
        const light = new THREE.PointLight(color, intensity);
        light.power = 740;  // GE Lumens @ 60W incade.
        light.decay = 2;
        light.distance = Infinity;
        light.position.set(0, 2, 0);
        scene.add(light);
        
        const helper = new THREE.PointLightHelper(light);
        scene.add(helper);
      }
    
      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);
      }
      render();
      window.onresize = render;
    }
    
    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.min.js"></script>
    <canvas id="c"></canvas>

    【讨论】:

    • 感谢您的回答。你知道我在哪里可以找到更多关于曝光的信息吗?为什么是^5?为什么 .7 是合理的曝光率?等等...如果 PBR 的重点是我们输入真实世界的值并获得真实世界的结果,那么我想了解这些值的来源。
    • 抱歉,0.7 应该是 0.168。 pow 是我想使演示滑块产生一个对数结果,当移动时看起来很自然(我看到我忘记链接到它的演示)。对于现实生活中的值,您不仅必须使用 f-stop,还必须使用快门速度、ISO、胶片尺寸、间接照明等。通常 EV(曝光值,f-stop+快门)或 Lux 用于[相对] 曝光的真实场景,我不确定如何将其转换为三个曝光设置,我怀疑这可能有点武断。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-29
    • 1970-01-01
    相关资源
    最近更新 更多