I'm making a little OpenGL renderer. Currently I use VAOs/VBOs and batch all the entities with the same VAO. I then draw using glDrawElementsInstanced
. I am wondering how can I send a different textures in the uniform for the Sampler2D since each entities might have a different texture ?
Here the batch Java side building the uniform buffer:
public class ContainerBatch extends Batch<VisualContainer> {
private VertexArray vao;
private Camera perspective;
private UniformBuffer buffer;
public ContainerBatch(ShaderProgram program, Camera perspective) {
super(program);
this.vao = new RectangleVertexArray();
this.perspective = perspective;
this.buffer = new UniformBuffer()
.setBinding(0)
.addMatrix4fEntry("quadsTransforms", true)
.addVector2fEntry("quadsSizes", true)
.addIntegerEntry("quadsTextures", true)
.addBooleanEntry("quadsHasTexture", true)
.addVector3fEntry("quadsFillColors", true)
.addFloatEntry("quadsOpacities", true)
.allocate();
}
public void prepare() {
if(this.size() > UniformBuffer.ARRAY_SIZE)
throw new IllegalStateException("Batch cannot contain more than " + UniformBuffer.ARRAY_SIZE + " models.");
this.program.use();
this.program.sendMatrix4f("perspective", this.perspective.getOrthographicView());
}
public void fillBuffer() {
IntStream.range(0, this.size()).parallel().forEach(i -> {
VisualContainer visualContainer = this.get(i);
if(this.perspective.contains(visualContainer) && visualContainer.isVisible()) {
buffer.insertMatrix4fAt("quadsTransforms", visualContainer.getWorldTransformation(), i);
buffer.insertVector2fAt("quadsSizes", visualContainer.getScale(), i);
if(visualContainer.getTexture() != null) {
buffer.insertIntegerAt("quadsTextures", visualContainer.getTexture().getId(), i);
buffer.insertBooleanAt("quadsHasTexture", true, i);
} else {
buffer.insertIntegerAt("quadsTextures", 0, i);
buffer.insertBooleanAt("quadsHasTexture", false, i);
}
buffer.insertVector3fAt("quadsFillColors", visualContainer.getFillColor(), i);
buffer.insertFloatAt("quadsOpacities", visualContainer.getOpacity(), i);
}
});
}
public void draw(float depth) {
this.fillBuffer();
this.program.use();
this.program.sendUniformBuffer(this.buffer);
this.program.sendFloat("depth", depth);
if(this.perspective.isDirty()) {
this.program.sendMatrix4f("perspective", this.perspective.getOrthographicView());
this.program.sendVector4f("viewport", this.perspective.getViewport());
}
this.vao.bind();
this.vao.getIndexBuffer().bind();
glDrawElementsInstanced(GL_TRIANGLES, this.vao.getIndexBuffer().getCount(), GL_UNSIGNED_INT, 0, this.size());
}
}
Here's my vertex shader:
#version 460 core
const int MAX_QUADS_PER_SCENE = _[MAX_QUADS];
uniform mat4 perspective;
uniform vec4 viewport;
uniform float depth;
layout (location = 0) in vec3 vertex;
layout (location = 1) in vec2 texCoord;
layout(std140, binding=0) uniform quads {
mat4 quadsTransforms[MAX_QUADS_PER_SCENE];
vec2 quadsSizes[MAX_QUADS_PER_SCENE];
int quadsTextures[MAX_QUADS_PER_SCENE];
int quadsHasTexture[MAX_QUADS_PER_SCENE];
vec3 quadsFillColors[MAX_QUADS_PER_SCENE];
float quadsOpacities[MAX_QUADS_PER_SCENE];
};
out vec2 quadTexCoord;
out vec2 quadSize;
out vec3 quadColor;
out float quadOpacity;
out int textureSampler;
out int hasTexture;
void main() {
quadTexCoord = texCoord;
quadSize = quadsSizes[gl_InstanceID];
textureSampler = quadsTextures[gl_InstanceID];
quadColor = quadsFillColors[gl_InstanceID];
quadOpacity = quadsOpacities[gl_InstanceID];
float ndcDepth = (depth / 500) - 1;
mat4 quadMatrice = quadsTransforms[gl_InstanceID];
gl_Position = perspective * quadMatrice * vec4(vertex.xy, ndcDepth, 1.0);
}
And here's my fragment shader:
#version 460 core
out vec4 outColor;
in vec2 quadTexCoord;
in vec2 quadSize;
in vec3 quadColor;
in float quadOpacity;
in flat int textureSampler;
in flat int hasTexture;
void main() {
if(hasTexture == 1) {
vec4 texturePixelColor = texture(sampler2D(textureSampler), quadTexCoord);
texturePixelColor.w = min(texturePixelColor.w, quadOpacity);
outColor = texturePixelColor;
} else {
outColor = vec4(quadColor, quadOpacity);
}
}
As you can see for the shader, I tried sending the texture id directly and using it as a sampler to no avail. To my understanding Sampler2Ds needs to be dynamic uniforms which means I can only send one with my draw call. Of course I could use an atlas here and change the texture coordinates. I'm wondering if this is possible using multiple images.
Thank you.