Why OpenGL?

I recently moving on to the Python.

The first reason is that I wanted to use TensorFlow for future machine learning programming.

The second is the coding style in Python.

It is very intuitive and code readability was quite impressive for me.

Since I was a MATLAB user, however, I was quite disappointed about the interface of matplotlib.

It does not behave as I expected and it is quite hard to draw figures as I expected.

I'm in the field of numerical analysis especially in the finite element method (FEM).

Since I use high order affine element, it is very important that I have full control on the surface patch.

In MATLAB, I usually use patch to draw figures.

However, I could not find any good reference manipulating patch element on matplotlib.

Since I planning to build my own graphic tools to visualize my data set, I decided to learn GUI programming.

My first choice is PyOpenGL (if it turns out to be not good for my purpose, I will learn other module).

Since I do not have any experience in GUI programming, it was quite difficult to understand.

How did I learn OpenGL?

I found a good tutorial on from the Youtuber sentdex.

He explains about the PyOpenGL very easily and show very simple examples to help understanding.

What I have learned now is how to draw polygons in 3D.

I used 2 modules, pygame and OpenGL, for the job done.

Clearly, OpenGL is for the use of OpenGL and pygame for the interaction with keyboard and mouse.

I think pygame can be deleted, but it is quite easy to make user interactive interface with this module.

How to draw?

To draw some polygons, I have to do like

import pygame                    # user interactive
from pygame.locals import *    # to avoid namespace flooding
from OpenGL.GL import *        # for basic OpenGL functions
from OpenGL.GLU import *     # for advanced OpenGL functions
import numpy as np                 # for numpy array and pi

def main():
    # generate data to draw
    x, y, n4e = gen_tri_mesh_on_rect(30, 30, 0, 1, 0, 1)   # returns x, y, and triangle index
    z = np.sin(x*np.pi) * np.sin(y*np.pi)
    display = (800, 600)  # canvas size
    pygame.display.set_mode(display, DOUBLEBUF | OPENGL)  # canvas size, double buffur, using OpenGL
    gluPerspective(45.0, display[0]/display[1], 0.1, 100.0)  # viewing angle, aspect ratio, depth min, depth max
    glTranslatef(0.0, 0.0, -5)  # move camera away from origin by 5
    draw_triangles(n4e, x, y, z)

The drawing function for triangle is looks like this.

def draw_triangles(n4e, x, y, z):  # n4e : triangle index, x, y, z : coordinate array
    glBegin(GL_TRIANGLES)      # Let OpenGL know that I'm drawing triangles
    xmid = (min(x)+max(x))/2       # Get mid point
    ymid = (min(y)+max(y))/2
    for tri in n4e:                           # for every triangle
        for idx in tri:                        # for every vertex in each triangle
            glVertex3fv((x[idx] - xmid, z[idx], y[idx] - ymid))   # feed in triangle vertex
    glEnd()                                   # end of drawing

Here, n4e is nE x 3 integer type array and x,y,z are 1D array.

Note that I put 3d coordinate for glVertex3fv in the order of (x,z,y).

This is because PyOpenGL's coordinate system is not the same as in the mathematical plotting.

The consider horizontal direction as x and vertical direction as y, and depth as z.

Therefore, I have to translate (x,y,z) to (x,z,y) to get the right position.

Now, I know how to draw triangles.

Future Work

I also make a loop that takes user input to interact with perspective of resulting plot.

In next post, I will explain how to take input from keyboard and mouse.

Also, it turns out that the code I posted is quite slow even for the small number of triangles.

This is quite unreasonable if we consider 3d game.

They draw easily 10M of polygons per frame.

I think the main reason for the horrible frame rate is because I did not optimize anything.

However, since I'm on the beginning stage, I will stick on this algorithm.

(If you have any idea to optimize this code, please comment below)

One possible way to gain performance is to utilize graphic cards.

There are so called vbo in OpenGL which represents vertex_buffer_object.

This stays on the graphic card memory so that I can draw polygons much faster.