It's tough to provide the "best approach" without any code providing further context of what you're trying to do.
- Is this the best/modern approach using a vertex shader and fragment shader? There is a lot of image examples from ~5-10 years ago that do something different.
Without seeing the tutorials, it's hard to give an answer. However, I'm assuming you're referring to examples using the fixed-function pipeline. If so, then yes, stick to shaders.
- If I have four images loaded, can I re-use the same vertex and fragment shaders for each image?
Assuming your fragment shader somewhat matches the one you linked to (4.1.texture.fs), i.e. boiling down to something like this:
#version 330 core
out vec4 fragColor;
in vec2 vTexCoord;
uniform sampler2D tex;
void main() {
fragColor = texture(tex, vTexCoord);
}
Then yes, you can reuse the shader. Assuming your current approach involves 4 draw calls, then just bind the needed texture prior to the draw call.
- My current thinking on approaching rendering the images in a 2x2 grid is to create 4 vertices[] with each quadrant (-1 to 0, 0 to 1, etc). This would mean I would need 4 vertex VAO objects. Is this the best approach, or is there something simpler that can be done?
To my understanding, your vertex data doesn't change for each image. Only the position and, well, the actual image. So instead of duplicating the vertex arrays and vertex data, then you can use a matrix in your vertex shader to transform the vertices.
You'll get introduced to this in the subsequent LearnOpenGL "Transformations" tutorial.
In short, you'll add uniform mat4 mvp
to your vertex shader, and multiply it with the vertex position, something like this:
#version 330 core
layout (location = 0) in vec3 pos;
uniform mat4 mvp;
void main() {
gl_Position = mvp * vec4(pos, 1.0);
}
There's also alternative ways, in which you can accomplish what you're trying to do, with a single draw call.
To use an array texture, your shader needs to specify sampler2DArray
instead of sampler2D
. Along with your vTexCoord
needing to provide a third coordinate, representing the layer.
#version 330 core
out vec4 fragColor;
in vec3 vTexCoord;
uniform sampler2DArray tex;
void main() {
fragColor = texture(tex, vTexCoord);
}
Whereas compared to a uniform
array of textures. You'd add a layer
attribute to your vertex data and shaders.
Vertex Shader:
#version 330 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in uint layer;
flat out uint vLayer;
uniform mat4 mvp;
void main() {
vTexCoord = texCoord;
vLayer = index;
gl_Position = mvp * vec4(position, 0.0, 1.0);
}
Fragment Shader:
#version 330 core
out vec4 fragColor;
in vec2 vTexCoord;
flat in uint vLayer;
uniform sampler2D tex[4];
void main() {
fragColor = texture(tex[vLayer], vTexCoord);
}