WebGL2.0: renderizado a textura

RTT (renderizado a textura)

RTT (Render to Texture) significa renderizar a textura. En un proceso normal de renderizado de gráficos, el resultado final se renderiza en el framebuffer antes de mostrarse en la pantalla. RTT renderiza la escena en una textura y la usa más tarde.

1. Crea objetos de textura.

Para hacer RTT, primero cree un objeto de textura:

// 创建渲染对象
const targetTextureWidth = 256;   // 纹理的长度与宽度
const targetTextureHeight = 256;
const targetTexture = gl.createTexture();  // 创建纹理对象
gl.bindTexture(gl.TEXTURE_2D, targetTexture); // 进行bind,以下操作针对的是当前bind对象
 
{
  // 定义 0 级的大小和格式,不需要mipmap只需定义level 0即可
  const level = 0;
  const internalFormat = gl.RGBA; // 每个像素使用RGBA表示
  const border = 0;                         // 纹理的border,必须为0
  const format = gl.RGBA;
  const type = gl.UNSIGNED_BYTE; // 像素每个通道的存储格式
  const data = null;                             // 设置成null
  gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
                targetTextureWidth, targetTextureHeight, border,
                format, type, data);
 
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
}

Cabe señalar que aquí solo se crea un objeto de textura y no se proporcionan datos, por lo que los datos se establecen en nulos.

2. Crea un framebuffer

A continuación, debe crear un framebuffer, que es un conjunto de archivos adjuntos, que son texturas o renderbuffers. Los renderbuffers son similares a las texturas, pero admiten algunos formatos y opciones que las texturas no admiten. Sin embargo, el renderbuffer no se puede proporcionar directamente al sombreador como una textura.

// 创建并绑定帧缓冲
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
 
// 附加纹理为第一个颜色附件
const attachmentPoint = gl.COLOR_ATTACHMENT0;
gl.framebufferTexture2D(
    gl.FRAMEBUFFER, attachmentPoint, gl.TEXTURE_2D, targetTexture, level);
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);

3. Crea vínculos profundos

Al renderizar una textura, puede optar por no crear un vínculo de profundidad, por lo que no hay detección de profundidad y la relación de oclusión de la textura renderizada puede ser incorrecta. Si necesita crear un archivo adjunto profundo, puede seguir estos pasos:

// 创建一个深度纹理
const depthTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, depthTexture);
 
// 设置深度缓冲的大小和targetTexture相同
{
    
    
  // 定义 0 级的大小和格式
  const level = 0;
  const internalFormat = gl.DEPTH_COMPONENT24;
  const border = 0;
  const format = gl.DEPTH_COMPONENT;
  const type = gl.UNSIGNED_INT;
  const data = null;
  gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
                targetTextureWidth, targetTextureHeight, border,
                format, type, data);
 
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
 
  // 将深度纹理附加到缓冲帧
  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthTexture, level);
}

4. Renderizar y generar texturas

Antes de renderizar, debe vincular el framebuffer y configurar la ventana gráfica. Aquí está el código que hace el renderizado:

// 绑定帧缓冲
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);

// 设置视口大小
gl.viewport(0, 0, targetTextureWidth, targetTextureHeight);

// 清空画布颜色缓冲区和深度缓冲区
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

// 设置相机
// ...

// 设置光源
// ...

// 绘制场景
// ...

5. Usa texturas

Renderizado a textura, los escenarios de uso que conozco hasta ahora incluyen los siguientes:
1. Pasarla directamente al sombreador para su uso.La
textura generada se puede pasar directamente al sombreador y usarse en el sombreador para renderizar. Antes de renderizar, debe desvincular el Framebuffer y usar el objeto de textura para dibujar:

// 将帧缓冲的绑定解除
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
 
// 使用生成的纹理进行绘制
gl.bindTexture(gl.TEXTURE_2D, targetTexture);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.useProgram(program);
gl.drawArrays(gl.TRIANGLES, 0, 6);

2. Lea la textura en una matriz y luego úsela más. Puede usarse para seleccionar objetos, generar texturas, depurar Shader, etc.

// 读取纹理到数组
const pixels = new Uint8Array(targetTextureWidth * targetTextureHeight * 4);
gl.readPixels(0, 0, targetTextureWidth, targetTextureHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);

Aquí, usamos la función gl.readPixels() para leer los datos de píxeles del framebuffer en una matriz. Esta matriz son los datos de textura que finalmente generamos y que se pueden usar en renderizaciones posteriores. Si desea utilizar esta matriz para regenerar la textura, puede presionar el siguiente código:

// 创建纹理对象
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);

// 设置纹理参数
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

// 将像素数据绑定到纹理对象上
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, targetTextureWidth, targetTextureHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixels);

Algunos desarrolladores convierten los valores intermedios del Shader en una textura para depurar. Algunos programas representan el ID del objeto de la escena en la textura para la selección de objetos.
3. Mapa de sombras
En el Mapeo de sombras, primero debe renderizar la escena una vez para generar un mapa de profundidad (Mapa de profundidad), que en realidad es una textura que almacena la información de profundidad de la escena vista desde la perspectiva de la fuente de luz. Luego, el mapa de profundidad se aplica a la escena para realizar cálculos de sombras. La renderización de texturas es una tecnología básica para implementar Shadow Mapping.

Supongo que te gusta

Origin blog.csdn.net/loveoobaby/article/details/129328716
Recomendado
Clasificación