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.
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
I'm open for comments or remarks to this solution, feel free to contribute with code simplifications or other approaches.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With