python调用opengl_python-OpenGL基础知识:每个对象调用一次glDrawElements

继续我对OpenGL基础知识的探索(请参见this question),我试图弄清楚使用OpenGL绘制场景的基本原理.

我试图渲染一个简单的立方体,在每个方向上重复n次.

我的方法似乎产生了可怕的性能:1000个多维数据集使性能低于50fps(在QuadroFX 1800上,大约是GeForce 9600GT).

我绘制这些多维数据集的方法如下:

完成一次:

>在模型空间中设置包含我的多维数据集顶点的顶点缓冲区和数组缓冲区

>设置一个数组缓冲区,索引要绘制的立方体为12个三角形

为每一帧完成:

>更新顶点着色器使用的统一值以一次移动所有多维数据集

为每个立方体,每个框架完成:

>更新顶点着色器用来将每个立方体移到其位置的统一值

>调用glDrawElements绘制定位的立方体

这是理智的方法吗?如果不是,那该怎么办呢?我猜想我需要最小化对glUniform,glDrawElements或两者的调用,但是我不确定该怎么做.

我的小测试的完整代码:(取决于gletools和pyglet)

我知道我的初始化代码(至少)确实很丑陋.我现在关心的是每个帧的渲染代码,在稍后创建顶点缓冲区时,我会稍微简化一些工作.

import pyglet

from pyglet.gl import *

from pyglet.window import key

from numpy import deg2rad, tan

from gletools import ShaderProgram, FragmentShader, VertexShader, GeometryShader

vertexData = [-0.5, -0.5, -0.5, 1.0,

-0.5, 0.5, -0.5, 1.0,

0.5, -0.5, -0.5, 1.0,

0.5, 0.5, -0.5, 1.0,

-0.5, -0.5, 0.5, 1.0,

-0.5, 0.5, 0.5, 1.0,

0.5, -0.5, 0.5, 1.0,

0.5, 0.5, 0.5, 1.0]

elementArray = [2, 1, 0, 1, 2, 3,## back face

4, 7, 6, 4, 5, 7,## front face

1, 3, 5, 3, 7, 5,## top face

2, 0, 4, 2, 4, 6,## bottom face

1, 5, 4, 0, 1, 4,## left face

6, 7, 3, 6, 3, 2]## right face

def toGLArray(input):

return (GLfloat*len(input))(*input)

def toGLushortArray(input):

return (GLushort*len(input))(*input)

def initPerspectiveMatrix(aspectRatio = 1.0, fov = 45):

frustumScale = 1.0 / tan(deg2rad(fov) / 2.0)

fzNear = 0.5

fzFar = 300.0

perspectiveMatrix = [frustumScale*aspectRatio, 0.0 , 0.0 , 0.0 ,

0.0 , frustumScale, 0.0 , 0.0 ,

0.0 , 0.0 , (fzFar+fzNear)/(fzNear-fzFar) , -1.0,

0.0 , 0.0 , (2*fzFar*fzNear)/(fzNear-fzFar), 0.0 ]

return perspectiveMatrix

class ModelObject(object):

vbo = GLuint()

vao = GLuint()

eao = GLuint()

initDone = False

verticesPool = []

indexPool = []

def __init__(self, vertices, indexing):

super(ModelObject, self).__init__()

if not ModelObject.initDone:

glGenVertexArrays(1, ModelObject.vao)

glGenBuffers(1, ModelObject.vbo)

glGenBuffers(1, ModelObject.eao)

glBindVertexArray(ModelObject.vao)

initDone = True

self.numIndices = len(indexing)

self.offsetIntoVerticesPool = len(ModelObject.verticesPool)

ModelObject.verticesPool.extend(vertices)

self.offsetIntoElementArray = len(ModelObject.indexPool)

ModelObject.indexPool.extend(indexing)

glBindBuffer(GL_ARRAY_BUFFER, ModelObject.vbo)

glEnableVertexAttribArray(0) #position

glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0)

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ModelObject.eao)

glBufferData(GL_ARRAY_BUFFER, len(ModelObject.verticesPool)*4, toGLArray(ModelObject.verticesPool), GL_STREAM_DRAW)

glBufferData(GL_ELEMENT_ARRAY_BUFFER, len(ModelObject.indexPool)*2, toGLushortArray(ModelObject.indexPool), GL_STREAM_DRAW)

def draw(self):

glDrawElements(GL_TRIANGLES, self.numIndices, GL_UNSIGNED_SHORT, self.offsetIntoElementArray)

class PositionedObject(object):

def __init__(self, mesh, pos, objOffsetUf):

super(PositionedObject, self).__init__()

self.mesh = mesh

self.pos = pos

self.objOffsetUf = objOffsetUf

def draw(self):

glUniform3f(self.objOffsetUf, self.pos[0], self.pos[1], self.pos[2])

self.mesh.draw()

w = 800

h = 600

AR = float(h)/float(w)

window = pyglet.window.Window(width=w, height=h, vsync=False)

window.set_exclusive_mouse(True)

pyglet.clock.set_fps_limit(None)

## input

forward = [False]

left = [False]

back = [False]

right = [False]

up = [False]

down = [False]

inputs = {key.Z: forward, key.Q: left, key.S: back, key.D: right,

key.UP: forward, key.LEFT: left, key.DOWN: back, key.RIGHT: right,

key.PAGEUP: up, key.PAGEDOWN: down}

## camera

camX = 0.0

camY = 0.0

camZ = -1.0

def simulate(delta):

global camZ, camX, camY

scale = 10.0

move = scale*delta

if forward[0]:

camZ += move

if back[0]:

camZ += -move

if left[0]:

camX += move

if right[0]:

camX += -move

if up[0]:

camY += move

if down[0]:

camY += -move

pyglet.clock.schedule(simulate)

@window.event

def on_key_press(symbol, modifiers):

global forward, back, left, right, up, down

if symbol in inputs.keys():

inputs[symbol][0] = True

@window.event

def on_key_release(symbol, modifiers):

global forward, back, left, right, up, down

if symbol in inputs.keys():

inputs[symbol][0] = False

## uniforms for shaders

camOffsetUf = GLuint()

objOffsetUf = GLuint()

perspectiveMatrixUf = GLuint()

camRotationUf = GLuint()

program = ShaderProgram(

VertexShader('''

#version 330

layout(location = 0) in vec4 objCoord;

uniform vec3 objOffset;

uniform vec3 cameraOffset;

uniform mat4 perspMx;

void main()

{

mat4 translateCamera = mat4(1.0f, 0.0f, 0.0f, 0.0f,

0.0f, 1.0f, 0.0f, 0.0f,

0.0f, 0.0f, 1.0f, 0.0f,

cameraOffset.x, cameraOffset.y, cameraOffset.z, 1.0f);

mat4 translateObject = mat4(1.0f, 0.0f, 0.0f, 0.0f,

0.0f, 1.0f, 0.0f, 0.0f,

0.0f, 0.0f, 1.0f, 0.0f,

objOffset.x, objOffset.y, objOffset.z, 1.0f);

vec4 modelCoord = objCoord;

vec4 positionedModel = translateObject*modelCoord;

vec4 cameraPos = translateCamera*positionedModel;

gl_Position = perspMx * cameraPos;

}'''),

FragmentShader('''

#version 330

out vec4 outputColor;

const vec4 fillColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);

void main()

{

outputColor = fillColor;

}''')

)

shapes = []

def init():

global camOffsetUf, objOffsetUf

with program:

camOffsetUf = glGetUniformLocation(program.id, "cameraOffset")

objOffsetUf = glGetUniformLocation(program.id, "objOffset")

perspectiveMatrixUf = glGetUniformLocation(program.id, "perspMx")

glUniformMatrix4fv(perspectiveMatrixUf, 1, GL_FALSE, toGLArray(initPerspectiveMatrix(AR)))

obj = ModelObject(vertexData, elementArray)

nb = 20

for i in range(nb):

for j in range(nb):

for k in range(nb):

shapes.append(PositionedObject(obj, (float(i*2), float(j*2), float(k*2)), objOffsetUf))

glEnable(GL_CULL_FACE)

glCullFace(GL_BACK)

glFrontFace(GL_CW)

glEnable(GL_DEPTH_TEST)

glDepthMask(GL_TRUE)

glDepthFunc(GL_LEQUAL)

glDepthRange(0.0, 1.0)

glClearDepth(1.0)

def update(dt):

print pyglet.clock.get_fps()

pyglet.clock.schedule_interval(update, 1.0)

@window.event

def on_draw():

with program:

pyglet.clock.tick()

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

glUniform3f(camOffsetUf, camX, camY, camZ)

for shape in shapes:

shape.draw()

init()

pyglet.app.run()

解决方法:

基本上,当您每帧循环浏览一次数据时,您可能开始达到Python的性能极限.如果将代码重写为C,则​​性能可能会好得多.

无论如何,要提高OpenGL的性能(与语言无关),必须限制绘图调用(对glDrawElements的调用)的数量,以限制CPU使用率并改善CPU与GPU之间的通信.

根据您的目标,您有多种选择来加快测试速度:

>如果要使所有多维数据集保持静态,则可以通过预变换顶点将其几何形状合并到单个VBO中,然后对所有多维数据集发出一次绘制调用.

>如果要对所有多维数据集进行独立动画处理,则可以使用硬件实例化(如果硬件允许),或使用伪硬件实例化,则可以找到一些指针here.使用这些技术,基本上可以用一个绘制一个多维数据集绘制调用,然后由着色器根据其原始ID获取立方体位置.

标签:pyglet,opengl,python

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值