I need your help. Using python, I have to implement the lighting of my three-dimensional shape by the phong model. My figure is a deltoidal icositetrahedron. I was able to build this shape, found the coordinates of the vertices, and also calculated the normals to each face.
I used pygame, pyopengl.
To implement the phong lighting model, I managed to make ambient lighting and diffuse lighting, but I do not know what functions to use for specular lighting.
I tried to apply functions such as glMaterialfv() with different parameters, but it didn't work out for me.
Here is my code:
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
verticies = (
(0, - 0, 1.15894198417663574),
(0.63384598493576048, -0.63384598493576048, 0.63384598493576048),
(0.81949597597122192, 0, 0.81949597597122192),
(1.15894198417663574, 0, -0),
(0.81949597597122192, 0.81949597597122192, -0),
(0.81949597597122192, 0, -0.81949597597122192),
(0.63384598493576048, 0.63384598493576048, 0.63384598493576048),
(0.81949597597122192, -0.81949597597122192, 0),
(-0, 0.81949597597122192, 0.81949597597122192),
(-0.81949597597122192, 0, 0.81949597597122192),
(0.63384598493576048, 0.63384598493576048, -0.63384598493576048),
(0, 0, -1.15894198417663574),
(0, -0.81949597597122192, -0.81949597597122192),
(-0.81949597597122192, 0, -0.81949597597122192),
(0, 0.81949597597122192, -0.81949597597122192),
(0.63384598493576048, -0.63384598493576048, -0.63384598493576048),
(-0, 1.15894198417663574, 0),
(-0.81949597597122192, 0.81949597597122192, 0),
(-1.15894198417663574, 0, 0),
(-0.63384598493576048, 0.63384598493576048, 0.63384598493576048),
(0, -1.15894198417663574, 0),
(-0.81949597597122192, -0.81949597597122192, 0),
(0, -0.81949597597122192, 0.81949597597122192),
(-0.63384598493576048, -0.63384598493576048, 0.63384598493576048),
(-0.63384598493576048, 0.63384598493576048, -0.63384598493576048),
(-0.63384598493576048, -0.63384598493576048, -0.63384598493576048),
)
surfaces = (
(20, 21, 25, 12),
(21, 25, 13, 18),
(17, 24, 14, 16),
(18, 13, 24, 17),
(16, 14, 10, 4),
(3, 5, 15, 7),
(0, 2, 6, 8),
(0, 2, 1, 22),
(0, 22, 23, 9),
(0, 9, 19, 8),
(13, 11, 12, 25),
(11, 13, 24, 14),
(11, 14, 10, 5),
(11, 5, 15, 12),
(3, 5, 10, 4),
(17, 18, 9, 19),
(17, 19, 8, 16),
(16, 8, 6, 4),
(3, 2, 6, 4),
(3, 2, 1, 7),
(7, 1, 22, 20),
(20, 21, 23, 22),
(9, 23, 21, 18),
(15, 7, 20, 12),
)
normals = [
(-0.35740624923526854, -0.8628558767968414, -0.3574080425574267),
(-0.8628548655932644, -0.3574083665235253, -0.3574083665235253),
(-0.3574083665235253, 0.8628548655932644, -0.3574083665235253),
(-0.8628558767968414, 0.3574080425574267, -0.35740624923526854),
(0.3574080425574267, 0.8628558767968414, -0.35740624923526854),
(0.8628558767968414, -0.3574080425574267, -0.35740624923526854),
(0.35740624923526854, 0.3574080425574267, 0.8628558767968414),
(0.35740624923526854, -0.3574080425574267, 0.8628558767968414),
(-0.3574080425574267, -0.35740624923526854, 0.8628558767968414),
(-0.35740624923526854, 0.3574080425574267, 0.8628558767968414),
(-0.35740647831364963, -0.35740647831364963, -0.8628564298415289),
(-0.35740624923526854, 0.3574080425574267, -0.8628558767968414),
(0.3574080425574267, 0.35740624923526854, -0.8628558767968414),
(0.35740624923526854, -0.3574080425574267, -0.8628558767968414),
(0.8628558767968414, 0.3574080425574267, -0.35740624923526854),
(-0.8628564298415289, 0.35740647831364963, 0.35740647831364963),
(-0.3574083665235253, 0.8628548655932644, 0.3574083665235253),
(0.3574080425574267, 0.8628558767968414, 0.35740624923526854),
(0.8628558767968414, 0.3574080425574267, 0.35740624923526854),
(0.8628558767968414, -0.3574080425574267, 0.35740624923526854),
(0.3574083665235253, -0.8628548655932644, 0.3574083665235253),
(-0.35740624923526854, -0.8628558767968414, 0.3574080425574267),
(-0.8628548655932644, -0.3574083665235253, 0.3574083665235253),
(0.35740624923526854, -0.8628558767968414, -0.3574080425574267)
]
colors = (
(1,1,1),
(0,1,0),
(0,0,1),
(0,1,0),
(0,0,1),
(1,0,1),
(0,1,0),
(1,0,1),
(0,1,0),
(0,0,1),
)
edges = (
(16, 17),
(17, 18),
(18, 21),
(20, 21),
(3, 4),
(4, 16),
(7, 3),
(20, 7),
(0, 2),
(0, 9),
(0, 22),
(0, 8),
(11, 13),
(11, 12),
(11, 14),
(2, 3),
(8, 16),
(9, 18),
(22, 20),
(2, 1),
(1, 22),
(1, 7),
(5, 11),
(5, 15),
(15, 12),
(15, 7),
(5, 3),
(12, 20),
(16, 14),
(22, 23),
(23, 9),
(23, 21),
(13, 24),
(14, 24),
(17, 24),
(13, 25),
(12, 25),
(25, 21),
(13, 18),
(8, 6),
(2, 6),
(6, 4),
(10, 4),
(14, 10),
(5, 10),
(17, 19),
(19, 9),
(19, 8),
)
def Cube():
glBegin(GL_QUADS)
for i_surface, surface in enumerate(surfaces):
x = 0
glNormal3fv(normals[i_surface])
for vertex in surface:
#x+=1
glColor3fv(colors[x])
glVertex3fv(verticies[vertex])
glEnd()
glColor3fv(colors[0])
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(verticies[vertex])
glEnd()
def main():
global surfaces
pygame.init()
display = (800, 600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
clock = pygame.time.Clock()
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glMatrixMode(GL_MODELVIEW)
glTranslatef(0, 0, -5)
# Источник света - "от нас"
glLight(GL_LIGHT0, GL_POSITION, (0, 0, 1, 0.4))
# Ambient lighting
glLightfv(GL_LIGHT0, GL_AMBIENT, (0, 0, 0, 1))
# Diffuse lighting
glLightfv(GL_LIGHT0, GL_DIFFUSE, (0, 0.5, 0.1, 0))
#---------------------------------Specular Lighting------------It does not work!!!-----------
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (1,1,1,0))
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 128)
#--------------------------------------------------------------------------------------------
glEnable(GL_DEPTH_TEST)
while True:
# Обрабатываем события
for event in pygame.event.get():
# Если нажимаем крестик на окошке - выходим
if event.type == pygame.QUIT:
pygame.quit()
quit()
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_COLOR_MATERIAL)
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE )
#glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR)
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
glRotatef(10, 0, 1, 0)
elif keys[pygame.K_RIGHT]:
glRotatef(-10, 0, 1, 0)
elif keys[pygame.K_UP]:
glRotatef(10, 1, 0, 0)
elif keys[pygame.K_DOWN]:
glRotatef(-10, 1, 0, 0)
Cube()
glDisable(GL_LIGHT0)
glDisable(GL_LIGHTING)
glDisable(GL_COLOR_MATERIAL)
pygame.display.flip()
clock.tick(20)
if __name__ == '__main__':
main()
Everything in your code is correct. With the legacy OpenGL fixed function pipeline this is the best result you can get.
The fixed functions pipeline uses a Blinn–Phong reflection model. However, Gouraud Shading and not Phong Shading is used. While Phong Shading generally means the technique with which the light calculations are carried out per fragment, in Gouraud Shading the light calculations are carried out per vertex. The calculated light is interpolated along the (triangular) Primitives.
In the case of specular highlights, the light distribution is not linear and cannot be calculated with linear interpolation. The effect is distorted or is completely lost.
See what the difference between phong shading and gouraud shading? and OpenGL Lighting on texture plane is not working.
The lighting can be improved by tessellating the mesh in small triangles. This causes that the light is computed for more points (vertices) and the interpolation has less effect.
Nowadays the light is calculated per fragment (Phong shading). To do this, you need to implement a Shader program. See GLSL fixed function fragment program replacement.
Describing this all in detail would be way too broad for a single Stack Overflow answer. I recommend reading a good OpenGL tutorial. e.g.: Python Opengl (my favorite one is for c++ LearnOpenGL).
To implement Phong Shading for your specific legacy code, you need to write a version 1.10 GLSL shader. For a good example, see Per Fragment Lighting. You need to make some adjustments to the shader program in order for the color material to work.
Vertex shader
Fragment shader
Use PyOpenGLs
OpenGL.GL.shaders
module to compile and linke the shader:Install the shader and enable lighting before drawing the polygons and disable is before drawing the wireframe. e.g.:
Complete example: