1

I would like to encode object positions (x,y,z) and send to a GLSL shader, decode the data, perform some calculations and send the results back to the CPU. I have researched this issue and have found partial answers like decode rgb value to single float without bit-shift in glsl, but I have not been successful in encoding and decoding the results.

Here is a part of my code.`...

function init() {
  ...
  buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.bufferData(
    gl.ARRAY_BUFFER,
    new Float32Array([
      -1.0, 1.0,
      -1.0, -1.0,
      1.0, -1.0,
      1.0, 1.0
    ]),
    gl.STATIC_DRAW
  );

  texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, texture);

  vec1 = new THREE.Vector3(2.6, 3.3, 100.80); //example position vector

  data = new Uint8Array([float2Color(vec1.x).r, float2Color(vec1.x).g, float2Color(vec1.x).b, 255, //x
    float2Color(vec1.y).r, float2Color(vec1.y).g, float2Color(vec1.y).b, 255, //y
    float2Color(vec1.z).r, float2Color(vec1.z).g, float2Color(vec1.z).b, 255 //z
  ]);
   // This encodes to give me int8Array [ 2, 0, 0, 255, 3, 0, 0, 255, 100, 0, 2 more… ]
  
  gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
}

//render function

function render() {
  ...
  gl.drawArrays(gl.POINTS, 0, 2);
  var pixels = new Uint8Array(WIDTH * HEIGHT * 4);
  gl.readPixels(0, 0, WIDTH, HEIGHT, gl.RGBA, gl.FLOAT, pixels);
  pixels = new Uint8Array(pixels.buffer);
  
  //After getting the results from GLSL, pixels now look like this
  //Uint8Array [ 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, … ]
 


  var color = {
    r: pixels[0],
    g: pixels[1],
    b: pixels[2]
  };
  float1 = decodeVec3ToFloat(color); // I would like to decode and use the data after the position is updated in GLSL
}

function float2Color( f ) {
        b = Math.floor(f / 255.0 / 255.0);
        g = Math.floor((f - (b * 255.0 * 255.0) ) / 255.0);
        // r = Math.floor(f - (b * 255.0 * 255.0) - (g * 255.0) );
        r = Math.floor(f % 255);
        return {r:r, g:g, b:b};
    }

function decodeVec3ToFloat(color) {
        var result;
        result = color.r * 255.0;
        result += color.g * 255.0 * 255.0;
        result += color.b * 255.0 * 255.0 * 255.0;
        return result;
    }
Community
  • 1
  • 1
Fitz
  • 11
  • 2
  • `encode` is a very general term. why did the question you site, not answer your question? – gaitat Sep 29 '15 at 22:48
  • @gaitat. I say encode because shader textures work mostly with RGBA values. In that question they discussed encoding a float within a shader, but not sending it from JavaScript as a texture/buffer to the shader. I would like to send large amounts of floating positions (x,y,z) to the shader. – Fitz Sep 30 '15 at 13:57
  • a simple way would be to encode the (x,y,z) values you have to the (r,g,b) values of a texture. assign the texture to a plane and render it using a shader material. your texture will be send to the hardware. process it and when done use the gl readPixels to get it from the GPU to the CPU. – gaitat Sep 30 '15 at 14:23

1 Answers1

0

I've been working with this sort of thing myself. You can use DataTextures to achieve this, and pass them in and out as buffers manipulated by a simulation shader. The best example I've found so far uses a dated version of Three.js (v58) but can be easily updated. I found it helpful to get the scripts updated and then toy around with it until I understood it well enough for my use case. Note that in the example there are even fixed values passed through in the simulation shader, as well as the changing x,y,z values that are rendered in and out on the buffers. Good luck!

UPDATE:

I have since discoverer that the old THREE.FBOUtils script I was using above has been updated and reworked and is now called THREE.GPUComputationRenderer -- works great! (v80)

gromiczek
  • 2,970
  • 5
  • 28
  • 49