OpenGL - 3D 立方体 - 镜面聚光灯未显示

问题描述

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

多亏了这个tutorial,我成功地创建了一个 3D 立方体,并且我想让它在适当的照明下看起来更好。我特别喜欢镜面反射光产生的聚光灯,它为立方体提供了光泽。

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

enter image description 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))
glMaterialfv(GL_FRONT,GL_SHINInesS,1)
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE)

到目前为止我所拥有的

what I have so far

如果尝试增加光泽但高于 ~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,# 2
    (-1,# 3
    ( 1,1),# 4
    ( 1,# 5
    (-1,# 6
    (-1,# 7
    )

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

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

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

edges = (
    (0,(0,(2,7),(5,)


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,1))
    glMaterialfv(GL_FRONT,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,-5)
    # glrotatef(20,0)

    glLight(GL_LIGHT0,1))  # point light
    # glLightfv(GL_LIGHT0,GL_AMBIENT,1))
    # glLightfv(GL_LIGHT0,GL_DIFFUSE,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)
        Cube()

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

main()

解决方法

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

如果要实现Phong shading,需要使用shader程序。见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,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]]
        c = [[1.0,0.0],[1.0,0.5,1.0],1.0,[0.0,1.0]]
        n = [[0,0],[0,0]]
        e = [[0,2,3],5,6,2],[5,4,7,6],[4,3,7],[3,5]]
        index_array = [si*4+[0,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,GL_FLOAT,False,10*float_size,None)
        glVertexAttribPointer(1,c_void_p(3*float_size))
        glVertexAttribPointer(2,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,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,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,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))
        model = glm.rotate(model,angle2,0))

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

        glClearColor(0.2,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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...