我需要你的帮助。使用python,我必须通过phong模型实现我的三维形状的照明。我的图是一个三角形的二十四面体。我能够构建这个形状,找到顶点的坐标,还计算了每个面的法线。
我使用了 pygame、pyopengl。
为了实现 phong 光照模型,我设法制作了环境光照和漫射光照,但我不知道镜面光照使用什么函数。
我尝试应用具有不同参数的 glMaterialfv() 等函数,但它对我不起作用。
这是我的代码:
:
答案 0 :(得分:2)
您的代码中的所有内容都是正确的。使用旧的 OpenGL 固定功能管道,这是您可以获得的最佳结果。
固定函数管道使用 Blinn–Phong reflection model。但是,使用的是 Gouraud Shading 而不是 Phong Shading。虽然 Phong Shading 通常是指按片段执行光计算的技术,但在 Gouraud Shading 中,光计算是按顶点执行的。计算出的光沿(三角形)Primitives进行插值。
在镜面高光的情况下,光分布不是线性的,不能用线性插值计算。效果失真或完全消失。
请参阅 what the difference between phong shading and gouraud shading? 和 OpenGL Lighting on texture plane is not working。
可以通过将网格细分为小三角形来改善照明。这会导致为更多的点(顶点)计算光并且插值的影响较小。
如今,光是按片段计算的(Phong 着色)。为此,您需要实现一个 Shader 程序。见GLSL fixed function fragment program replacement。
详细描述这一切对于单一的 Stack Overflow 答案来说太宽泛了。我建议阅读一个好的 OpenGL 教程。例如:Python Opengl(我最喜欢的是 C++ LearnOpenGL)。
要为您的特定遗留代码实现 Phong 着色,您需要编写一个 version 1.10 GLSL 着色器。有关一个很好的示例,请参阅 Per Fragment Lighting。您需要对着色器程序进行一些调整,以使颜色材料起作用。
顶点着色器
varying vec3 vN;
varying vec3 v;
varying vec4 color;
void main(void)
{
v = vec3(gl_ModelViewMatrix * gl_Vertex);
vN = normalize(gl_NormalMatrix * gl_Normal);
color = gl_Color;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
片段着色器
varying vec3 vN;
varying vec3 v;
varying vec4 color;
#define MAX_LIGHTS 1
void main (void)
{
vec3 N = normalize(vN);
vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0);
for (int i=0;i<MAX_LIGHTS;i++)
{
vec3 L = normalize(gl_LightSource[i].position.xyz - v);
vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0)
vec3 R = normalize(-reflect(L,N));
vec4 Iamb = gl_LightSource[i].ambient;
vec4 Idiff = gl_LightSource[i].diffuse * max(dot(N,L), 0.0);
Idiff = clamp(Idiff, 0.0, 1.0);
vec4 Ispec = gl_LightSource[i].specular * pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);
Ispec = clamp(Ispec, 0.0, 1.0);
finalColor += Iamb + Idiff + Ispec;
}
gl_FragColor = color * finalColor;
}
使用 PyOpenGLs OpenGL.GL.shaders
模块编译和链接着色器:
def main():
global surfaces, program
pygame.init()
display = (800, 600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
clock = pygame.time.Clock()
program = compileProgram(
compileShader(vertex_shader, GL_VERTEX_SHADER),
compileShader(fragment_shader, GL_FRAGMENT_SHADER))
# [...]
在绘制多边形之前安装着色器并启用照明,并在绘制线框之前禁用。例如:
def Cube():
glEnable(GL_POLYGON_OFFSET_FILL)
glPolygonOffset(1.0, 1.0)
glEnable(GL_LIGHTING)
glUseProgram(program)
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()
glDisable(GL_LIGHTING)
glDisable(GL_POLYGON_OFFSET_FILL)
glUseProgram(0)
glColor3fv(colors[0])
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(verticies[vertex])
glEnd()
完整示例:
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GL.shaders import *
vertex_shader = """
varying vec3 vN;
varying vec3 v;
varying vec4 color;
void main(void)
{
v = vec3(gl_ModelViewMatrix * gl_Vertex);
vN = normalize(gl_NormalMatrix * gl_Normal);
color = gl_Color;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
"""
fragment_shader = """
varying vec3 vN;
varying vec3 v;
varying vec4 color;
#define MAX_LIGHTS 1
void main (void)
{
vec3 N = normalize(vN);
vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0);
for (int i=0;i<MAX_LIGHTS;i++)
{
vec3 L = normalize(gl_LightSource[i].position.xyz - v);
vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0)
vec3 R = normalize(-reflect(L,N));
vec4 Iamb = gl_LightSource[i].ambient;
vec4 Idiff = gl_LightSource[i].diffuse * max(dot(N,L), 0.0);
Idiff = clamp(Idiff, 0.0, 1.0);
vec4 Ispec = gl_LightSource[i].specular * pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);
Ispec = clamp(Ispec, 0.0, 1.0);
finalColor += Iamb + Idiff + Ispec;
}
gl_FragColor = color * finalColor;
}
"""
verticies = (
(0, - 0, 1.15894198417663574),
(0.63384598493576048, -0.63384598493576048, 0.63384598493576048),
(0.81949597597122192, 0, 0.81949597597122192),
(1.15894198417663574, 0, -0),
(0.81949597597122192, 0.81949597597122192, -0),
(0.81949597597122192, 0, -0.81949597597122192),
(0.63384598493576048, 0.63384598493576048, 0.63384598493576048),
(0.81949597597122192, -0.81949597597122192, 0),
(-0, 0.81949597597122192, 0.81949597597122192),
(-0.81949597597122192, 0, 0.81949597597122192),
(0.63384598493576048, 0.63384598493576048, -0.63384598493576048),
(0, 0, -1.15894198417663574),
(0, -0.81949597597122192, -0.81949597597122192),
(-0.81949597597122192, 0, -0.81949597597122192),
(0, 0.81949597597122192, -0.81949597597122192),
(0.63384598493576048, -0.63384598493576048, -0.63384598493576048),
(-0, 1.15894198417663574, 0),
(-0.81949597597122192, 0.81949597597122192, 0),
(-1.15894198417663574, 0, 0),
(-0.63384598493576048, 0.63384598493576048, 0.63384598493576048),
(0, -1.15894198417663574, 0),
(-0.81949597597122192, -0.81949597597122192, 0),
(0, -0.81949597597122192, 0.81949597597122192),
(-0.63384598493576048, -0.63384598493576048, 0.63384598493576048),
(-0.63384598493576048, 0.63384598493576048, -0.63384598493576048),
(-0.63384598493576048, -0.63384598493576048, -0.63384598493576048),
)
surfaces = (
(20, 21, 25, 12),
(21, 25, 13, 18),
(17, 24, 14, 16),
(18, 13, 24, 17),
(16, 14, 10, 4),
(3, 5, 15, 7),
(0, 2, 6, 8),
(0, 2, 1, 22),
(0, 22, 23, 9),
(0, 9, 19, 8),
(13, 11, 12, 25),
(11, 13, 24, 14),
(11, 14, 10, 5),
(11, 5, 15, 12),
(3, 5, 10, 4),
(17, 18, 9, 19),
(17, 19, 8, 16),
(16, 8, 6, 4),
(3, 2, 6, 4),
(3, 2, 1, 7),
(7, 1, 22, 20),
(20, 21, 23, 22),
(9, 23, 21, 18),
(15, 7, 20, 12),
)
normals = [
(-0.35740624923526854, -0.8628558767968414, -0.3574080425574267),
(-0.8628548655932644, -0.3574083665235253, -0.3574083665235253),
(-0.3574083665235253, 0.8628548655932644, -0.3574083665235253),
(-0.8628558767968414, 0.3574080425574267, -0.35740624923526854),
(0.3574080425574267, 0.8628558767968414, -0.35740624923526854),
(0.8628558767968414, -0.3574080425574267, -0.35740624923526854),
(0.35740624923526854, 0.3574080425574267, 0.8628558767968414),
(0.35740624923526854, -0.3574080425574267, 0.8628558767968414),
(-0.3574080425574267, -0.35740624923526854, 0.8628558767968414),
(-0.35740624923526854, 0.3574080425574267, 0.8628558767968414),
(-0.35740647831364963, -0.35740647831364963, -0.8628564298415289),
(-0.35740624923526854, 0.3574080425574267, -0.8628558767968414),
(0.3574080425574267, 0.35740624923526854, -0.8628558767968414),
(0.35740624923526854, -0.3574080425574267, -0.8628558767968414),
(0.8628558767968414, 0.3574080425574267, -0.35740624923526854),
(-0.8628564298415289, 0.35740647831364963, 0.35740647831364963),
(-0.3574083665235253, 0.8628548655932644, 0.3574083665235253),
(0.3574080425574267, 0.8628558767968414, 0.35740624923526854),
(0.8628558767968414, 0.3574080425574267, 0.35740624923526854),
(0.8628558767968414, -0.3574080425574267, 0.35740624923526854),
(0.3574083665235253, -0.8628548655932644, 0.3574083665235253),
(-0.35740624923526854, -0.8628558767968414, 0.3574080425574267),
(-0.8628548655932644, -0.3574083665235253, 0.3574083665235253),
(0.35740624923526854, -0.8628558767968414, -0.3574080425574267)
]
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 = (
(16, 17),
(17, 18),
(18, 21),
(20, 21),
(3, 4),
(4, 16),
(7, 3),
(20, 7),
(0, 2),
(0, 9),
(0, 22),
(0, 8),
(11, 13),
(11, 12),
(11, 14),
(2, 3),
(8, 16),
(9, 18),
(22, 20),
(2, 1),
(1, 22),
(1, 7),
(5, 11),
(5, 15),
(15, 12),
(15, 7),
(5, 3),
(12, 20),
(16, 14),
(22, 23),
(23, 9),
(23, 21),
(13, 24),
(14, 24),
(17, 24),
(13, 25),
(12, 25),
(25, 21),
(13, 18),
(8, 6),
(2, 6),
(6, 4),
(10, 4),
(14, 10),
(5, 10),
(17, 19),
(19, 9),
(19, 8),
)
def Cube():
glEnable(GL_POLYGON_OFFSET_FILL)
glPolygonOffset(1.0, 1.0)
glEnable(GL_LIGHTING)
glUseProgram(program)
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()
glDisable(GL_LIGHTING)
glDisable(GL_POLYGON_OFFSET_FILL)
glUseProgram(0)
glColor3fv(colors[0])
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(verticies[vertex])
glEnd()
def main():
global surfaces, program
pygame.init()
display = (800, 600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
clock = pygame.time.Clock()
program = compileProgram(
compileShader(vertex_shader, GL_VERTEX_SHADER),
compileShader(fragment_shader, GL_FRAGMENT_SHADER))
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.4))
# Ambient lighting
glLightfv(GL_LIGHT0, GL_AMBIENT, (0.2, 0.2, 0.2, 1))
# Diffuse lighting
glLightfv(GL_LIGHT0, GL_DIFFUSE, (0, 0.5, 0.1, 0))
#---------------------------------Specular Lighting------------It does not work!!!-----------
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (1,1,1,0))
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 128)
#--------------------------------------------------------------------------------------------
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)
#glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR)
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
glRotatef(5, 0, 1, 0)
elif keys[pygame.K_RIGHT]:
glRotatef(-5, 0, 1, 0)
elif keys[pygame.K_UP]:
glRotatef(5, 1, 0, 0)
elif keys[pygame.K_DOWN]:
glRotatef(-5, 1, 0, 0)
Cube()
glDisable(GL_LIGHT0)
glDisable(GL_LIGHTING)
glDisable(GL_COLOR_MATERIAL)
pygame.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()