使用python';在OpenGL API中,如何在元素索引数组的子集上执行GLD元素?
我正在努力熟悉python的OpenGL API,我已经到了可以对四边形进行纹理处理的地步。现在我想在不同的四边形上放置不同的纹理,所以我需要能够渲染四边形元素的子集,更改纹理,然后渲染其余的四边形使用python';在OpenGL API中,如何在元素索引数组的子集上执行GLD元素?,python,opengl,Python,Opengl,我正在努力熟悉python的OpenGL API,我已经到了可以对四边形进行纹理处理的地步。现在我想在不同的四边形上放置不同的纹理,所以我需要能够渲染四边形元素的子集,更改纹理,然后渲染其余的四边形 # based on http://www.pygame.org/wiki/GLSLExample import sys import pygame import OpenGL.GL as gl import OpenGL.GLU as glu import OpenGL.GLUT as g
# based on http://www.pygame.org/wiki/GLSLExample
import sys
import pygame
import OpenGL.GL as gl
import OpenGL.GLU as glu
import OpenGL.GLUT as glut
from OpenGL.arrays import vbo
import numpy
from math import *
from PIL import Image
def compile_shader(source, shader_type):
shader = gl.glCreateShader(shader_type)
#source = c_char_p(source)
length = -1 #c_int(-1)
gl.glShaderSource(shader, source)
gl.glCompileShader(shader)
status = gl.glGetShaderiv(shader, gl.GL_COMPILE_STATUS)
if not status:
print_log(shader)
gl.glDeleteShader(shader)
raise ValueError( 'Shader compilation failed' )
return shader
def compile_program(vertex_source, fragment_source):
vertex_shader = None
fragment_shader = None
program = gl.glCreateProgram()
if vertex_source:
vertex_shader = compile_shader(vertex_source, gl.GL_VERTEX_SHADER)
gl.glAttachShader(program, vertex_shader)
if fragment_source:
fragment_shader = compile_shader(fragment_source, gl.GL_FRAGMENT_SHADER)
gl.glAttachShader(program, fragment_shader)
gl.glLinkProgram(program)
if vertex_shader:
gl.glDeleteShader(vertex_shader)
if fragment_shader:
gl.glDeleteShader(fragment_shader)
return program
def load_texture(file_name):
image = Image.open(file_name)
width = image.size[0]
height = image.size[1]
image_bytes = image.convert("RGBA").tobytes ( "raw", "RGBA", 0, -1)
texture = gl.glGenTextures(1)
gl.glBindTexture ( gl.GL_TEXTURE_2D, texture )
gl.glTexParameterf ( gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_REPEAT )
gl.glTexParameterf ( gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_REPEAT )
gl.glTexParameteri ( gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER,gl.GL_NEAREST )
gl.glTexParameteri ( gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER,gl.GL_LINEAR_MIPMAP_LINEAR )
glu.gluBuild2DMipmaps ( gl.GL_TEXTURE_2D, gl.GL_RGBA, width, height, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, image_bytes )
return texture
def perspective_matrix(fov, aspect_, near, far):
# https://www.opengl.org/discussion_boards/showthread.php/166405-Perspective-Matrix-implementation
f = 1/tan(fov/2)
#print(f, fov)
wiggy = -2 * far * near / (far - near)
aspect = aspect_
return numpy.matrix( [
[ f/aspect, 0, 0, 0],
[0, f, 0, 0],
[0, 0, (far+near)/(near-far), wiggy],
[0, 0, -1, 0]] , dtype=numpy.float32)
def print_log(shader):
length = gl.glGetShaderiv(shader, gl.GL_INFO_LOG_LENGTH)
if length > 0:
log = gl.glGetShaderInfoLog(shader)
print(log, file=sys.stderr)
#
#
#
def translation_matrix(x, y, z):
return numpy.matrix([[1, 0, 0, x],
[0, 1, 0, y],
[0, 0, 1, z],
[0, 0, 0, 1]], numpy.float32)
def scale_matrix(scale):
return numpy.array([[scale, 0, 0, 0],
[0, scale, 0, 0],
[0, 0, scale, 0],
[0, 0, 0, 1]], numpy.float32)
def norm4( mat):
return [mat, mat / mat[0,3] ]
def rotation_matrix(radians, axis):
len = sqrt( axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2])
x = axis[0]/len
y = axis[1]/len
z = axis[2]/len
c = cos(radians)
s = sin(radians)
t=1-c
# http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/
return numpy.matrix( [[ t*x*x + c, t*x*y - z*s, t*x*z + y*s, 0],
[ t*x*y + z*s, t*y*y + c, t*y*z - x*s, 0],
[ t*x*z - y*s, t*y*z + x*s, t*z*z + c, 0],
[0,0,0,1]], dtype=numpy.float32)
def attributes( handle ):
# http://nullege.com/codes/show/src%40p%40y%40PyGLy-HEAD%40pygly%40shader.py/210/OpenGL.GL.glGetActiveAttrib/python
"""Returns an iterator for the attributes of the specified program.
Each attribute returns a tuple.
:rtype: (name, size, type)
:return: A tuple consisting of 3 values:
name is the variable name
size is the variable size in bytes
type is the GL enumeration
"""
# get number of active uniforms
num_attributes = gl.glGetProgramiv( handle, gl.GL_ACTIVE_ATTRIBUTES )
for index in range( num_attributes ):
yield attribute_for_index( handle, index )
def attribute_for_index( handle, index ):
"""Returns the attribute for the specified attribute index.
:rtype: tuple(name, size, type)
"""
# Constants like GLsizei are only found in OpenGL.constants
# for older versions of pyopengl
name_length = 30
glNameSize = (gl.constants.GLsizei)()
glSize = (gl.constants.GLint)()
glType = (gl.constants.GLenum)()
glName = (gl.constants.GLchar * name_length)()
gl.glGetActiveAttrib(
handle,
index,
name_length,
glNameSize,
glSize,
glType,
glName
)
name, size, type = glName.value, glSize.value, glType.value
return name, size, type
def app():
glut.glutInit(sys.argv)
width, height = 640, 480
pygame.init()
pygame.display.set_mode((width, height), pygame.OPENGL | pygame.DOUBLEBUF)
program = compile_program('''
// Vertex program
attribute vec2 vertex_uv;
uniform mat4 mvp;
varying vec3 pos;
varying vec2 texCoord;
void main() {
pos = gl_Vertex.xyz;
gl_Position = mvp * gl_Vertex;
texCoord = vertex_uv;
}
''', '''
// Fragment program
varying vec3 pos;
varying vec2 texCoord;
uniform sampler2D tex;
void main() {
gl_FragColor.rgb = texture(tex, texCoord);
//gl_FragColor.r = 0.5;
}
''')
persp =perspective_matrix(pi/4, 1024/float(768), 0.01, 1000)
mat_loc = gl.glGetUniformLocation(program, bytes("mvp", "ascii"))
print(mat_loc)
uv_loc = gl.glGetAttribLocation(program, bytes("vertex_uv", "ascii"))
print(uv_loc)
tmp = gl.glGetAttribLocation(program, bytes("gl_Vertex", "ascii"))
print([ "gl_Vertex", tmp] )
tex_loc = gl.glGetUniformLocation(program, bytes("tex", "ascii"))
print(["tex uniform location", tex_loc])
if False:
name_length = 30
glNameSize = (gl.constants.GLsizei)()
glSize = (gl.constants.GLint)()
glType = (gl.constants.GLenum)()
glName = (gl.constants.GLchar * name_length)()
gl.glGetActiveAttrib(program,1,
name_length,
glNameSize,
glSize,
glType,
glName)
print(glName.value)
for name,y,z in attributes(program):
print([name,y,z, gl.glGetAttribLocation(program, name)])
gl.glEnable(gl.GL_DEPTH_TEST)
vertices = [-1, -1, -1,
1, -1, -1,
1, 1, -1,
-1, 1, -1,
-1, -1, 1,
1, -1, 1,
1, 1, 1,
-1, 1, 1]
uvs = [0,0,
1,0,
1,1,
0,1,
0,0,
1,0,
1,1,
0,1,
]
indices = [0,1,2,3,
4,5,6,7,
# 8,9,10,11,
# 12,13,14,15,
# 16,17,18,19,
# 20,21,22,23
]
vert_buffer = vbo.VBO(numpy.array(vertices, dtype=numpy.float32))
uv_buffer = vbo.VBO(numpy.array(uvs, dtype=numpy.float32))
index_buffer = vbo.VBO(numpy.array(indices, dtype=numpy.uint16), target=gl.GL_ELEMENT_ARRAY_BUFFER)
#
texture1 = load_texture("bear64.png")
texture2 = load_texture("flamingo64.gif")
#
quit = False
angle = 0
gl.glUseProgram(program)
# bind all our buffers out here because this scene is so static
index_buffer.bind()
vert_buffer.bind()
gl.glEnableVertexAttribArray(0);
gl.glVertexAttribPointer(0, 3, gl.GL_FLOAT, False, 0, None)
if uv_loc>=0:
uv_buffer.bind()
gl.glEnableVertexAttribArray(uv_loc)
gl.glVertexAttribPointer(uv_loc, 2, gl.GL_FLOAT, False, 0, None)
import time
while not quit:
t0 = time.time()
for e in pygame.event.get():
if e.type == pygame.QUIT:
quit=True
elif e.type == pygame.KEYDOWN:
print(e.key)
if e.key == pygame.K_q:
quit = True
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
z = (t0/10)%1
mvp = persp*translation_matrix(0,0,-5)* scale_matrix(1) * rotation_matrix(pi*0.4, [-1,0,0]) *rotation_matrix(z*pi*2, [0,0,1])
#print( mvp.dot([0,0,0,1]) )
mvp_ = numpy.asfortranarray(mvp, dtype=numpy.float32)
gl.glUniformMatrix4fv(mat_loc, 1, False, mvp_)
gl.glBindTexture(gl.GL_TEXTURE_2D, texture1)
gl.glUniform1i( tex_loc, 0)
gl.glDrawElements(gl.GL_QUADS, 4, gl.GL_UNSIGNED_SHORT, None)
gl.glBindTexture(gl.GL_TEXTURE_2D, texture2)
#gl.glDrawElements(gl.GL_QUADS, len(indices)-4, gl.GL_UNSIGNED_SHORT, 4*2)
pygame.display.flip()
if __name__ == '__main__':
app()
让我为这个例子的巨大而道歉,但OpenGL并不是紧凑型的
我的问题是:如何调用gl.gldrawerelements
,以便它从index\u缓冲区
(它是从索引
构建的)中绘制剩余的四边形?我所看到的所有示例在指针字段中都没有使用。这与webGL不同,在webGL中,您可以传递0
以从元素的开头开始,或者传递i*2
以从i
th索引开始
要运行该示例,您需要一个bear64.png和flamingo64.gif。任何旧图像都可以使用,但您可以尝试。来自OpenGL 4参考(glBindBuffer): 而非零缓冲区对象绑定到 GL\u元素\u数组\u缓冲区目标,的索引参数 GLDrawerElements、GLDrawerElementsInstanced、GLDrawerElementsBaseVertex、, glDrawRangeElements、glDrawRangeElementsBaseVertex、, GLMultiDrawerements或GLMultiDrawerementsBaseVertex被解释 作为在基本机器中测量的缓冲区对象内的偏移量 单位 因此,应在“基本机器单位”中输入偏移量。它实际上是开始索引*索引类型大小。在您的例子中,索引类型是SHORT,SHORT size是2。诀窍是必须将值转换为C void指针,如下所示:
gl.glDrawElements(gl.GL_QUADS, len(indices)- start,
gl.GL_UNSIGNED_SHORT, ctypes.c_void_p(start*2)).
我正在奔向不同的活动,但这可能是你的答案。我们明天会更仔细地调查。祝你好运。在尝试了这个调用之后,我认为它的开始和结束参数绑定了索引数组引用的顶点索引(意思是
start如果我将None
更改为4*2
以尝试在索引数组中的第四个短字符开始,它将不会绘制任何内容。如果我使用0而不是None,它甚至会失败:gl.glpaurements(gl.gl\u QUADS,4,gl.gl\u UNSIGNED\u short,0)
尝试强制使用c\u void\u ptr作为最后一个参数:gl.glpaurements)(gl.gl_QUADS,4,gl.gl_UNSIGNED_SHORT,ctypes.c_void_ptr(start*size))几乎都是这样。真正起作用的行是gl.gldrawerelements(gl.gl_QUADS,len(index)-start,gl.gl_UNSIGNED_SHORT,ctypes.c_void_p(start*2))
将该代码示例合并到您的答案中,我会将其标记为已接受。太棒了!我实际上从未用Python编写过OpenGL:-D