Цели рендеринга

Цель рендеринга в three.js - это в основном текстура, которую вы можете рендерить. После рендеринга вы можете использовать эту текстуру как любую другую текстуру.

Давайте сделаем простой пример. Начнем с примера статьи об отзывчивости.

Рендеринг к цели рендеринга практически идентичен обычному рендерингу. Сначала мы создаем WebGLRenderTarget.

const rtWidth = 512;
const rtHeight = 512;
const renderTarget = new THREE.WebGLRenderTarget(rtWidth, rtHeight);

Затем нам нужна Camera и Scene

const rtFov = 75;
const rtAspect = rtWidth / rtHeight;
const rtNear = 0.1;
const rtFar = 5;
const rtCamera = new THREE.PerspectiveCamera(rtFov, rtAspect, rtNear, rtFar);
rtCamera.position.z = 2;

const rtScene = new THREE.Scene();
rtScene.background = new THREE.Color('red');

Обратите внимание, что мы устанавливаем aspect для aspect рендеринга, а не для canvas. Правильный aspect зависит от того, для чего мы выполняем рендеринг. В этом случае мы будем использовать текстуру цели рендеринга на стороне куба. Поскольку грани куба являются квадратными, мы хотим, чтобы aspect = 1.0.

Мы заполняем сцену материалом. В этом случае мы используем свет и 3 куба из предыдущей статьи.

{
  const color = 0xFFFFFF;
  const intensity = 1;
  const light = new THREE.DirectionalLight(color, intensity);
  light.position.set(-1, 2, 4);
*  rtScene.add(light);
}

const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);

function makeInstance(geometry, color, x) {
  const material = new THREE.MeshPhongMaterial({color});

  const cube = new THREE.Mesh(geometry, material);
*  rtScene.add(cube);

  cube.position.x = x;

  return cube;
}

*const rtCubes = [
  makeInstance(geometry, 0x44aa88,  0),
  makeInstance(geometry, 0x8844aa, -2),
  makeInstance(geometry, 0xaa8844,  2),
];

Scene и Camera из предыдущей статьи все еще там. Мы будем использовать их для рендеринга на холст. Нам просто нужно добавить материал для рендеринга.

Давайте добавим куб, который использует текстуру цели рендеринга.

const material = new THREE.MeshPhongMaterial({
  map: renderTarget.texture,
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

Теперь во время рендеринга сначала мы рендерим целевую сцену рендеринга в цель рендеринга.

function render(time) {
  time *= 0.001;

  ...

  // rotate all the cubes in the render target scene
  rtCubes.forEach((cube, ndx) => {
    const speed = 1 + ndx * .1;
    const rot = time * speed;
    cube.rotation.x = rot;
    cube.rotation.y = rot;
  });

  // draw render target scene to render target
  renderer.setRenderTarget(renderTarget);
  renderer.render(rtScene, rtCamera);
  renderer.setRenderTarget(null);

Затем мы визуализируем сцену с помощью одного куба, который использует текстуру цели рендеринга для холста.

  // rotate the cube in the scene
  cube.rotation.x = time;
  cube.rotation.y = time * 1.1;

  // render the scene to the canvas
  renderer.render(scene, camera);

И вуаля

Куб красный, потому что мы установили background rtScene на красный, чтобы текстура цели рендеринга была очищена до красного.

Цели рендеринга используются для всех видов вещей. Тени используют цели рендеринга. Сбор может использовать цель рендеринга. Различные виды эффектов постобработки требуют целей рендеринга. Для рендеринга зеркала заднего вида в автомобиле или просмотра в реальном времени на мониторе в 3D-сцене может использоваться цель рендеринга.

Несколько замечаний по использованию WebGLRenderTarget.

  • По умолчанию WebGLRenderTarget создает 2 текстуры. Цветная текстура и текстура глубины / трафарета. Если вам не нужны текстуры глубины или трафарета, вы можете попросить не создавать их, передав параметры. Пример:

      const rt = new THREE.WebGLRenderTarget(width, height, {
        depthBuffer: false,
        stencilBuffer: false,
      });
    
  • Возможно, вам придется изменить размер цели рендеринга

    В приведенном выше примере мы делаем цель рендеринга фиксированного размера, 512x512. Для таких вещей, как постобработка, вам обычно нужно сделать цель рендеринга того же размера, что и ваш холст. В нашем коде это означало бы, что при изменении размера холста мы также обновляли бы и размер цели рендеринга, и камеру, которую мы используем при рендеринге, цели рендеринга. Пример:

    function render(time) {
      time *= 0.001;
    
      if (resizeRendererToDisplaySize(renderer)) {
        const canvas = renderer.domElement;
        camera.aspect = canvas.clientWidth / canvas.clientHeight;
        camera.updateProjectionMatrix();
    
    +    renderTarget.setSize(canvas.width, canvas.height);
    +    rtCamera.aspect = camera.aspect;
    +    rtCamera.updateProjectionMatrix();
    }