Skip to content

Instantly share code, notes, and snippets.

@greggman
Last active Sep 24, 2022
Embed
What would you like to do?
Draw a Texture where every mip color and we select them with TEXTURE_BASE_LEVEL and TEXTURE_MAX_LEVEL

Draw a Texture where every mip color and we select them with TEXTURE_BASE_LEVEL and TEXTURE_MAX_LEVEL

view on jsgist

canvas { border: 1px solid black; }
<canvas></canvas>
<p>
A texture with different colors in each mip level should render
just fine if TEXTURE_BASE_LEVEL and TEXTURE_MAX_LEVEL are set to a specfic level.
</p>
<p>
Also rendering to the various levels should work regardless of TEXTURE_BASE_LEVEL, TEXTURE_MAX_LEVEL
settings as the texture is immutable.
</p>
import 'https://greggman.github.io/webgl-lint/webgl-lint.js';
const gl = document.querySelector('canvas').getContext('webgl2');
const ext = gl.getExtension('WEBGL_debug_renderer_info');
if (ext) {
console.log('UNMASKED_VENDOR_WEBGL:', gl.getParameter(ext.UNMASKED_VENDOR_WEBGL));
console.log('UNMASKED_RENDERER_WEBGL:', gl.getParameter(ext.UNMASKED_RENDERER_WEBGL));
}
const vs = `#version 300 es
layout(location = 0) in vec4 position;
void main() {
gl_Position = position;
gl_PointSize = 50.0;
}
`;
const fs = `#version 300 es
precision highp float;
uniform sampler2D tex;
out vec4 outColor;
void main() {
outColor = vec4(texture(tex, gl_PointCoord.xy).rgb, 1);
}
`;
const fs2 = `#version 300 es
precision highp float;
out vec4 outColor;
uniform vec4 color;
void main() {
outColor = color;
}
`;
function createShader(gl, type, src) {
const sh = gl.createShader(type);
gl.shaderSource(sh, src);
gl.compileShader(sh);
return sh;
}
const prg = gl.createProgram(gl);
gl.attachShader(prg, createShader(gl, gl.VERTEX_SHADER, vs));
gl.attachShader(prg, createShader(gl, gl.FRAGMENT_SHADER, fs));
gl.linkProgram(prg);
gl.useProgram(prg);
const prg2 = gl.createProgram(gl);
gl.attachShader(prg2, createShader(gl, gl.VERTEX_SHADER, vs));
gl.attachShader(prg2, createShader(gl, gl.FRAGMENT_SHADER, fs2));
gl.linkProgram(prg2);
const colorLoc = gl.getUniformLocation(prg2, "color");
const r = [255, 0, 0, 255];
const g = [0, 255, 0, 255];
const b = [0, 0, 255, 255];
// Put a different format mip in each layer
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texStorage2D(gl.TEXTURE_2D, 3, gl.RGBA8, 5, 5);
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 5, 5, gl.RGBA, gl.UNSIGNED_BYTE,
new Uint8Array([
...r, ...r, ...r, ...r, ...r,
...r, ...r, ...r, ...r, ...r,
...r, ...r, ...r, ...r, ...r,
...r, ...r, ...r, ...r, ...r,
...r, ...r, ...r, ...r, ...r,
]));
gl.texSubImage2D(gl.TEXTURE_2D, 1, 0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE,
new Uint8Array([
...g, ...g,
...g, ...g,
]));
gl.texSubImage2D(gl.TEXTURE_2D, 2, 0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE,
new Uint8Array([
...b,
]));
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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL, 0);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 0);
gl.vertexAttrib2f(0, -0.5, 0);
gl.drawArrays(gl.POINTS, 0, 1);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL, 1);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 1);
gl.vertexAttrib2f(0, 0, 0);
gl.drawArrays(gl.POINTS, 0, 1);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL, 2);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 2);
gl.vertexAttrib2f(0, 0.5, 0);
gl.drawArrays(gl.POINTS, 0, 1);
// render to the first mip
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.viewport(0, 0, 5, 5);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
gl.useProgram(prg2);
gl.uniform4fv(colorLoc, [0, 1, 1, 1]); // cyan
gl.vertexAttrib2f(0, 0, 0);
gl.drawArrays(gl.POINTS, 0, 1);
// render to the 2nd mip
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 1);
gl.viewport(0, 0, 2, 2);
gl.useProgram(prg2);
gl.uniform4fv(colorLoc, [1, 0, 1, 1]); // magenta
gl.vertexAttrib2f(0, 0, 0);
gl.drawArrays(gl.POINTS, 0, 1);
// render to the 3rd mip
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 2);
gl.viewport(0, 0, 1, 1);
gl.useProgram(prg2);
gl.uniform4fv(colorLoc, [1, 1, 0, 1]); // yellow
gl.vertexAttrib2f(0, 0, 0);
gl.drawArrays(gl.POINTS, 0, 1);
// draw the first mip
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.useProgram(prg);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL, 0);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 0);
gl.vertexAttrib2f(0, -0.5, -0.66);
gl.drawArrays(gl.POINTS, 0, 1);
// draw the 2nd mip
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL, 1);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 1);
gl.vertexAttrib2f(0, 0, -0.66);
gl.drawArrays(gl.POINTS, 0, 1);
// draw the 3rd mip
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL, 2);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 2);
gl.vertexAttrib2f(0, 0.5, -0.66);
gl.drawArrays(gl.POINTS, 0, 1);
const err = gl.getError();
console.log(err ? `GL ERROR: ${err}` : 'no gl errors');
{"name":"Draw a Texture where every mip color and we select them with TEXTURE_BASE_LEVEL and TEXTURE_MAX_LEVEL","settings":{},"filenames":["index.css","index.html","index.js"]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment