Texture is displayed as black in pyOpenGL - python

I try to load in the texture using this method:
#classmethod
def load_texture(cls, file_name: str):
try:
img = Image.open(f"{sys.path[0]}/res/{file_name}.png")
except Exception as e:
print(e)
raise SystemExit
try:
ix, iy, image = img.size[0], img.size[1], img.tobytes("raw", "RGBA", 0, -1)
except SystemError:
ix, iy, image = img.size[0], img.size[1], img.tobytes("raw", "RGBX", 0, -1)
texture_id = glGenTextures(1) # generate a texture texture_id
cls.__textures.append(texture_id)
glBindTexture(GL_TEXTURE_2D, texture_id) # make it current
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
# copy the texture into the current texture texture_id
glTexImage2D(GL_TEXTURE_2D, 0, 3, ix, iy, 0, GL_RGBA, GL_UNSIGNED_BYTE, image)
return texture_id
And display it with this method:
#staticmethod
def render(model: TexturedModel):
raw_model = model.get_raw_model()
glBindVertexArray(raw_model.get_vao_id()) # bind the desired VAO to be able to use it
glEnableVertexAttribArray(0) # we have put the indices in the 0th address
glEnableVertexAttribArray(1) # we have put the textures in the 1st address
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, model.get_texture().get_id())
glDrawElements(GL_TRIANGLES, raw_model.get_vertex_count(), GL_UNSIGNED_INT, None)
glDisableVertexAttribArray(0) # disable the attributeList after using it
glDisableVertexAttribArray(1) # disable the attributeList after using it
glBindVertexArray(0) # unbind the VAO
What exactly is going wrong? I suppose the texture isn't getting loaded in right as it's displayed black.
Edit: I think it could also be something wrong with the shaders so here is my:
shader_program.py:
from OpenGL.GL import *
from OpenGL.GLUT import *
from abc import abstractmethod # for abstract methods
class ShaderProgram:
"""
Class for loading and linking all shaders to the program.
"""
def __init__(self, vertex_file: str, fragment_file: str):
self.__vertex_shader_id = self.load_shader(vertex_file, GL_VERTEX_SHADER)
self.__fragment_shader_id = self.load_shader(fragment_file, GL_FRAGMENT_SHADER)
self.__program_id = glCreateProgram() # create program
glAttachShader(self.__program_id, self.__vertex_shader_id) # attach the shader to the program
glAttachShader(self.__program_id, self.__fragment_shader_id) # attach the shader to the program
self.bind_attributes()
glLinkProgram(self.__program_id) # link the program to the shaders
glValidateProgram(self.__program_id) # validate the program
def start(self):
glUseProgram(self.get_program_id())
#staticmethod
def stop():
glUseProgram(0)
def clean_up(self):
self.stop()
glDetachShader(self.get_program_id(), self.get_vertex_shader_id())
glDetachShader(self.get_program_id(), self.get_fragment_shader_id())
glDeleteShader(self.get_vertex_shader_id())
glDeleteShader(self.get_fragment_shader_id())
glDeleteProgram(self.get_program_id())
#abstractmethod
def bind_attributes(self):
pass
def bind_attribute(self, attribute: int, variable_name: str):
glBindAttribLocation(self.get_program_id(), attribute, variable_name)
#staticmethod
def load_shader(file: str, shader_type: int):
try:
shader_file = open(file, 'r') # read file
shader_source = ''.join(shader_file.readlines()) # create a continuous string
except Exception as e:
print(e) # print exception
raise SystemExit
shader_id = glCreateShader(shader_type) # create the shader
glShaderSource(shader_id, shader_source) # load the shader source code
glCompileShader(shader_id) # compile the shader
if glGetShaderiv(shader_id, GL_COMPILE_STATUS) == GL_FALSE:
print(glGetShaderInfoLog(shader_id)) # print the info log if it didn't compile correctly
print("Could not compile shader.")
raise SystemExit
return shader_id
def get_program_id(self):
return self.__program_id
def get_vertex_shader_id(self):
return self.__vertex_shader_id
def get_fragment_shader_id(self):
return self.__fragment_shader_id
my static_shader.py:
from .shader_program import ShaderProgram
import sys
class StaticShader(ShaderProgram):
__VERTEX_FILE = f"{sys.path[0]}/shaders/vertexShader.txt"
__FRAGMENT_FILE = f"{sys.path[0]}/shaders/fragmentShader.txt"
def __init__(self):
super().__init__(self.get_vertex_file(), self.get_fragment_file())
def bind_attributes(self):
super().bind_attribute(0, "position")
super().bind_attribute(1, "texture_coords")
#classmethod
def get_vertex_file(cls):
return cls.__VERTEX_FILE
#classmethod
def get_fragment_file(cls):
return cls.__FRAGMENT_FILE
my fragmentShader.txt:
#version 400 core
in vec2 pass_texture_coords;
out vec4 out_color;
uniform sampler2D texture_sampler;
void main(void){
out_color = texture(texture_sampler, pass_texture_coords);
}
and my vertexShader.txt:
#version 400 core
in vec3 position;
in vec2 texture_coords;
out vec2 pass_texture_coords;
void main(void){
gl_Position = vec4(position, 1.0);
pass_texture_coords = texture_coords;
}
I created a GitHub repository if you want to check it for yourself: https://github.com/AndreasSabelfeld/pyOpenGL-3DEngine

In loader.py I needed to include:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
in the load_texture method before the glTexImage2D call.
Why? I don't know.
Does it work? Yes.

Related

glGenVertexArrays function doesn't work in every Python script

The glGenVertexArrays function throws this excpetion in one script (loader.py): "OpenGL.error.NullFunctionError: Attempt to call an undefined function glGenVertexArrays", but not in the other script (display_manager.py)
I guess it has something to do with initialization.
loader.py (the 'create_vao' function is relevant)
from raw_model import RawModel
from OpenGL.GL import *
from OpenGL.GLUT import *
class Loader:
__vaos = []
__vbos = []
def load_to_vao(self, positions: list):
vao_id = self.create_vao()
self.store_data_in_attribute_list(0, positions)
self.unbind_vao()
return RawModel(vao_id, len(positions)//3)
#classmethod
def clean_up(cls):
for vao in cls.__vaos:
glDeleteVertexArrays(vao)
for vbo in cls.__vbos:
glDeleteBuffers(vbo)
#classmethod
def create_vao(cls):
vao_id = glGenVertexArrays(1)
cls.__vaos.append(vao_id)
glBindVertexArray(vao_id)
return vao_id
#classmethod
def store_data_in_attribute_list(cls, attribute_number: int, data: list):
vbo_id = glGenBuffers()
cls.__vbos.append(vbo_id)
glBindBuffer(GL_ARRAY_BUFFER, vbo_id)
glBufferData(GL_ARRAY_BUFFER, data, GL_STATIC_DRAW)
glVertexAttribPointer(attribute_number, 3, GL_FLOAT, False, 0, 0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
#staticmethod
def unbind_vao():
glBindVertexArray(0)
display_manager.py (the 'create_display' function is relevant):
from OpenGL.GL import *
from OpenGL.GLUT import *
class DisplayManager:
def __init__(self, x: int = 1920, y: int = 1080):
if x is not None: self.__width = x
if y is not None: self.__height = y
def create_display(self, window_name):
glutInit()
glutInitDisplayMode(GLUT_RGBA) # initialize colors
glutInitWindowSize(self.get_width(), self.get_height()) # set windows size
glutInitWindowPosition(0, 0) # set window position
glutCreateWindow(f"{window_name}") # create window (with a name) and set window attribute
print(glGenVertexArrays(1))
input("This ran")
glutDisplayFunc(self.update_display)
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS) # prevent program from stopping
#staticmethod
def update_display():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # Remove everything from screen (i.e. displays all white)
glLoadIdentity() # Reset all graphic/shape's position
glutSwapBuffers() # Important for double buffering
def get_width(self):
return self.__width
def get_height(self):
return self.__height
#classmethod
def set_window(cls, window):
cls.__WIND = window
I already tried to include the glutInit function into the loader.py script, with no success. I also tried to figure out in which scripts the glGenVertexArrays function works, with no real clue.
In my main.py function I called the create_vao method before I even created the window. Swapping the order did the trick.

Why glVertexAttribPointer throws 1282 error while trying to draw one point on screen with pyOpenGL and glfw?

I have separated the program to three different files, but I don't understand why I get error on glVertexAttribPointer on line 70. I'm using Python 3.10.8
main.py
import glfw
import Shaders
from OpenGL.GL import *
from OpenGL.GLUT import *
from Math_3d import Vector2f
class Window:
def __init__(self, width: int, height: int, title: str):
if not glfw.init():
raise Exception("glfw can not be initialized")
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
self._win = glfw.create_window(width, height, title, None, None)
if not self._win:
glfw.terminate()
raise Exception("glfw window can not be created")
glfw.set_window_pos(self._win, 400, 200)
glfw.make_context_current(self._win)
def createshaders(self):
# Request program and shader slots from the GPU
program = glCreateProgram()
vertex = glCreateShader(GL_VERTEX_SHADER)
fragment = glCreateShader(GL_FRAGMENT_SHADER)
# Set shader sources
glShaderSource(vertex, Shaders.vertex_code)
glShaderSource(fragment, Shaders.fragment_code)
# Compile shaders
glCompileShader(vertex)
glCompileShader(fragment)
if not glGetShaderiv(vertex, GL_COMPILE_STATUS):
report_shader = glGetShaderInfoLog(vertex)
print(report_shader)
raise RuntimeError("Vertex shader compilation error")
if not glGetShaderiv(fragment, GL_COMPILE_STATUS):
report_frag = glGetShaderInfoLog(fragment)
print(report_frag)
raise RuntimeError("Fragment shader compilation error")
# Link objects to program
glAttachShader(program, vertex)
glAttachShader(program, fragment)
glLinkProgram(program)
if not glGetProgramiv(program, GL_LINK_STATUS):
print(glGetProgramInfoLog(program))
raise RuntimeError('Linking error')
# Get rid of shaders
glDetachShader(program, vertex)
glDetachShader(program, fragment)
# Make default program to run
glUseProgram(program)
# Vertex Buffer Object
# Create point vertex data
v2f_1 = Vector2f(0.0, 0.0)
# Request a buffer slot from GPU
buffer = glGenBuffers(1)
# Make this buffer the default one
glBindBuffer(GL_ARRAY_BUFFER, buffer)
strides = v2f_1.data.strides[0]
loc = glGetAttribLocation(program, 'position')
glEnableVertexAttribArray(loc)
glVertexAttribPointer(loc, 2, GL_FLOAT, False, strides, None)
# glBufferData(GL_ARRAY_BUFFER, v2f_1, v2f_1, GL_DYNAMIC_DRAW)
def renderscene(self):
while not glfw.window_should_close(self._win):
glfw.poll_events()
glClear(GL_COLOR_BUFFER_BIT)
glDrawArrays(GL_POINTS, 0, 1)
glfw.swap_buffers(self._win)
glfw.terminate()
if __name__ == '__main__':
win = Window(1024, 768, "GLFW Window")
win.createshaders() # Create and initialize shaders and initialize Vertex Buffer Object
win.renderscene() # Swap buffer and render scene
Shaders.py
vertex_code = """
attribute vec2 position;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
}
"""
fragment_code = """
void main()
{
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
"""
Math_3d.py
import numpy as np
class Vector2f:
def __init__(self, x, y):
self.data = np.array([x, y], dtype=np.float32)
if __name__ == '__main__':
vec2 = Vector2f(0.0, 0.0)
print(vec2.data)
print(type(vec2.data.strides[0]))
print(vec2.data.strides[0])
I have tried to debug the line 70, but did not get any good result while using PyCharm.
Any recommendations on this? Closest answers would be according to 61491497 and 56957118 what I am aiming for.
You're using a Core profile OpenGL Context (glfw.OPENGL_CORE_PROFILE). Therefore you have to create a Vertex Array Obejct:
class Window:
# [...]
def createshaders(self):
# [...]
v2f_1 = Vector2f(0.0, 0.0)
# Request a buffer slot from GPU
buffer = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, buffer)
strides = v2f_1.data.strides[0]
glBufferData(GL_ARRAY_BUFFER, v2f_1.data, GL_DYNAMIC_DRAW)
vao = glGenVertexArrays(1)
glBindVertexArray(vao)
loc = glGetAttribLocation(program, 'position')
glEnableVertexAttribArray(loc)
glVertexAttribPointer(loc, 2, GL_FLOAT, False, strides, None)
Additionally, you need to change either the background color or the fragment color, because you won't be able to see a black point on a black background. e.g. red:
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);

Drawing an OpenGL triangle in Python

Here is my code so far:
main.py_
from Application import Application
if __name__ == '__main__':
app = Application()
app.run()
Triangle.py_
import contextlib
import logging as log
from OpenGL import GL as gl
import ctypes
import sys
class Triangle:
vertex_array_id = 0
vertex_data = []
program_id = 0
shader_id = 0
def __init__(self):
print('Triangle.__init__(self)')
self.create_vertex_buffer()
self.load_shaders()
def create_vertex_array_object(self):
log.debug('create_vertex_array_object(self):')
self.vertex_array_id = gl.glGenVertexArrays(1)
try:
gl.glBindVertexArray(self.vertex_array_id)
yield
finally:
log.debug('~create_vertex_array_object(self):')
gl.glDeleteVertexArrays(1, [self.vertex_array_id])
def create_vertex_buffer(self):
with self.create_vertex_array_object():
# A triangle
self.vertex_data = [-1, -1, 0,
1, -1, 0,
0, 1, 0]
attr_id = 0 # No particular reason for 0,
# but must match the layout location in the shader.
log.debug('creating and binding the vertex buffer (VBO)')
vertex_buffer = gl.glGenBuffers(1)
try:
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vertex_buffer)
array_type = (gl.GLfloat * len(self.vertex_data))
gl.glBufferData(gl.GL_ARRAY_BUFFER,
len(self.vertex_data) * ctypes.sizeof(ctypes.c_float),
array_type(*self.vertex_data),
gl.GL_STATIC_DRAW)
log.debug('setting the vertex attributes')
gl.glVertexAttribPointer(
attr_id, # attribute 0.
3, # components per vertex attribute
gl.GL_FLOAT, # type
False, # to be normalized?
0, # stride
None # array buffer offset
)
gl.glEnableVertexAttribArray(attr_id) # use currently bound VAO
yield
finally:
log.debug('cleaning up buffer')
# gl.glDisableVertexAttribArray(attr_id)
# gl.glDeleteBuffers(1, [vertex_buffer])
def load_shaders(self):
shaders = {
gl.GL_VERTEX_SHADER: '''\
#version 330 core
layout(location = 0) in vec3 vertexPosition_modelspace;
void main(){
gl_Position.xyz = vertexPosition_modelspace;
gl_Position.w = 1.0;
}
''',
gl.GL_FRAGMENT_SHADER: '''\
#version 330 core
out vec3 color;
void main(){
color = vec3(1,0,0);
}
'''
}
log.debug('creating the shader program')
self.program_id = gl.glCreateProgram()
try:
shader_ids = []
for shader_type, shader_src in shaders.items():
self.shader_id = gl.glCreateShader(shader_type)
gl.glShaderSource(self.shader_id, shader_src)
log.debug(f'compiling the {shader_type} shader')
gl.glCompileShader(self.shader_id)
# check if compilation was successful
result = gl.glGetShaderiv(self.shader_id, gl.GL_COMPILE_STATUS)
info_log_len = gl.glGetShaderiv(self.shader_id, gl.GL_INFO_LOG_LENGTH)
if info_log_len:
logmsg = gl.glGetShaderInfoLog(self.shader_id)
log.error(logmsg)
sys.exit(10)
gl.glAttachShader(self.program_id, self.shader_id)
shader_ids.append(self.shader_id)
log.debug('linking shader program')
gl.glLinkProgram(self.program_id)
# check if linking was successful
result = gl.glGetProgramiv(self.program_id, gl.GL_LINK_STATUS)
info_log_len = gl.glGetProgramiv(self.program_id, gl.GL_INFO_LOG_LENGTH)
if info_log_len:
logmsg = gl.glGetProgramInfoLog(self.program_id)
log.error(logmsg)
sys.exit(11)
log.debug('installing shader program into rendering state')
gl.glUseProgram(self.program_id)
yield
finally:
log.debug('cleaning up shader program')
for self.shader_id in self.shader_ids:
gl.glDetachShader(self.program_id, self.shader_id)
gl.glDeleteShader(self.shader_id)
gl.glUseProgram(0)
gl.glDeleteProgram(self.program_id)
def render(self):
gl.glDrawArrays(gl.GL_TRIANGLES, 0, 3) # Starting from vertex 0
Application.py_
import contextlib
import glfw
import sys
from OpenGL import GL as gl
import logging as log
from Triangle import Triangle
class Application:
tri = Triangle()
def __init__(self):
print("Application.__init__(self)")
#contextlib.contextmanager
def create_main_window(self):
log.debug('create_main_window(self):')
if not glfw.init():
sys.exit(1)
try:
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, True)
glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
title = 'Tutorial 2: First Triangle'
window = glfw.create_window(500, 400, title, None, None)
if not window:
sys.exit(2)
glfw.make_context_current(window)
gl.glClearColor(0, 0, 0.4, 0)
yield window
finally:
log.debug('~create_main_window(self):')
glfw.terminate()
def main_loop(self, window):
while (
glfw.get_key(window, glfw.KEY_ESCAPE) != glfw.PRESS and
not glfw.window_should_close(window)
):
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
self.tri.render()
glfw.swap_buffers(window)
glfw.poll_events()
def run(self):
log.basicConfig(level=log.DEBUG)
with self.create_main_window() as window:
self.main_loop(window)
From the console I have this coming out:
DEBUG:root:create_main_window(self):
Triangle.__init__(self)
Application.__init__(self)
DEBUG:root:~create_main_window(self):
Traceback (most recent call last):
File "C:\Users\prussos\PycharmProjects\pythonProject3\main.py", line 5, in <module>
app.run()
File "C:\Users\prussos\PycharmProjects\pythonProject3\Application.py", line 51, in run
self.main_loop(window)
File "C:\Users\prussos\PycharmProjects\pythonProject3\Application.py", line 44, in main_loop
self.tri.render()
File "C:\Users\prussos\PycharmProjects\pythonProject3\Triangle.py", line 131, in render
gl.glDrawArrays(gl.GL_TRIANGLES, 0, 3) # Starting from vertex 0
File "C:\Users\prussos\PycharmProjects\pythonProject3\venv\lib\site-packages\OpenGL\platform\baseplatform.py", line 415, in __call__
return self( *args, **named )
File "C:\Users\prussos\PycharmProjects\pythonProject3\venv\lib\site-packages\OpenGL\error.py", line 230, in glCheckError
raise self._errorClass(
OpenGL.error.GLError: GLError(
err = 1282,
description = b'invalid operation',
baseOperation = glDrawArrays,
cArguments = (GL_TRIANGLES, 0, 3)
)
Process finished with exit code 1
There seems to be a drawing error that is happening but I really I not quite exactly sure how to start to troubleshoot this thing yet. The code was moved over from gitlabs into a class based system for python. So a draw arrays that is an invalid operation what could that be coming from in OpenGL library is anyone familiar with it enough to know what place to edit here?
When you call an OpenGL instruction, you need a valid and up-to-date OpenGL context. The OpenGL Context is created with the OpenGl window. The OpenGL objects (VAO, VBO and shaders) are create in the constructor of the Triangle class. Therefore you can construct an object of this class only after creating the OpenGL window:
class Application:
# tri = Triangle() # <-- DELETE
def __init__(self):
print("Application.__init__(self)")
#contextlib.contextmanager
def create_main_window(self):
log.debug('create_main_window(self):')
if not glfw.init():
sys.exit(1)
try:
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, True)
glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
title = 'Tutorial 2: First Triangle'
window = glfw.create_window(500, 400, title, None, None)
if not window:
sys.exit(2)
glfw.make_context_current(window)
gl.glClearColor(0, 0, 0.4, 0)
yield window
finally:
log.debug('~create_main_window(self):')
glfw.terminate()
def main_loop(self, window):
self.tri = Triangle() # IINSERT
while (
glfw.get_key(window, glfw.KEY_ESCAPE) != glfw.PRESS and
not glfw.window_should_close(window)
):
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
self.tri.render()
glfw.swap_buffers(window)
glfw.poll_events()
def run(self):
log.basicConfig(level=log.DEBUG)
with self.create_main_window() as window:
self.main_loop(window)

PyOpengGL raises error when I compile shaders

I am running through a cumulation of OpenGL shader tutorials and mixing and matching stuff, trying to get a custom shader implemented. I have the following Python code and traceback:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QOpenGLWidget
from PyQt5.QtCore import Qt
from OpenGL.GL import (
glLoadIdentity, glTranslatef, glRotatef,
glClear, glBegin, glEnd,
glColor3fv, glVertex3fv,
GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT,
GL_QUADS, GL_LINES,
shaders, GL_VERTEX_SHADER, GL_FRAGMENT_SHADER
)
from OpenGL.GLU import gluPerspective
class mainWindow(QMainWindow): #Main class.
def keyPressEvent(self, event): #This is the keypress detector.
try:
key = event.key()
except:
key = -1
#print(key)
if key == 16777216:
exit()
vertices = [
(-1, 1, 0),
(1, 1, 0),
(1, -1, 0),
(-1, -1, 0)
]
wires = [
(0, 1),
(1, 2),
(2, 3),
(0, 3)
]
facets = [
(0, 1, 2, 3)
]
zoomLevel = -5
rotateDegreeH = 0
rotateDegreeV = -45
vertShaderCode = """#version 120
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}"""
fragShaderCode = """#version 120
void main() {
gl_FragColor = vec4( 0, 1, 0, 1 );
}"""
def __init__(self):
super(mainWindow, self).__init__()
self.sizeX = 700 #Variables used for the setting of the size of everything
self.sizeY = 600
self.setGeometry(0, 0, self.sizeX + 50, self.sizeY) #Set the window size
#make shaders
VERTEX_SHADER = shaders.compileShader(self.vertShaderCode, GL_VERTEX_SHADER)
FRAGMENT_SHADER = shaders.compileShader(self.fragShaderCode, GL_FRAGMENT_SHADER)
self.shader = shaders.compileProgram(VERTEX_SHADER,FRAGMENT_SHADER)
self.openGLWidget = QOpenGLWidget(self) #Create the GLWidget
self.openGLWidget.setGeometry(0, 0, self.sizeX, self.sizeY)
self.openGLWidget.initializeGL()
self.openGLWidget.resizeGL(self.sizeX, self.sizeY) #Resize GL's knowledge of the window to match the physical size?
self.openGLWidget.paintGL = self.paintGL #override the default function with my own?
def nav(self, hVal = 0, vVal = 0, zVal = 0):
self.zoomLevel += zVal
self.rotateDegreeH += hVal
self.rotateDegreeV += vVal
self.openGLWidget.update()
def paintGL(self):
#This function uses shape objects, such as cube() or mesh(). Shape objects require the following:
#a list named 'vertices' - This list is a list of points, from which edges and faces are drawn.
#a list named 'wires' - This list is a list of tuples which refer to vertices, dictating where to draw wires.
#a list named 'facets' - This list is a list of tuples which refer to vertices, ditating where to draw facets.
#a bool named 'render' - This bool is used to dictate whether or not to draw the shape.
#a bool named 'drawWires' - This bool is used to dictate whether wires should be drawn.
#a bool named 'drawFaces' - This bool is used to dictate whether facets should be drawn.
shaders.glUseProgram(self.shader)
glLoadIdentity()
gluPerspective(45, self.sizeX / self.sizeY, 0.1, 110.0) #set perspective?
glTranslatef(0, 0, self.zoomLevel) #I used -10 instead of -2 in the PyGame version.
glRotatef(self.rotateDegreeV, 1, 0, 0) #I used 2 instead of 1 in the PyGame version.
glRotatef(self.rotateDegreeH, 0, 0, 1)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glBegin(GL_LINES)
for w in self.wires:
for v in w:
glVertex3fv(self.vertices[v])
glEnd()
glBegin(GL_QUADS)
for f in self.facets:
for v in f:
glVertex3fv(self.vertices[v])
glEnd()
app = QApplication([])
window = mainWindow()
window.show()
sys.exit(app.exec_())
C:\Users\ccronk22\Documents\Python\glShaders>pygl002.py
Traceback (most recent call last):
File "C:\Users\ccronk22\AppData\Local\Programs\Python\Python38\lib\site-packages\OpenGL\latebind.py", line 43, in __call__
return self._finalCall( *args, **named )
TypeError: 'NoneType' object is not callable
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\ccronk22\Documents\Python\glShaders\pyGL002.py", line 109, in <module>
window = mainWindow()
File "C:\Users\ccronk22\Documents\Python\glShaders\pyGL002.py", line 59, in __init__
VERTEX_SHADER = shaders.compileShader(self.vertShaderCode, GL_VERTEX_SHADER)
File "C:\Users\ccronk22\AppData\Local\Programs\Python\Python38\lib\site-packages\OpenGL\GL\shaders.py", line 228, in compileShader
shader = glCreateShader(shaderType)
File "C:\Users\ccronk22\AppData\Local\Programs\Python\Python38\lib\site-packages\OpenGL\latebind.py", line 46, in __call__
self._finalCall = self.finalise()
File "C:\Users\ccronk22\AppData\Local\Programs\Python\Python38\lib\site-packages\OpenGL\extensions.py", line 242, in finalise
raise error.NullFunctionError(
OpenGL.error.NullFunctionError: Attempt to call an undefined alternate function (glCreateShader, glCreateShaderObjectARB), check for bool(glCreateShader) before calling
C:\Users\ccronk22\Documents\Python\glShaders>
The above code works well if you comment out the compileShader, compileProgram, and useProgram lines. It produces a white square, viewed from an above angle:
def __init__(self):
super(mainWindow, self).__init__()
self.sizeX = 700 #Variables used for the setting of the size of everything
self.sizeY = 600
self.setGeometry(0, 0, self.sizeX + 50, self.sizeY) #Set the window size
#make shaders
#VERTEX_SHADER = shaders.compileShader(self.vertShaderCode, GL_VERTEX_SHADER)
#FRAGMENT_SHADER = shaders.compileShader(self.fragShaderCode, GL_FRAGMENT_SHADER)
#self.shader = shaders.compileProgram(VERTEX_SHADER,FRAGMENT_SHADER)
[…]
def paintGL(self):
#This function uses shape objects, such as cube() or mesh(). Shape objects require the following:
#a list named 'vertices' - This list is a list of points, from which edges and faces are drawn.
#a list named 'wires' - This list is a list of tuples which refer to vertices, dictating where to draw wires.
#a list named 'facets' - This list is a list of tuples which refer to vertices, ditating where to draw facets.
#a bool named 'render' - This bool is used to dictate whether or not to draw the shape.
#a bool named 'drawWires' - This bool is used to dictate whether wires should be drawn.
#a bool named 'drawFaces' - This bool is used to dictate whether facets should be drawn.
#shaders.glUseProgram(self.shader)
Some additional information:
I am attempting to make the code from http://pyopengl.sourceforge.net/context/tutorials/shader_1.html work in the PyQt5 context, with only the OpenGL and PyQt5 APIs. The tutorial was written in Python2. I am using Python3.
So, what am I doing wrong with my shader compilation? Is it in the Python or GLSL?
To compile and link the shader you need a valid and current OpenGL Context. Note the OpenGL context have to be current when any OpenGL instruction is invoked.
QOpenGLWidget provides the virtual methods
def initializeGL ()
def paintGL ()
def resizeGL (w, h)
where the OpenGL context is active. This methods are callbacks and invoked by Qts event handling. Don't call them in your code.
Create the shader in the initializeGL callback:
class mainWindow(QMainWindow):
def __init__(self):
super(mainWindow, self).__init__()
self.sizeX = 700 #Variables used for the setting of the size of everything
self.sizeY = 600
self.setGeometry(0, 0, self.sizeX + 50, self.sizeY) #Set the window size
self.openGLWidget = QOpenGLWidget(self) #Create the GLWidget
self.openGLWidget.setGeometry(0, 0, self.sizeX, self.sizeY)
self.openGLWidget.resizeGL(self.sizeX, self.sizeY) #Resize GL's knowledge of the window to match the physical size?
self.openGLWidget.initializeGL = self.initializeGL
self.openGLWidget.paintGL = self.paintGL #override the default function with my own?
self.shader = None
def nav(self, hVal = 0, vVal = 0, zVal = 0):
self.zoomLevel += zVal
self.rotateDegreeH += hVal
self.rotateDegreeV += vVal
self.openGLWidget.update()
def initializeGL(self):
#make shaders
VERTEX_SHADER = shaders.compileShader(self.vertShaderCode, GL_VERTEX_SHADER)
FRAGMENT_SHADER = shaders.compileShader(self.fragShaderCode, GL_FRAGMENT_SHADER)
self.shader = shaders.compileProgram(VERTEX_SHADER,FRAGMENT_SHADER)
def paintGL(self):
glUseProgram(self.shader)
# [...]
(The import of glUseProgram is missing in your code)

OpenGL 4.2+ and shader_image_load_store for 3D textures not working?

I am trying to figure out why I'm not able to write into 3D textures using the (now built-in) shader_image_load_store extension.
I created two simple examples (in python to make it easier): one to write into a 2D texture, that works, and one to write into a 3D texture that does not work
the (working) 2D version is as following:
#! /usr/bin/env python
from PyQt4 import QtGui, QtCore
from PyQt4.QtOpenGL import *
from OpenGL.GL import *
from OpenGL.GLU import *
import sys
iTexSize = 256
_vsClearSource = """
#version 440 compatibility
void main() {
gl_Position = ftransform();
gl_FrontColor = gl_Color;
}
"""
_fsClearSource = """
#version 440 compatibility
uniform int iPrimitiveCount;
uniform int iSliceIndex;
layout(size4x32, binding=0) coherent uniform image2D volColorVolume;
const int iMaxTexSize = 255;
void main() {
ivec2 ivecVolumeCoordinate = ivec2(gl_FragCoord.x, gl_FragCoord.y ); //, iSliceIndex);
vec4 vecVolumeValue = vec4(0,1,0,1); // vec4( float(iSlabIndex)/float(iPrimitiveCount)); //,0.0,0.0,0.0);
imageStore(volColorVolume, ivecVolumeCoordinate, vecVolumeValue);
gl_FragData[0] = vec4(1,0,1,1);
}
"""
_fsFillSource = """
#version 440 compatibility
uniform int iPrimitiveCount;
uniform int iSliceIndex;
layout(size4x32, binding=0) coherent uniform image2D volColorVolume;
const int iMaxTexSize = 255;
void main() {
ivec2 ivecVolumeCoordinate = ivec2(gl_FragCoord.x, gl_FragCoord.y );
vec4 vecVolumeValue = vec4( float(gl_FragCoord.x) / float(iMaxTexSize) , float(gl_FragCoord.y) / float(iMaxTexSize) , 0 , 1 );
imageStore(volColorVolume, ivecVolumeCoordinate, vecVolumeValue);
gl_FragData[0] = vec4(1,0,1,1);
}
"""
class Viewer3DWidget(QGLWidget):
def __init__(self, parent):
QGLWidget.__init__(self, parent)
self.uWidth = 0
self.uHeight = 0
self.texColorTexture = None
self.fboRendering = None
self.texColorVolume = None
self.vecBackgroundColor = (1.,1.,1.)
self.vecDrawBuffers = [ GL_COLOR_ATTACHMENT0 , GL_COLOR_ATTACHMENT1 , GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 ]
self.fSurfacesSpacing = 1.0
self.fSurfacesTransparency = 1.0
def initializeGL(self):
self.shaShaderFill = QGLShaderProgram(self.context())
self.shaShaderFill.addShaderFromSourceCode(QGLShader.Vertex, _vsClearSource)
self.shaShaderFill.addShaderFromSourceCode(QGLShader.Fragment, _fsFillSource)
self.shaShaderFill.link()
self.shaShaderClear = QGLShaderProgram(self.context())
self.shaShaderClear.addShaderFromSourceCode(QGLShader.Vertex, _vsClearSource)
self.shaShaderClear.addShaderFromSourceCode(QGLShader.Fragment, _fsClearSource)
self.shaShaderClear.link()
glClearColor(1.0, 1.0, 1.0, 1.0)
glClearDepth(1.0)
def initRenderTargets(self):
global iTexSize
if (self.texColorTexture is None):
self.texColorTexture = glGenTextures( 1 )
if (self.fboRendering is None):
self.fboRendering = glGenFramebuffers(1)
glBindTexture( GL_TEXTURE_RECTANGLE, self.texColorTexture )
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA32F, iTexSize, iTexSize, 0, GL_RGBA, GL_FLOAT, None)
glBindTexture(GL_TEXTURE_RECTANGLE, 0);
glBindFramebuffer(GL_FRAMEBUFFER, self.fboRendering)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, self.texColorTexture, 0)
glBindFramebuffer(GL_FRAMEBUFFER, 0)
def deleteRenderTargets(self):
if (self.fboAccumulation is not None):
glDeleteFramebuffers(1,self.fboRendering)
self.fboAccumulation = None
if (self.texColorTexture is not None):
glDeleteTextures( self.texColorTexture )
self.texColorTexture = None
def initColorVolume(self):
if (self.texColorVolume is None):
self.texColorVolume = glGenTextures( 1 )
glBindTexture( GL_TEXTURE_2D, self.texColorVolume )
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
#glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, iTexSize, iTexSize, 0, GL_RGBA, GL_FLOAT, None);
glBindTexture(GL_TEXTURE_2D, 0);
def fillVolume(self, bClear):
global iTexSize
shaShader = self.shaShaderClear
if(not bClear):
shaShader = self.shaShaderFill
if (not self.fboRendering):
self.initRenderTargets()
if (not self.texColorVolume):
self.initColorVolume()
glMatrixMode( GL_PROJECTION )
glLoadIdentity()
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glBindImageTexture(0,self.texColorVolume,0,GL_FALSE,0,GL_READ_WRITE,GL_RGBA32F);
glBindFramebuffer(GL_FRAMEBUFFER, self.fboRendering);
glDrawBuffers(1, self.vecDrawBuffers);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
shaShader.bind()
shaShader.setUniformValue("iPrimitiveCount", iTexSize)
shaShader.setUniformValue("volColorVolume", 0)
for i in range(iTexSize):
shaShader.setUniformValue("iSliceIndex", i)
glBegin(GL_QUADS);
glVertex2f(-1.0, -1.0);
glVertex2f(1.0, -1.0);
glVertex2f(1.0, 1.0);
glVertex2f(-1.0, 1.0);
glEnd();
#sync
glMemoryBarrier(GL_ALL_BARRIER_BITS);
glBindImageTexture(0,0,0,GL_FALSE,0,GL_READ_WRITE,GL_RGBA32F);
shaShader.release()
glBindFramebuffer(GL_FRAMEBUFFER, 0);
def paintGL(self):
if (self.uWidth is 0):
return
if (not self.fboRendering):
self.initRenderTargets()
self.initColorVolume()
glMatrixMode( GL_PROJECTION )
glLoadIdentity()
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
self.fillVolume(True)
#draw into the volume
self.fillVolume(False)
#slice the volume
self.displayTexture()
glFlush()
def displayTexture(self): #essentially not useable here
glMatrixMode( GL_PROJECTION )
glLoadIdentity()
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glDisable(GL_BLEND)
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glColor(1.0, 1.0,1.0)
glEnable(GL_TEXTURE_2D);
glBindTexture( GL_TEXTURE_2D, self.texColorVolume )
glBegin(GL_QUADS);
glTexCoord2f(0,0) #,0.5)
glVertex2f(-1.0, -1.0);
glTexCoord2f(1,0) #,0.5)
glVertex2f(1.0, -1.0);
glTexCoord2f(1,1) #,0.5)
glVertex2f(1.0, 1.0);
glTexCoord2f(0,1) #,0.5)
glVertex2f(-1.0, 1.0);
glEnd();
glBindTexture( GL_TEXTURE_2D, 0 )
def resizeGL(self, widthInPixels, heightInPixels):
if ((widthInPixels is not self.uWidth) or (heightInPixels is not self.uHeight)):
self.uWidth = widthInPixels
self.uHeight = heightInPixels
glViewport(0, 0, widthInPixels, heightInPixels)
self.update()
class TestImageLoadStore2D(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setWindowTitle('TestImageLoadStore2D')
self.statusBar().showMessage("Hello there")
exit = QtGui.QAction("Exit", self)
exit.setShortcut("Ctrl+Q")
exit.setStatusTip('Exit application')
self.connect(exit, QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()'))
self.viewer3D = Viewer3DWidget(self)
self.setCentralWidget(self.viewer3D)
self.resize(500,500)
def closeEvent(self, event):
event.accept()
if __name__ == '__main__':
# app = QtGui.QApplication(['Python Qt OpenGL Demo'])
app = QtGui.QApplication(sys.argv)
window = TestImageLoadStore2D()
window.show()
sys.exit(app.exec_())
while the non-working 3D version is as following:
#! /usr/bin/env python
from PyQt4 import QtGui, QtCore
from PyQt4.QtOpenGL import *
from OpenGL.GL import *
from OpenGL.GLU import *
import sys
iTexSize = 256
_vsClearSource = """
#version 440 compatibility
void main() {
gl_Position = ftransform();
gl_FrontColor = gl_Color;
}
"""
_fsClearSource = """
#version 440 compatibility
uniform int iPrimitiveCount;
uniform int iSliceIndex;
layout(size4x32, binding=0) writeonly uniform image3D volColorVolume;
//layout(rgba32f, binding=0) writeonly uniform image3D volColorVolume;
const int iMaxTexSize = 255;
void main() {
ivec3 ivecVolumeCoordinate = ivec3(gl_FragCoord.x, gl_FragCoord.y, 0); //iSliceIndex);
vec4 vecVolumeValue = vec4(0,1,0,1); // vec4( float(iSlabIndex)/float(iPrimitiveCount)); //,0.0,0.0,0.0);
imageStore(volColorVolume, ivecVolumeCoordinate, vecVolumeValue);
memoryBarrier();
gl_FragData[0] = vec4(1,0,1,1);
}
"""
_fsFillSource = """
#version 440 compatibility
uniform int iPrimitiveCount;
uniform int iSliceIndex;
layout(size4x32, binding=0) writeonly uniform image3D volColorVolume;
const int iMaxTexSize = 255;
void main() {
ivec3 ivecVolumeCoordinate = ivec3(gl_FragCoord.x, gl_FragCoord.y, 0); //iSliceIndex);
vec4 vecVolumeValue = vec4( float(gl_FragCoord.x) / float(iMaxTexSize) , float(gl_FragCoord.y) / float(iMaxTexSize) , float(iSliceIndex)/float(iPrimitiveCount) , 1 );
imageStore(volColorVolume, ivecVolumeCoordinate, vecVolumeValue);
memoryBarrier();
gl_FragData[0] = vec4(1,0,1,1);
}
"""
class Viewer3DWidget(QGLWidget):
def __init__(self, parent):
QGLWidget.__init__(self, parent)
self.uWidth = 0
self.uHeight = 0
self.texColorTexture = None
self.fboRendering = None
self.texColorVolume = None
self.vecBackgroundColor = (1.,1.,1.)
self.vecDrawBuffers = [ GL_COLOR_ATTACHMENT0 , GL_COLOR_ATTACHMENT1 , GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 ]
self.fSurfacesSpacing = 1.0
self.fSurfacesTransparency = 1.0
self.fZCoord = 0.0
def setZCoordinate(self, fZCoordinate):
self.fZCoord = fZCoordinate
self.update()
def initializeGL(self):
self.shaShaderFill = QGLShaderProgram(self.context())
self.shaShaderFill.addShaderFromSourceCode(QGLShader.Vertex, _vsClearSource)
self.shaShaderFill.addShaderFromSourceCode(QGLShader.Fragment, _fsFillSource)
self.shaShaderFill.link()
self.shaShaderClear = QGLShaderProgram(self.context())
self.shaShaderClear.addShaderFromSourceCode(QGLShader.Vertex, _vsClearSource)
self.shaShaderClear.addShaderFromSourceCode(QGLShader.Fragment, _fsClearSource)
self.shaShaderClear.link()
glClearColor(1.0, 1.0, 1.0, 1.0)
glClearDepth(1.0)
def initRenderTargets(self):
global iTexSize
if (self.texColorTexture is None):
self.texColorTexture = glGenTextures( 1 )
if (self.fboRendering is None):
self.fboRendering = glGenFramebuffers(1)
glBindTexture( GL_TEXTURE_RECTANGLE, self.texColorTexture )
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA32F, iTexSize, iTexSize, 0, GL_RGBA, GL_FLOAT, None)
glBindTexture(GL_TEXTURE_RECTANGLE, 0);
glBindFramebuffer(GL_FRAMEBUFFER, self.fboRendering)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, self.texColorTexture, 0)
glBindFramebuffer(GL_FRAMEBUFFER, 0)
def deleteRenderTargets(self):
if (self.fboAccumulation is not None):
glDeleteFramebuffers(1,self.fboRendering)
self.fboAccumulation = None
if (self.texColorTexture is not None):
glDeleteTextures( self.texColorTexture )
self.texColorTexture = None
def initColorVolume(self):
if (self.texColorVolume is None):
self.texColorVolume = glGenTextures( 1 )
glBindTexture( GL_TEXTURE_3D, self.texColorVolume )
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP)
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA32F, iTexSize, iTexSize, iTexSize, 0, GL_RGBA, GL_FLOAT, None);
glBindTexture(GL_TEXTURE_3D, 0);
def fillVolume(self, bClear):
global iTexSize
shaShader = self.shaShaderClear
if(not bClear):
shaShader = self.shaShaderFill
if (not self.fboRendering):
self.initRenderTargets()
if (not self.texColorVolume):
self.initColorVolume()
glMatrixMode( GL_PROJECTION )
glLoadIdentity()
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glBindImageTexture(0,self.texColorVolume,0,GL_FALSE,0,GL_WRITE_ONLY,GL_RGBA32F);
glBindFramebuffer(GL_FRAMEBUFFER, self.fboRendering);
glDrawBuffers(1, self.vecDrawBuffers);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
shaShader.bind()
shaShader.setUniformValue("iPrimitiveCount", iTexSize)
shaShader.setUniformValue("volColorVolume", 0)
for i in range(iTexSize):
shaShader.setUniformValue("iSliceIndex", i)
glBegin(GL_QUADS);
glVertex2f(-1.0, -1.0);
glVertex2f(1.0, -1.0);
glVertex2f(1.0, 1.0);
glVertex2f(-1.0, 1.0);
glEnd();
#sync
glMemoryBarrier(GL_ALL_BARRIER_BITS);
glMemoryBarrier(GL_ALL_BARRIER_BITS);
glBindImageTexture(0,0,0,GL_FALSE,0,GL_WRITE_ONLY,GL_RGBA32F);
shaShader.release()
glBindFramebuffer(GL_FRAMEBUFFER, 0);
def paintGL(self):
if (self.uWidth is 0):
return
if (not self.fboRendering):
self.initRenderTargets()
self.initColorVolume()
glMatrixMode( GL_PROJECTION )
glLoadIdentity()
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
self.fillVolume(True)
#draw into the volume
#self.fillVolume(False)
#slice the volume
self.displayTexture()
glFlush()
def displayTexture(self): #essentially not useable here
glMatrixMode( GL_PROJECTION )
glLoadIdentity()
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glDisable(GL_BLEND)
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glColor(1.0, 1.0,1.0)
glEnable(GL_TEXTURE_3D);
glBindTexture( GL_TEXTURE_3D, self.texColorVolume )
fZCoord = self.fZCoord
glBegin(GL_QUADS);
glTexCoord3f(0,0,fZCoord)
glVertex2f(-1.0, -1.0);
glTexCoord3f(1,0,fZCoord)
glVertex2f(1.0, -1.0);
glTexCoord3f(1,1,fZCoord)
glVertex2f(1.0, 1.0);
glTexCoord3f(0,1,fZCoord)
glVertex2f(-1.0, 1.0);
glEnd();
glBindTexture( GL_TEXTURE_3D, 0 )
def resizeGL(self, widthInPixels, heightInPixels):
if ((widthInPixels is not self.uWidth) or (heightInPixels is not self.uHeight)):
self.uWidth = widthInPixels
self.uHeight = heightInPixels
glViewport(0, 0, widthInPixels, heightInPixels)
self.update()
class TestImageLoadStore3D(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setWindowTitle('TestImageLoadStore3D')
self.statusBar().showMessage("Hello there")
exit = QtGui.QAction("Exit", self)
exit.setShortcut("Ctrl+Q")
exit.setStatusTip('Exit application')
self.connect(exit, QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()'))
self.setToolTip('This is a window, or <b>something</b>')
self.viewer3D = Viewer3DWidget(self)
parentWidget = QtGui.QWidget()
slider1 = QtGui.QSlider(QtCore.Qt.Horizontal, None)
slider1.setRange(0,10000)
slider1.setValue(5000)
slider1.setMaximumWidth(120)
slider1.valueChanged.connect(self.slider1Handler)
vbox = QtGui.QVBoxLayout()
vbox.addWidget(slider1)
vbox.addStretch(1)
self.viewer3D.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )
hbox = QtGui.QHBoxLayout()
hbox.addLayout(vbox)
hbox.addWidget(self.viewer3D)
parentWidget.setLayout(hbox)
self.setCentralWidget(parentWidget)
self.resize(500,500)
def closeEvent(self, event):
event.accept()
def slider1Handler(self, iVal):
fVal = iVal / 10000.0
#print "zcoord: ",fVal
self.viewer3D.setZCoordinate(fVal)
if __name__ == '__main__':
# app = QtGui.QApplication(['Python Qt OpenGL Demo'])
app = QtGui.QApplication(sys.argv)
window = TestImageLoadStore3D()
window.show()
sys.exit(app.exec_())
the code is not extra neat, also because i copy/pasted/modified some older pyopengl code i had.
The problem is that the values written in the 3D texture make absolute no sense.
I ran it using the latest version of PyOpenGL (the experimental one), a Quadro K5000 and the latest drivers (332.76), that also provide the support for OpenGL 4.4 .
I'm not sure what i might be doing wrong, also because i haven't found many examples of writing into 3D textures (actually none, and i also looked in the latest version of the red book)
Can someone enlighten me?
Your problem is here in your frag shader:
layout(size4x32, binding=0) writeonly uniform image3D volColorVolume;
You are binding the 3D texture via
glBindImageTexture(0,self.texColorVolume,0,GL_FALSE,0,GL_WRITE_ONLY,GL_RGBA32F);
Let me quote from the OpenGL 4.4 spec, section 8.26 "Texture Image Loads and Stores" (emphasis mine):
If the texture identified by texture is a one-dimensional array,
two-dimensional array, three-dimensional, cube map, cube map array, or
two-dimensional multisample array texture, it is possible to bind
either the entire texture level or a single layer or face of the
texture level. If layered is TRUE, the entire level is bound. If
layered is FALSE, only the single layer identified by layer will be
bound. When layered is FALSE, the single bound layer is treated as a
different texture target for image accesses:
one-dimensional array texture layers are treated as one-dimensional textures;
two-dimensional array, three-dimensional, cube map, cube map array texture layers are treated as two-dimensional textures; and
two-dimensional multisample array textures are treated as two-dimensional multisample textures.
So, if you just bind one layer of a 3D texture with the layered parameter set to GL_FALSE (as you are currently doing), it will act as if it is just a 2D texture, so either just use an image2D and access it with 2D coords, or bind it with layered set to GL_TRUE and a valid range of layers you will be able to write into a specific layer/slices of your texture using an image3D and 3-dimensional image coordinates.
you have like 60 semicolons in python. Python doesn't use semicolons. In fact, I'm pretty sure python is the only programming language that actually doesn't use semicolons.

Categories