Voxelers / mcthings

A Python framework for creating 3D scenes in Minecraft and Minetest
Apache License 2.0
57 stars 10 forks source link

Learn OpenGL #123

Closed acs closed 3 years ago

acs commented 3 years ago

It is time to start learning OpenGL. Needed for #122 and in general, to understand the details of computer 3D graphics.

The two main references are:

My idea is to start using the NeHe Python tutorials. Let's see.

“Modern” OpenGL (version 3.x and higher, latest is 4.5) which uses lower level API’s to give you more flexibility. But we are using the older versions during the learning process. From this cool intro: http://15462.courses.cs.cmu.edu/spring2018content/lectures/00_opengl/00_opengl_slides.pdf

Great book with lots of references to free resources: http://www.realtimerendering.com/

https://learnopengl.com/book/book_pdf.pdf

«OpenGL is an API for accessing a hardware-based rasterizer. As such, it conforms to the model for rasterization-based 3D renderers. A rasterizer receives a sequence of triangles from the user, performs operations on them, and writes pixels based on this triangle data. This is a simplification of how rasterization works in OpenGL, but it is useful for our purposes.» https://paroj.github.io/gltut/Basics/Intro%20Graphics%20and%20Rendering.html

acs commented 3 years ago

GLUT is the windowing library used instead of pygame of pyglet. It seems to be more low level. Let's see. Because it is unmaintained for more then 20 years: https://www.opengl.org/resources/libraries/glut/ But probably FreeGLUT is what we are using inside PyOpenGL: http://freeglut.sourceforge.net/ (An alternative: https://www.glfw.org/ with python support https://github.com/pyglfw/pyglfw)

The idea is to use https://wiki.python.org/moin/PyOpenGL and in the Python examples is used: https://github.com/gamedev-net/nehe-opengl/blob/master/python/lesson01/ztvE1/lesson1.py

The contents from this lesso1 is in NeHe tutorials at: http://nehe.gamedev.net/tutorial/creating_an_opengl_window_(win32)/13001/

Let's check if it useful this combination to learn OpenGL. The first thing is to try to run the code. And as expected, there are issue, Some functions don't exist anymore:

glutSetIdleFuncCallback glutSetReshapeFuncCallback glutSetKeyboardFuncCallback

And of course, it is python2 code which needs some love to work on python3. Once all is fixed following lesson02 a nice blank sreen is show:

Screenshot from 2020-07-18 11-51-48

It seems that lesson2 has updated code: https://github.com/gamedev-net/nehe-opengl/blob/master/python/lesson02/ztvDB/Lesson%2002/lesson02.py

This one works like a charm (just fix the print so it works in python3):

Screenshot from 2020-07-18 11-49-30

Let's comparte and try to fix also lesson1.

acs commented 3 years ago

http://www.wag.caltech.edu/home/rpm/python_course/Lecture_7.pdf A nice intro to OpenGL from 2000 by Richard P. Muller

This code is pretty similar to the one the the tutorials, so it is great to confirm things.

acs commented 3 years ago

Lesson 1: "This program will create a blank OpenGL window"

Original my own fixed working with PyOpenGL and Python3.

The contents of the tutorial (1-5): lesson1

Is it possible that a tutorial for C++ in Windows from 2000 is useful for learning OpenGL in Python in 2020? Let's see.

The Rendering Context is linked to the Device Context which is linked to the GDI to show OpenGL results in a window.

The GDI I remember is something specific for Windows.

The creation and destroy oof the window in our case is done by GLUT. So we can forget about this part of the tutorial. But it is important to know that there is a OpenGL Rendering Context. In our case is the window created and destoryed by GLUT:

        window = glutCreateWindow("Jeff Molofee's GL Code Tutorial ... NeHe '99")
...
        glutDestroyWindow(window)

There are a lot of things at the start of lesson1 that are handled by the GLUT library in our case. But the concepts are the same, so it is not a waste of time reading them. And once we are totally OpenGL, the window is juts where our work will be shown, the code will be the same in the tutorial and in Python.

We have some important matrices:

and critical concepts:

This is not in Python: glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) which tell OpenGL we want the best perspective correction to be done.

Ok, after reading this first lesson, yes, we can learn OpenGL from this tutorials. There are tons of Windows specific stuff that is not needed because of GLUT, but the OpenGL code it the same except the glHint line. So great!

acs commented 3 years ago

Common to all lessons

So it seems that all the code can be reused and just change the DrawGLScene from lesson to lesson.

acs commented 3 years ago

After reviewing all lessons, probably we should focus in the first 10 lessons. After them, the rest are pretty specialized. At this point we should move to other goals.

acs commented 3 years ago

Lesson 2

Drawing 3D models it is no that hard for basic shapes:

    # Draw a triangle
    glBegin(GL_POLYGON)  # Start drawing a polygon
    glVertex3f(0.0, 1.0, 0.0)  # Top
    glVertex3f(1.0, -1.0, 0.0)  # Bottom Right
    glVertex3f(-1.0, -1.0, 0.0)  # Bottom Left
    glEnd()  # We are done with the polygon
    glBegin(GL_QUADS)  # Start drawing a 4 sided polygon
    glVertex3f(-1.0, 1.0, 0.0)  # Top Left
    glVertex3f(1.0, 1.0, 0.0)  # Top Right
    glVertex3f(1.0, -1.0, 0.0)  # Bottom Right
    glVertex3f(-1.0, -1.0, 0.0)  # Bottom Left
    glEnd()  # We are done with the polygon

To show the results when you are working with Double Buffering:

glutSwapBuffers()

Units

It is important to understand for example in the glVertex3 how to define the coordinates. We are working in 2D: the z coordinate is always 0. But, whats is the value for 1.0?

Screenshot from 2020-07-19 23-52-13

The dimensions of the GLUT Window are:

glutInitWindowSize(640, 480)

So, howto translate then top of the triangle 'glVertex3f(0.0, 1.0, 0.0)' to a pixel coordinates?

Probably this is done with the perspective:

gluPerspective(45.0, float(Width) / float(Height), 0.1, 100.0)

with the aspect ratio: float(Width) / float(Height). But I am not totally sure about that.

The coordinates are relatives to the block glBegin(GL_POLYGON) ... glEnd()

(0, 0, 0) is the center of the glBegin block. The top y-axis of the window seems to be a 2.5. So 480/2 = 240 = 2.5

But doing this exercise is wrong. The size of the shapes depends on the perspective, the position of the viewer ... so it is all relative. By default 1 is related the max size with respect to the aspect ratio and the dimensions of the screen.

And the drawing begins in tthe center of the glBegin block. Ok, let's continue with this intuitive idea.

acs commented 3 years ago

Lesson3

This is a pretty easy lesson un which I directly modify the lesson2 sample. The Python code from the tutorial is not always updated with the tutorial contents (probably the content was updated), so it is better to follow this approach.

You set a color before adding a vertex. When the figure is closed, for example the triangle, if all the vertexes are from the same color, the triangle color will be the same. If not, the inside color will change from the color of a vertex to the color of the other vertex. The smoothing of colors is because of glShadeModel(GL_SMOOTH).

To set a vertex color:

glColor3f(1.0, 0.0, 0.0)

Screenshot from 2020-07-20 07-20-45

acs commented 3 years ago

Refactoring

Ok, after 3 tutorials, is clear that the code to modify between tutorials is going to be small. So let's create a basic OpenGLApp class with all the shared code and inherit from it in each sample. And we will just redefined the needed methods.

Also, I do a heavy refactoring of the code to be more pythonic.

acs commented 3 years ago

Lesson4

Completed also lesson4 with rotations pretty fast. i have created a gif animation with peek

The rotation speed is x1, x10 (x1: 1 degree per refresh)

lesson4_x1 lesson4_x10

acs commented 3 years ago

Lesson 5

Ok, let's add volumen to our trianble and square converting them in a pyramid and a cube! Our 2D scene will show its 3D nature (ok, in the rotation sample, the 3D was clear also).

Lesson completed for the Pyramid. Things are getting cooler but we need to start selecting better colors :)

lesson5_pyr

acs commented 3 years ago

And the rotating cube

lesso5_cube

acs commented 3 years ago

Performance testing starts:

cubes

https://twitter.com/acstw/status/1285697498825338893

acs commented 3 years ago

Lesson 6

Ok, let's continue with textures. This sample seems to be more tricky because it has two versions, one with glaux (for loading images) and the other one with SOIL. There are bindings for python: https://pypi.org/project/pysoil/ (but they are unmaintained, the project does not exists anymore and there are no samples).

Let's try to find some other tutorials that we can use as the base for loading the texture. The python version for this lesson could help: https://github.com/gamedev-net/nehe-opengl/blob/master/python/lesson6/lesson6.py

There are other samples like: http://www.magikcode.com/?p=122

And pretty goood: http://www.opengl-tutorial.org/beginners-tutorials/tutorial-5-a-textured-cube/ But using C.

The translation details to Python to NeHe lesson 6: http://pyopengl.sourceforge.net/context/tutorials/nehe6.html

Ok, I have my first texture applied to a square:

Screenshot from 2020-07-22 08-29-05

Next step is to play with real textures and apply them to 3D objects!

acs commented 3 years ago

And the textures working in 3D models:

voxopengl

acs commented 3 years ago

So what's next? I don't pretend to learn all OpenGL with deep this time, but there are three more topics I would like to cover:

Taking a look to the tutorials, 7-10 must be covered also.

And then I will try to jump to:

Let's see how far I reach. During the trip I am refactoring the Python code so probably at the end, a mini framework for OpenGL with Python will emerge.

acs commented 3 years ago

Lesson 7: Texture Filters, Lighting & Keyboard Control

Topics: use three different texture filters, move an object using keys on the keyboard, apply simple lighting to your OpenGL scene

All done: https://twitter.com/acstw/status/1286713147831844864

acs commented 3 years ago

Lesson 8: Blending

What is so important about blending? "Blending is used to combine the color of a given pixel that is about to be drawn with the pixel that is already on the screen." It materials are opaque there is no blending, just draw the pixel of the outer object. But if they are transparent in some grade, the blending magic starts. Ok, time to explore this world of blending.

All done:

https://github.com/acs/opengl-samples/commit/8db755ae46badc38e40d3b1f4fcf50f06dc0cece

acs commented 3 years ago

Ok, I would like to focus now in physics. But I am not totally sure where is the best place to learn about physics in 3D. ¿OpenGL? ¿Vulkan? Is it the same?

Maybe it is time to learn a bit Vulkan API. I will stop here my OpenGL trip until I decide where to continue.

acs commented 3 years ago

After taking a quick look, OpenGL has more resources about physics than Vulkan, so I will continue with OpenGL. Next step is to find then best way to learn howto apply physics to 3D models with OpenGL.

https://github.com/bulletphysics/bullet3 Is this what we are searching for? Playing with it we will learn more about collision detection and physics engines which is a good thing. And probably we will know better the way to follow.

acs commented 3 years ago

Ok, after researching about physics engines, it is a huge topic, so let's try to get some basics concepts from the tutorial:

http://nehe.gamedev.net/tutorial/introduction_to_physical_simulations/18005/

also, reading and reading it seems that this chapter is more valuable:

https://sites.google.com/site/letsmakeavoxelengine/home/physics

acs commented 3 years ago

Lesson 9: Moving Bitmaps In 3D Space

http://nehe.gamedev.net/tutorial/moving_bitmaps_in_3d_space/17001/

It is the same that what I have already done for cubes.py sample. The logic is more complex so I have decided not to invest time in this tutorial.

acs commented 3 years ago

Probably we must also learn from more updated resources like:

https://learnopengl.com/Getting-started/Hello-Triangle

in order to use modern OpenGL and windowing systems, like GLFW: https://learnopengl.com/Getting-started/Creating-a-window

acs commented 3 years ago

Matrices

In the code of OpenGL all are matrices. And the different operations are done with them. Let's review why matrices are used and the basic math around them.

http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/ https://open.gl/transformations

After reading both articles, in OpenGL we work normally with vectors of 4d and convert them using different transformations. A key concept in transformations is the order in which they have to be applied:

The order it not commutative and if we don't follow it, we will have strange results.

«The job of transforming 3D points into 2D coordinates on your screen is also accomplished through matrix transformations»

3D to 2D pipeline:

Screenshot from 2020-07-25 17-29-24

acs commented 3 years ago

OpenGL in Linux

The OpenGL implementation in Linux is done by Mesa: https://en.wikipedia.org/wiki/Mesa_(computer_graphics) It offers the API for OpenGL, Vulkan and others APis. And it implements them using the video driver specific for the available graphics card. It seems that Mesa used DRM API which is the one implemented by the graphics drivers.

OpenGL in Linux

Linux Graphics Stack

In my case it is:

[~]$ glxinfo | grep -i opengl
OpenGL vendor string: Intel
OpenGL renderer string: Mesa Intel(R) UHD Graphics 620 (KBL GT2)
OpenGL core profile version string: 4.6 (Core Profile) Mesa 20.1.3
OpenGL core profile shading language version string: 4.60
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile
OpenGL core profile extensions:
OpenGL version string: 4.6 (Compatibility Profile) Mesa 20.1.3
OpenGL shading language version string: 4.60
OpenGL context flags: (none)
OpenGL profile mask: compatibility profile
OpenGL extensions:
OpenGL ES profile version string: OpenGL ES 3.2 Mesa 20.1.3
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.20
OpenGL ES profile extensions:

Then intel drivers are described in: https://01.org/linuxgraphics: «The Intel Linux Graphics project is composed by different components, such as Kernel, Mesa, VAAPI, xf86-video-intel, and LibDRM. »

The name of the driver is i915:

[~]$ lsmod | grep i915
i915                 2600960  39
i2c_algo_bit           16384  1 i915
cec                    61440  1 i915
drm_kms_helper        249856  1 i915
drm                   618496  12 drm_kms_helper,i915
video                  53248  2 thinkpad_acpi,i915

For testing OpenGL in Linux:

acs commented 3 years ago

Ok, time to return to the NeHe tutorials, the 10 about creating a simple 3D World.

Loading And Moving Through A 3D World

acs commented 3 years ago

I have decided to stop my research in OpenGl, which is for rendering rasterized graphics, in order to put our focus in ray tracing. if needed, I will continue with OpenGL in the future. It has been a great time. And we have the python samples ready to be used in the future.

acs commented 3 years ago

Great tutorials using C: https://antongerdelan.net/opengl/hellotriangle.html

acs commented 3 years ago

https://www.bassi.io/articles/2015/02/17/using-opengl-with-gtk/ OpenGL and GTK+