【问题标题】:How to make specular lighting on python to implement the Phong lighting?如何在 python 上制作镜面光照来实现 Phong 光照?
【发布时间】:2021-08-05 06:11:27
【问题描述】:

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

我用过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()

【问题讨论】:

    标签: python opengl pyopengl phong specular


    【解决方案1】:

    您的代码中的所有内容都是正确的。使用旧版 OpenGL 固定功能管道,这是您可以获得的最佳结果。
    固定功能管道使用Blinn–Phong reflection model。但是,使用了Gouraud Shading 而不是Phong Shading。虽然 Phong 着色通常是指对每个片段进行光计算的技术,但在 Gouraud 着色中,光计算是对每个顶点进行的。计算出的光线沿(三角形)Primitives 进行插值。
    在镜面高光的情况下,光分布不是线性的,不能用线性插值计算。效果失真或完全丢失。
    请参阅what the difference between phong shading and gouraud shading?OpenGL Lighting on texture plane is not working

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

    如今,光是按片段计算的(Phong 着色)。为此,您需要实现一个Shader 程序。见GLSL fixed function fragment program replacement

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


    要为您的特定遗留代码实现 Phong 着色,您需要编写一个 version 1.10 GLSL 着色器。一个很好的例子,请参阅Per Fragment Lighting。您需要对着色器程序进行一些调整才能使颜色材料正常工作。

    顶点着色器

    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; 
    }
    

    使用 PyOpenGLs OpenGL.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()
    

    【讨论】:

    猜你喜欢
    • 2020-07-24
    • 2012-10-28
    • 2018-06-18
    • 1970-01-01
    • 1970-01-01
    • 2015-01-31
    • 2013-11-29
    • 2011-12-27
    • 1970-01-01
    相关资源
    最近更新 更多