如何在python中使用glDrawArrayInstanced?

问题描述

我有一个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,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,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])).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,c_view)
gluniformMatrix4fv(self.proj_location,c_projection)
gluniformMatrix4fv(self.model_location,c_model)
gluniformMatrix4fv(self.translate_location,c_translate)
gluniformMatrix4fv(self.scale_location,c_scale)
gluniformMatrix4fv(self.rotate_location,c_rotate)
gluniformMatrix4fv(self.light_location,c_light)

我尝试通过设置偏移量矢量

offset = [(0,(10,10)]

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

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

解决方法

顶点着色器在语义上不正确。您必须根据类型vec3的变量offset构造一个vec2

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

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

实际上,您已经使用了序列(,)运算符。参见GLSL 4.60 - Expressions

[...]通过返回以逗号分隔的表达式列表中最右边的表达式的类型和值,对表达式进行操作的sequence(,)运算符。

因此,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,y1)

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

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