webgl2 trouble rendering float texture to canvas

If I use webgl2 to render something (e.g. a triangle) to an RGBA UNSIGNED_BYTE texture, then render that texture to the canvas, everything works fine. But I’m having trouble getting my example to work when rendering a RGBA32F FLOAT texture to the canvas. Instead I just get a solid black box, but no error message. Any ideas how to get the float example working?

This example is with an int texture, which works as expected (outputs purple triangle with white background as the texture, which is overlayed on a larger grey background)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>"use strict";
function main() {
// Get the WebGL context
const canvas = document.querySelector("#canvas");
const gl = canvas.getContext("webgl2");
const textureWidth = 100;
const textureHeight = 100;
// Render purple triangle to texture
{
const vertexShaderSource = `#version 300 es
in vec4 a_position;
void main() {
gl_Position = a_position;
}
`;
const fragmentShaderSource = `#version 300 es
precision highp float;
out vec4 outColor;
void main() {
outColor = vec4(1,0,1, 1);
}
`;
// create/compile shaders
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
const program = createProgram(gl, vertexShader, fragmentShader);
// set a_position attribute
const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const positions = [
-1, -1,
0, 1,
1, 0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);
gl.enableVertexAttribArray(positionAttributeLocation);
// Tell the attribute how to get data out of positionBuffer
const size = 2; // 2 components per iteration
let type = gl.FLOAT; // the data is 32bit floats
const normalize = false; // don't normalize the data
const stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
let offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset);
gl.useProgram(program);
// set up the target texture
const targetTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, targetTexture);
const level = 0;
const internalFormat = gl.RGBA;
const border = 0;
const format = gl.RGBA;
type = gl.UNSIGNED_BYTE;
const data = null;
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
textureWidth, textureHeight, border,
format, type, data);
// set the filtering so we don't need mips
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);
// Create and bind the framebuffer
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
// attach the texture as the first color attachment
const attachmentPoint = gl.COLOR_ATTACHMENT0;
gl.framebufferTexture2D(
gl.FRAMEBUFFER, attachmentPoint, gl.TEXTURE_2D, targetTexture, level);
gl.viewport(0, 0, textureWidth, textureHeight);
// Clear the canvas
gl.clearColor(1,1,1,1);
gl.clear(gl.COLOR_BUFFER_BIT);
const primitiveType = gl.TRIANGLES;
offset = 0;
const count = 3;
gl.drawArrays(primitiveType, offset, count);
}
// Now draw the texture to the canvas
{
const vertexShaderSource = `#version 300 es
in vec2 a_position;
in vec2 a_texCoord;
out vec2 v_texCoord;
void main() {
gl_Position = vec4(a_position, 0, 1);
v_texCoord = a_texCoord;
}
`;
const fragmentShaderSource = `#version 300 es
precision highp float;
uniform sampler2D u_image;
in vec2 v_texCoord;
out vec4 outColor;
void main() {
outColor = texture(u_image , v_texCoord);
}
`;
// render to the canvas
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
const program = webglUtils.createProgramFromSources(gl,
[vertexShaderSource, fragmentShaderSource]);
const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
const texCoordAttributeLocation = gl.getAttribLocation(program, "a_texCoord");
// lookup uniforms
const imageLocation = gl.getUniformLocation(program, "u_image");
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);
const positionBuffer = gl.createBuffer();
gl.enableVertexAttribArray(positionAttributeLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
let size = 2; // 2 components per iteration
let type = gl.FLOAT; // the data is 32bit floats
let normalize = false; // don't normalize the data
let stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
let offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset);
const texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0, 0,
0, 1,
1, 0,
1, 0,
1, 1,
0, 1
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(texCoordAttributeLocation);
size = 2; // 2 components per iteration
type = gl.FLOAT; // the data is 32bit floats
normalize = false; // don't normalize the data
stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(
texCoordAttributeLocation, size, type, normalize, stride, offset);
window.gl = gl
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// Clear the canvas to grey
gl.clearColor(0.5,0.5,0.5,1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(program);
gl.uniform1i(imageLocation, 0);
// Bind the position buffer so gl.bufferData that will be called
// in setRectangle puts data in the position buffer
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// Set a rectangle the same size as the image.
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
-0.5, -0.5,
-0.5, 0.5,
0.5, -0.5,
0.5, -0.5,
0.5, 0.5,
-0.5, 0.5
]), gl.STATIC_DRAW);
// Draw the rectangle.
const primitiveType = gl.TRIANGLES;
offset = 0;
const count = 6;
gl.drawArrays(primitiveType, offset, count);
}
}
main();
function createShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (success) {
return shader;
}
console.log(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return undefined;
}
function createProgram(gl, vertexShader, fragmentShader) {
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
const success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (success) {
return program;
}
console.log(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
return undefined;
}
</code>
<code>"use strict"; function main() { // Get the WebGL context const canvas = document.querySelector("#canvas"); const gl = canvas.getContext("webgl2"); const textureWidth = 100; const textureHeight = 100; // Render purple triangle to texture { const vertexShaderSource = `#version 300 es in vec4 a_position; void main() { gl_Position = a_position; } `; const fragmentShaderSource = `#version 300 es precision highp float; out vec4 outColor; void main() { outColor = vec4(1,0,1, 1); } `; // create/compile shaders const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource); const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource); const program = createProgram(gl, vertexShader, fragmentShader); // set a_position attribute const positionAttributeLocation = gl.getAttribLocation(program, "a_position"); const positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); const positions = [ -1, -1, 0, 1, 1, 0 ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); const vao = gl.createVertexArray(); gl.bindVertexArray(vao); gl.enableVertexAttribArray(positionAttributeLocation); // Tell the attribute how to get data out of positionBuffer const size = 2; // 2 components per iteration let type = gl.FLOAT; // the data is 32bit floats const normalize = false; // don't normalize the data const stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position let offset = 0; // start at the beginning of the buffer gl.vertexAttribPointer( positionAttributeLocation, size, type, normalize, stride, offset); gl.useProgram(program); // set up the target texture const targetTexture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, targetTexture); const level = 0; const internalFormat = gl.RGBA; const border = 0; const format = gl.RGBA; type = gl.UNSIGNED_BYTE; const data = null; gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, textureWidth, textureHeight, border, format, type, data); // set the filtering so we don't need mips 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); // Create and bind the framebuffer const fb = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, fb); // attach the texture as the first color attachment const attachmentPoint = gl.COLOR_ATTACHMENT0; gl.framebufferTexture2D( gl.FRAMEBUFFER, attachmentPoint, gl.TEXTURE_2D, targetTexture, level); gl.viewport(0, 0, textureWidth, textureHeight); // Clear the canvas gl.clearColor(1,1,1,1); gl.clear(gl.COLOR_BUFFER_BIT); const primitiveType = gl.TRIANGLES; offset = 0; const count = 3; gl.drawArrays(primitiveType, offset, count); } // Now draw the texture to the canvas { const vertexShaderSource = `#version 300 es in vec2 a_position; in vec2 a_texCoord; out vec2 v_texCoord; void main() { gl_Position = vec4(a_position, 0, 1); v_texCoord = a_texCoord; } `; const fragmentShaderSource = `#version 300 es precision highp float; uniform sampler2D u_image; in vec2 v_texCoord; out vec4 outColor; void main() { outColor = texture(u_image , v_texCoord); } `; // render to the canvas gl.bindFramebuffer(gl.FRAMEBUFFER, null); const program = webglUtils.createProgramFromSources(gl, [vertexShaderSource, fragmentShaderSource]); const positionAttributeLocation = gl.getAttribLocation(program, "a_position"); const texCoordAttributeLocation = gl.getAttribLocation(program, "a_texCoord"); // lookup uniforms const imageLocation = gl.getUniformLocation(program, "u_image"); const vao = gl.createVertexArray(); gl.bindVertexArray(vao); const positionBuffer = gl.createBuffer(); gl.enableVertexAttribArray(positionAttributeLocation); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); let size = 2; // 2 components per iteration let type = gl.FLOAT; // the data is 32bit floats let normalize = false; // don't normalize the data let stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position let offset = 0; // start at the beginning of the buffer gl.vertexAttribPointer( positionAttributeLocation, size, type, normalize, stride, offset); const texCoordBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1 ]), gl.STATIC_DRAW); gl.enableVertexAttribArray(texCoordAttributeLocation); size = 2; // 2 components per iteration type = gl.FLOAT; // the data is 32bit floats normalize = false; // don't normalize the data stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position offset = 0; // start at the beginning of the buffer gl.vertexAttribPointer( texCoordAttributeLocation, size, type, normalize, stride, offset); window.gl = gl webglUtils.resizeCanvasToDisplaySize(gl.canvas); gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); // Clear the canvas to grey gl.clearColor(0.5,0.5,0.5,1); gl.clear(gl.COLOR_BUFFER_BIT); gl.useProgram(program); gl.uniform1i(imageLocation, 0); // Bind the position buffer so gl.bufferData that will be called // in setRectangle puts data in the position buffer gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); // Set a rectangle the same size as the image. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5 ]), gl.STATIC_DRAW); // Draw the rectangle. const primitiveType = gl.TRIANGLES; offset = 0; const count = 6; gl.drawArrays(primitiveType, offset, count); } } main(); function createShader(gl, type, source) { const shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (success) { return shader; } console.log(gl.getShaderInfoLog(shader)); gl.deleteShader(shader); return undefined; } function createProgram(gl, vertexShader, fragmentShader) { const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); const success = gl.getProgramParameter(program, gl.LINK_STATUS); if (success) { return program; } console.log(gl.getProgramInfoLog(program)); gl.deleteProgram(program); return undefined; } </code>
"use strict";



function main() {

  // Get the WebGL context
  const canvas = document.querySelector("#canvas");
  const gl = canvas.getContext("webgl2");
  const textureWidth = 100;
  const textureHeight = 100;

  // Render purple triangle to texture
  {
    const vertexShaderSource = `#version 300 es

    in vec4 a_position;

    void main() {

    gl_Position = a_position;
    }
    `;

    const fragmentShaderSource = `#version 300 es

    precision highp float;

    out vec4 outColor;

    void main() {
    outColor = vec4(1,0,1, 1);
    }
    `;


    // create/compile shaders
    const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
    const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

    const program = createProgram(gl, vertexShader, fragmentShader);

    // set a_position attribute
    const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
    const positionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    const positions = [
      -1, -1,
      0, 1,
      1, 0
    ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

    const vao = gl.createVertexArray();
    gl.bindVertexArray(vao);
    gl.enableVertexAttribArray(positionAttributeLocation);

    // Tell the attribute how to get data out of positionBuffer 
    const size = 2;          // 2 components per iteration
    let type = gl.FLOAT;   // the data is 32bit floats
    const normalize = false; // don't normalize the data
    const stride = 0;        // 0 = move forward size * sizeof(type) each iteration to get the next position
    let offset = 0;        // start at the beginning of the buffer
    gl.vertexAttribPointer(
      positionAttributeLocation, size, type, normalize, stride, offset);


    
    gl.useProgram(program);


    // set up the target texture
    const targetTexture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, targetTexture);
  
    const level = 0;
    const internalFormat = gl.RGBA;
    const border = 0;
    const format = gl.RGBA;
    type = gl.UNSIGNED_BYTE;
    const data = null;
    gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
                  textureWidth, textureHeight, border,
                  format, type, data);

    // set the filtering so we don't need mips
    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);

    // Create and bind the framebuffer
    const fb = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    
    // attach the texture as the first color attachment
    const attachmentPoint = gl.COLOR_ATTACHMENT0;
    gl.framebufferTexture2D(
        gl.FRAMEBUFFER, attachmentPoint, gl.TEXTURE_2D, targetTexture, level);

    gl.viewport(0, 0, textureWidth, textureHeight);

    // Clear the canvas
    gl.clearColor(1,1,1,1);
    gl.clear(gl.COLOR_BUFFER_BIT);

    const primitiveType = gl.TRIANGLES;
    offset = 0;
    const count = 3;

    gl.drawArrays(primitiveType, offset, count);

  }

  // Now draw the texture to the canvas
  {

    const vertexShaderSource = `#version 300 es

    in vec2 a_position;
    in vec2 a_texCoord;

    out vec2 v_texCoord;

    void main() {

      gl_Position = vec4(a_position, 0, 1);
      v_texCoord = a_texCoord;
    }
    `;

    const fragmentShaderSource = `#version 300 es

    precision highp float;

    uniform sampler2D u_image;

    in vec2 v_texCoord;

    out vec4 outColor;

    void main() {

      outColor = texture(u_image , v_texCoord);
    }
    `;

    // render to the canvas
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);

    const program = webglUtils.createProgramFromSources(gl,
      [vertexShaderSource, fragmentShaderSource]);

    const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
    const texCoordAttributeLocation = gl.getAttribLocation(program, "a_texCoord");

    // lookup uniforms
    const imageLocation = gl.getUniformLocation(program, "u_image");

    const vao = gl.createVertexArray();
    gl.bindVertexArray(vao);


    const positionBuffer = gl.createBuffer();
    gl.enableVertexAttribArray(positionAttributeLocation);
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

    let size = 2;          // 2 components per iteration
    let type = gl.FLOAT;   // the data is 32bit floats
    let normalize = false; // don't normalize the data
    let stride = 0;        // 0 = move forward size * sizeof(type) each iteration to get the next position
    let offset = 0;        // start at the beginning of the buffer
    gl.vertexAttribPointer(
        positionAttributeLocation, size, type, normalize, stride, offset);

    const texCoordBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        0, 0,
        0, 1,
        1, 0,
        1, 0,
        1, 1,
        0, 1 
    ]), gl.STATIC_DRAW);

    gl.enableVertexAttribArray(texCoordAttributeLocation);
    size = 2;          // 2 components per iteration
    type = gl.FLOAT;   // the data is 32bit floats
    normalize = false; // don't normalize the data
    stride = 0;        // 0 = move forward size * sizeof(type) each iteration to get the next position
    offset = 0;        // start at the beginning of the buffer
    gl.vertexAttribPointer(
        texCoordAttributeLocation, size, type, normalize, stride, offset);

    window.gl = gl
    webglUtils.resizeCanvasToDisplaySize(gl.canvas);

    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

    // Clear the canvas to grey
    gl.clearColor(0.5,0.5,0.5,1);
    gl.clear(gl.COLOR_BUFFER_BIT);

    gl.useProgram(program);

    gl.uniform1i(imageLocation, 0);

    // Bind the position buffer so gl.bufferData that will be called
    // in setRectangle puts data in the position buffer
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    // Set a rectangle the same size as the image.
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
      -0.5, -0.5,
      -0.5, 0.5,
      0.5, -0.5,
      0.5, -0.5,
      0.5, 0.5,
      -0.5, 0.5
    ]), gl.STATIC_DRAW);

    // Draw the rectangle.
    const primitiveType = gl.TRIANGLES;
    offset = 0;
    const count = 6;
    gl.drawArrays(primitiveType, offset, count);

  }

}

main();

function createShader(gl, type, source) {
  const shader = gl.createShader(type);
  gl.shaderSource(shader, source);
  gl.compileShader(shader);
  const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
  if (success) {
    return shader;
  }

  console.log(gl.getShaderInfoLog(shader));  
  gl.deleteShader(shader);
  return undefined;
}

function createProgram(gl, vertexShader, fragmentShader) {
  const program = gl.createProgram();
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);
  const success = gl.getProgramParameter(program, gl.LINK_STATUS);
  if (success) {
    return program;
  }

  console.log(gl.getProgramInfoLog(program));  
  gl.deleteProgram(program);
  return undefined;
}

And this is the very similar code with the changes to enable a float32 texture. No errors in the console, but I just get a black square on a grey background. No purple triangle 🙁

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>"use strict";
function main() {
// Get the WebGL context
const canvas = document.querySelector("#canvas");
const gl = canvas.getContext("webgl2");
const textureWidth = 100;
const textureHeight = 100;
// Render purple triangle to texture
{
const vertexShaderSource = `#version 300 es
in vec4 a_position;
void main() {
gl_Position = a_position;
}
`;
const fragmentShaderSource = `#version 300 es
precision highp float;
out vec4 outColor;
void main() {
outColor = vec4(1,0,1, 1);
}
`;
// create/compile shaders
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
const program = createProgram(gl, vertexShader, fragmentShader);
// set a_position attribute
const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const positions = [
-1, -1,
0, 1,
1, 0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);
gl.enableVertexAttribArray(positionAttributeLocation);
// Tell the attribute how to get data out of positionBuffer
const size = 2; // 2 components per iteration
let type = gl.FLOAT; // the data is 32bit floats
const normalize = false; // don't normalize the data
const stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
let offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset);
gl.useProgram(program);
// set up the target texture
// enable float texture rendering
const ext = gl.getExtension("EXT_color_buffer_float");
const targetTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, targetTexture);
const level = 0;
const internalFormat = gl.RGBA32F;
const border = 0;
const format = gl.RGBA;
type = gl.FLOAT;
const data = null;
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
textureWidth, textureHeight, border,
format, type, data);
// set the filtering so we don't need mips
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);
// Create and bind the framebuffer
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
// attach the texture as the first color attachment
const attachmentPoint = gl.COLOR_ATTACHMENT0;
gl.framebufferTexture2D(
gl.FRAMEBUFFER, attachmentPoint, gl.TEXTURE_2D, targetTexture, level);
gl.viewport(0, 0, textureWidth, textureHeight);
// Clear the canvas
gl.clearColor(1,1,1,1);
gl.clear(gl.COLOR_BUFFER_BIT);
const primitiveType = gl.TRIANGLES;
offset = 0;
const count = 3;
gl.drawArrays(primitiveType, offset, count);
}
// Now draw the texture to the canvas
{
const vertexShaderSource = `#version 300 es
in vec2 a_position;
in vec2 a_texCoord;
out vec2 v_texCoord;
void main() {
gl_Position = vec4(a_position, 0, 1);
v_texCoord = a_texCoord;
}
`;
const fragmentShaderSource = `#version 300 es
precision highp float;
uniform sampler2D u_image;
in vec2 v_texCoord;
out vec4 outColor;
void main() {
outColor = texture(u_image , v_texCoord);
}
`;
// render to the canvas
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
const program = webglUtils.createProgramFromSources(gl,
[vertexShaderSource, fragmentShaderSource]);
const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
const texCoordAttributeLocation = gl.getAttribLocation(program, "a_texCoord");
// lookup uniforms
const imageLocation = gl.getUniformLocation(program, "u_image");
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);
const positionBuffer = gl.createBuffer();
gl.enableVertexAttribArray(positionAttributeLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
let size = 2; // 2 components per iteration
let type = gl.FLOAT; // the data is 32bit floats
let normalize = false; // don't normalize the data
let stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
let offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset);
const texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0, 0,
0, 1,
1, 0,
1, 0,
1, 1,
0, 1
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(texCoordAttributeLocation);
size = 2; // 2 components per iteration
type = gl.FLOAT; // the data is 32bit floats
normalize = false; // don't normalize the data
stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(
texCoordAttributeLocation, size, type, normalize, stride, offset);
window.gl = gl
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// Clear the canvas to grey
gl.clearColor(0.5,0.5,0.5,1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(program);
gl.uniform1i(imageLocation, 0);
// Bind the position buffer so gl.bufferData that will be called
// in setRectangle puts data in the position buffer
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// Set a rectangle the same size as the image.
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
-0.5, -0.5,
-0.5, 0.5,
0.5, -0.5,
0.5, -0.5,
0.5, 0.5,
-0.5, 0.5
]), gl.STATIC_DRAW);
// Draw the rectangle.
const primitiveType = gl.TRIANGLES;
offset = 0;
const count = 6;
gl.drawArrays(primitiveType, offset, count);
}
}
main();
function createShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (success) {
return shader;
}
console.log(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return undefined;
}
function createProgram(gl, vertexShader, fragmentShader) {
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
const success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (success) {
return program;
}
console.log(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
return undefined;
}
</code>
<code>"use strict"; function main() { // Get the WebGL context const canvas = document.querySelector("#canvas"); const gl = canvas.getContext("webgl2"); const textureWidth = 100; const textureHeight = 100; // Render purple triangle to texture { const vertexShaderSource = `#version 300 es in vec4 a_position; void main() { gl_Position = a_position; } `; const fragmentShaderSource = `#version 300 es precision highp float; out vec4 outColor; void main() { outColor = vec4(1,0,1, 1); } `; // create/compile shaders const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource); const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource); const program = createProgram(gl, vertexShader, fragmentShader); // set a_position attribute const positionAttributeLocation = gl.getAttribLocation(program, "a_position"); const positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); const positions = [ -1, -1, 0, 1, 1, 0 ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); const vao = gl.createVertexArray(); gl.bindVertexArray(vao); gl.enableVertexAttribArray(positionAttributeLocation); // Tell the attribute how to get data out of positionBuffer const size = 2; // 2 components per iteration let type = gl.FLOAT; // the data is 32bit floats const normalize = false; // don't normalize the data const stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position let offset = 0; // start at the beginning of the buffer gl.vertexAttribPointer( positionAttributeLocation, size, type, normalize, stride, offset); gl.useProgram(program); // set up the target texture // enable float texture rendering const ext = gl.getExtension("EXT_color_buffer_float"); const targetTexture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, targetTexture); const level = 0; const internalFormat = gl.RGBA32F; const border = 0; const format = gl.RGBA; type = gl.FLOAT; const data = null; gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, textureWidth, textureHeight, border, format, type, data); // set the filtering so we don't need mips 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); // Create and bind the framebuffer const fb = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, fb); // attach the texture as the first color attachment const attachmentPoint = gl.COLOR_ATTACHMENT0; gl.framebufferTexture2D( gl.FRAMEBUFFER, attachmentPoint, gl.TEXTURE_2D, targetTexture, level); gl.viewport(0, 0, textureWidth, textureHeight); // Clear the canvas gl.clearColor(1,1,1,1); gl.clear(gl.COLOR_BUFFER_BIT); const primitiveType = gl.TRIANGLES; offset = 0; const count = 3; gl.drawArrays(primitiveType, offset, count); } // Now draw the texture to the canvas { const vertexShaderSource = `#version 300 es in vec2 a_position; in vec2 a_texCoord; out vec2 v_texCoord; void main() { gl_Position = vec4(a_position, 0, 1); v_texCoord = a_texCoord; } `; const fragmentShaderSource = `#version 300 es precision highp float; uniform sampler2D u_image; in vec2 v_texCoord; out vec4 outColor; void main() { outColor = texture(u_image , v_texCoord); } `; // render to the canvas gl.bindFramebuffer(gl.FRAMEBUFFER, null); const program = webglUtils.createProgramFromSources(gl, [vertexShaderSource, fragmentShaderSource]); const positionAttributeLocation = gl.getAttribLocation(program, "a_position"); const texCoordAttributeLocation = gl.getAttribLocation(program, "a_texCoord"); // lookup uniforms const imageLocation = gl.getUniformLocation(program, "u_image"); const vao = gl.createVertexArray(); gl.bindVertexArray(vao); const positionBuffer = gl.createBuffer(); gl.enableVertexAttribArray(positionAttributeLocation); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); let size = 2; // 2 components per iteration let type = gl.FLOAT; // the data is 32bit floats let normalize = false; // don't normalize the data let stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position let offset = 0; // start at the beginning of the buffer gl.vertexAttribPointer( positionAttributeLocation, size, type, normalize, stride, offset); const texCoordBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1 ]), gl.STATIC_DRAW); gl.enableVertexAttribArray(texCoordAttributeLocation); size = 2; // 2 components per iteration type = gl.FLOAT; // the data is 32bit floats normalize = false; // don't normalize the data stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position offset = 0; // start at the beginning of the buffer gl.vertexAttribPointer( texCoordAttributeLocation, size, type, normalize, stride, offset); window.gl = gl webglUtils.resizeCanvasToDisplaySize(gl.canvas); gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); // Clear the canvas to grey gl.clearColor(0.5,0.5,0.5,1); gl.clear(gl.COLOR_BUFFER_BIT); gl.useProgram(program); gl.uniform1i(imageLocation, 0); // Bind the position buffer so gl.bufferData that will be called // in setRectangle puts data in the position buffer gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); // Set a rectangle the same size as the image. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5 ]), gl.STATIC_DRAW); // Draw the rectangle. const primitiveType = gl.TRIANGLES; offset = 0; const count = 6; gl.drawArrays(primitiveType, offset, count); } } main(); function createShader(gl, type, source) { const shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (success) { return shader; } console.log(gl.getShaderInfoLog(shader)); gl.deleteShader(shader); return undefined; } function createProgram(gl, vertexShader, fragmentShader) { const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); const success = gl.getProgramParameter(program, gl.LINK_STATUS); if (success) { return program; } console.log(gl.getProgramInfoLog(program)); gl.deleteProgram(program); return undefined; } </code>
"use strict";



function main() {

  // Get the WebGL context
  const canvas = document.querySelector("#canvas");
  const gl = canvas.getContext("webgl2");
  const textureWidth = 100;
  const textureHeight = 100;

  // Render purple triangle to texture
  {
    const vertexShaderSource = `#version 300 es

    in vec4 a_position;

    void main() {

    gl_Position = a_position;
    }
    `;

    const fragmentShaderSource = `#version 300 es

    precision highp float;

    out vec4 outColor;

    void main() {
    outColor = vec4(1,0,1, 1);
    }
    `;


    // create/compile shaders
    const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
    const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

    const program = createProgram(gl, vertexShader, fragmentShader);

    // set a_position attribute
    const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
    const positionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    const positions = [
      -1, -1,
      0, 1,
      1, 0
    ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

    const vao = gl.createVertexArray();
    gl.bindVertexArray(vao);
    gl.enableVertexAttribArray(positionAttributeLocation);

    // Tell the attribute how to get data out of positionBuffer 
    const size = 2;          // 2 components per iteration
    let type = gl.FLOAT;   // the data is 32bit floats
    const normalize = false; // don't normalize the data
    const stride = 0;        // 0 = move forward size * sizeof(type) each iteration to get the next position
    let offset = 0;        // start at the beginning of the buffer
    gl.vertexAttribPointer(
      positionAttributeLocation, size, type, normalize, stride, offset);


    
    gl.useProgram(program);


    // set up the target texture

    // enable float texture rendering
    const ext = gl.getExtension("EXT_color_buffer_float");


    const targetTexture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, targetTexture);
  
    const level = 0;
    const internalFormat = gl.RGBA32F;
    const border = 0;
    const format = gl.RGBA;
    type = gl.FLOAT;
    const data = null;
    gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
                  textureWidth, textureHeight, border,
                  format, type, data);

    // set the filtering so we don't need mips
    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);

    // Create and bind the framebuffer
    const fb = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    
    // attach the texture as the first color attachment
    const attachmentPoint = gl.COLOR_ATTACHMENT0;
    gl.framebufferTexture2D(
        gl.FRAMEBUFFER, attachmentPoint, gl.TEXTURE_2D, targetTexture, level);

    gl.viewport(0, 0, textureWidth, textureHeight);

    // Clear the canvas
    gl.clearColor(1,1,1,1);
    gl.clear(gl.COLOR_BUFFER_BIT);

    const primitiveType = gl.TRIANGLES;
    offset = 0;
    const count = 3;

    gl.drawArrays(primitiveType, offset, count);

  }

  // Now draw the texture to the canvas
  {

    const vertexShaderSource = `#version 300 es

    in vec2 a_position;
    in vec2 a_texCoord;

    out vec2 v_texCoord;

    void main() {

      gl_Position = vec4(a_position, 0, 1);
      v_texCoord = a_texCoord;
    }
    `;

    const fragmentShaderSource = `#version 300 es

    precision highp float;

    uniform sampler2D u_image;

    in vec2 v_texCoord;

    out vec4 outColor;

    void main() {

      outColor = texture(u_image , v_texCoord);
    }
    `;

    // render to the canvas
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);

    const program = webglUtils.createProgramFromSources(gl,
      [vertexShaderSource, fragmentShaderSource]);

    const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
    const texCoordAttributeLocation = gl.getAttribLocation(program, "a_texCoord");

    // lookup uniforms
    const imageLocation = gl.getUniformLocation(program, "u_image");

    const vao = gl.createVertexArray();
    gl.bindVertexArray(vao);


    const positionBuffer = gl.createBuffer();
    gl.enableVertexAttribArray(positionAttributeLocation);
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

    let size = 2;          // 2 components per iteration
    let type = gl.FLOAT;   // the data is 32bit floats
    let normalize = false; // don't normalize the data
    let stride = 0;        // 0 = move forward size * sizeof(type) each iteration to get the next position
    let offset = 0;        // start at the beginning of the buffer
    gl.vertexAttribPointer(
        positionAttributeLocation, size, type, normalize, stride, offset);

    const texCoordBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        0, 0,
        0, 1,
        1, 0,
        1, 0,
        1, 1,
        0, 1 
    ]), gl.STATIC_DRAW);

    gl.enableVertexAttribArray(texCoordAttributeLocation);
    size = 2;          // 2 components per iteration
    type = gl.FLOAT;   // the data is 32bit floats
    normalize = false; // don't normalize the data
    stride = 0;        // 0 = move forward size * sizeof(type) each iteration to get the next position
    offset = 0;        // start at the beginning of the buffer
    gl.vertexAttribPointer(
        texCoordAttributeLocation, size, type, normalize, stride, offset);

    window.gl = gl
    webglUtils.resizeCanvasToDisplaySize(gl.canvas);

    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

    // Clear the canvas to grey
    gl.clearColor(0.5,0.5,0.5,1);
    gl.clear(gl.COLOR_BUFFER_BIT);

    gl.useProgram(program);

    gl.uniform1i(imageLocation, 0);

    // Bind the position buffer so gl.bufferData that will be called
    // in setRectangle puts data in the position buffer
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    // Set a rectangle the same size as the image.
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
      -0.5, -0.5,
      -0.5, 0.5,
      0.5, -0.5,
      0.5, -0.5,
      0.5, 0.5,
      -0.5, 0.5
    ]), gl.STATIC_DRAW);

    // Draw the rectangle.
    const primitiveType = gl.TRIANGLES;
    offset = 0;
    const count = 6;
    gl.drawArrays(primitiveType, offset, count);

  }

}

main();

function createShader(gl, type, source) {
  const shader = gl.createShader(type);
  gl.shaderSource(shader, source);
  gl.compileShader(shader);
  const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
  if (success) {
    return shader;
  }

  console.log(gl.getShaderInfoLog(shader));  
  gl.deleteShader(shader);
  return undefined;
}

function createProgram(gl, vertexShader, fragmentShader) {
  const program = gl.createProgram();
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);
  const success = gl.getProgramParameter(program, gl.LINK_STATUS);
  if (success) {
    return program;
  }

  console.log(gl.getProgramInfoLog(program));  
  gl.deleteProgram(program);
  return undefined;
}

New contributor

user123 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật