【问题标题】:OpenGL - 3D cube - Specular spot light not showing [duplicate]OpenGL - 3D 立方体 - 高光聚光灯不显示 [重复]
【发布时间】:2021-01-29 12:31:43
【问题描述】:

我最近开始通过 pyOpenGL 学习 OpenGL,我一直在为很多概念而苦苦挣扎,尤其是照明。

感谢tutorial,我设法创建了一个 3D 立方体,我希望通过适当的照明使它看起来更好。我特别发现镜面光产生的聚光灯,它为立方体提供了光泽的外观。

期望的输出(其中之一,拍摄here

这是我对灯光的处理

glLight(GL_LIGHT0, GL_POSITION,  (1.1, 0., .3, 1))  # point light
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_COLOR_MATERIAL)

... draw cube ...
glMaterialfv(GL_FRONT, GL_SPECULAR, (1, 1, 1, 1))
glMaterialfv(GL_FRONT, GL_SHININESS, 1)
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)

到目前为止我所拥有的

如果尝试增加光泽度但高于约 30,则所有灯光效果都会消失。 任何帮助将不胜感激,或者只是好的文档(最好使用 pyOpenGL,并且不使用顶点/片段着色器)。

谢谢!

如果需要完整代码:

import pygame
from OpenGL.GL import shaders
from pygame.locals import *

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

verticies = (
    ( 1, -1, -1), # 0
    ( 1,  1, -1), # 1
    (-1,  1, -1), # 2
    (-1, -1, -1), # 3
    ( 1, -1,  1), # 4
    ( 1,  1,  1), # 5
    (-1, -1,  1), # 6
    (-1,  1,  1), # 7
    )

surfaces = (
    (0,1,2,3),
    (3,2,7,6),
    (6,7,5,4),
    (4,5,1,0),
    (1,5,7,2),
    (4,0,3,6),
    )

normals = [
    ( 0,  0, -1),  # surface 0
    (-1,  0,  0),  # surface 1
    ( 0,  0,  1),  # surface 2
    ( 1,  0,  0),  # surface 3
    ( 0,  1,  0),  # surface 4
    ( 0, -1,  0)   # surface 5
]

colors = [(1, 0.2, 0)] * 12

edges = (
    (0,1),
    (0,3),
    (0,4),
    (2,1),
    (2,3),
    (2,7),
    (6,3),
    (6,4),
    (6,7),
    (5,1),
    (5,4),
    (5,7),
    )


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

    glMaterialfv(GL_FRONT, GL_SPECULAR, (1, 1, 1, 1))
    glMaterialfv(GL_FRONT, GL_SHININESS, 1)
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)


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)
    # glRotatef(20, 1, 0, 0)

    glLight(GL_LIGHT0, GL_POSITION,  (1.1, 0., .3, 1))  # point light
    # glLightfv(GL_LIGHT0, GL_AMBIENT, (0, 0, 1, 1))
    # glLightfv(GL_LIGHT0, GL_DIFFUSE, (1, 1, 1, 1))

    glEnable(GL_LIGHTING)
    glEnable(GL_LIGHT0)
    glEnable(GL_COLOR_MATERIAL)

    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)

        glRotatef(0.2, 0, 1, 0)
        Cube()

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

main()

【问题讨论】:

  • 您在尝试实现的示例中看到的是每个片段(或每个像素)照明,您需要着色器来执行此操作。通过在此处使用固定管道,您将绑定到“每个顶点”光照。

标签: python opengl pyopengl light


【解决方案1】:

使用已弃用的 OpenGL 光照模式无法获得您想要的效果。与 Phong shading 相比,OpenGL Blinn–Phong 反射模型使用 Gouraud shading。在 Gouraud 着色时,光是按顶点计算的(顶点着色器),而在 Phong 着色时,光是按片段计算的(片段着色器)。见what the difference between phong shading and gouraud shading?
但是,通过镶嵌立方体的侧面可以获得更好的效果。

如果要实现Phong shading,则需要使用着色器程序。见GLSL fixed function fragment program replacement

完整示例:

import os 
import math 
import ctypes 
import glm 
from OpenGL.GLUT import *
from OpenGL.GL import *
from OpenGL.GL.shaders import *
from OpenGL.arrays import *

class MyWindow:

    __glsl_vert = """
        #version 450 core

        layout (location = 0) in vec3 a_pos;
        layout (location = 1) in vec3 a_nv;
        layout (location = 2) in vec4 a_col;

        out vec3 v_pos;
        out vec3 v_nv;
        out vec4 v_color;

        uniform mat4 u_proj; 
        uniform mat4 u_view; 
        uniform mat4 u_model; 

        void main()
        {
            mat4 model_view = u_view * u_model;
            mat3 normal     = transpose(inverse(mat3(model_view)));
            
            vec4 view_pos   = model_view * vec4(a_pos.xyz, 1.0);

            v_pos       = view_pos.xyz;
            v_nv        = normal * a_nv;  
            v_color     = a_col;
            gl_Position = u_proj * view_pos;
        }
    """

    __glsl_frag = """
        #version 450 core
        
        out vec4 frag_color;
        in  vec3 v_pos;
        in  vec3 v_nv;
        in  vec4 v_color;

        void main()
        {
            vec3  L     = normalize(vec3(0.0, 0.0, 1.0));
            vec3  N     = normalize(v_nv);
            vec3  V     = -normalize(v_pos);
            vec3  H     = normalize(V + L);
            float ka    = 0.1;
            float kd    = max(0.0, dot(N, L)) * 0.1;
            float NdotH = max(0.0, dot(N, H));
            float sh    = 100.0;
            float ks    = pow(NdotH, sh);
            frag_color  = vec4(v_color.rgb * (ka + kd + ks), v_color.a);
        }
    """

    def __init__(self, w, h):
        
        self.__caption = 'OpenGL Window'
        self.__vp_valid = False
        self.__vp_size = [w, h]

        glutInit()
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
        glutInitWindowSize(self.__vp_size[0], self.__vp_size[1])
        self.__glut_wnd = glutCreateWindow(self.__caption)

        self.__program = compileProgram( 
            compileShader( self.__glsl_vert, GL_VERTEX_SHADER ),
            compileShader( self.__glsl_frag, GL_FRAGMENT_SHADER ),
        )
        self.___attrib = { a : glGetAttribLocation (self.__program, a) for a in ['a_pos', 'a_nv', 'a_col'] }
        print(self.___attrib)
        self.___uniform = { u : glGetUniformLocation (self.__program, u) for u in ['u_model', 'u_view', 'u_proj'] }
        print(self.___uniform)

        v = [[-1,-1,1], [1,-1,1], [1,1,1], [-1,1,1], [-1,-1,-1], [1,-1,-1], [1,1,-1], [-1,1,-1]]
        c = [[1.0, 0.0, 0.0], [1.0, 0.5, 0.0], [1.0, 0.0, 1.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]
        n = [[0,0,1], [1,0,0], [0,0,-1], [-1,0,0], [0,1,0], [0,-1,0]]
        e = [[0,1,2,3], [1,5,6,2], [5,4,7,6], [4,0,3,7], [3,2,6,7], [1,0,4,5]]
        index_array = [si*4+[0, 1, 2, 0, 2, 3][vi] for si in range(6) for vi in range(6)]
        attr_array = []
        for si in range(len(e)):
            for vi in e[si]:
                attr_array += [*v[vi], *n[si], *c[si], 1]
        
        self.__no_vert = len(attr_array) // 10
        self.__no_indices = len(index_array)
        vertex_attributes = (ctypes.c_float * len(attr_array))(*attr_array)
        indices = (ctypes.c_uint32 * self.__no_indices)(*index_array)
        
        self.__vao = glGenVertexArrays(1)
        self.__vbo, self.__ibo = glGenBuffers(2)
        
        glBindVertexArray(self.__vao)

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.__ibo)
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW)

        glBindBuffer(GL_ARRAY_BUFFER, self.__vbo)
        glBufferData(GL_ARRAY_BUFFER, vertex_attributes, GL_STATIC_DRAW)

        float_size = ctypes.sizeof(ctypes.c_float)   
        glVertexAttribPointer(0, 3, GL_FLOAT, False, 10*float_size, None)
        glVertexAttribPointer(1, 3, GL_FLOAT, False, 10*float_size, c_void_p(3*float_size))
        glVertexAttribPointer(2, 4, GL_FLOAT, False, 10*float_size, c_void_p(6*float_size))
        glEnableVertexAttribArray(0)
        glEnableVertexAttribArray(1)
        glEnableVertexAttribArray(2)

        glEnable(GL_DEPTH_TEST)
        glUseProgram(self.__program)

        glutReshapeFunc(self.__reshape)
        glutDisplayFunc(self.__mainloop)

    def run(self):
        self.__starttime = 0
        self.__starttime = self.elapsed_ms()
        glutMainLoop()

    def elapsed_ms(self):
      return glutGet(GLUT_ELAPSED_TIME) - self.__starttime

    def __reshape(self, w, h):
        self.__vp_valid = False

    def __mainloop(self):

        if not self.__vp_valid:
            self.__vp_size = [glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)]
            self.__vp_valid = True
            glViewport(0, 0, self.__vp_size[0], self.__vp_size[1])

        proj  = glm.mat4(1)
        view  = glm.mat4(1)
        model = glm.mat4(1)

        aspect = self.__vp_size[0]/self.__vp_size[1]
        proj = glm.perspective(glm.radians(90.0), aspect, 0.1, 10.0)

        view = glm.lookAt(glm.vec3(0,-3,0), glm.vec3(0, 0, 0), glm.vec3(0,0,1))
        
        angle1 = self.elapsed_ms() * math.pi * 2 / 5000.0
        angle2 = self.elapsed_ms() * math.pi * 2 / 7333.0
        model = glm.rotate(model, angle1, glm.vec3(1, 0, 0))
        model = glm.rotate(model, angle2, glm.vec3(0, 1, 0))

        glUniformMatrix4fv(self.___uniform['u_proj'], 1, GL_FALSE, glm.value_ptr(proj) )
        glUniformMatrix4fv(self.___uniform['u_view'], 1, GL_FALSE, glm.value_ptr(view) )
        glUniformMatrix4fv(self.___uniform['u_model'], 1, GL_FALSE, glm.value_ptr(model) )

        glClearColor(0.2, 0.3, 0.3, 1.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
          
        glDrawElements(GL_TRIANGLES, self.__no_indices, GL_UNSIGNED_INT, None)

        glutSwapBuffers()
        glutPostRedisplay()


window = MyWindow(800, 600)
window.run()

另见Python, OpenGL 4.6, Cube

【讨论】:

  • 感谢所有文档 :)
猜你喜欢
  • 1970-01-01
  • 2020-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-14
相关资源
最近更新 更多