I have a python OpenGL application in which I am trying to render multiple objects at the same time, without any luck. For some reason, only one object is drawn no matter how much I change the offsets. This are my fragment shaders:
self.vertex_shader_source = b"""
#version 330
in layout(location = 0) vec3 positions;
in layout(location = 1) vec2 textureCoords;
in layout(location = 2) vec3 normals;
uniform mat4 light;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform mat4 rotate;
uniform mat4 translate;
uniform mat4 scale;
uniform vec2 offsets[2];
out vec2 textures;
out vec3 fragNormal;
void main()
{
fragNormal = (light * vec4(normals, 0.0f)).xyz;
vec2 offset = offsets[gl_InstanceID];
gl_Position = projection * view * model * rotate * translate * scale * vec4(positions + (offset, 0), 1.0f);
textures = vec2(textureCoords.x, 1 - textureCoords.y);
}
"""
self.fragment_shader_source = b"""
#version 330
in vec2 textures;
in vec3 fragNormal;
uniform sampler2D sampTexture;
out vec4 outColor;
void main()
{
vec3 ambientLightIntensity = vec3(0.9f, 0.9f, 0.9f);
vec3 sunLightIntensity = vec3(0.0f, 0.2f, 0.0f);
vec3 sunLightDirection = normalize(vec3(0.0f, 0.0f, 0.0f));
vec4 texel = texture(sampTexture, textures);
vec3 lightIntensity = ambientLightIntensity + sunLightIntensity * fragNormal * max(dot(fragNormal, sunLightDirection), 0.0f);
outColor = vec4(texel.rgb * lightIntensity, texel.a);
}
"""
And after compiling them, this is how I set up the environment:
self.vertex_array_object = glGenVertexArrays(1)
glBindVertexArray(self.vertex_array_object)
vertex_buffer_object = GLuint(0)
glGenBuffers(1, vertex_buffer_object)
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object)
glBufferData(GL_ARRAY_BUFFER, len(self.object.model) * 4, self.object.c_model, GL_STATIC_DRAW)
# vertices
vertex_offset = 0
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, self.object.model.itemsize * 3, ctypes.c_void_p(vertex_offset))
glEnableVertexAttribArray(0)
# textures
texture_offset = len(self.object.vertex_index) * 12
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, self.object.model.itemsize * 2, ctypes.c_void_p(texture_offset))
glEnableVertexAttribArray(1)
# normals
normal_offset = texture_offset + len(self.object.texture_index) * 8
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, self.object.model.itemsize * 3, ctypes.c_void_p(normal_offset))
glEnableVertexAttribArray(2)
/* texture mapping … */
view = pyrr.matrix44.create_from_translation(pyrr.Vector3([0.0, 0.0, -3.0])).flatten()
projection = pyrr.matrix44.create_perspective_projection_matrix(80.0, 1280 / 720, 0.1, 100.0).flatten()
model = pyrr.matrix44.create_from_translation(pyrr.Vector3([2.0, -0.5, -1.7])).flatten()
translate = pyrr.matrix44.create_from_translation(pyrr.Vector3([0, -0.15, 0])).flatten()
scale = pyrr.matrix44.create_from_scale(pyrr.Vector3([0, 0, 0])).flatten()
light = pyrr.matrix44.create_from_translation(pyrr.Vector3([2.0, 10.5, 1.7])).flatten()
self.rot_y = pyrr.Matrix44.from_y_rotation(0).flatten()
c_view = (GLfloat * len(view))(*view)
c_projection = (GLfloat * len(projection))(*projection)
c_model = (GLfloat * len(model))(*model)
c_translate = (GLfloat * len(translate))(*translate)
c_scale = (GLfloat * len(translate))(*translate)
c_rotate = (GLfloat * len(self.rot_y))(*self.rot_y)
c_light = (GLfloat * len(light))(*light)
self.rotate_location = glGetUniformLocation(self.shader, b"rotate")
self.translate_location = glGetUniformLocation(self.shader, b"translate")
self.scale_location = glGetUniformLocation(self.shader, b"scale")
self.view_location = glGetUniformLocation(self.shader, b"view")
self.proj_location = glGetUniformLocation(self.shader, b"projection")
self.model_location = glGetUniformLocation(self.shader, b"model")
self.light_location = glGetUniformLocation(self.shader, b"light")
self.offset_location = glGetUniformLocation(self.shader, b"offsets")
glUniformMatrix4fv(self.view_location, 1, GL_FALSE, c_view)
glUniformMatrix4fv(self.proj_location, 1, GL_FALSE, c_projection)
glUniformMatrix4fv(self.model_location, 1, GL_FALSE, c_model)
glUniformMatrix4fv(self.translate_location, 1, GL_FALSE, c_translate)
glUniformMatrix4fv(self.scale_location, 1, GL_FALSE, c_scale)
glUniformMatrix4fv(self.rotate_location, 1, GL_FALSE, c_rotate)
glUniformMatrix4fv(self.light_location, 1, GL_FALSE, c_light)
I tried by setting up the offset vector like
offset = [(0, 0), (10, 10)]
and pass it to the shader using glUniform2fv but this shows up only one object (I only need 2 for now). This is how I draw the objects:
glBindVertexArray(self.vertex_array_object)
glDrawArraysInstanced(GL_TRIANGLES, 0, len(self.object.vertex_index), 2)
glBindVertexArray(0)
The vertex shader is semantically incorrect. You have to construct a vec3
from the variable offset with type vec2
:
vec4(positions + (offset, 0), 1.0f)
vec4(positions + vec3(offset, 0.0), 1.0)
Actually you have used the sequence (,
) operator. See GLSL 4.60 - Expressions:
[...] The sequence (,) operator that operates on expressions by returning the type and value of the right-most expression in a comma separated list of expressions.
Hence the result of positions + (offset, 0)
is the same as the result of positions + 0
.
Use glUniform2fv
to set the uniforms:
self.offset_location = glGetUniformLocation(self.shader, b"offsets")
glUniform2fv(self.offset_location, 2, [x0, y0, x1, y1])
Alternatively you can set the uniforms in the array separately:
self.offset_0_location = glGetUniformLocation(self.shader, b"offsets[0]")
glUniform2f(self.offset_0_location, x0, y0)
self.offset_1_location = glGetUniformLocation(self.shader, b"offsets[1]")
glUniform2f(self.offset_1_location, x1, y1)
In addition, a scale of (0, 0, 0) makes no sense at all, since it means that all vertices become (0, 0, 0). Change the scale to (1, 1, 1):
scale = pyrr.matrix44.create_from_scale(pyrr.Vector3([1, 1, 1])).flatten()