Warm tip: This article is reproduced from stackoverflow.com, please click
opengl python python-3.x

hdrexposure program from SB OpenGL rendering blank screen

发布于 2020-03-27 10:27:06

Relatively simple program drawing a blank screen. Ported from Superbible Opengl 7th ed.

The program is currently drawing a blank screen. Although the textoverlay is working correctly.

Update: Added the use of glGetError to add additional error checking. Though there is no error produced by it. Still a blank screen however.

Update and SUCCESS: The program is now rendering the hdr image perfect. Thanks to Rabbid76 excellent answer. It was also a ktxloader that needed a fix. Thank you.

Expected output is:

expected output

support files: hdrexposure_support.zip

ported from: hdrexposure.cpp

source code:

#!/usr/bin/python3

import sys
import time
import ctypes

fullscreen = True
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 textoverlay import OVERLAY_
from shader import shader_load, link_from_shaders

from sbmath import m3dDegToRad, m3dRadToDeg, m3dTranslateMatrix44, m3dRotationMatrix44, \
    m3dMultiply, m3dOrtho, m3dPerspective, rotation_matrix, translate, m3dScaleMatrix44, \
    scale, m3dLookAt, normalize

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
from math import cos, sin
import glm
identityMatrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]

myobject = SBMObject()
ktxobject = KTXObject()
overlay = OVERLAY_()

texture = GLuint(0)
program = GLuint(0)
vao = GLuint(0)
exposure=1.0

vs_source = '''
#version 420 core

void main(void)
{
    const vec4 vertices[] = vec4[](vec4(-1.0, -1.0, 0.5, 1.0),
                                   vec4( 1.0, -1.0, 0.5, 1.0),
                                   vec4(-1.0,  1.0, 0.5, 1.0),
                                   vec4( 1.0,  1.0, 0.5, 1.0));

    gl_Position = vertices[gl_VertexID];
}
'''

fs_source = '''
#version 430 core

uniform sampler2D s;

uniform float exposure;

out vec4 color;

void main(void)
{
    vec4 c = texture(s, gl_FragCoord.xy / vec2(512.0, 512.0));
    c.xyz = vec3(1.0) - exp(-c.xyz * exposure);
    color = c;
}
'''
def checkGLError():
    status = glGetError()
    if status != GL_NO_ERROR:
        raise RuntimeError('gl error %s' % (status,))

class Scene:

    def __init__(self, width, height):
        global overlay
        global texture
        global program
        global vao    

        self.width = width
        self.height = height

        overlay.init(80, 50)

        #// Generate a name for the texture
        glGenTextures(1, texture)

        #// Load texture from file
        texture = ktxobject.ktx_load("treelights_2k.ktx")

        #// Now bind it to the context using the GL_TEXTURE_2D binding point
        glBindTexture(GL_TEXTURE_2D, texture)

        program = glCreateProgram()
        fs = glCreateShader(GL_FRAGMENT_SHADER)
        glShaderSource(fs, fs_source)
        glCompileShader(fs)

        if not glGetShaderiv(fs, GL_COMPILE_STATUS):
            print( 'compile error:' )
            print( glGetShaderInfoLog(fs) )

        vs = glCreateShader(GL_VERTEX_SHADER)
        glShaderSource(vs, vs_source)
        glCompileShader(vs)

        if not glGetShaderiv(vs, GL_COMPILE_STATUS):
            print( 'compile error:' )
            print( glGetShaderInfoLog(vs) )

        glAttachShader(program, vs)
        glAttachShader(program, fs)

        glLinkProgram(program)

        if not glGetProgramiv(program, GL_LINK_STATUS):
            print( 'link error:' )
            print( glGetProgramInfoLog(program) )

        glGenVertexArrays(1, vao)
        glBindVertexArray(vao)


    def display(self):
        global texture
        global program

        currentTime = time.time()

        green = [ 0.0, 0.25, 0.0, 1.0 ]
        glClearBufferfv(GL_COLOR, 0, green)

        glActiveTexture(GL_TEXTURE0)
        glBindTexture(GL_TEXTURE_2D, texture)
        glUseProgram(program)
        glViewport(0, 0, self.width, self.height)
        glUniform1f(0, exposure)
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)

        overlay.clear()
        buffer = ("Exposure = %2.2f (Numpad +/- to change)" % exposure)
        overlay.drawText(buffer, 0, 0)
        overlay.draw()

        checkGLError()

        glutSwapBuffers()

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

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

        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
        elif key == b'+':
            exposure *= 1.1
        elif key == b'-':
            exposure /= 1.1

    def init(self):
        pass

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

if __name__ == '__main__':
    glutInit()
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
    glutInitWindowSize(512, 512)
    w1 = glutCreateWindow('OpenGL SuperBible - HDR Exposure')
    glutInitWindowPosition(int((1360/2)-(512/2)), int((768/2)-(512/2)))
    fullscreen = 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:

enter image description here

I was getting before updating the fragment shader: enter image description here

Any help is appreciated. Thank You.

Questioner
Stan S.
Viewed
42
Rabbid76 2019-07-04 05:46

The result of exp(0.0) is 1.0, so the result of 1.0-exp(0.0) is 0.0.
You've to ensure that the value of the uniform exposure is not 0.0, to get a result greater than 0.0 for the expression:

c.xyz = vec3(1.0) - exp(-c.xyz * exposure);

The texture data is of type float. Create numpy.array with the element type numpy.float32, from the byte array, before initializing the texture image:

for i in range(0, h.miplevels):

    if h.gltype == GL_FLOAT:

        float_data = np.frombuffer(data[ptr:], dtype=np.float32)
        glTexSubImage2D(GL_TEXTURE_2D, i, 0, 0, width, height, h.glformat, h.gltype, float_data)

    else: # h.type == GL_UNSIGNED_BYTE

        glTexSubImage2D(GL_TEXTURE_2D, i, 0, 0, width, height, h.glformat, h.gltype, data[ptr:])

    ptr += height * calculate_stride(h, width, 1)

Note, you've to implement different cases for different types.