Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Packing vertex data into a WebGL texture

I am trying to store a vertex array in a WebGL texture but can't really figure out how to do it correctly. The purpose of this is to pass the vertices to my fragment shader and process them for raytracing.

My JavaScript code looks currently like this:

var a = new ArrayBuffer();
// Model.VerticeMap is an array holding all vertices [x1, y1, z1, x2, y2, z2, ...]
a = Model.VerticeMap;  // array length: 36864
var dataArray = new Float32Array(a);
var vMapTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, vMapTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 2, 2, 0, gl.RGB, gl.FLOAT, dataArray);

I get no errors with a texture width and height of 2. Taking higher values results in the error ArrayBufferView not big enough for request.

I am also using the extension OES_texture_float for float values in textures.

I must admit that I'm not 100% sure what I'm doing there. It was more of a back and forth and I was kind of happy when I got to the point of not getting any errors with this code. My main thought was to store the x,y,z values of every vertex as r,g,b values of every pixel of the texture. Therefore the texture size would have to be equal with or higher than the number of triangles of my 3D model. Unfortunately, texture sizes in WebGL are limited to power of two numbers. The number of vertices should also be variable, since I'm planning to render multiple models in my scene.

I would be grateful for some assistance concerning the correct usage of an ArrayBuffer, a Float32Array and the texImage2D() command to solve my problem of sending vertices to a fragment shader in WebGL.

like image 658
Feppster Avatar asked Nov 26 '22 09:11

Feppster


1 Answers

I think I found a solution for my problem:

First we need to calculate a fitting texture width

var vMapTexture = gl.createTexture();
var vertexTextureWidth = Math.ceil(Math.sqrt(verticeCount/3));

With verticeCount being the length of our vertex array, we divide it by 3 to fit it in the RGB components of a pixel, take the squareroot of it and round it up to make sure that all our vertices fit in the texture. The texture width is also equal with the texture height.

Next, we create a Float32Array

var a = new Float32Array(vertexTextureWidth * vertexTextureWidth * 3);

I fill it with the values from my vertex array

for(var i = 0; i < (verticeCount); i++){
a[i] = Model.VerticeMap[i];
}

Now set your texture to be active and bind it:

gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, vMapTexture);
gl.uniform1i(gl.getUniformLocation(this.program, "uVertexTexture"), 1);

To pack the data into the texture, I use the following line

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, vertexTextureWidth, vertexTextureWidth, 0, gl.RGB, gl.FLOAT, a);

I use the RGB format an the FLOAT type. In order to do this, you have to enable the OES_texture_float extension.

Finally, add the following texture parameters:

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
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);

The resulting texture now contains my vertex array and looks like this

RGB Vertex Texture

I'm open for comments or remarks to this solution, feel free to contribute with code simplifications or other approaches.

like image 186
Feppster Avatar answered Jan 02 '23 21:01

Feppster