如何使用 pygame 和 pyopengl 正确添加灯光以使对象获得更好的视野
Posted
技术标签:
【中文标题】如何使用 pygame 和 pyopengl 正确添加灯光以使对象获得更好的视野【英文标题】:How to correctly add a light to make object get a better view with pygame and pyopengl 【发布时间】:2019-06-09 13:00:04 【问题描述】:我正在关注https://pythonprogramming.net/opengl-pyopengl-python-pygame-tutorial/ 中提供的教程,他在其中教授如何使用 pyOpenGL 和 pygame 渲染立方体。
渲染立方体时,教程将颜色设置为立方体的所有顶点,然后显示。但是,在我的项目中,我使用https://www.pygame.org/wiki/OBJFileLoader 中提供的代码从 .obj 文件加载对象,并且我的大多数对象都是全白的。
结论:当我在屏幕上渲染时,我只能看到全白,非常难看。所以我坚持使用灯光来更好地观察物体,但我无法做到这一点。
我对 pyOpenGl 知之甚少,找不到更深入的教程。
这是教程中提供的部分代码和结果。 (顶点、边、曲面和颜色变量是元组的元组)
def Cube():
glBegin(GL_QUADS)
for surface in surfaces:
x = 0
for vertex in surface:
x+=1
glColor3fv(colors[x])
glVertex3fv(verticies[vertex])
glEnd()
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(verticies[vertex])
glEnd()
def main():
pygame.init()
display = (800,600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glTranslatef(0.0,0.0, -5)
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(1, 3, 1, 1)
Cube()
pygame.display.flip()
pygame.time.wait(10)
main()
我试图编辑 main 函数来插入一个简单的灯光,但是立方体中的颜色就消失了:
def main():
pygame.init()
display = (800,600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glTranslatef(0.0,0.0, -5)
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(1, 3, 1, 1)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glPushMatrix()
glTranslatef(0.0,0.0, 5)
glLight(GL_LIGHT0, GL_POSITION, (0, 1, 0, 1))
glLightfv(GL_LIGHT0, GL_AMBIENT, (0, 1.5, 1, 0))
glPopMatrix()
Cube()
glDisable(GL_LIGHT0)
glDisable(GL_LIGHTING)
pygame.display.flip()
pygame.time.wait(10)
我想要的是带有颜色并被灯光照亮的立方体。我的代码有什么问题以及如何解决?
【问题讨论】:
【参考方案1】:启用光照 (GL_LIGHTING
) 时,颜色取自材质参数 (glMaterial
)。
如果你仍然想使用当前颜色,你必须启用GL_COLOR_MATERIAL
并设置颜色材料参数(glColorMaterial
)。
环境光不依赖于光源的方向。您必须定义漫反射和/或镜面反射光。见glLightfv
:
当灯光位置由glLightfv(GL_LIGHT0, GL_POSITION, pos)
设置时,则位置乘以当前模型视图矩阵。所以必须在模型变换之前设置好世界空间中的光照位置。
在设置投影矩阵之前切换到矩阵模式GL_PROJECTION
。否则,灯光位置将乘以投影矩阵。
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)) # directional light from the front
glLight(GL_LIGHT0, GL_POSITION, (5, 5, 5, 1)) # point light from the left, top, front
glLightfv(GL_LIGHT0, GL_AMBIENT, (0, 0, 0, 1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (1, 1, 1, 1))
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 )
glRotatef(1, 3, 1, 1)
Cube()
glDisable(GL_LIGHT0)
glDisable(GL_LIGHTING)
glDisable(GL_COLOR_MATERIAL)
pygame.display.flip()
漫反射(和镜面反射)光取决于表面的Normal 向量。
定义一个法线向量元组数组(x, y, z)
。请注意,以下定义是一个示例。由于您绘制了一个有 6 个面的立方体,因此您必须定义 6 个法向量,但向量的方向取决于您的顶点坐标,我不知道。
normals = [
( 0, 0, -1), # surface 0
(-1, 0, 0), # surface 1
( 0, 1, 1), # surface 2
( 1, 0, 0), # surface 3
( 0, 1, 0), # surface 4
( 0, -1, 0) # surface 5
]
并在绘制对象时设置合适的法向量:
def Cube():
glBegin(GL_QUADS)
for i_surface, surface in enumerate(surfaces):
x = 0
glNormal3fv(normals[i_surface]) # set the normal vector the vertices of the 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()
启用Depth Test (glEnable(GL_DEPTH_TEST)
) 以获得如下动画:
完整示例代码:
import pygame
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,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 = (
(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()
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)) # directional light from the front
glLight(GL_LIGHT0, GL_POSITION, (5, 5, 5, 1)) # point light from the left, top, front
glLightfv(GL_LIGHT0, GL_AMBIENT, (0, 0, 0, 1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (1, 1, 1, 1))
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 )
glRotatef(1, 3, 1, 1)
Cube()
glDisable(GL_LIGHT0)
glDisable(GL_LIGHTING)
glDisable(GL_COLOR_MATERIAL)
pygame.display.flip()
clock.tick(60)
main()
【讨论】:
我还有一个问题。有没有办法设置光的强度?示例来指定白天和夜晚的灯光。我想在项目过程中改变强度。 @guilhermerodrigues 您必须动态更改灯光颜色 (glLightfv(GL_LIGHT0, GL_DIFFUSE, (1, 1, 1, 1))
)。例如glLightfv(GL_LIGHT0, GL_DIFFUSE, (0.5, 0.5, 0.5, 1))` 以一半的强度照亮。
我有一个问题。如何为复杂的 .obj 文件构造法线向量
@Bramanta 如果您有任何问题,请提出一个新的公开问题以上是关于如何使用 pygame 和 pyopengl 正确添加灯光以使对象获得更好的视野的主要内容,如果未能解决你的问题,请参考以下文章
如何在 PyOpenGL 中将 png 图像作为图像叠加层?