Webgl 每像素纹理 1 位
Webgl 1 bit per pixel texture
有没有办法在 WebGL 中使用每像素 1 位的纹理数据(例如 32 字节数据中的纹理 16×16px)或者是否需要先将数据从 1bpp 解包到 8bpp?
我找到了类似的 OpenGL 相关问答 ,但在我看来,WebGL 没有 GL_BITMAP 数据类型常量。
WebGL 本身没有一位每像素格式。您必须自己解压数据。
您可以使用 gl.ALPHA
或 gl.LUMINANCE
格式将其解压缩为每个像素 1 个字节
您可以尝试创建一个片段着色器来解包,不知道精度问题是否会让您丧命。像
precision mediump float;
varying vec2 v_texcoord;
uniform vec2 u_textureSize;
uniform sampler2D u_texture;
void main() {
float texelCoord = floor(v_texcoord.x * u_textureSize.x);
float bit = mod(texelCoord, 8.0);
float byte = texelCoord / 8.0;
vec2 uv = vec2(byte / u_textureSize.x, v_texcoord.y);
float eightPixels = texture2D(u_texture, uv).r * 255.0;
float pixel = mod(floor(eightPixels / pow(2.0, bit)), 2.0);
gl_FragColor = vec4(pixel, pixel, pixel, 1.0);
}
嗯,我想我们应该测试一下......
// Using TWGL.js because it's easier and I'm lazy
var gl = twgl.getWebGLContext(document.getElementById("c"));
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
var arrays = {
position: [-1, -1, 0, 1, -1, 0, -1, 1, 0, -1, 1, 0, 1, -1, 0, 1, 1, 0],
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
function render(time) {
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
var uniforms = {
u_texture: twgl.createTexture(gl, {
format: gl.LUMINANCE,
min: gl.NEAREST,
mag: gl.NEAREST,
width: 1,
src: [ 0x3C, 0x42, 0xBD, 0x81, 0xA5, 0x81, 0x42, 0x3C, ],
}),
u_textureSize: [8, 8],
};
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
console.log("foo");
twgl.drawBufferInfo(gl, gl.TRIANGLES, bufferInfo);
}
render();
canvas { border: 1px solid red; }
<script src="//twgljs.org/dist/twgl-full.min.js"></script>
<canvas id="c"></canvas>
<script id="vs" type="notjs">
attribute vec4 position;
varying vec2 v_texcoord;
void main() {
gl_Position = position;
v_texcoord = position.xy * 0.5 + 0.5;
}
</script>
<script id="fs" type="notjs">
precision mediump float;
varying vec2 v_texcoord;
uniform vec2 u_textureSize;
uniform sampler2D u_texture;
void main() {
float texelCoord = floor(v_texcoord.x * u_textureSize.x);
float bit = mod(texelCoord, 8.0);
float byte = texelCoord / 8.0;
vec2 uv = vec2(byte / u_textureSize.x, v_texcoord.y);
float eightPixels = texture2D(u_texture, uv).r * 255.0;
float pixel = mod(floor(eightPixels / pow(2.0, bit)), 2.0);
gl_FragColor = vec4(pixel, pixel, pixel, 1.0);
}
</script>
正如 gman 回答的那样 ():WebGL 不支持每像素一位格式。
所以我使用 LUMINANCE 格式并手动解压数据:
int off = 0;
for (int i=0;i<packedData.length;i++,off+=8) {
int val = packedData[i];
for (int j=0;j<8;j++) {
unpackedData[off+j] = ((val&(1<<j))!=0)?255:0;
}
}
有没有办法在 WebGL 中使用每像素 1 位的纹理数据(例如 32 字节数据中的纹理 16×16px)或者是否需要先将数据从 1bpp 解包到 8bpp?
我找到了类似的 OpenGL 相关问答 ,但在我看来,WebGL 没有 GL_BITMAP 数据类型常量。
WebGL 本身没有一位每像素格式。您必须自己解压数据。
您可以使用 gl.ALPHA
或 gl.LUMINANCE
您可以尝试创建一个片段着色器来解包,不知道精度问题是否会让您丧命。像
precision mediump float;
varying vec2 v_texcoord;
uniform vec2 u_textureSize;
uniform sampler2D u_texture;
void main() {
float texelCoord = floor(v_texcoord.x * u_textureSize.x);
float bit = mod(texelCoord, 8.0);
float byte = texelCoord / 8.0;
vec2 uv = vec2(byte / u_textureSize.x, v_texcoord.y);
float eightPixels = texture2D(u_texture, uv).r * 255.0;
float pixel = mod(floor(eightPixels / pow(2.0, bit)), 2.0);
gl_FragColor = vec4(pixel, pixel, pixel, 1.0);
}
嗯,我想我们应该测试一下......
// Using TWGL.js because it's easier and I'm lazy
var gl = twgl.getWebGLContext(document.getElementById("c"));
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
var arrays = {
position: [-1, -1, 0, 1, -1, 0, -1, 1, 0, -1, 1, 0, 1, -1, 0, 1, 1, 0],
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
function render(time) {
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
var uniforms = {
u_texture: twgl.createTexture(gl, {
format: gl.LUMINANCE,
min: gl.NEAREST,
mag: gl.NEAREST,
width: 1,
src: [ 0x3C, 0x42, 0xBD, 0x81, 0xA5, 0x81, 0x42, 0x3C, ],
}),
u_textureSize: [8, 8],
};
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
console.log("foo");
twgl.drawBufferInfo(gl, gl.TRIANGLES, bufferInfo);
}
render();
canvas { border: 1px solid red; }
<script src="//twgljs.org/dist/twgl-full.min.js"></script>
<canvas id="c"></canvas>
<script id="vs" type="notjs">
attribute vec4 position;
varying vec2 v_texcoord;
void main() {
gl_Position = position;
v_texcoord = position.xy * 0.5 + 0.5;
}
</script>
<script id="fs" type="notjs">
precision mediump float;
varying vec2 v_texcoord;
uniform vec2 u_textureSize;
uniform sampler2D u_texture;
void main() {
float texelCoord = floor(v_texcoord.x * u_textureSize.x);
float bit = mod(texelCoord, 8.0);
float byte = texelCoord / 8.0;
vec2 uv = vec2(byte / u_textureSize.x, v_texcoord.y);
float eightPixels = texture2D(u_texture, uv).r * 255.0;
float pixel = mod(floor(eightPixels / pow(2.0, bit)), 2.0);
gl_FragColor = vec4(pixel, pixel, pixel, 1.0);
}
</script>
正如 gman 回答的那样 (
所以我使用 LUMINANCE 格式并手动解压数据:
int off = 0;
for (int i=0;i<packedData.length;i++,off+=8) {
int val = packedData[i];
for (int j=0;j<8;j++) {
unpackedData[off+j] = ((val&(1<<j))!=0)?255:0;
}
}