opengl 漫射光变得奇怪的方向,但不会根据 GL_SPOT_DIRECTION 改变

问题描述

我正在三角形条(立方体)上使用 opengl 做一些非常简单的漫射照明。然后我尝试添加一些旋转,一切都消失了。

这是一个 MRE:

import pygame
pygame.init()
from OpenGL import GL
from OpenGL import glu
import math
import numpy as np
import copy

def Rec(r,angle):
    x = r*math.cos(angle)
    y = r*math.sin(angle)
    return x,y

def Pol(x,y):
    r = (x**2 + y**2)**(1/2)
    angle = math.atan2(y,x)
    return r,angle

class Cube:
    def __init__(self,pos,size,color):
        self.identity_vertices = np.array(((0.5,0.5,0.5),(-0.5,(0.5,-0.5,-0.5),-0.5)))
        self.redefine(pos,color)
        
    def draw(self):
        GL.glMaterialfv(GL.GL_FRONT_AND_BACK,GL.GL_DIFFUSE,self.color)
        
        GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
        data = (GL.GLfloat * len(self.vertices))(*self.vertices)
        GL.glVertexPointer(3,GL.GL_FLOAT,data)
        GL.glDrawArrays(GL.GL_TRIANGLE_STRIP,14)
        GL.gldisableClientState(GL.GL_VERTEX_ARRAY)

    def update(self):
        self.vertices = copy.copy(self.identity_vertices)
        self.vertices*=self._size
        self.vertices+=self._pos
        self.vertices=self.vertices.flatten()

    def redefine(self,color):
        self._pos = [*pos]
        self._size = [*size]
        self.color = color

        self.update()

display = (600,500)

screen = pygame.display.set_mode(display,pygame.DOUBLEBUF|pygame.OPENGL)

GL.glEnable(GL.GL_DEPTH_TEST)
GL.glEnable(GL.GL_LIGHTING)
GL.glEnable(GL.GL_LIGHT0)
GL.glLightfv(GL.GL_LIGHT0,(1.0,1.0,1.0))
GL.glLightfv(GL.GL_LIGHT0,GL.GL_AMBIENT,(0.1,0.1,1.0))

GL.glMatrixMode(GL.GL_PROJECTION)
GL.glLoadIdentity()

glu.gluPerspective(60,(display[0]/display[1]),100.0)

c = Cube((0,0),(2,2,2),(0.0,1.0))

pos = [0,8,0]

rot = math.pi

run = 1
clock = pygame.time.Clock()
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = 0
    pressed = pygame.key.get_pressed()
    if pressed[pygame.K_LEFT]:
        rot += 0.1
    if pressed[pygame.K_RIGHT]:
        rot -= 0.1

    pos[0],pos[2] = Rec(8,rot)

    GL.glMatrixMode(GL.GL_MODELVIEW)
    GL.glLoadIdentity()

    GL.glLightfv(GL.GL_LIGHT0,GL.GL_POSITION,pos)
    GL.glLightfv(GL.GL_LIGHT0,GL.GL_SPOT_DIRECTION,[*map(lambda x: math.copysign(1,-x),pos)])
    
    glu.gluLookAt(*pos,1,0)

    GL.glClearColor(0,1)
    GL.glClear(GL.GL_COLOR_BUFFER_BIT|GL.GL_DEPTH_BUFFER_BIT)
    
    c.draw()
    
    pygame.display.flip()
    clock.tick(60)
    
pygame.quit()

我的问题是光照是均匀的,整个立方体都是灰色或青色(或介于两者之间),并且没有提供渐变。此外,立方体通常是完全黑暗的,它只在特定旋转时显示。您可以通过使用左右箭头键围绕立方体旋转来重现此问题

运行一些测试后,我发现立方体唯一点亮的时间是相机相对于立方体位于负 z 方向时。这是有道理的,因为文档声明照明的认方向是 (0,1)。然后我尝试通过更改 GL_SPOT_DIRECTION解决这个问题,以适应这一点,但无济于事,因为这没有改变任何东西。而且,我正在使用漫射照明,它根本不应该有方向

为什么漫射照明会出现这种奇怪的方向性(如果这就是问题所在,那可能是完全不同的东西,这正是我诊断的情况),我该如何解决这个问题?

解决方法

如果您使用 OpenGL 固定功能管道,则可能需要调用 glEnable(GL_NORMALIZE)。这将标准化您作为图形管道输入的每个法线(即您要绘制)。

通常,如果你知道你的法线是什么并且被正确绑定,你不需要这种显式的规范化。

主要是,要创建一个对象,您需要:

glBegin(GL_TRIANGLES);
{
    glNormal3f(nx,ny,nz);
    glColor3f(cx,cy,cz);
    glVertex3f(vx,vy,vz);
    
    // Here you add your vertices that you might want to draw in triangles
    // 3 x vertices per triangle
    ...
}
glEnd();

多维数据集使用 GL_QUADS 可能更容易:

glBegin(GL_QUADS);
{
    glNormal3f(nx,vz);
    
    // Here you add your vertices that you might want to draw in quads.
    // 4 x vertices per quad
    ...
}
glEnd();