glBufferSubData, еще не реализован вывод типов для списков - рендеринг экземпляров - PullRequest
1 голос
/ 28 июня 2019

Портирование по главе 7 Пример рендеринга экземпляров из Superbible OpenGL 7th ed.и столкнуться с проблемой с функцией glBufferSubData

Что бы я с ней ни делал, она не примет данные.Сделайте это указателем, байтовой строкой, самим списком.Пожалуйста, помогите любую помощь будет очень ценится.Спасибо.

Обновление: Используя превосходный ответ от Rabbid76, функция glBufferSubData теперь принимает данные, и numpy версия очень хорошая, версия ctypes - проницательный ответ и оченьхорошо знать.Кроме того, что касается второго параметра, он действительно должен быть int или long, а не GLuint(0) в python.

Обновление и успех: еще один очень хороший ответ от Rabbid76, чтобы заставить рендеринг работать.Функция glVertexAttribPointer нуждается в указателе длины исходных списков данных, чтобы ее можно было сместить.Большое спасибо.

исходный код для: instancedattribs.py

#!/usr/bin/python3

import sys
import time
import ctypes

fullscreen = True

try:
    from OpenGL.GLUT import *
    from OpenGL.GL import *
    from OpenGL.GLU import *
    from OpenGL.raw.GL.ARB.vertex_array_object import glGenVertexArrays, glBindVertexArray
except:
    print ('''
    ERROR: PyOpenGL not installed properly.
        ''')
    sys.exit()


import numpy as np


square_buffer = GLuint(0)
square_vao = GLuint(0)
square_program = GLuint(0)



square_vs_source = '''
#version 410 core

layout (location = 0) in vec4 position;
layout (location = 1) in vec4 instance_color;
layout (location = 2) in vec4 instance_position;

out Fragment
{
    vec4 color;
} fragment;

void main(void)
{
    gl_Position = (position + instance_position) * vec4(0.25, 0.25, 1.0, 1.0);
    fragment.color = instance_color;
}
'''

square_fs_source = '''
#version 410 core
precision highp float;

in Fragment
{
    vec4 color;
} fragment;

out vec4 color;

void main(void)
{
    color = fragment.color;
}
'''



class Scene:

    def __init__(self, width, height):

        global square_buffer
        global square_vao
        global square_program

        self.width = width
        self.height = height

        square_vertices = np.array([
            -1.0, -1.0, 0.0, 1.0,
             1.0, -1.0, 0.0, 1.0,
             1.0,  1.0, 0.0, 1.0,
            -1.0,  1.0, 0.0, 1.0], dtype='float32')

        instance_colors = np.array([
            1.0, 0.0, 0.0, 1.0,
            0.0, 1.0, 0.0, 1.0,
            0.0, 0.0, 1.0, 1.0,
            1.0, 1.0, 0.0, 1.0], dtype='float32')

        instance_positions = np.array([
            -2.0, -2.0, 0.0, 0.0,
             2.0, -2.0, 0.0, 0.0,
             2.0,  2.0, 0.0, 0.0,
            -2.0,  2.0, 0.0, 0.0], dtype='float32')

        glGenVertexArrays(1, square_vao)
        glGenBuffers(1, square_buffer)
        glBindVertexArray(square_vao)
        glBindBuffer(GL_ARRAY_BUFFER, square_buffer)

        offset = 0  # not GLuint(0)

        bufferSize = (len(square_vertices) + len(instance_colors) + len(instance_positions))*4
        glBufferData(GL_ARRAY_BUFFER, bufferSize, None, GL_STATIC_DRAW)

        glBufferSubData(GL_ARRAY_BUFFER, offset, len(square_vertices)*4, square_vertices)
        offset += len(square_vertices)*4

        glBufferSubData(GL_ARRAY_BUFFER, offset, len(instance_colors)*4, instance_colors)
        offset += len(instance_colors)*4

        glBufferSubData(GL_ARRAY_BUFFER, offset, len(instance_positions)*4, instance_positions)
        offset += len(instance_positions)*4

        glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, None)
        offsetInstanceColor =  len(square_vertices)*4
        glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(offsetInstanceColor))
        offsetInstancPosition =  (len(instance_colors) + len(instance_positions))*4
        glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(offsetInstancPosition))


        glEnableVertexAttribArray(0)
        glEnableVertexAttribArray(1)
        glEnableVertexAttribArray(2)

        glVertexAttribDivisor(1, 1)
        glVertexAttribDivisor(2, 1)

        square_program = glCreateProgram()

        square_vs = GLuint(0)

        square_vs = glCreateShader(GL_VERTEX_SHADER)
        glShaderSource(square_vs, square_vs_source)
        glCompileShader(square_vs)
        glAttachShader(square_program, square_vs)

        square_fs = GLuint(0)

        square_fs = glCreateShader(GL_FRAGMENT_SHADER)
        glShaderSource(square_fs, square_fs_source)
        glCompileShader(square_fs)
        glAttachShader(square_program, square_fs)

        glLinkProgram(square_program)
        glDeleteShader(square_vs)
        glDeleteShader(square_fs)


    def display(self):

        black = [ 0.0, 0.0, 0.0, 0.0 ]
        glClearBufferfv(GL_COLOR, 0, black)

        glUseProgram(square_program)
        glBindVertexArray(square_vao)
        glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, 4)

        glutSwapBuffers()

    def reshape(self, width, height):
        self.width = width
        self.height = height

    def keyboard(self, key, x, y ):
        global fullscreen

        print ('key:' , key)
        if key == b'\x1b': # ESC
            sys.exit()

        elif key == b'f' or key == b'F': #fullscreen toggle

            if (fullscreen == True):
                glutReshapeWindow(512, 512)
                glutPositionWindow(int((1360/2)-(512/2)), int((768/2)-(512/2)))
                fullscreen = False
            else:
                glutFullScreen()
                fullscreen = True

        print('done')

    def init(self):
        pass

    def timer(self, blah):

        glutPostRedisplay()
        glutTimerFunc( int(1/60), self.timer, 0)
        time.sleep(1/60.0)


if __name__ == '__main__':
    start = time.time()

    glutInit()


    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)

    glutInitWindowSize(512, 512)

    w1 = glutCreateWindow('OpenGL SuperBible - Instanced Attributes')
    glutInitWindowPosition(int((1360/2)-(512/2)), int((768/2)-(512/2)))

    fullscreen = False
    many_cubes = False
    #glutFullScreen()

    scene = Scene(512,512)
    glutReshapeFunc(scene.reshape)
    glutDisplayFunc(scene.display)
    glutKeyboardFunc(scene.keyboard)

    glutIdleFunc(scene.display)
    #glutTimerFunc( int(1/60), scene.timer, 0)

    scene.init()

    glutMainLoop()

ожидаемый результат рендеринга: picture of output of rendering

Портировано из: instancedattribs.cpp

1 Ответ

1 голос
/ 28 июня 2019

По сравнению с glBufferData, PyOpenGl glBufferSubData параметр size не может быть пропущен.
You 've для передачи размера буфера (в байтах) и указателя на буфер.Но обратите внимание, что 2-й и 3-й параметры должны быть Python int или long, даже PyOpneGL GLuint вызовет ошибку.

У вас есть некоторые возможности, либо создайте массив PyOpenGL's GLfloat

offset = 0
dataArray = (GLfloat*len(square_vertices))(*square_vertices)
glBufferSubData(GL_ARRAY_BUFFER, offset, len(dataArray)*4, dataArray)

или используйте встроенную питонную ctypes библиотеку:

import ctypes
offset = 0
dataArray = (ctypes.c_float*len(square_vertices))(*square_vertices)
glBufferSubData(GL_ARRAY_BUFFER, offset, len(dataArray)*4, dataArray)

или создайте NumPy массив:

import numpy as np 
offset = 0
dataArray = np.array(square_vertices, dtype='float32')
glBufferSubData(GL_ARRAY_BUFFER, offset, len(dataArray)*4, dataArray)

Обратите внимание, что для 2-го и 3-го параметра вы можете использовать приведение к int (например, int(offset)) или long (например, long(offset)).


Также обратите внимание, что параметры смещения и размера для glBufferData, glBufferSubData и glVertexAttribPointer представляют собой значения в байтах, а не количество элементов массивов.
Размерв байтах рассчитывается на количество элементов, умноженное на размер 1 элемента.
Размер 1 элемента равен 4, поскольку размер float (GLfloat, ctypes.c_float, 'float32') в байтахравно 4.

Если указанный буферный объект связан, то последний параметр glVertexAttribPointer обрабатывается как смещение байта в хранилище данных буферного объекта, но тип параметра по-прежнему является указателем.Так что вы должны использовать ctypes.c_void_p(offset).Если смещение равно 0, можно передать None.

bufferSize = (len(square_vertices) + len(instance_colors) + len(instance_positions))*4
glBufferData(GL_ARRAY_BUFFER, bufferSize, None, GL_STATIC_DRAW)

glBufferSubData(GL_ARRAY_BUFFER, offset, len(square_vertices)*4, square_vertices)
offset += len(square_vertices)*4

glBufferSubData(GL_ARRAY_BUFFER, offset, len(instance_colors)*4, instance_colors)
offset += len(instance_colors)*4

glBufferSubData(GL_ARRAY_BUFFER, offset, len(instance_positions)*4, instance_positions)
offset += len(instance_positions)*4

glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, None)
offsetInstanceColor =  len(square_vertices)*4
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(offsetInstanceColor))
offsetInstancPosition =  (len(instance_colors) + len(instance_positions))*4
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(offsetInstancPosition))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...