我如何在 python 中使用 glDrawArraysInstanced?

How could I use glDrawArrayInstanced in python?

我有一个 python OpenGL 应用程序,我试图在其中同时渲染多个对象,但没有任何运气。出于某种原因,无论我如何更改偏移量,都只会绘制一个对象。这是我的片段着色器:

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);
}
"""

在编译它们之后,我是这样设置环境的:

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)

我试过像

这样设置偏移向量
offset = [(0, 0), (10, 10)]

并使用 glUniform2fv 将它传递给着色器,但这只显示一个对象(我现在只需要 2 个)。这就是我绘制对象的方式:

glBindVertexArray(self.vertex_array_object)
glDrawArraysInstanced(GL_TRIANGLES, 0, len(self.object.vertex_index), 2)
glBindVertexArray(0)

顶点着色器在语义上不正确。您必须从类型为 vec2:

的变量 offset 构造一个 vec3

vec4(positions + (offset, 0), 1.0f)

vec4(positions + vec3(offset, 0.0), 1.0)

实际上您已经使用了序列 (,) 运算符。见 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.

因此positions + (offset, 0)的结果与positions + 0的结果相同。


使用glUniform2fv设置制服:

self.offset_location = glGetUniformLocation(self.shader, b"offsets")
glUniform2fv(self.offset_location, 2, [x0, y0, x1, y1])

或者你可以单独设置数组中的制服:

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)

此外,(0, 0, 0) 的比例完全没有意义,因为它意味着所有顶点都变成 (0, 0, 0)。将比例更改为 (1, 1, 1):

scale = pyrr.matrix44.create_from_scale(pyrr.Vector3([1, 1, 1])).flatten()