问题描述
我最近开始通过 pyOpenGL 学习 OpenGL,但我一直在为很多概念而苦苦挣扎,尤其是光照。
多亏了这个tutorial,我成功地创建了一个 3D 立方体,并且我想让它在适当的照明下看起来更好。我特别喜欢镜面反射光产生的聚光灯,它为立方体提供了光泽。
这是我用灯光做的事情
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)
如果尝试增加光泽但高于 ~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()