2

我需要你的帮助。使用 python,我必须通过 phong 模型实现我的 3D 形状的照明。我的图是一个三角形的二十面体。我能够构建这个形状,找到顶点的坐标,并计算出每个面的法线。

我用过pygame,pyopengl。

为了实现 phong 光照模型,我设法制作了环境光照和漫反射光照,但我不知道要使用哪些函数来实现镜面光照。

我试图用不同的参数应用诸如 glMaterialfv() 之类的函数,但对我来说没有用。

这是我的代码:

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()
4

1 回答 1

4

您的代码中的所有内容都是正确的。使用传统的 OpenGL 固定功能管道,这是您可以获得的最佳结果。
固定函数管道使用Blinn-Phong 反射模型。但是,使用Gouraud 着色而不是Phong 着色。虽然 Phong 着色通常意味着对每个片段进行光计算的技术,但在 Gouraud 着色中,光计算是对每个顶点进行的。计算的光沿(三角形)Primitives插值。
在镜面高光的情况下,光分布不是线性的,不能用线性插值计算。效果失真或完全丢失。
phong shading 和 gouraud shading 有什么区别?并且纹理平面上的 OpenGL 照明不起作用

可以通过将网格细分为小三角形来改善照明。这会导致计算更多点(顶点)的光,并且插值的影响较小。

现在,光是按片段计算的(Phong 着色)。为此,您需要实现一个Shader程序。请参阅GLSL 固定功能片段程序替换

对于单个 Stack Overflow 答案来说,详细描述这一切将过于宽泛。我建议阅读一个好的 OpenGL 教程。例如:Python Opengl(我最喜欢的是 c++ LearnOpenGL)。


要为您的特定遗留代码实现 Phong 着色,您需要编写1.10 版 GLSL着色器。有关一个很好的示例,请参阅每片段照明。您需要对着色器程序进行一些调整才能使颜色材料起作用。

顶点着色器

varying vec3 vN;
varying vec3 v;
varying vec4 color;
void main(void)  
{     
   v = vec3(gl_ModelViewMatrix * gl_Vertex);       
   vN = normalize(gl_NormalMatrix * gl_Normal);
   color = gl_Color;
   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;  
}

片段着色器

varying vec3 vN;
varying vec3 v; 
varying vec4 color;
#define MAX_LIGHTS 1 
void main (void) 
{ 
   vec3 N = normalize(vN);
   vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0);
   
   for (int i=0;i<MAX_LIGHTS;i++)
   {
      vec3 L = normalize(gl_LightSource[i].position.xyz - v); 
      vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0) 
      vec3 R = normalize(-reflect(L,N)); 
   
      vec4 Iamb = gl_LightSource[i].ambient; 
      vec4 Idiff = gl_LightSource[i].diffuse * max(dot(N,L), 0.0);
      Idiff = clamp(Idiff, 0.0, 1.0); 
      vec4 Ispec = gl_LightSource[i].specular * pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);
      Ispec = clamp(Ispec, 0.0, 1.0); 
   
      finalColor += Iamb + Idiff + Ispec;
   }
   gl_FragColor = color * finalColor; 
}

使用 PyOpenGLsOpenGL.GL.shaders模块编译和链接着色器:

def main():
    global surfaces, program

    pygame.init()
    display = (800, 600)
    pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
    clock = pygame.time.Clock()

    program = compileProgram( 
        compileShader(vertex_shader, GL_VERTEX_SHADER),
        compileShader(fragment_shader, GL_FRAGMENT_SHADER))

    # [...]

在绘制多边形之前安装着色器并启用照明,在绘制线框之前禁用。例如:

def Cube():

    glEnable(GL_POLYGON_OFFSET_FILL)
    glPolygonOffset(1.0, 1.0)
    glEnable(GL_LIGHTING)  

    glUseProgram(program)
    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()

    glDisable(GL_LIGHTING)
    glDisable(GL_POLYGON_OFFSET_FILL)

    glUseProgram(0)
    glColor3fv(colors[0])
    glBegin(GL_LINES)
    for edge in edges:
        for vertex in edge:
            glVertex3fv(verticies[vertex])
    glEnd()

完整示例:

import pygame
from pygame.locals import *

from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GL.shaders import *

vertex_shader = """
varying vec3 vN;
varying vec3 v;
varying vec4 color;
void main(void)  
{     
   v = vec3(gl_ModelViewMatrix * gl_Vertex);       
   vN = normalize(gl_NormalMatrix * gl_Normal);
   color = gl_Color;
   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;  
}
"""

fragment_shader = """
varying vec3 vN;
varying vec3 v; 
varying vec4 color;
#define MAX_LIGHTS 1 
void main (void) 
{ 
   vec3 N = normalize(vN);
   vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0);
   
   for (int i=0;i<MAX_LIGHTS;i++)
   {
      vec3 L = normalize(gl_LightSource[i].position.xyz - v); 
      vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0) 
      vec3 R = normalize(-reflect(L,N)); 
   
      vec4 Iamb = gl_LightSource[i].ambient; 
      vec4 Idiff = gl_LightSource[i].diffuse * max(dot(N,L), 0.0);
      Idiff = clamp(Idiff, 0.0, 1.0); 
      vec4 Ispec = gl_LightSource[i].specular * pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);
      Ispec = clamp(Ispec, 0.0, 1.0); 
   
      finalColor += Iamb + Idiff + Ispec;
   }
   gl_FragColor = color * finalColor; 
}
"""

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():

    glEnable(GL_POLYGON_OFFSET_FILL)
    glPolygonOffset(1.0, 1.0)
    glEnable(GL_LIGHTING)  

    glUseProgram(program)
    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()

    glDisable(GL_LIGHTING)
    glDisable(GL_POLYGON_OFFSET_FILL)

    glUseProgram(0)
    glColor3fv(colors[0])
    glBegin(GL_LINES)
    for edge in edges:
        for vertex in edge:
            glVertex3fv(verticies[vertex])
    glEnd()


def main():
    global surfaces, program

    pygame.init()
    display = (800, 600)
    pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
    clock = pygame.time.Clock()

    program = compileProgram( 
        compileShader(vertex_shader, GL_VERTEX_SHADER),
        compileShader(fragment_shader, GL_FRAGMENT_SHADER))

    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.2, 0.2, 0.2, 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(5, 0, 1, 0)
        elif keys[pygame.K_RIGHT]:
            glRotatef(-5, 0, 1, 0)
        elif keys[pygame.K_UP]:
            glRotatef(5, 1, 0, 0)
        elif keys[pygame.K_DOWN]:
            glRotatef(-5, 1, 0, 0)

        Cube()

        glDisable(GL_LIGHT0)
        glDisable(GL_LIGHTING)
        glDisable(GL_COLOR_MATERIAL)

        pygame.display.flip()
        clock.tick(60)

if __name__ == '__main__':
    main()
于 2021-05-15T09:22:10.487 回答