尝试使用opengl函数glMapBufferRange在python中制作Alienrain [英] Trying to make alienrain in python using the opengl function glMapBufferRange

查看:125
本文介绍了尝试使用opengl函数glMapBufferRange在python中制作Alienrain的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

仅四行代码导致我从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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆