mirror of
https://github.com/cyberboy666/r_e_c_u_r.git
synced 2025-12-14 12:20:03 +01:00
Create shader_example.py
This commit is contained in:
157
shader_experiments/shader_example.py
Normal file
157
shader_experiments/shader_example.py
Normal file
@@ -0,0 +1,157 @@
|
||||
# PyQt4 imports
|
||||
from PyQt4 import QtGui, QtCore, QtOpenGL
|
||||
from PyQt4.QtOpenGL import QGLWidget
|
||||
# PyOpenGL imports
|
||||
import OpenGL.GL as gl
|
||||
import OpenGL.arrays.vbo as glvbo
|
||||
|
||||
# Window creation function.
|
||||
def create_window(window_class):
|
||||
"""Create a Qt window in Python, or interactively in IPython with Qt GUI
|
||||
event loop integration:
|
||||
# in ~/.ipython/ipython_config.py
|
||||
c.TerminalIPythonApp.gui = 'qt'
|
||||
c.TerminalIPythonApp.pylab = 'qt'
|
||||
See also:
|
||||
http://ipython.org/ipython-doc/dev/interactive/qtconsole.html#qt-and-the-qtconsole
|
||||
"""
|
||||
app_created = False
|
||||
app = QtCore.QCoreApplication.instance()
|
||||
if app is None:
|
||||
app = QtGui.QApplication(sys.argv)
|
||||
app_created = True
|
||||
app.references = set()
|
||||
window = window_class()
|
||||
app.references.add(window)
|
||||
window.show()
|
||||
if app_created:
|
||||
app.exec_()
|
||||
return window
|
||||
|
||||
def compile_vertex_shader(source):
|
||||
"""Compile a vertex shader from source."""
|
||||
vertex_shader = gl.glCreateShader(gl.GL_VERTEX_SHADER)
|
||||
gl.glShaderSource(vertex_shader, source)
|
||||
gl.glCompileShader(vertex_shader)
|
||||
# check compilation error
|
||||
result = gl.glGetShaderiv(vertex_shader, gl.GL_COMPILE_STATUS)
|
||||
if not(result):
|
||||
raise RuntimeError(gl.glGetShaderInfoLog(vertex_shader))
|
||||
return vertex_shader
|
||||
|
||||
def compile_fragment_shader(source):
|
||||
"""Compile a fragment shader from source."""
|
||||
fragment_shader = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
|
||||
gl.glShaderSource(fragment_shader, source)
|
||||
gl.glCompileShader(fragment_shader)
|
||||
# check compilation error
|
||||
result = gl.glGetShaderiv(fragment_shader, gl.GL_COMPILE_STATUS)
|
||||
if not(result):
|
||||
raise RuntimeError(gl.glGetShaderInfoLog(fragment_shader))
|
||||
return fragment_shader
|
||||
|
||||
def link_shader_program(vertex_shader, fragment_shader):
|
||||
"""Create a shader program with from compiled shaders."""
|
||||
program = gl.glCreateProgram()
|
||||
gl.glAttachShader(program, vertex_shader)
|
||||
gl.glAttachShader(program, fragment_shader)
|
||||
gl.glLinkProgram(program)
|
||||
# check linking error
|
||||
result = gl.glGetProgramiv(program, gl.GL_LINK_STATUS)
|
||||
if not(result):
|
||||
raise RuntimeError(gl.glGetProgramInfoLog(program))
|
||||
return program
|
||||
|
||||
# Vertex shader
|
||||
VS = """
|
||||
#version 330
|
||||
// Attribute variable that contains coordinates of the vertices.
|
||||
layout(location = 0) in vec2 position;
|
||||
|
||||
// Main function, which needs to set `gl_Position`.
|
||||
void main()
|
||||
{
|
||||
// The final position is transformed from a null signal to a sinewave here.
|
||||
// We pass the position to gl_Position, by converting it into
|
||||
// a 4D vector. The last coordinate should be 0 when rendering 2D figures.
|
||||
gl_Position = vec4(position.x, .2 * sin(20 * position.x), 0., 1.);
|
||||
}
|
||||
"""
|
||||
|
||||
# Fragment shader
|
||||
FS = """
|
||||
#version 330
|
||||
// Output variable of the fragment shader, which is a 4D vector containing the
|
||||
// RGBA components of the pixel color.
|
||||
out vec4 out_color;
|
||||
|
||||
// Main fragment shader function.
|
||||
void main()
|
||||
{
|
||||
// We simply set the pixel color to yellow.
|
||||
out_color = vec4(1., 1., 0., 1.);
|
||||
}
|
||||
"""
|
||||
|
||||
class GLPlotWidget(QGLWidget):
|
||||
# default window size
|
||||
width, height = 600, 600
|
||||
|
||||
def initializeGL(self):
|
||||
"""Initialize OpenGL, VBOs, upload data on the GPU, etc."""
|
||||
# background color
|
||||
gl.glClearColor(0, 0, 0, 0)
|
||||
# create a Vertex Buffer Object with the specified data
|
||||
self.vbo = glvbo.VBO(self.data)
|
||||
# compile the vertex shader
|
||||
vs = compile_vertex_shader(VS)
|
||||
# compile the fragment shader
|
||||
fs = compile_fragment_shader(FS)
|
||||
# compile the vertex shader
|
||||
self.shaders_program = link_shader_program(vs, fs)
|
||||
|
||||
def paintGL(self):
|
||||
"""Paint the scene."""
|
||||
# clear the buffer
|
||||
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
|
||||
# bind the VBO
|
||||
self.vbo.bind()
|
||||
# tell OpenGL that the VBO contains an array of vertices
|
||||
# prepare the shader
|
||||
gl.glEnableVertexAttribArray(0)
|
||||
# these vertices contain 2 single precision coordinates
|
||||
gl.glVertexAttribPointer(0, 2, gl.GL_FLOAT, gl.GL_FALSE, 0, None)
|
||||
gl.glUseProgram(self.shaders_program)
|
||||
# draw "count" points from the VBO
|
||||
gl.glDrawArrays(gl.GL_LINE_STRIP, 0, len(self.data))
|
||||
|
||||
def resizeGL(self, width, height):
|
||||
"""Called upon window resizing: reinitialize the viewport."""
|
||||
# update the window size
|
||||
self.width, self.height = width, height
|
||||
# paint within the whole window
|
||||
gl.glViewport(0, 0, width, height)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# import numpy for generating random data points
|
||||
import sys
|
||||
import numpy as np
|
||||
|
||||
# null signal
|
||||
data = np.zeros((10000, 2), dtype=np.float32)
|
||||
data[:,0] = np.linspace(-1., 1., len(data))
|
||||
|
||||
# define a Qt window with an OpenGL widget inside it
|
||||
class TestWindow(QtGui.QMainWindow):
|
||||
def __init__(self):
|
||||
super(TestWindow, self).__init__()
|
||||
# initialize the GL widget
|
||||
self.widget = GLPlotWidget()
|
||||
self.widget.data = data
|
||||
# put the window at the screen position (100, 100)
|
||||
self.setGeometry(100, 100, self.widget.width, self.widget.height)
|
||||
self.setCentralWidget(self.widget)
|
||||
self.show()
|
||||
|
||||
# show the window
|
||||
win = create_window(TestWindow)
|
||||
Reference in New Issue
Block a user