I am constructing some terrain for a 3D game (in C) as a 2D grid of tiles, the corners of which have height into the 3rd dimension. In the middle of each tile is another vertex, the height of which is the average of the heights of the tile corners around it. This means that, for each tile, there are 4 triangles to be drawn, with every triangle sharing a 1 point in the middle and 2 on the corners of the tile. I figured that a GL_TRIANGLE_FAN would be appropriate for this task.
In the code below, struct vbo_vert
is a struct containing a vec3
and an unsigned char
, in that order. Each triangle fan consists of 6 vertices (one for the middle, one for each of the corners, and another back on top of the first corner to close the square), and each vertex is sent to the GPU with a number from 0 to 4 in the byte member of the struct so that the vertex shader can determine the texturing. c_vec
is an array of vec3
positions of the tile corners, and t_vec
is a similar array for the positions of those central vertices.
//Assembling the triangle fans
struct vbo_vert tri_fan[256][1536] = {0};
for (int i = 0; i < 255; i++) {
for (int j = 0; j < 255; j++) {
int j_6 = (j * 6);
tri_fan[i][j_6 + 0] =
(struct vbo_vert){t_vec[i][j], 0};
tri_fan[i][j_6 + 1] =
(struct vbo_vert){c_vec[i][j], 1};
tri_fan[i][j_6 + 2] =
(struct vbo_vert){c_vec[i + 1][j], 2};
tri_fan[i][j_6 + 3] =
(struct vbo_vert){c_vec[i + 1][j + 1], 3};
tri_fan[i][j_6 + 4] =
(struct vbo_vert){c_vec[i][j + 1], 4};
tri_fan[i][j_6 + 5] =
(struct vbo_vert){c_vec[i][j], 1};
}
}
After this I open a texture. I fairly sure that the image-reading and texture-writing code is sound because I use practically the same code to texture models made of GL_TRIANGLES elsewhere and it works great. Then I send tri_fan to the GPU, and I know that the VAO and Array Pointers are good because I can draw the terrain as a wireframe and it looks fine. That just leaves the shader program.
//Vertex shader
#version 330 core
layout (location = 0) in vec3 a_pos;
layout (location = 1) in int a_texref;
out vec3 v_pos;
out vec2 v_tex;
uniform mat4 model;
uniform mat4 view;
uniform mat4 proj;
void main()
{
gl_Position = proj * view * model * vec4(a_pos, 1.0f);
v_pos = a_pos;
if ((a_texref == 0)) {
v_tex = vec2(0.5, 0.5);
} else if (a_texref == 1) {
v_tex = vec2(0.0, 1.0);
} else if (a_texref == 2) {
v_tex = vec2(0.0, 0.0);
} else if (a_texref == 3) {
v_tex = vec2(1.0f, 0.0f);
} else if (a_texref == 4) {
v_tex = vec2(1.0, 1.0);
}
}
#version 330 core
out vec4 FragColour;
in vec3 v_pos;
in vec2 v_tex;
uniform sampler2D tex_sam1;
void main()
{
FragColour = texture(tex_sam1, v_tex);
}
I do not see a problem with these shaders. However I do not understand shaders as well as I could. When I render the scene with this test texture:
It renders like this:
The blue lines lie on the edge of the tiles, and the white dot is in the center.
EDIT: upon testing further I worked out that the center vertex's uv is being set correctly, but all the other vertices are being set to whatever comes last in the else if
ladder in the vertex shader.
I haven't been able to get through this issue. I was having similar texturing problems when I was using triangle strips to make the mesh before I realised that I could be more efficient using fans compared to the way I was doing it. I'm guessing that it is some weird quirk with how the shaders handle fans that I don't understand, or I have miswritten some code somewhere, in which case I will leave the question up as a testament to the importance of re-reading your code :-P. And There is probably a way better way to do the texturing that I am trying to do. Any insight into this issue is appreciated.
t_vec
, not the array of tile corners,c_vec
, like the rest of them. – Architect Jul 09 '21 at 09:40