Я пытаюсь реализовать простую программу, которая пишет в текстуру, а затем читает из нее на основе этого поста . Я ожидал получить массив значений от 0 до 99, вместо этого я получаю вывод фрагмента кода ниже, который пропускает значения, такие как 4,5,6,7 и добавляет дополнительные 0.
Почему я иногда имеют пропущенные значения и те 0, и что я могу сделать, чтобы решить эту проблему?
Ожидается:
[0,1,2,3,4,5,6,7,8, ... 97,98,99]
Вывод:
const gl = document.createElement("canvas").getContext("webgl");
const vs = `
attribute vec4 position;
attribute vec2 texcoord;
varying vec2 v_texcoord;
void main() {
gl_Position = position;
v_texcoord = texcoord;
}
`;
const fs = `
precision highp float;
uniform sampler2D u_srcData;
uniform float u_add;
varying vec2 v_texcoord;
void main() {
vec4 value = texture2D(u_srcData, v_texcoord);
// We can't choose the destination here.
// It has already been decided by however
// we asked WebGL to rasterize.
gl_FragColor = value + u_add;
}
`;
const program = buildProgram(vs,fs)
const size = 100;
// Uint8Array values default to 0
const srcData = new Uint8Array(size);
// let's use slight more interesting numbers
for (let i = 0; i < size; ++i) {
srcData[i] = i;
}
//console.log('srcData:')
//console.log(srcData)
// Put that data in a texture. NOTE: Textures
// are (generally) 2 dimensional and have a limit
// on their dimensions. That means you can't make
// a 1000000 by 1 texture. Most GPUs limit from
// between 2048 to 16384.
// In our case we're doing 10000 so we could use
// a 100x100 texture. Except that WebGL can
// process 4 values at a time (red, green, blue, alpha)
// so a 50x50 will give us 10000 values
const srcTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, srcTex);
const level = 0;
const width = Math.sqrt(size / 4);
if (width % 1 !== 0) {
// we need some other technique to fit
// our data into a texture.
alert('size does not have integer square root');
}
const height = width;
const border = 0;
const internalFormat = gl.RGBA;
const format = gl.RGBA;
const type = gl.UNSIGNED_BYTE;
gl.texImage2D(
gl.TEXTURE_2D, level, internalFormat,
width, height, border, format, type, srcData);
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_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
// create a destination texture
const dstTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, dstTex);
gl.texImage2D(
gl.TEXTURE_2D, level, internalFormat,
width, height, border, format, type, null);
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_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
// make a framebuffer so we can render to the
// destination texture
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
// and attach the destination texture
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, dstTex, level);
gl.useProgram(program)
var data = [
//x,y,texX,texY
-1,-1,0,0,
.1,-1,1,0,
-1,1,0,1,
-1,1,0,1,
1,-1,1,0,
1,1,1,1,
]
// buffer
const positionBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER,positionBuffer)
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(data),gl.STATIC_DRAW)
// pointer
const positionLoc = gl.getAttribLocation(program,'position')
gl.vertexAttribPointer(
positionLoc,
2,
gl.FLOAT,
0,
4*Float32Array.BYTES_PER_ELEMENT,
0*Float32Array.BYTES_PER_ELEMENT
)
gl.enableVertexAttribArray(positionLoc)
const texcoordLoc = gl.getAttribLocation(program,'texcoord')
gl.vertexAttribPointer(
texcoordLoc,
2,
gl.FLOAT,
0,
4*Float32Array.BYTES_PER_ELEMENT,
2*Float32Array.BYTES_PER_ELEMENT
)
gl.enableVertexAttribArray(texcoordLoc)
// gl.activeTexture(gl.TEXTURE0)
gl.bindTexture(gl.TEXTURE_2D,srcTex)
gl.uniform1f(gl.getUniformLocation(program,'u_add'), 0 / 255)
gl.uniform1i(gl.getUniformLocation(program,'u_srcData'),0)
// set the viewport to match the destination size
gl.viewport(0, 0, width, height);
// draw the quad (2 triangles)
const offset = 0;
const numVertices = 6;
gl.drawArrays(gl.TRIANGLES, offset, numVertices);
// pull out the result
const dstData = new Uint8Array(size);
gl.readPixels(0, 0, width, height, format, type, dstData);
console.log('dstData:');
console.log(dstData);
// FUNCTIONS
function buildShader(type,source){
const shader = gl.createShader(type)
gl.shaderSource(shader,source)
gl.compileShader(shader)
if(!gl.getShaderParameter(shader,gl.COMPILE_STATUS)){
throw new Error('ERROR compiling shader type '+type+' Info: '+gl.getShaderInfoLog(shader))
}
return shader
}
function buildProgram(vs,fs){
const program = gl.createProgram()
gl.attachShader(program,buildShader(gl.VERTEX_SHADER,vs))
gl.attachShader(program,buildShader(gl.FRAGMENT_SHADER,fs))
gl.linkProgram(program)
gl.validateProgram(program)
if(!gl.getProgramParameter(program,gl.LINK_STATUS)){
throw new Error('ERROR: linking program. Info: '+gl.getProgramInfoLog(program))
}
if(!gl.getProgramParameter(program,gl.VALIDATE_STATUS)){
throw new Error('ERROR: validating program. Info: '+gl.getProgramInfoLog(program))
}
return program
}