Как выразить структуру C ++ или GLM как пустой массив? - PullRequest
0 голосов
/ 15 сентября 2018

Я хочу выразить приведенную ниже структуру в виде массива.

struct UniformBufferObject {
    glm::mat4 model;
    glm::mat4 view;
    glm::mat4 proj;
};

После этого массив numpy должен читаться как макет GLSL:

layout(binding = 0) uniform UniformBufferObject {
    mat4 model;
    mat4 view;
    mat4 proj;
} ubo;

В приведенных выше утверждениях mat4 обозначает матрицу 4x4.

Ниже я создал список Python, который затем преобразую в массив Numpy (без копирования) с формой 4x4, где каждый элемент представляет собой dtype=float32.

Вопрос: Что мне делать дальше, чтобы представить структуру UniformBufferObject в виде массива numpy?

>>> model = [0.1, 0.1, 0.1, 1, 0.1, 0.1, 0.1, 1, 0.1, 0.1, 0.1, 1, 0.1, 0.1, 0.1, 0,]
>>> view = [0.2, 0.2, 0.2, 1, 0.2, 0.2, 0.2, 1, 0.2, 0.2, 0.2, 1, 0.2, 0.2, 0.2, 0,]
>>> proj = [0.3, 0.3, 0.3, 1, 0.3, 0.3, 0.3, 1, 0.3, 0.3, 0.3, 1, 0.3, 0.3, 0.3, 0,]
>>> modeln = np.asarray(model, dtype= 'f4').reshape(4,4)
>>> viewn = np.asarray(view, dtype= 'f4').reshape(4,4)
>>> projn = np.asarray(proj, dtype= 'f4').reshape(4,4)
>>> modeln
array([[0.1, 0.1, 0.1, 1. ],
       [0.1, 0.1, 0.1, 1. ],
       [0.1, 0.1, 0.1, 1. ],
       [0.1, 0.1, 0.1, 0. ]], dtype=float32)
>>> viewn
array([[0.2, 0.2, 0.2, 1. ],
       [0.2, 0.2, 0.2, 1. ],
       [0.2, 0.2, 0.2, 1. ],
       [0.2, 0.2, 0.2, 0. ]], dtype=float32)
>>> projn
array([[0.3, 0.3, 0.3, 1. ],
       [0.3, 0.3, 0.3, 1. ],
       [0.3, 0.3, 0.3, 1. ],
       [0.3, 0.3, 0.3, 0. ]], dtype=float32)
>>> 

1 Ответ

0 голосов
/ 24 февраля 2019

Если в GLSL Унифицированный блок указан следующим образом

 layout(binding = 0) uniform UniformBufferObject {
     mat4 model;
     mat4 view;
     mat4 proj;
 } ubo;

тогда OpenGL не гарантирует, что члены в этом блоке хранятся в последовательном порядке. OpenGL не дает никаких гарантий относительно расположения в памяти, выравнивания или порядка элементов.

Для достижения четко определенного порядка и структуры памяти будет использоваться квалификатор структуры памяти std140. Макет std140 предоставляется начиная с OpenGL 3.1 и соответственно OpenGL ES 3.0 или расширения OpenGL ARB_uniform_buffer_object :

layout(std140, binding = 0) uniform UniformBufferObject {
    mat4 model;
    mat4 view;
    mat4 proj;
} ubo;

Подробное описание макета можно найти по адресу:

В случае вышеуказанного однородного блока с компоновкой std140 3 матрицы плотно упакованы. Объем памяти составляет 48 (3 * 4 * 4) float с подряд и имеет размер 192 байта

mat4 model     byte offset   0: size in bytes  64 = 4*4*sizeof(float)
mat4 view      byte offset  64: size in bytes  64 = 4*4*sizeof(float)
mat4 proj      byte offset 128: size in bytes  64 = 4*4*sizeof(float)
--------------------------------------------------------------------
                                size in bytes 192 = 3*4*4*sizeof(float)

Для создания буфера, соответствующего этой схеме памяти, может использоваться квартира numpy.array:

, например

 model = [0.1, 0.1, 0.1, 1, 0.1, 0.1, 0.1, 1, 0.1, 0.1, 0.1, 1, 0.1, 0.1, 0.1, 0,]
 view = [0.2, 0.2, 0.2, 1, 0.2, 0.2, 0.2, 1, 0.2, 0.2, 0.2, 1, 0.2, 0.2, 0.2, 0,]
 proj = [0.3, 0.3, 0.3, 1, 0.3, 0.3, 0.3, 1, 0.3, 0.3, 0.3, 1, 0.3, 0.3, 0.3, 0,]
import numpy as np

ubo_data = np.array([model, view, proj], dtype='f4')

Нет необходимости reshap() в массиве. Но, конечно, вы можете сделать это, если хотите получить доступ к элементам матрицы модели (ubo_data[0]), матрице вида (ubo_data[1]) и матрице проекции (ubo_data[2]) напрямую:

ubo_data = np.array([model, view, proj], dtype='f4').reshape(3, 4, 4)

Обратите внимание, что даже нет необходимости использовать NumPy . Буфер с той же разметкой памяти может быть сгенерирован массивом ctypes :

import ctypes

ubo_data = (ctypes.c_float * 48)(*model, *view, *proj)

Используя PyOpenGL , каждый из вышеуказанных массивов данных можно использовать для создания и инициализации хранилища буфера унифицированного блочного буфера с помощью glBufferData

ubo = glGenBuffers( 1 )
glBindBuffer(GL_UNIFORM_BUFFER, ubo)
glBufferData(GL_UNIFORM_BUFFER, ubo_data, GL_STATIC_DRAW)
glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo)
glBindBuffer(GL_UNIFORM_BUFFER, 0)

или обновить хранилище данных существующего буфера на glBufferSubData:

glBindBuffer(GL_UNIFORM_BUFFER, ubo)
glBufferSubData(GL_UNIFORM_BUFFER, 0, ubo_data)

Обратите внимание, что при использовании PyGLM данные такого единого буфера могут обновляться напрямую:

например:.

import glm
model = glm.mat4(1)
view  = glm.lookAt(glm.vec3(0,-3,0), glm.vec3(0,0,0), glm.vec3(0,0,1))
proj  = glm.perspective(glm.radians(90), 800.0/600.0, 0.1, 100)

glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0,                      glm.sizeof(glm.mat4), glm.value_ptr(model))
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 1*glm.sizeof(glm.mat4), glm.sizeof(glm.mat4), glm.value_ptr(view))
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 2*glm.sizeof(glm.mat4), glm.sizeof(glm.mat4), glm.value_ptr(proj))
...