Reputation: 1107
I've implemented a simple batch rendering setup for 2D. It appears to be working, except for some artifacts that kind of look like Z-fighting on a single surface.
TL;DR? I recorded a video demonstrating what I'm seeing and what "fixes" it.
There are three textures bound:
Some of the quads are only textured, some are only shaded with a flat color, and some are textured and tinted.
Here's the vertex shader:
#version 460 core
layout(location = 0) in vec3 _position;
layout(location = 1) in vec4 _color;
layout(location = 2) in vec2 _texture_coords;
layout(location = 3) in int _texture_index;
layout(location = 4) in float _tiling_factor;
uniform mat4 viewproj_matrix;
out vec4 color;
out vec2 texture_coords;
out flat int texture_index;
out float tiling_factor;
void main()
{
color = _color;
texture_coords = _texture_coords;
texture_index = _texture_index;
tiling_factor = _tiling_factor;
gl_Position = viewproj_matrix * vec4(_position, 1.0);
}
And the fragment shader:
#version 460 core
layout(location = 0) out vec4 final_color;
in vec4 color;
in vec2 texture_coords;
in flat int texture_index;
in float tiling_factor;
uniform sampler2D textures[32];
void main()
{
final_color = (
texture(textures[texture_index], texture_coords * tiling_factor) * color
);
}
It's pretty simple, of course. But I'm also a novice, so simple is good. This behavior seems related to sampling multiple textures. I say that because, as I demonstrated in the video, the artifacts go away if I'm sampling only one of the three bound textures. The situation also resolves itself when I force the batches to be a single quad in size.
Here's the code to draw a flat shaded quad:
void Renderer2D::draw_quad(const RenderAPI &api, const glm::vec3 &position,
const glm::vec4 &color,
const float rotation, const glm::vec3 &scale) {
if(_batch.quad_count >= _batch.max_quads) {
_flush_and_reset();
}
_batch.api = &api;
glm::mat4 transform = glm::translate(_ident, position) *
glm::rotate(_ident, glm::radians(rotation), _z_axis) *
glm::scale(_ident, scale);
for(uint32_t corner = 0; corner < _corners_per_quad; corner++) {
_batch.vertex_buffer_ptr->position = transform * _vertex_coords[corner];
_batch.vertex_buffer_ptr->color = color;
_batch.vertex_buffer_ptr->texture_coord = _texture_coords[corner];
_batch.vertex_buffer_ptr->texture_index = _white_texture_index;
_batch.vertex_buffer_ptr->tiling_factor = _default_tiling;
_batch.vertex_buffer_ptr++;
}
_batch.quad_count++;
_stats.quad_count++;
}
And if you're interested in more, here's the whole Renderer2D class. Hopefully this is enough information, but there also isn't that much code in the whole shebang.
What I'm struggling with is finding angles to troubleshoot this from. Any guidance, theories, pointers, or guesses are welcome. I'm looking forward to strengthening my GPU/3D math/etc debugging skillset. =)
Upvotes: 0
Views: 221
Reputation: 118
Looks like you are trying to render multiple textures inside a single invocation group. This means that you are sampling textures with variables which are not dynamically uniform. This causes sampling to lose implicit derivatives, infact they become undefined.
There are many ways to split up an invocation group so you can sample textures in a dynamically uniform way. You could use a 3D texture to hold all of the different textures although this requires all the textures be the same size, or use a texture atlas. Another way is to use separate draw calls for each unique texture or better use MultiDraw commands which is the same thing but can group multiple draw calls into a single one while keeping the invocation groups separate.
Upvotes: 1