Promo Icon

鈿★笍 Limited Black Friday Deal

Get 50% off on the React Three Fiber Ultimate Course with the promo code ULTIMATE50

Buy Now

$85.00 $42.50

Render Target

Starter pack

Cuando usamos React Three Fiber simplemente a帽adimos un componente Canvas y ponemos nuestra escena 3D dentro, y se renderizar谩 en la pantalla.

Si tienes algo de experiencia con Three.js, sabes que primero necesitamos crear un WebGLRenderer y luego llamar a renderer.render(scene, camera) para renderizar nuestra escena en la pantalla.

Afortunadamente, React Three Fiber hace todo esto por nosotros tras bambalinas, pero para casos de uso m谩s avanzados, es importante saber c贸mo funciona.

El rol del renderer es procesar la escena 3D para crear la imagen 2D real que vemos en la pantalla.

Por defecto, la salida del renderer est谩 configurada para el componente Canvas y se muestra en la pantalla, pero tambi茅n podemos mostrarla en una textura (a trav茅s de un WebGLRenderTarget).

Por ahora puede parecer un poco conceptual, veamos c贸mo funciona en la pr谩ctica y de qu茅 maneras creativas podemos usarlo.

C谩mara de Seguridad

Para entender c贸mo funcionan los Render Targets y qu茅 podemos hacer con ellos, prepar茅 una escena 3D que contiene:

  • Un modelo 3D de una sala de estar de Alex Safayan CC-BY v铆a Poly Pizza
  • Un avatar de Ready Player Me (como el que usamos en las lecciones de portfolio) viendo a Bob Esponja en la TV
  • Un control remoto 2D con m煤ltiples botones

Avatar 3D viendo la TV

El objetivo es crear un sistema de vigilancia renderizando la escena desde el punto de vista de una c谩mara de seguridad en la TV.

Renderizando la escena a una textura

Para renderizar nuestra escena actual a una textura, necesitaremos crear un Render Target.

Gracias a la biblioteca Drei, podemos crear f谩cilmente un Render Target con el hook useFBO:

// ...
import { useFBO } from "@react-three/drei";

export const Experience = () => {
  const cornerRenderTarget = useFBO();
  // ...
};

Si quieres saber c贸mo crear un Render Target desde cero, puedes consultar el c贸digo fuente del hook useFBO aqu铆. Es un buen reflejo tener para entender c贸mo funcionan las cosas bajo el cap贸.

Ahora que tenemos un Render Target, necesitamos decirle a nuestro renderer que renderice nuestra scene usando nuestra camera.

Todos esos objetos est谩n disponibles en el root state de nuestra aplicaci贸n React Three Fiber. Este es el objeto que retorna el hook useThree.

La propiedad gl es el renderer.

Pero, como queremos mostrar lo que est谩 sucediendo en tiempo real en el TV, realizaremos el proceso en cada frame usando el hook useFrame.

La funci贸n de callback incluye el root state, por lo que podemos acceder a nuestras variables directamente desde 茅l:

// ...
import { useFrame } from "@react-three/fiber";

export const Experience = () => {
  // ...
  useFrame(({ gl, camera, scene }) => {
    gl.setRenderTarget(cornerRenderTarget);
    gl.render(scene, camera);
    gl.setRenderTarget(null);
  });
  // ...
};

Lo que estamos haciendo aqu铆 es:

  • Configurar el Render Target como la salida del renderer
  • Renderizar la scene usando la camera y, como la salida del renderer est谩 configurada en el Render Target, renderizar谩 la escena en 茅l
  • Configurar la salida del renderer a null para renderizar la escena en el lienzo de nuevo

Ahora que tenemos nuestro Render Target, necesitamos mostrarlo en el TV. Vamos a a帽adir una referencia al material que actualmente renderiza el video:

// ...
import { useRef } from "react";

export const Experience = () => {
  // ...
  const tvMaterial = useRef();
  // ...
  return (
    <>
      {/* ... */}
      <group position-y={-0.5}>
        <group>
          <Sky />
          <Avatar rotation-y={Math.PI} scale={0.45} position-z={0.34} />
          <Gltf src="models/Room.glb" scale={0.3} rotation-y={-Math.PI / 2} />
          <mesh position-x={0.055} position-y={0.48} position-z={-0.601}>
            <planeGeometry args={[0.63, 0.44]} />
            <meshBasicMaterial ref={tvMaterial} />
          </mesh>
        </group>
      </group>
      {/* ... */}
    </>
  );
};

Y luego, podemos usar el hook useFrame para actualizar la propiedad map del material con nuestro Render Target:

// ...
export const Experience = () => {
  // ...
  useFrame(({ gl, camera, scene }) => {
    // ...
    tvMaterial.current.map = cornerRenderTarget.texture;
  });
  // ...
};

3D avatar watching to the TV with the security camera view

Ahora podemos ver la vista de la c谩mara de seguridad en el TV, pero la pantalla del TV en la vista de la c谩mara de seguridad est谩 vac铆a.

Esto se debe a que cuando renderizamos la escena en el Render Target, nuestra pantalla est谩 vac铆a.

Efecto Inception

Para ver la vista de la c谩mara de seguridad dentro de la pantalla de la TV de la pantalla de la TV 馃く, necesitamos:

  • Crear otro render target (lo nombraremos bufferRenderTarget)
  • Renderizar la escena en 茅l
  • Adjuntarlo al material de la pantalla de la TV
  • Renderizar la escena en el cornerRenderTarget
  • Adjuntarlo al material de la TV
// ...
export const Experience = () => {
  const bufferRenderTarget = useFBO();

  // ...
  useFrame(({ gl, camera, scene }) => {
    gl.setRenderTarget(bufferRenderTarget);
    gl.render(scene, camera);
    tvMaterial.current.map = bufferRenderTarget.texture;
    gl.setRenderTarget(cornerRenderTarget);
    gl.render(scene, camera);
    gl.setRenderTarget(null);
    tvMaterial.current.map = cornerRenderTarget.texture;
  });
  // ...
};

Podr铆a sonar aterrador, pero en realidad es bastante simple. Solo piensa en lo que est谩 ocurriendo en cada paso.

隆Ahora nuestra escena se renderiza infinitamente dentro de la pantalla de la TV!

Aunque es el efecto m谩s realista que podemos crear, no es el m谩s creativo. Vamos a eliminar el efecto inception y mostrar Spongebob Squarepants en la pantalla en su lugar:

End of lesson preview

To get access to the entire lesson, you need to purchase the course.