0

I'm trying to implement a simple program that writes into texture then reads from it based off this post. I expected to get an array of values from 0 to 99, instead I get the output of the code snippet below which skips values such as 4,5,6,7 and adds in extra 0's.

Why do I occasionally have values that are skipped and those 0's, and what can I do to solve this?

Expected:

[0,1,2,3,4,5,6,7,8, ... 97,98,99]

Output:

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
}
user8380672
  • 520
  • 1
  • 9
  • 20

1 Answers1

0

As gman pointed out, had a .1 instead of a 1 in data.

user8380672
  • 520
  • 1
  • 9
  • 20