Frage

weiter auf meinen Erkundungen der Grundlagen der OpenGL (siehe diese Frage ), ich, um herauszufinden, die grundlegenden Prinzipien versucht, mit OpenGL eine Szene zu ziehen.

Ich versuche, einen einfachen Würfel zu machen in jede Richtung n-mal wiederholt.

Meine Methode scheint schreckliche Leistung zu erhalten. 1000 Würfel bringt Leistung unter 50fps (auf einem QuadroFX 1800 etwa eine GeForce 9600GT)

Meine Methode, um diese Würfel für das Zeichnen ist wie folgt:

getan einmal:

  • einen Eckenpuffer und Array-Puffer, der meinen Würfelscheitel im Modellbereich einzurichten
  • ein Array Puffer Indizieren des Würfels zum Zeichnen als Dreiecke 12
  • einrichten

für jeden Rahmen durchgeführt:

  • update einheitliche Werte, die vom Vertex-Shader verwendet, um alle Würfel zu bewegen auf einmal

für jeden Würfel gemacht, für jeden Rahmen:

  • update einheitliche Werte durch den Vertex-Shader verwendet, um jeden Würfel auf seine Position zu bewegen
  • Anruf glDrawElements das positionierte Würfel zeichnen

Ist das eine vernünftige Methode? Wenn nicht, wie geht man über so etwas wie das? Ich vermute, ich brauche Anrufe glUniform, glDrawElements zu minimieren, oder beides, aber ich bin nicht sicher, wie das zu tun.


Voll Code für meinen kleinen Test: (abhängig von gletools und Pyglet)

Ich bin mir bewusst, dass mein init-Code (mindestens) ist wirklich hässlich; Ich bin in diesem Augenblick für jeden Rahmen mit dem Rendering-Code betreffen, ich etwas für die Erzeugung der Vertexpuffer etwas weniger verrückt bewegen würde und so später.

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()
War es hilfreich?

Lösung

Im Grunde genommen, wie Sie durch Daten sind Looping einmal pro Frame, sind Sie wahrscheinlich beginnen Python Leistungsgrenzen zu treffen. Es ist wahrscheinlich, dass, wenn Sie Ihren Code in neu geschrieben, sagen wir, C würden Sie viel bessere Leistung haben.

Wie auch immer, zur Leistungssteigerung in OpenGL, unabhängig von der Sprache, haben Sie die Anzahl der Auslosung Anrufe (Anrufe glDrawElements) zu begrenzen, die CPU-Auslastung zu begrenzen und die Kommunikation zwischen CPU und GPU zu verbessern.

Abhängig von Ihrem Ziel, haben Sie mehrere Möglichkeiten, um Ihre Prüfung zu beschleunigen:

  • , wenn alle Würfel sind statisch bleiben, können Sie deren Geometrien in einem einzigen VBO kombinieren könnte, durch die Eckpunkte pretransforming, und geben Sie einen einzelnen Zeichenaufruf für alle Ihre Würfel schneiden.

  • , wenn alle Würfel unabhängig voneinander animiert werden, Sie Hardware verwenden könnte Instancing (wenn Ihre Hardware es erlaubt) oder Pseudo-Hardware-Instancing, können Sie einige Hinweise hier . Mit Hilfe dieser Techniken können Sie im Grunde mehr Würfel mit einem einzigen Zeichenaufruf ziehen, dann liegt es an den Shader die Würfelposition nach seiner primitiven id zu holen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top