尝试使用opengl函数glMapBufferRange在python中制作Alienrain [英] Trying to make alienrain in python using the opengl function glMapBufferRange
问题描述
仅四行代码导致我从OpenGL Superbible移植的外星雨程序出现问题.使用功能 glMapBufferRange
Just 4 little lines causing a problem with the alien rain program that I ported from the OpenGL Superbible. It seems I am having issues trying to write to memory after using the function glMapBufferRange
更新:Rabbid76出色的代码解决了该问题,并提供了有价值的解释说明.谢谢.
Update: Excellent code by Rabbid76 has solved the problem and provided valuable insight of explanation. Thank You.
必需文件: ktxloader.py , aliens.ktx
Alienrain.py的源代码
Source code of alienrain.py
#!/usr/bin/python3
import sys
import time
sys.path.append("./shared")
#from sbmloader import SBMObject # location of sbm file format loader
from ktxloader import KTXObject # location of ktx file format loader
#from sbmath import m3dDegToRad, m3dRadToDeg, m3dTranslateMatrix44, m3dRotationMatrix44, m3dMultiply, m3dOrtho, m3dPerspective, rotation_matrix, translate, m3dScaleMatrix44
fullscreen = True
import numpy.matlib
import numpy as np
import math
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()
identityMatrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]
render_prog = GLuint(0)
render_vao = GLuint(0)
tex_alien_array = GLuint(0)
rain_buffer = GLuint(0)
droplet_x_offset = []
droplet_rot_speed = []
droplet_fall_speed = []
seed = 0x13371337
import random
import ctypes
random.seed (0x13371337)
def random_float():
# global seed
# res=0.0
# tmp=0
# seed *= 16807;
# tmp = seed ^ (seed >> 4) ^ (seed << 15);
# res = (tmp >> 9) | 0x3F800000;
# return (res - 1.0);
return (random.random() - 1.0)
class Scene:
def __init__(self, width, height):
global render_prog
global render_vao
global tex_alien_array
global rain_buffer
global droplet_x_offset, droplet_rot_speed, droplet_fall_speed
self.width = width
self.height = height
vs = GLuint(0)
fs = GLuint(0)
vs_source = '''
#version 410 core
layout (location = 0) in int alien_index;
out VS_OUT
{
flat int alien;
vec2 tc;
} vs_out;
struct droplet_t
{
float x_offset;
float y_offset;
float orientation;
float unused;
};
layout (std140) uniform droplets
{
droplet_t droplet[256];
};
void main(void)
{
const vec2[4] position = vec2[4](vec2(-0.5, -0.5),
vec2( 0.5, -0.5),
vec2(-0.5, 0.5),
vec2( 0.5, 0.5));
vs_out.tc = position[gl_VertexID].xy + vec2(0.5);
float co = cos(droplet[alien_index].orientation);
float so = sin(droplet[alien_index].orientation);
mat2 rot = mat2(vec2(co, so),
vec2(-so, co));
vec2 pos = 0.25 * rot * position[gl_VertexID];
gl_Position = vec4(pos.x + droplet[alien_index].x_offset,
pos.y + droplet[alien_index].y_offset,
0.5, 1.0);
vs_out.alien = alien_index % 64;
}
'''
fs_source = '''
#version 410 core
layout (location = 0) out vec4 color;
in VS_OUT
{
flat int alien;
vec2 tc;
} fs_in;
uniform sampler2DArray tex_aliens;
void main(void)
{
color = texture(tex_aliens, vec3(fs_in.tc, float(fs_in.alien)));
}
'''
vs = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vs, vs_source)
glCompileShader(vs)
glGetShaderInfoLog(vs)
fs = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fs, fs_source)
glCompileShader(fs)
glGetShaderInfoLog(vs)
render_prog = glCreateProgram()
glAttachShader(render_prog, vs)
glAttachShader(render_prog, fs)
glLinkProgram(render_prog)
glDeleteShader(vs)
glDeleteShader(fs)
glGetProgramInfoLog(render_prog)
glGenVertexArrays(1, render_vao)
glBindVertexArray(render_vao)
ktxobj = KTXObject()
tex_alien_array = ktxobj.ktx_load("aliens.ktx")
glBindTexture(GL_TEXTURE_2D_ARRAY, tex_alien_array)
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
glGenBuffers(1, rain_buffer)
glBindBuffer(GL_UNIFORM_BUFFER, rain_buffer)
glBufferData(GL_UNIFORM_BUFFER, 256*4*4, None, GL_DYNAMIC_DRAW)
for i in range(0, 256):
droplet_x_offset.append(random_float() * 2.0 - 1.0)
droplet_rot_speed.append( (random_float() + 0.5) * (-3.0 if (i & 1) else 3.0) )
droplet_fall_speed.append ( random_float() + 0.2 )
glBindVertexArray(render_vao);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
def display(self):
global rain_buffer
green = [ 0.0, 0.1, 0.0, 0.0 ]
currentTime = time.time()
t = currentTime
glViewport(0, 0, self.width, self.height)
glClearBufferfv(GL_COLOR, 0, green)
glUseProgram(render_prog);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, rain_buffer);
droplet = glMapBufferRange(GL_UNIFORM_BUFFER, 0, 256*4*4, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT)
float_array = ((ctypes.c_float * 4) * 256).from_address(droplet)
for i in range(0, 256):
float_array[i][0] = droplet_x_offset[i] + 2
float_array[i][1] = 2.0-math.fmod((t + float(i)) * droplet_fall_speed[i], 4.31 ) * random_float()
float_array[i][2] = droplet_rot_speed[i] * t * random_float() * math.pi
float_array[i][3] = 0.0
glUnmapBuffer(GL_UNIFORM_BUFFER);
for alien_index in range(0, 256):
glVertexAttribI1i(0, alien_index);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glutSwapBuffers()
def reshape(self, width, height):
self.width = width
self.height = height
def keyboard(self, key, x, y ):
global fullscreen
global many_cubes
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 - Alien Rain')
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()
当前输出为: 更新:非常类似于预期的输出.除了速度非常快,每个外星人的旋转都不如预期的输出平稳.如果有人想修改获取它的值,请这样做.否则,将回答该问题.
Current output is: Update: very similar to expected output. Except it very fast and the rotations of each alien are not as smooth as the expected output. If anyone wants to tinker with the values to get it, please do. Otherwise this question is answered.
输出应为:
这是 alienrain.cpp 用来创建Alienrain.py
Here's the alienrain.cpp that was used to create alienrain.py
推荐答案
First of all, the 2nd parameter of glBufferData
is the buffer data in bytes.
由于glsl数据结构为
Since the glsl data structure is
struct droplet_t
{
float x_offset;
float y_offset;
float orientation;
float unused;
};
layout (std140) uniform droplets
{
droplet_t droplet[256];
};
缓冲区的大小为4 * 4 * 256,因为float
的大小为4,因此该结构具有4个类型为flaot
的元素,而数组具有256个元素
the buffer size is 4*4*256, because the size of a float
is 4, t he structure has 4 elements of type flaot
and the array has 256 elements
glBufferData(GL_UNIFORM_BUFFER, 256*4*4, None, GL_DYNAMIC_DRAW)
说明
droplet = glMapBufferRange(GL_UNIFORM_BUFFER, 0, 256*4*4, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT)
以正确的大小返回指向已分配内存区域的指针.您必须用数据填充此内存.
最简单的解决方案是使用(在python内置的)库 ctypes
,它具有方便的功能 .from_address()
:
returns a pointer to a allocated memory region with the proper size. You've to fill this memory with data.
The easiest solution is to use the (in python built-in) library ctypes
, which has the handy function .from_address()
:
此方法使用地址指定的内存返回ctypes类型实例.
This method returns a ctypes type instance using the memory specified by address.
所以说明
float_array = ((ctypes.c_float * 4) * 256).from_address(droplet)
将二维数组包装"到由droplet
寻址的内存中,该数组包含256个元素,每个元素具有4个类型为float
的元素.
"wraps" a 2 dimensional array to the memory addressed by droplet
, with 256 elements and each element has 4 elements of type float
.
可以通过简单的赋值语句将值设置为数组.例如:
The values can be set to the array, by a simple assignment statement. e.g.:
import random
import math
import ctypes
glBindBufferBase(GL_UNIFORM_BUFFER, 0, rain_buffer);
droplet = glMapBufferRange(GL_UNIFORM_BUFFER, 0, 256*4*4, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT)
float_array = ((ctypes.c_float * 4) * 256).from_address(droplet)
for i in range(0, 256):
float_array[i][0] = random.random() * 2 -1
float_array[i][1] = random.random() * 2 -1
float_array[i][2] = random.random() * math.pi * 2
float_array[i][3] = 0.0
这篇关于尝试使用opengl函数glMapBufferRange在python中制作Alienrain的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!