[PYTHON] Programmation Shader avec pyOpenGL

Présentez pyOpenGL

Cette fois, le but est de toucher GLSL plutôt que de faire quelque chose avec OpenGL. J'ai décidé d'utiliser python + pyOpenGL (c'est plus facile de charger des textures et celle-ci !!)

Tout d'abord, introduisez pyOpenGL et PyOpenGL-Demo.

% sudo pip install PyOpenGL PyOpenGL-Demo

Exécutez ensuite l'exemple pour vous assurer qu'il est correctement installé.

% cd /Library/Python/2.7/site-package/PyOpenGL-Demo/GLUT/
% python shader-test.py

Ensuite, la fenêtre suivante s'affiche. pyopengl.png

Créer un modèle pour la programmation des shaders

J'ai décidé de créer un modèle pour spécifier le programme vertex shader, le programme fragment shader et la texture à partir de la ligne de commande. Fondamentalement, j'ai décidé d'empaqueter le shader-test.py utilisé ci-dessus. Le code réel est le suivant.

shader-test.py


#! /usr/bin/env python
import numpy as np
import sys
import time
import Image
import OpenGL
OpenGL.ERROR_ON_COPY = True
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

# PyOpenGL 3.0.1 introduces this convenience module...
from OpenGL.GL.shaders import *

vertices = None
indices = None

def InitGL( vertex_shade_code, fragment_shader_code, texture_image ):
    glClearColor(0.0, 0.0, 0.0, 0.0)

    texture_id = glGenTextures( 1 )
    glPixelStorei( GL_UNPACK_ALIGNMENT, 1 )
    glActiveTexture( GL_TEXTURE0 )
    glBindTexture( GL_TEXTURE_2D, texture_id )

    if texture_image.mode == 'RGB':
        glTexImage2D( GL_TEXTURE_2D,
                      0,
                      4,
                      texture_image.size[0],
                      texture_image.size[1],
                      0,
                      GL_RGB,
                      GL_UNSIGNED_BYTE,
                      texture_image.tostring() )
    else:
        glTexImage2D( GL_TEXTURE_2D,
                      0,
                      4,
                      texture_image.size[0],
                      texture_image.size[1],
                      0,
                      GL_RGBA,
                      GL_UNSIGNED_BYTE,
                      texture_image.tostring() )
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR )
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR )
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE )
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE )

    program = compileProgram(
        compileShader( vertex_shade_code,GL_VERTEX_SHADER),
        compileShader( fragment_shader_code,GL_FRAGMENT_SHADER),)

    glUseProgram(program)
    glUniform1i( glGetUniformLocation( program, "s_texture" ), 0 );
    glUniform1f( glGetUniformLocation( program, "texture_width" ), float( texture_image.size[ 0 ] ) )
    glUniform1f( glGetUniformLocation( program, "texture_height" ), float( texture_image.size[ 1 ] ) )


    global vertices
    global indices
    position_vertices = [ -1.0,  1.0, 0.0,
                          -1.0, -1.0, 0.0,
                           1.0, -1.0, 0.0,
                           1.0,  1.0, 0.0, ]
    texture_vertices = [ 0.0, 0.0,
                         0.0, texture_image.size[ 1 ],
                         texture_image.size[ 0 ], texture_image.size[ 1 ],
                         texture_image.size[ 0 ], 0.0 ]

    indices = [ 0, 1, 2, 0, 2, 3 ]

    position_loc = glGetAttribLocation( program, 'a_position' )
    glVertexAttribPointer( position_loc,
                           3,
                           GL_FLOAT,
                           GL_FALSE,
                           3 * 4,
                           np.array( position_vertices, np.float32 ) )

    tex_loc = glGetAttribLocation( program, 'a_texCoord' )
    glVertexAttribPointer( tex_loc,
                           2,
                           GL_FLOAT,
                           GL_FALSE,
                           2 * 4,
                           np.array( texture_vertices, np.float32 ) )

    glEnableVertexAttribArray( position_loc )
    glEnableVertexAttribArray( tex_loc )


def ReSizeGLScene(Width, Height):
    glViewport(0, 0, Width, Height)

# The main drawing function.
def DrawGLScene():
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    glEnable( GL_TEXTURE_2D )

    glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, np.array( indices, np.uint16 ) )
    glDisable(GL_TEXTURE_2D)

    glutSwapBuffers()

def keyPressed(*args):
    # If escape is pressed, kill everything.
    if args[0] == '\x1b':
        sys.exit()

def usage():
    print "usage:%s vertex_shader_file fragment_shader_file texture_file" % sys.argv[ 0 ]

def main():
    try:
        vertex_shader_file = sys.argv[ 1 ]
        fragment_shader_file = sys.argv[ 2 ]
        texture_file = sys.argv[ 3 ]
    except IndexError:
        usage()
        sys.exit( -1 )

    vertex_shade_code = '\n'.join( open( vertex_shader_file, 'r' ).readlines() )
    fragment_shader_code = '\n'.join( open( fragment_shader_file, 'r' ).readlines() )
    texture_image = Image.open( texture_file )
    print texture_image.mode
    assert texture_image.mode == 'RGBA' or texture_image.mode == 'RGB'

    glutInit(sys.argv)

    if texture_image.mode == 'RGBA':
        glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH)
    else:
        glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)

    window_width,window_height = texture_image.size
    glutInitWindowSize( window_width, window_height )

    # the window starts at the upper left corner of the screen
    glutInitWindowPosition(0, 0)

    glutCreateWindow( sys.argv[ 0 ] )

    glutDisplayFunc(DrawGLScene)

    # Uncomment this line to get full screen.
    #glutFullScreen()

    # When we are doing nothing, redraw the scene.
    glutIdleFunc(DrawGLScene)

    # Register the function called when our window is resized.
    glutReshapeFunc(ReSizeGLScene)

    # Register the function called when the keyboard is pressed.
    glutKeyboardFunc(keyPressed)

    # Initialize our window.
    InitGL( vertex_shade_code, fragment_shader_code, texture_image )

    # Start Event Processing Engine
    glutMainLoop()

if __name__ == "__main__":
    print "Hit ESC key to quit."
    main()

Et avec le programme vertex shader ci-dessous

shader.vert


attribute vec4 a_position;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;
uniform float texture_width;
uniform float texture_height;

void main() {
    v_texCoord = a_texCoord;
    gl_Position = a_position;
}

Pour exécuter le programme fragment shader ci-dessous

shader.frag


varying vec2 v_texCoord;
uniform sampler2D s_texture;
uniform float texture_width;
uniform float texture_height;

void main() {
    float t_x = v_texCoord.x / texture_width;
    float t_y = v_texCoord.y / texture_height;
    float d_x = 1.0 / texture_width;
    float d_y = 1.0 / texture_height;

    vec4 v1 = texture2D( s_texture, vec2( t_x, t_y ) + vec2( d_x, 0.0 ) );
    vec4 v2 = texture2D( s_texture, vec2( t_x, t_y ) - vec2( d_x, 0.0 ) );
    vec4 v3 = texture2D( s_texture, vec2( t_x, t_y ) + vec2( 0.0, d_y ) );
    vec4 v4 = texture2D( s_texture, vec2( t_x, t_y ) - vec2( 0.0, d_y ) );
    gl_FragColor = ( abs( v1 - v2 ) + abs( v3 - v4 ) ) / 2.0;
}

Comme ça

% python shader-test.py shader.vert shader.frag texture.png

Le résultat ressemble à ceci pygl_result.jpg

Recommended Posts

Programmation Shader avec pyOpenGL
Programmation asynchrone avec libev # 2
3. 3. Programmation IA avec Python
Programmation Python avec Atom
Programmation compétitive avec python
Programmation asynchrone avec libev
Programmation linéaire avec PuLP
Programmation avec Python Flask
Programmation asynchrone avec libev # 3
Programmation avec Python et Tkinter
Essayez de programmer avec un shell!
Essayez la programmation GUI avec Hy
Jeu éducatif de programmation avec SenseHAT
Programmation réseau avec Python Scapy
Applications avec PyOpenCL (PIL et PyOpenGL)
Programmation facile Python + OpenCV avec Canopy
Dessinez avec PyOpenGL. Confusion autour de VBO
Programmation pour les humains avec un __repr__ bien défini
Programmation de compétition avec les paramètres de l'environnement local python
Programmation GUI à l'aide de kivy ~ Partie 4 Divers boutons ~
Programmation normale avec la programmation Node-RED avec Raspberry Pi 3
Programmation sonore avec Go (super niveau d'introduction)
Ce que vous pouvez faire avec des compétences en programmation