2011-04-06

WebGL - Convert chars to float

 All info is derived from:
http://www.khronos.org/registry/typedarray/specs/latest/


The basic problem, is you create a vertex buffer object (VBO) and write vertex data into it, such as vertex position, texture coordinates, normals, and weight and weight index values.
In case you have never used a "matrix palette" the basic idea is:
  • Construct a VBO with space for your weights and weight indices (4-8 floats)
  • Convert your weight values into floats, store in your array,
  • For the index values, convert to uint8 values, which refers to the shader' current matrix palette
    • This is defined as an array of uniform matrices; usually less than 28 matrices long
    • all GPU bone animation routines do this internally, ultimately.
  • Then, before you draw a group in your polygon, load the palette with the matrices needed.
  • In the shader, simply multiply with your input vertex to compute the output vertex, and multiply each stage with the weight required.
It doesn't take a of lot of inspection to see multiple problems. For one, you are limited by the number of weights applied to a vertex, and you need multiple shaders for each count, such as matrixshd1, matrixshd2, and so on. You also have to load the uniforms in for each group that changes the matrix palette. Also, depending on your shading pipeline, you have to multiply and convert the matrices before sending to the GPU.

All those problems aside, and you suddenly realize that in javascript, there IS no way to convert bytes into a float. In C, this was typecast trickery.

Here is (one way) convert arbitrary bytes into a float for your VBO data:

function utilUCharToFloat( inarray ){

//Step 1: Create a un-editable array buffer (in bytes) of size 4

var n = new ArrayBuffer(4);

//Step 2: Create a "view" of that buffer as a Uint8 view.
//This allows you to write into it as bytes.
//We choose a 0 offset, and a 4 length for explicitness

var vb = new Uint8Array( n, 0, 4 )

//Write into it with your bytes

vb[0] = inarray[0];
vb[1] = inarray[1];
vb[2] = inarray[2];
vb[3] = inarray[3];

//Create a new view as a float.
//This view uses the same data as the vb view, but is read/written to like a float.

vf = new Float32Array( n, 0, 1 );

//The first element, a 32 bit float (8*4 = 32) is returned,

return vf[0];
}

You can do the exact opposite and convert bytes to float using the same logic.

Hope this helps, it's critical to being able to use matrix palette weighting.

-Z

No comments: