In this Python Modern Opengl programming i want to show you creating Triangle with GLFW. so before this we had some articles on Modern Opengl and also window creation with GLFW.
Python Modern Opengl Triangle With GLFW
Let’s create our example, So now this the complete code for Python Modern Opengl Triangle with GLFW
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
import glfw from OpenGL.GL import * import OpenGL.GL.shaders import numpy as np def main(): if not glfw.init(): return window = glfw.create_window(720, 600, "Opengl GLFW Triangle", None, None) if not window: glfw.terminate() return glfw.make_context_current(window) triangle = [-0.5,-0.5,0.0, 0.5,-0.5,0.0, 0.0,0.5,0.0] # convert to 32bit float triangle = np.array(triangle, dtype = np.float32) VERTEX_SHADER = """ #version 330 in vec4 position; void main() { gl_Position = position; } """ FRAGMENT_SHADER = """ #version 330 void main() { gl_FragColor = vec4(0.0f, 1.0f,0.0f,1.0f); } """ # Compile The Program and shaders shader = OpenGL.GL.shaders.compileProgram(OpenGL.GL.shaders.compileShader(VERTEX_SHADER,GL_VERTEX_SHADER), OpenGL.GL.shaders.compileShader(FRAGMENT_SHADER, GL_FRAGMENT_SHADER)) #Create Buffer object in gpu VBO = glGenBuffers(1) #Bind the buffer glBindBuffer(GL_ARRAY_BUFFER, VBO) glBufferData(GL_ARRAY_BUFFER, 36, triangle, GL_STATIC_DRAW) #get the position from vertex shader position = glGetAttribLocation(shader, 'position') glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(position) glUseProgram(shader) glClearColor(0.0,0.0,1.0,1.0) while not glfw.window_should_close(window): glfw.poll_events() glClear(GL_COLOR_BUFFER_BIT) #Draw Triangle glDrawArrays(GL_TRIANGLES, 0, 3) glfw.swap_buffers(window) glfw.terminate() if __name__ == "__main__": main() |
So in the above code iam not going to explain the window creation process in GLFW because i have already an article about that you can check the above links.
These are the triangle vertices
1 2 3 |
triangle = [-0.5,-0.5,0.0, 0.5,-0.5,0.0, 0.0,0.5,0.0] |
And these the vertex and fragment shaders
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
VERTEX_SHADER = """ #version 330 in vec4 position; void main() { gl_Position = position; } """ FRAGMENT_SHADER = """ #version 330 void main() { gl_FragColor = vec4(0.0f, 1.0f,0.0f,1.0f); } """ |
What Are Shaders?
Shaders are little programs that rest on the GPU. These programs are run for each specific section of the graphics pipeline. So In a basic sense, shaders are nothing more than programs transforming inputs to outputs. Shaders are also very isolated programs
Vertex shader
The vertex shader is a program on the graphics card that processes each vertex and its attributes as they appear in the vertex array. Its duty is to output the final vertex position in device coordinates and to output any data the fragment shader requires. That’s why the 3D transformation should take place here. The fragment shader depends on attributes like the color and texture coordinates, which will usually be passed from input to output without any calculations.
Fragment shader
So the output from the vertex shader is interpolated over all the pixels on the screen covered by a primitive. These pixels are called fragments and this is what the fragment shader operates on. Just like the vertex shader it has one mandatory output, the final color of a fragment. It’s up to you to write the code for computing this color from vertex colors, texture coordinates and any other data coming from the vertex shader.
In this line of code we compile the program and shaders
1 2 |
shader = OpenGL.GL.shaders.compileProgram(OpenGL.GL.shaders.compileShader(VERTEX_SHADER,GL_VERTEX_SHADER), OpenGL.GL.shaders.compileShader(FRAGMENT_SHADER, GL_FRAGMENT_SHADER)) |
The next step is to upload this vertex data to the graphics card. This is important because the memory on your graphics card is much faster and you won’t have to send the data again every time your scene needs to be rendered (about 60 times per second).
This is done by creating a Vertex Buffer Object (VBO):
1 |
VBO = glGenBuffers(1) |
To upload the actual data to it you first have to make it the active object by calling glBindBuffer()
1 |
glBindBuffer(GL_ARRAY_BUFFER, VBO) |
GL_ARRAY_BUFFER this is a type of buffer and also there different types of buffer for right now the are not important.
Now it is time to copy the vertex data
1 |
glBufferData(GL_ARRAY_BUFFER, 36, triangle, GL_STATIC_DRAW) |
- GL_STATIC_DRAW: So the vertex data will be uploaded once and drawn many times (e.g. the world).
- GL_DYNAMIC_DRAW: The vertex data will be created once, changed from time to time, but drawn many times more than that.
- GL_STREAM_DRAW: The vertex data will be uploaded once and drawn once.
So run the code and this will be the result
Subscribe and Get Free Video Courses & Articles in your Email
What if i wanna use index buffers