I am not sure if this is a zig or OpenGL issue, so please let me know so that I will post this question in somewhere else.
After having some luck on plotting a triangle using OpenGL with zig and port the main features of the sb7.h framework from the book, I decided to take a step further to port the “indexed Cube” example from the OpenGL superbible, trying to learn about the buffers and doing transformation using the matrix library, which I have picked the zm library by griush which some other opengl projects did use it.
The original C++ implementation consists two buffers objects, vertex_indices, and vertex_positions. This is the zig version of the arrays:
const vertex_positions = [_]app.gl.float{
-0.25, -0.25, -0.25,
-0.25, 0.25, -0.25,
0.25, -0.25, -0.25,
0.25, 0.25, -0.25,
0.25, -0.25, 0.25,
0.25, 0.25, 0.25,
-0.25, -0.25, 0.25,
-0.25, 0.25, 0.25,
};
const vertex_indices = [_]app.gl.ushort{
0, 1, 2,
2, 1, 3,
2, 3, 4,
4, 3, 5,
4, 5, 6,
6, 5, 7,
6, 7, 0,
0, 7, 1,
6, 0, 2,
2, 4, 6,
7, 5, 3,
7, 3, 1,
};
With this two arrays, I needed to declare two buffer objects as shown:
// creating a new buffer usually following the following pattern:
app.gl.GenBuffers(1, (&position_buffer)[0..1]);
app.gl.BindBuffer(app.gl.ARRAY_BUFFER, position_buffer);
app.gl.BufferData(
app.gl.ARRAY_BUFFER,
@sizeOf(f32) * vertex_positions.len,
&vertex_positions,
app.gl.STATIC_DRAW,
);
// set up a vertex attribute array
app.gl.EnableVertexAttribArray(0);
app.gl.VertexAttribPointer(0, 3, app.gl.FLOAT, app.gl.FALSE, 0, 0);
// the vertex index array buffer
app.gl.GenBuffers(1, (&index_buffer)[0..1]);
app.gl.BindBuffer(app.gl.ELEMENT_ARRAY_BUFFER, index_buffer);
app.gl.BufferData(
app.gl.ELEMENT_ARRAY_BUFFER,
@sizeOf(app.gl.ushort) * vertex_indices.len,
&vertex_indices,
app.gl.STATIC_DRAW,
);
Meanwhile, I have two uniforms in my code to calculate the position, orientation and perspective of my cube, which are the following:
mv_location = app.gl.GetUniformLocation(program, "mv_matrix");
proj_location = app.gl.GetUniformLocation(program, "proj_matrix");
which corresponding to the following equation in my vertex shader code for calculating the movement and the perspective of the cube:
gl_Position = proj_matrix * mv_matrix * position;
Where the data of these matrices calculated as the following:
For proj_matrix:
// zig perspective is radian based
const proj_matrix = zm.Mat4f.perspective(
std.math.degreesToRadians(50),
8.0 / 6.0,
0.1,
1000,
);
app.gl.UniformMatrix4fv(proj_location, 1, app.gl.FALSE, @ptrCast(&proj_matrix));
Corresponding to the original C++ code from the book:
// C++ is degree based, thus no radian convertion
vmath::mat4 proj_matrix = vmath::perspective(50.0f,
(float)info.windowWidth / (float)info.windowHeight,
0.1f,
1000.0f);
glUniformMatrix4fv(proj_location, 1, GL_FALSE, proj_matrix);
app.gl.UniformMatrix4fv(mv_location, 1, app.gl.FALSE, @ptrCast(&mv_matrix));
app.gl.DrawElements(app.gl.TRIANGLES, 36, app.gl.UNSIGNED_SHORT, 0);
For the transforms, I did the following:
// sin() and cos() in C++ are in radian, but vmath::rotate is in degree afaik
// thus the lack of radian conversion in the trigonometric functions.
var mv_matrix = zm.Mat4f.translation(
0.0,
0.0,
-4.0,
);
const mv_b = zm.Mat4f.translation(
@sin(2.1 * f) * 0.5,
@cos(1.7 * f) * 0.5,
@sin(1.3 * f) * @cos(1.5 * f) * 2.0,
);
const mv_c = zm.Mat4f.rotation(
zm.Vec3f{ 0.0, 1.0, 0.0 },
std.math.degreesToRadians(current_time_f32 * 45.0),
);
const mv_d = zm.Mat4f.rotation(
zm.Vec3f{ 1.0, 0.0, 0.0 },
std.math.degreesToRadians(current_time_f32 * 81.0),
);
mv_matrix = mv_matrix.multiply(mv_b.multiply(mv_c.multiply(mv_d)));
comparing to C++
float f = (float)currentTime * 0.3f;
vmath::mat4 mv_matrix = vmath::translate(0.0f, 0.0f, -4.0f) *
vmath::translate(sinf(2.1f * f) * 0.5f,
cosf(1.7f * f) * 0.5f,
sinf(1.3f * f) * cosf(1.5f * f) * 2.0f) *
vmath::rotate((float)currentTime * 45.0f, 0.0f, 1.0f, 0.0f) *
vmath::rotate((float)currentTime * 81.0f, 1.0f, 0.0f, 0.0f);
glUniformMatrix4fv(mv_location, 1, GL_FALSE, mv_matrix);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0);
The code above should be where the problem are, and the problem is the following:
This is the intended behavior from the original C++ implementation in the book, a cube moving and spinning on a green screen:
However, my version doesn’t have the cube present, only a blank green screen, so I tried to identify the problem of the code, starting by removing the CULL_FACE, DEPTH_TEST, and LEQUAL so that the cube can be appeared out of bound, and I have gotten some random stripes instead of a cube:
For that reason, I knew the projection messed up, so I have removed the proj_matrix in my shader code such that the gl_position only calculates the transformation and the given vertices of the cubes:
It seems like something has rendered, but it looks like a truncated pyramid rather than a cube, and this happens whenever the first translation of the mv_matrix have a non-zero value in the z axis.
Thus, here are some questions:
- Any one has some luck on generating your first cube using zig with OpenGL?
- For people who have used the OpenGL binding generator (or other gl libraries and bindings), did I messed on configuring the buffers, vertex Attributes and uniforms?
- For any zm users, based on the matrix transforms, did I use the library wrong, passing some wrong types?
I know this question might lack details and it is more complex as usual, so here is the repo about my “cube” and feel free to ask any questions so that I could give you a more precise information.