Skip to content
This repository has been archived by the owner on Jul 18, 2023. It is now read-only.

API. OpenGL

Cyrille Rossant edited this page Feb 26, 2014 · 1 revision

OpenGL wrapper API

This document describes the full specification of the OpenGL wrapper API.

Overview

This layer encapsulates raw OpenGL 2.0 features in a simpler object-oriented interface.

Features

  • Make OpenGL API not suck
    • Object-oriented access to GL objects
    • No global variables--user never needs to bind() anything (context managers, hooray!) (LC: I think this is possible without making any assumptions about the way GL API is used. Any counterexamples?)
  • ShaderProgram class
    • Links multiple Shaders together
    • Provides easy access (read/write) to attributes and uniforms
    • Nicely formatted error messages
    • Introspection--anything OpenGL will tell us about the shader should be wrapped (uniform/attribute names and types, function signatures, etc.)
    • Debugging support--easy mechanism for returning data from GPU
  • VertexShader & FragmentShader classes
    • Automatic shader compiling
    • Simple way to combine multiple parts of code, allowing for code addition and code templating.
  • VertexBuffer class
    • Automatic conversion from numpy arrays
    • 'View' objects for accessing (read/write) specific fields or sub-regions of the buffer
    • glMapBuffer support
    • Appendable
  • Texture classes (1D, 2D, 3D, cube?)
    • Image handling for standard texture use--image/video display
    • For passing arbitrary arrays to shaders (like Nicolas's Collection class). This will be a common use case; needs to be as painless as possible
  • Picking support (AK: depends on implementation whether this fits in this layer.)
  • Render to texture (FBO)

Interface

All GL objects are created and configured. Then, this module creates three functions:

  • initializeGL()
  • paintGL()
  • resizeGL(width, height)

which should be called from the corresponding functions in the GUI backend (Qt, wx, glut, etc.).

Also, the GL objects have update methods which can be used to update any parameter of the objects (vertex buffer data, textures, uniform values, etc.).

Examples

Example 1: triangle

This example displays a triangle with a gradient of colors between each corner.

vbo = VertexBuffer([...])  # TODO
shaders = VertexShader(...)  # TODO
# ...

Example 2: Basic line-drawing.

  1. Create shader

  2. Create vertex buffer

  3. Assign buffer data to shader attributes

  4. Draw primitives

     import vispy.opengl as opengl
    
     def init_gl():
         program = opengl.ShaderProgram(
             opengl.VertexShader(vertex_code1),
             opengl.VertexShader(vertex_code2),
             opengl.FragmentShader(fragment_code),
             )  
    
         vertex_data = np.zeros(dtype=[
             ('pos', float, 3),
             ('color', float, 4),
             ]) 
    
         ## fill vertex_data here  
    
         vbo = Buffer(vertex_data)
    
     def paint_gl():
         with enable(program, vbo):
             ## program takes care of locating/setting attributes, while
             ## vbo takes care of finding correct offset, stride, and data type
             program['in_position'] = vbo['pos']
             program['in_color'] = vbo['color']
             glDrawArrays(GL_LINE_STRIP, 0, len(vbo))
    

Example 3: Image class using a texture

class Image(Visual):
    def __init__(self, data):
        self._texture = Texture2D()
        self._texture.set_data(data)
        self._progam = ShaderProgram(vertexAaShader, fragmentAAShader)
        self._vertices = ...
    def paint(self):
        with enable(self._texture, self._program):
            self._vertices.draw()  # or something similar

Full specification

For already implemented classes, see http://vispy.readthedocs.org/en/latest/oogl.html

Below are the classes in progress ...

Texture class

Done (more or less).

VertexBuffer class

FrameBuffer class

Shader class

class Shader:
    def __init__(self, type, source=None):
      if source is not None:
          self.set_source(source)

    def _compile(self):
       # private method called by shaderProgram at the right time

    def set_source(self, source):
        ....
    
    def add_source(self, source):
        ... for later 

class FragmentShader(Shader):
    def __init__(self, source):
        Shader.__init__(self, gl.GL_FRAGMENT_SHADER)

Dito for VertexShader

class ShaderProgram:
   def __init__(self, *shaders):
       self._shaders = []
       for shader in shaders:
           self.add_shader(shader)

   def _enable(self):
       # will be called from a context manager (e.g. "with shader")
       # Compile if necessary
       # Link if necessary
       glUseProgram(self._handle)
   
   def _disable(self):
       # dito
   
   def delete():
       # Remove the program and shaders from opengl
       # is also called from __del__ method.
       # typically the user does not need this.
  
  def add_shader(self, shader):
      self._shaders.append(shader)
      ...
  
  def get_vertex_shader(self, index=0):
      # Pick index-th shader from self._shader that is a Vertex shader
  
  def get_fragment_shader(self, index=0):
      # Pick index-th shader from self._shader that is a Fragment shader
  
  def set_uniform(self, *arg):
      ... # Deal with lazy as well as direct mode.
  
  def set_attribute(self, *args):
      ... # vertex attributes. Deal with lazy as well as direct mode.
Clone this wiki locally