我如何使 OpenGL 镜面光工作?
How do i make OpenGL Specular Light work?
如何使 OpenGL 中的镜面照明发挥作用?我使用 python 并且我一直在尝试了解它是如何工作的,我已经能够使纹理工作、深度、创建基本的游戏玩法,但现在我正在尝试使镜面照明工作得像一个手电筒,所以我不断地改变它的位置与玩家相同的位置和玩家正在看的方向,但它不起作用!
import pyglet, math
from pyglet.gl import *
tela = pyglet.window.Window(height=500, width=500, caption="Halloween")
glEnable(GL_DEPTH_TEST)
glEnable(GL_TEXTURE_2D)
glEnable(GL_LIGHTING)
glLightfv(GL_LIGHT0, GL_AMBIENT, (GLfloat*4)(0,0,0,1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (GLfloat*4)(0,0,0,1))
glEnable(GL_LIGHT0)
tela.set_mouse_visible(False)
pos = [0,0,0]
rotX = rotY = pre = 0
comando = {"a":0,"d":0,"w":0,"s":0}
Dparede = pyglet.image.load("inf/Parede_Branca.png").get_image_data().get_data('RGBA', 225*4)
parede = pyglet.resource.image("inf/Parede_Branca.png").get_texture()
Dchao = pyglet.image.load("inf/Madeira.png").get_image_data().get_data('RGBA', 225*4)
chao = pyglet.resource.image("inf/Madeira.png").get_texture()
@tela.event
def on_draw():
global pos, comando, rotX, rotY, parede, chao, Dchao, Dparede
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
if comando["w"] == 1:
pos[2] += math.cos(math.pi*rotX/180)
pos[0] += math.sin(math.pi*rotX/180)
if comando["s"] == 1:
pos[2] -= math.cos(math.pi*rotX/180)
pos[0] -= math.sin(math.pi*rotX/180)
if comando["d"] == 1:
pos[2] += math.sin(math.pi*rotX/180)
pos[0] -= math.cos(math.pi*rotX/180)
if comando["a"] == 1:
pos[2] -= math.sin(math.pi*rotX/180)
pos[0] += math.cos(math.pi*rotX/180)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45, 1, 0.1, 1000)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
if pos[0] < -188:
pos[0] = -188
if pos[2] < -188:
pos[2] = -188
if pos[0] > 188:
pos[0] = 188
if pos[2] > 188:
pos[2] = 188
glLightfv(GL_LIGHT0, GL_SPECULAR, (GLfloat*4)(1,1,1,1))
glLightfv(GL_LIGHT0, GL_POSITION, (GLfloat*4)(pos[0],pos[1]-1,pos[2],1))
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, (GLfloat*3)(pos[0]+1000*(math.sin(math.pi*rotX/180)),pos[1]+1000*(math.cos(math.pi*rotY/180)), pos[2]+1000*(math.cos(math.pi*rotX/180))))
glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, (GLfloat*1)(45))
gluLookAt(pos[0], pos[1], pos[2], pos[0]+math.sin(math.pi*rotX/180), pos[1]+math.cos(math.pi*rotY/180), pos[2]+math.cos(math.pi*rotX/180), 0, 10, 0)
glBindTexture(GL_TEXTURE_2D, chao.id)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 225, 225, 0, GL_RGBA, GL_UNSIGNED_BYTE, Dchao)
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (GLfloat*4)(1,1,1,1))
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, (GLfloat*1)(100))
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (GLfloat*4)(0,0,0,1))
# chão
glBegin(GL_POLYGON)
glTexCoord2f(0,0)
glVertex3f(-200,-20,200)
glTexCoord2f(0,10)
glVertex3f(-200,-20,-200)
glTexCoord2f(10,10)
glVertex3f(200,-20,-200)
glTexCoord2f(10,0)
glVertex3f(200,-20,200)
glEnd()
glBindTexture(GL_TEXTURE_2D, parede.id)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 225, 225, 0, GL_RGBA, GL_UNSIGNED_BYTE, Dparede)
# teto
glBegin(GL_POLYGON)
glTexCoord2f(0,0)
glVertex3f(-200,20,200)
glTexCoord2f(0,50)
glVertex3f(-200,20,-200)
glTexCoord2f(50,50)
glVertex3f(200,20,-200)
glTexCoord2f(50,0)
glVertex3f(200,20,200)
glEnd()
# parede
glBegin(GL_POLYGON)
glTexCoord2f(0,0)
glVertex3f(-200,20,200)
glTexCoord2f(0,50)
glVertex3f(-200,20,-200)
glTexCoord2f(10,50)
glVertex3f(-200,-20,-200)
glTexCoord2f(10,0)
glVertex3f(-200,-20,200)
glEnd()
# parede
glBegin(GL_POLYGON)
glTexCoord2f(0,0)
glVertex3f(-200,-20,-200)
glTexCoord2f(0,50)
glVertex3f(200,-20,-200)
glTexCoord2f(10,50)
glVertex3f(200,20,-200)
glTexCoord2f(10,0)
glVertex3f(-200,20,-200)
glEnd()
# parede
glBegin(GL_POLYGON)
glTexCoord2f(0,0)
glVertex3f(200,-20,-200)
glTexCoord2f(0,50)
glVertex3f(200,-20,200)
glTexCoord2f(10,50)
glVertex3f(200,20,200)
glTexCoord2f(10,0)
glVertex3f(200,20,-200)
glEnd()
# parede
glBegin(GL_POLYGON)
glTexCoord2f(0,0)
glVertex3f(-200,-20,200)
glTexCoord2f(0,50)
glVertex3f(200,-20,200)
glTexCoord2f(10,50)
glVertex3f(200,20,200)
glTexCoord2f(10,0)
glVertex3f(-200,20,200)
glEnd()
@tela.event
def on_key_press(k,m):
global comando
if k == pyglet.window.key.A:
comando["a"] = 1
if k == pyglet.window.key.D:
comando["d"] = 1
if k == pyglet.window.key.W:
comando["w"] = 1
if k == pyglet.window.key.S:
comando["s"] = 1
if k == pyglet.window.key.Q:
tela.close()
@tela.event
def on_key_release(k,m):
global comando
if k == pyglet.window.key.A:
comando["a"] = 0
if k == pyglet.window.key.D:
comando["d"] = 0
if k == pyglet.window.key.W:
comando["w"] = 0
if k == pyglet.window.key.S:
comando["s"] = 0
@tela.event
def on_mouse_motion(x, y, dx, dy):
global rotX, rotY, pre
if pre == 0:
rotX-=dx/2
if rotY >= 0:
rotY = -1
if rotY <= -180:
rotY = -179
rotY+=dy
if x > 400 or x < 100 or y > 400 or y < 100:
tela.set_mouse_position(250,250)
pre = 1
else:
pre = 0
def SRO(dt):
on_draw()
pyglet.clock.schedule_interval(SRO, 1/120)
pyglet.app.run()
我已经尝试更改 glMaterial,或更改照明中的不同内容,但没有任何效果,我只想让照明像手电筒一样工作,请用代码给出答案
你想做的是不可能的,因为gouraud shading of the fixed function light model. See also ,这是一个关于类似问题的问题。您必须将表面(墙壁和地板)细分为更小的瓷砖,因为灯光仅针对顶点坐标进行计算并在表面上进行插值。表面中间的镜面高光不会出现。
我知道这不会让你满意。但请注意,glBegin
/glEnd
sequences, the fixed function matrix stack and fixed function, per vertex light model, is deprecated since decades. See Fixed Function Pipeline and Legacy OpenGL 绘制的那幅画。
阅读 Vertex Specification and Shader 了解最先进的渲染方式。
如果你想 "see" 任何东西,你必须跳过聚光灯,因为它不适用于你的几何体:
glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, (GLfloat*1)(45))
但激活环境漫射光:
glEnable(GL_LIGHTING)
glLightfv(GL_LIGHT0, GL_AMBIENT, (GLfloat*4)(1,1,1,1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (GLfloat*4)(1,1,1,1))
glEnable(GL_LIGHT0)
对于光的计算,需要表面的法向量。
激活灯光模型GL_LIGHT_MODEL_TWO_SIDE
侧面:
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE)
通过glNormal3f
设置法向量:
# chão
glBegin(GL_POLYGON)
glNormal3f(0, -1, 0)
glTexCoord2f(0,0)
glVertex3f(-200,-20,200)
glTexCoord2f(0,10)
glVertex3f(-200,-20,-200)
glTexCoord2f(10,10)
glVertex3f(200,-20,-200)
glTexCoord2f(10,0)
glVertex3f(200,-20,200)
glEnd()
glBindTexture(GL_TEXTURE_2D, parede.id)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, Dparede)
# teto
glBegin(GL_POLYGON)
glNormal3f(0, -1, 0)
glTexCoord2f(0,0)
glVertex3f(-200,20,200)
glTexCoord2f(0,50)
glVertex3f(-200,20,-200)
glTexCoord2f(50,50)
glVertex3f(200,20,-200)
glTexCoord2f(50,0)
glVertex3f(200,20,200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(-1, 0, 0)
glTexCoord2f(0,0)
glVertex3f(-200,20,200)
glTexCoord2f(0,50)
glVertex3f(-200,20,-200)
glTexCoord2f(10,50)
glVertex3f(-200,-20,-200)
glTexCoord2f(10,0)
glVertex3f(-200,-20,200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(0, 0, 1)
glTexCoord2f(0,0)
glVertex3f(-200,-20,-200)
glTexCoord2f(0,50)
glVertex3f(200,-20,-200)
glTexCoord2f(10,50)
glVertex3f(200,20,-200)
glTexCoord2f(10,0)
glVertex3f(-200,20,-200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(-1, 0, 0)
glTexCoord2f(0,0)
glVertex3f(200,-20,-200)
glTexCoord2f(0,50)
glVertex3f(200,-20,200)
glTexCoord2f(10,50)
glVertex3f(200,20,200)
glTexCoord2f(10,0)
glVertex3f(200,20,-200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(0, 0, 1)
glTexCoord2f(0,0)
glVertex3f(-200,-20,200)
glTexCoord2f(0,50)
glVertex3f(200,-20,200)
glTexCoord2f(10,50)
glVertex3f(200,20,200)
glTexCoord2f(10,0)
glVertex3f(-200,20,200)
glEnd()
当光源位置由glLightfv(GL_LIGHT0, GL_POSITION, pos)
设置时,则位置乘以当前模型视图矩阵。
这意味着如果在设置视图矩阵(gluLookAt
)之前设置位置,则灯光位置是相对于相机(视图space位置)。
如果在设置视图矩阵之后设置,那么灯光位置必须在世界坐标中,因为它是由视图矩阵转换的。
如果您希望光源是相机位置,则必须将光源设置到位置 (0, 0, 0),在 视图之前矩阵由 gluLookAt
设置。
glLightfv(GL_LIGHT0, GL_POSITION, (GLfloat*4)(0,0,0,1))
gluLookAt(pos[0], pos[1], pos[2], pos[0]+math.sin(math.pi*rotX/180), pos[1]+math.cos(math.pi*rotY/180), pos[2]+math.cos(math.pi*rotX/180), 0, 10, 0)
如果你想让聚光灯(或多或少)起作用,那么唯一的可能就是使用一个非常小的GL_SHININESS
参数(例如1):
glLightfv(GL_LIGHT0, GL_POSITION, (GLfloat*4)(0,0,0,1))
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, (GLfloat*3)(0, 0, -1))
glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, (GLfloat*1)(45))
gluLookAt(pos[0], pos[1], pos[2], pos[0]+math.sin(math.pi*rotX/180), pos[1]+math.cos(math.pi*rotY/180), pos[2]+math.cos(math.pi*rotX/180), 0, 10, 0)
glLightfv(GL_LIGHT0, GL_AMBIENT, (GLfloat*4)(0,0,0,1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (GLfloat*4)(0,0,0,1))
glLightfv(GL_LIGHT0, GL_SPECULAR, (GLfloat*4)(1,1,1,1))
# [...]
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, (GLfloat*1)(1))
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (GLfloat*4)(1,1,1,1))
另一种可能性是实现一个简单的 Per Fragment Lighting 着色器程序:
创建着色器程序源代码:
vert_code = b"""
varying vec3 N;
varying vec3 v;
varying vec2 uv;
void main(void)
{
uv = gl_MultiTexCoord0.xy;
v = vec3(gl_ModelViewMatrix * gl_Vertex);
N = normalize(gl_NormalMatrix * gl_Normal);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
"""
frag_code = b"""
varying vec3 N;
varying vec3 v;
varying vec2 uv;
uniform sampler2D u_texture;
void main (void)
{
vec3 L = normalize(gl_LightSource[0].position.xyz - v);
vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0)
vec3 R = normalize(-reflect(L,N));
//calculate Ambient Term:
vec4 Iamb = gl_FrontLightProduct[0].ambient;
float spotCos = dot(gl_LightSource[0].spotDirection, -E);
float sotCutOff = step(gl_LightSource[0].spotCosCutoff, spotCos);
//calculate Diffuse Term:
vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0);
Idiff = clamp(Idiff, 0.0, 1.0) * sotCutOff;
// calculate Specular Term:
vec4 Ispec = gl_FrontLightProduct[0].specular
* pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);
Ispec = clamp(Ispec, 0.0, 1.0) * sotCutOff;
vec4 texColor = texture2D(u_texture, uv);
gl_FragColor = vec4(texColor.rgb * (Iamb + Idiff + Ispec), texColor.a);
}
"""
编译并link程序:
from ctypes import *
sh_code_list = [(GL_VERTEX_SHADER, vert_code), (GL_FRAGMENT_SHADER, frag_code)]
sh_objs = []
for sh_code in sh_code_list:
sh_obj = glCreateShader(sh_code[0])
src_buffer = create_string_buffer(sh_code[1])
buf_pointer = cast(pointer(pointer(src_buffer)), POINTER(POINTER(c_char)))
glShaderSource(sh_obj, 1, buf_pointer, None)
glCompileShader(sh_obj)
temp = c_int(0)
glGetShaderiv(sh_obj, GL_COMPILE_STATUS, byref(temp))
if not temp:
glGetShaderiv(sh_obj, GL_INFO_LOG_LENGTH, byref(temp))
buffer = create_string_buffer(temp.value)
glGetShaderInfoLog(sh_obj, temp, None, buffer)
print( 'compile error:' )
print(buffer.value)
sh_objs.append(sh_obj)
program = glCreateProgram()
for shObj in sh_objs:
glAttachShader(program, shObj)
glLinkProgram(program)
temp = c_int(0)
glGetProgramiv(program, GL_LINK_STATUS, byref(temp))
if not temp:
glGetProgramiv(program, GL_INFO_LOG_LENGTH, byref(temp))
buffer = create_string_buffer(temp.value)
glGetProgramInfoLog(program, temp, None, buffer)
print( 'link error:' )
print(buffer.value)
在程序主循环之前加载纹理:
glBindTexture(GL_TEXTURE_2D, chao.id)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, Dchao)
glBindTexture(GL_TEXTURE_2D, parede.id)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, Dparede)
绘制场景时使用程序:
@tela.event
def on_draw():
global pos, comando, rotX, rotY, parede, chao, Dchao, Dparede
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
if comando["w"] == 1:
pos[2] += math.cos(math.pi*rotX/180)
pos[0] += math.sin(math.pi*rotX/180)
if comando["s"] == 1:
pos[2] -= math.cos(math.pi*rotX/180)
pos[0] -= math.sin(math.pi*rotX/180)
if comando["d"] == 1:
pos[2] += math.sin(math.pi*rotX/180)
pos[0] -= math.cos(math.pi*rotX/180)
if comando["a"] == 1:
pos[2] -= math.sin(math.pi*rotX/180)
pos[0] += math.cos(math.pi*rotX/180)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45, 1, 0.1, 1000)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
if pos[0] < -188:
pos[0] = -188
if pos[2] < -188:
pos[2] = -188
if pos[0] > 188:
pos[0] = 188
if pos[2] > 188:
pos[2] = 188
glLightfv(GL_LIGHT0, GL_POSITION, (GLfloat*4)(0,0,0,1))
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, (GLfloat*3)(0, 0, -1))
glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, (GLfloat*1)(45))
gluLookAt(pos[0], pos[1], pos[2], pos[0]+math.sin(math.pi*rotX/180), pos[1]+math.cos(math.pi*rotY/180), pos[2]+math.cos(math.pi*rotX/180), 0, 10, 0)
glLightfv(GL_LIGHT0, GL_AMBIENT, (GLfloat*4)(0.2,0.2,0.2,1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (GLfloat*4)(0.8,0.8,0.8,1))
glLightfv(GL_LIGHT0, GL_SPECULAR, (GLfloat*4)(1,1,1,1))
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, (GLfloat*1)(100))
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (GLfloat*4)(1,1,1,1))
glBindTexture(GL_TEXTURE_2D, chao.id)
glUseProgram(program)
# chão
glBegin(GL_POLYGON)
glNormal3f(0, 1, 0)
glTexCoord2f(0,0)
glVertex3f(-200,-20,200)
glTexCoord2f(0,10)
glVertex3f(-200,-20,-200)
glTexCoord2f(10,10)
glVertex3f(200,-20,-200)
glTexCoord2f(10,0)
glVertex3f(200,-20,200)
glEnd()
glBindTexture(GL_TEXTURE_2D, parede.id)
# teto
glBegin(GL_POLYGON)
glNormal3f(0, -1, 0)
glTexCoord2f(0,0)
glVertex3f(-200,20,200)
glTexCoord2f(0,10)
glVertex3f(-200,20,-200)
glTexCoord2f(10,10)
glVertex3f(200,20,-200)
glTexCoord2f(10,0)
glVertex3f(200,20,200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(-1, 0, 0)
glTexCoord2f(0,0)
glVertex3f(-200,20,200)
glTexCoord2f(10,0)
glVertex3f(-200,20,-200)
glTexCoord2f(10,1)
glVertex3f(-200,-20,-200)
glTexCoord2f(0,1)
glVertex3f(-200,-20,200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(0, 0, 1)
glTexCoord2f(0,0)
glVertex3f(-200,-20,-200)
glTexCoord2f(10,0)
glVertex3f(200,-20,-200)
glTexCoord2f(10,1)
glVertex3f(200,20,-200)
glTexCoord2f(0,1)
glVertex3f(-200,20,-200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(-1, 0, 0)
glTexCoord2f(0,0)
glVertex3f(200,-20,-200)
glTexCoord2f(10,0)
glVertex3f(200,-20,200)
glTexCoord2f(10,1)
glVertex3f(200,20,200)
glTexCoord2f(0,1)
glVertex3f(200,20,-200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(0, 0, 1)
glTexCoord2f(0,0)
glVertex3f(-200,-20,200)
glTexCoord2f(10,0)
glVertex3f(200,-20,200)
glTexCoord2f(10,1)
glVertex3f(200,20,200)
glTexCoord2f(0,1)
glVertex3f(-200,20,200)
glEnd()
如何使 OpenGL 中的镜面照明发挥作用?我使用 python 并且我一直在尝试了解它是如何工作的,我已经能够使纹理工作、深度、创建基本的游戏玩法,但现在我正在尝试使镜面照明工作得像一个手电筒,所以我不断地改变它的位置与玩家相同的位置和玩家正在看的方向,但它不起作用!
import pyglet, math
from pyglet.gl import *
tela = pyglet.window.Window(height=500, width=500, caption="Halloween")
glEnable(GL_DEPTH_TEST)
glEnable(GL_TEXTURE_2D)
glEnable(GL_LIGHTING)
glLightfv(GL_LIGHT0, GL_AMBIENT, (GLfloat*4)(0,0,0,1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (GLfloat*4)(0,0,0,1))
glEnable(GL_LIGHT0)
tela.set_mouse_visible(False)
pos = [0,0,0]
rotX = rotY = pre = 0
comando = {"a":0,"d":0,"w":0,"s":0}
Dparede = pyglet.image.load("inf/Parede_Branca.png").get_image_data().get_data('RGBA', 225*4)
parede = pyglet.resource.image("inf/Parede_Branca.png").get_texture()
Dchao = pyglet.image.load("inf/Madeira.png").get_image_data().get_data('RGBA', 225*4)
chao = pyglet.resource.image("inf/Madeira.png").get_texture()
@tela.event
def on_draw():
global pos, comando, rotX, rotY, parede, chao, Dchao, Dparede
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
if comando["w"] == 1:
pos[2] += math.cos(math.pi*rotX/180)
pos[0] += math.sin(math.pi*rotX/180)
if comando["s"] == 1:
pos[2] -= math.cos(math.pi*rotX/180)
pos[0] -= math.sin(math.pi*rotX/180)
if comando["d"] == 1:
pos[2] += math.sin(math.pi*rotX/180)
pos[0] -= math.cos(math.pi*rotX/180)
if comando["a"] == 1:
pos[2] -= math.sin(math.pi*rotX/180)
pos[0] += math.cos(math.pi*rotX/180)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45, 1, 0.1, 1000)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
if pos[0] < -188:
pos[0] = -188
if pos[2] < -188:
pos[2] = -188
if pos[0] > 188:
pos[0] = 188
if pos[2] > 188:
pos[2] = 188
glLightfv(GL_LIGHT0, GL_SPECULAR, (GLfloat*4)(1,1,1,1))
glLightfv(GL_LIGHT0, GL_POSITION, (GLfloat*4)(pos[0],pos[1]-1,pos[2],1))
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, (GLfloat*3)(pos[0]+1000*(math.sin(math.pi*rotX/180)),pos[1]+1000*(math.cos(math.pi*rotY/180)), pos[2]+1000*(math.cos(math.pi*rotX/180))))
glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, (GLfloat*1)(45))
gluLookAt(pos[0], pos[1], pos[2], pos[0]+math.sin(math.pi*rotX/180), pos[1]+math.cos(math.pi*rotY/180), pos[2]+math.cos(math.pi*rotX/180), 0, 10, 0)
glBindTexture(GL_TEXTURE_2D, chao.id)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 225, 225, 0, GL_RGBA, GL_UNSIGNED_BYTE, Dchao)
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (GLfloat*4)(1,1,1,1))
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, (GLfloat*1)(100))
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (GLfloat*4)(0,0,0,1))
# chão
glBegin(GL_POLYGON)
glTexCoord2f(0,0)
glVertex3f(-200,-20,200)
glTexCoord2f(0,10)
glVertex3f(-200,-20,-200)
glTexCoord2f(10,10)
glVertex3f(200,-20,-200)
glTexCoord2f(10,0)
glVertex3f(200,-20,200)
glEnd()
glBindTexture(GL_TEXTURE_2D, parede.id)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 225, 225, 0, GL_RGBA, GL_UNSIGNED_BYTE, Dparede)
# teto
glBegin(GL_POLYGON)
glTexCoord2f(0,0)
glVertex3f(-200,20,200)
glTexCoord2f(0,50)
glVertex3f(-200,20,-200)
glTexCoord2f(50,50)
glVertex3f(200,20,-200)
glTexCoord2f(50,0)
glVertex3f(200,20,200)
glEnd()
# parede
glBegin(GL_POLYGON)
glTexCoord2f(0,0)
glVertex3f(-200,20,200)
glTexCoord2f(0,50)
glVertex3f(-200,20,-200)
glTexCoord2f(10,50)
glVertex3f(-200,-20,-200)
glTexCoord2f(10,0)
glVertex3f(-200,-20,200)
glEnd()
# parede
glBegin(GL_POLYGON)
glTexCoord2f(0,0)
glVertex3f(-200,-20,-200)
glTexCoord2f(0,50)
glVertex3f(200,-20,-200)
glTexCoord2f(10,50)
glVertex3f(200,20,-200)
glTexCoord2f(10,0)
glVertex3f(-200,20,-200)
glEnd()
# parede
glBegin(GL_POLYGON)
glTexCoord2f(0,0)
glVertex3f(200,-20,-200)
glTexCoord2f(0,50)
glVertex3f(200,-20,200)
glTexCoord2f(10,50)
glVertex3f(200,20,200)
glTexCoord2f(10,0)
glVertex3f(200,20,-200)
glEnd()
# parede
glBegin(GL_POLYGON)
glTexCoord2f(0,0)
glVertex3f(-200,-20,200)
glTexCoord2f(0,50)
glVertex3f(200,-20,200)
glTexCoord2f(10,50)
glVertex3f(200,20,200)
glTexCoord2f(10,0)
glVertex3f(-200,20,200)
glEnd()
@tela.event
def on_key_press(k,m):
global comando
if k == pyglet.window.key.A:
comando["a"] = 1
if k == pyglet.window.key.D:
comando["d"] = 1
if k == pyglet.window.key.W:
comando["w"] = 1
if k == pyglet.window.key.S:
comando["s"] = 1
if k == pyglet.window.key.Q:
tela.close()
@tela.event
def on_key_release(k,m):
global comando
if k == pyglet.window.key.A:
comando["a"] = 0
if k == pyglet.window.key.D:
comando["d"] = 0
if k == pyglet.window.key.W:
comando["w"] = 0
if k == pyglet.window.key.S:
comando["s"] = 0
@tela.event
def on_mouse_motion(x, y, dx, dy):
global rotX, rotY, pre
if pre == 0:
rotX-=dx/2
if rotY >= 0:
rotY = -1
if rotY <= -180:
rotY = -179
rotY+=dy
if x > 400 or x < 100 or y > 400 or y < 100:
tela.set_mouse_position(250,250)
pre = 1
else:
pre = 0
def SRO(dt):
on_draw()
pyglet.clock.schedule_interval(SRO, 1/120)
pyglet.app.run()
我已经尝试更改 glMaterial,或更改照明中的不同内容,但没有任何效果,我只想让照明像手电筒一样工作,请用代码给出答案
你想做的是不可能的,因为gouraud shading of the fixed function light model. See also
我知道这不会让你满意。但请注意,glBegin
/glEnd
sequences, the fixed function matrix stack and fixed function, per vertex light model, is deprecated since decades. See Fixed Function Pipeline and Legacy OpenGL 绘制的那幅画。
阅读 Vertex Specification and Shader 了解最先进的渲染方式。
如果你想 "see" 任何东西,你必须跳过聚光灯,因为它不适用于你的几何体:
glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, (GLfloat*1)(45))
但激活环境漫射光:
glEnable(GL_LIGHTING)
glLightfv(GL_LIGHT0, GL_AMBIENT, (GLfloat*4)(1,1,1,1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (GLfloat*4)(1,1,1,1))
glEnable(GL_LIGHT0)
对于光的计算,需要表面的法向量。
激活灯光模型GL_LIGHT_MODEL_TWO_SIDE
侧面:
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE)
通过glNormal3f
设置法向量:
# chão
glBegin(GL_POLYGON)
glNormal3f(0, -1, 0)
glTexCoord2f(0,0)
glVertex3f(-200,-20,200)
glTexCoord2f(0,10)
glVertex3f(-200,-20,-200)
glTexCoord2f(10,10)
glVertex3f(200,-20,-200)
glTexCoord2f(10,0)
glVertex3f(200,-20,200)
glEnd()
glBindTexture(GL_TEXTURE_2D, parede.id)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, Dparede)
# teto
glBegin(GL_POLYGON)
glNormal3f(0, -1, 0)
glTexCoord2f(0,0)
glVertex3f(-200,20,200)
glTexCoord2f(0,50)
glVertex3f(-200,20,-200)
glTexCoord2f(50,50)
glVertex3f(200,20,-200)
glTexCoord2f(50,0)
glVertex3f(200,20,200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(-1, 0, 0)
glTexCoord2f(0,0)
glVertex3f(-200,20,200)
glTexCoord2f(0,50)
glVertex3f(-200,20,-200)
glTexCoord2f(10,50)
glVertex3f(-200,-20,-200)
glTexCoord2f(10,0)
glVertex3f(-200,-20,200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(0, 0, 1)
glTexCoord2f(0,0)
glVertex3f(-200,-20,-200)
glTexCoord2f(0,50)
glVertex3f(200,-20,-200)
glTexCoord2f(10,50)
glVertex3f(200,20,-200)
glTexCoord2f(10,0)
glVertex3f(-200,20,-200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(-1, 0, 0)
glTexCoord2f(0,0)
glVertex3f(200,-20,-200)
glTexCoord2f(0,50)
glVertex3f(200,-20,200)
glTexCoord2f(10,50)
glVertex3f(200,20,200)
glTexCoord2f(10,0)
glVertex3f(200,20,-200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(0, 0, 1)
glTexCoord2f(0,0)
glVertex3f(-200,-20,200)
glTexCoord2f(0,50)
glVertex3f(200,-20,200)
glTexCoord2f(10,50)
glVertex3f(200,20,200)
glTexCoord2f(10,0)
glVertex3f(-200,20,200)
glEnd()
当光源位置由glLightfv(GL_LIGHT0, GL_POSITION, pos)
设置时,则位置乘以当前模型视图矩阵。
这意味着如果在设置视图矩阵(gluLookAt
)之前设置位置,则灯光位置是相对于相机(视图space位置)。
如果在设置视图矩阵之后设置,那么灯光位置必须在世界坐标中,因为它是由视图矩阵转换的。
如果您希望光源是相机位置,则必须将光源设置到位置 (0, 0, 0),在 视图之前矩阵由 gluLookAt
设置。
glLightfv(GL_LIGHT0, GL_POSITION, (GLfloat*4)(0,0,0,1))
gluLookAt(pos[0], pos[1], pos[2], pos[0]+math.sin(math.pi*rotX/180), pos[1]+math.cos(math.pi*rotY/180), pos[2]+math.cos(math.pi*rotX/180), 0, 10, 0)
如果你想让聚光灯(或多或少)起作用,那么唯一的可能就是使用一个非常小的GL_SHININESS
参数(例如1):
glLightfv(GL_LIGHT0, GL_POSITION, (GLfloat*4)(0,0,0,1))
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, (GLfloat*3)(0, 0, -1))
glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, (GLfloat*1)(45))
gluLookAt(pos[0], pos[1], pos[2], pos[0]+math.sin(math.pi*rotX/180), pos[1]+math.cos(math.pi*rotY/180), pos[2]+math.cos(math.pi*rotX/180), 0, 10, 0)
glLightfv(GL_LIGHT0, GL_AMBIENT, (GLfloat*4)(0,0,0,1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (GLfloat*4)(0,0,0,1))
glLightfv(GL_LIGHT0, GL_SPECULAR, (GLfloat*4)(1,1,1,1))
# [...]
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, (GLfloat*1)(1))
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (GLfloat*4)(1,1,1,1))
另一种可能性是实现一个简单的 Per Fragment Lighting 着色器程序:
创建着色器程序源代码:
vert_code = b"""
varying vec3 N;
varying vec3 v;
varying vec2 uv;
void main(void)
{
uv = gl_MultiTexCoord0.xy;
v = vec3(gl_ModelViewMatrix * gl_Vertex);
N = normalize(gl_NormalMatrix * gl_Normal);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
"""
frag_code = b"""
varying vec3 N;
varying vec3 v;
varying vec2 uv;
uniform sampler2D u_texture;
void main (void)
{
vec3 L = normalize(gl_LightSource[0].position.xyz - v);
vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0)
vec3 R = normalize(-reflect(L,N));
//calculate Ambient Term:
vec4 Iamb = gl_FrontLightProduct[0].ambient;
float spotCos = dot(gl_LightSource[0].spotDirection, -E);
float sotCutOff = step(gl_LightSource[0].spotCosCutoff, spotCos);
//calculate Diffuse Term:
vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0);
Idiff = clamp(Idiff, 0.0, 1.0) * sotCutOff;
// calculate Specular Term:
vec4 Ispec = gl_FrontLightProduct[0].specular
* pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);
Ispec = clamp(Ispec, 0.0, 1.0) * sotCutOff;
vec4 texColor = texture2D(u_texture, uv);
gl_FragColor = vec4(texColor.rgb * (Iamb + Idiff + Ispec), texColor.a);
}
"""
编译并link程序:
from ctypes import *
sh_code_list = [(GL_VERTEX_SHADER, vert_code), (GL_FRAGMENT_SHADER, frag_code)]
sh_objs = []
for sh_code in sh_code_list:
sh_obj = glCreateShader(sh_code[0])
src_buffer = create_string_buffer(sh_code[1])
buf_pointer = cast(pointer(pointer(src_buffer)), POINTER(POINTER(c_char)))
glShaderSource(sh_obj, 1, buf_pointer, None)
glCompileShader(sh_obj)
temp = c_int(0)
glGetShaderiv(sh_obj, GL_COMPILE_STATUS, byref(temp))
if not temp:
glGetShaderiv(sh_obj, GL_INFO_LOG_LENGTH, byref(temp))
buffer = create_string_buffer(temp.value)
glGetShaderInfoLog(sh_obj, temp, None, buffer)
print( 'compile error:' )
print(buffer.value)
sh_objs.append(sh_obj)
program = glCreateProgram()
for shObj in sh_objs:
glAttachShader(program, shObj)
glLinkProgram(program)
temp = c_int(0)
glGetProgramiv(program, GL_LINK_STATUS, byref(temp))
if not temp:
glGetProgramiv(program, GL_INFO_LOG_LENGTH, byref(temp))
buffer = create_string_buffer(temp.value)
glGetProgramInfoLog(program, temp, None, buffer)
print( 'link error:' )
print(buffer.value)
在程序主循环之前加载纹理:
glBindTexture(GL_TEXTURE_2D, chao.id)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, Dchao)
glBindTexture(GL_TEXTURE_2D, parede.id)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, Dparede)
绘制场景时使用程序:
@tela.event
def on_draw():
global pos, comando, rotX, rotY, parede, chao, Dchao, Dparede
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
if comando["w"] == 1:
pos[2] += math.cos(math.pi*rotX/180)
pos[0] += math.sin(math.pi*rotX/180)
if comando["s"] == 1:
pos[2] -= math.cos(math.pi*rotX/180)
pos[0] -= math.sin(math.pi*rotX/180)
if comando["d"] == 1:
pos[2] += math.sin(math.pi*rotX/180)
pos[0] -= math.cos(math.pi*rotX/180)
if comando["a"] == 1:
pos[2] -= math.sin(math.pi*rotX/180)
pos[0] += math.cos(math.pi*rotX/180)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45, 1, 0.1, 1000)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
if pos[0] < -188:
pos[0] = -188
if pos[2] < -188:
pos[2] = -188
if pos[0] > 188:
pos[0] = 188
if pos[2] > 188:
pos[2] = 188
glLightfv(GL_LIGHT0, GL_POSITION, (GLfloat*4)(0,0,0,1))
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, (GLfloat*3)(0, 0, -1))
glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, (GLfloat*1)(45))
gluLookAt(pos[0], pos[1], pos[2], pos[0]+math.sin(math.pi*rotX/180), pos[1]+math.cos(math.pi*rotY/180), pos[2]+math.cos(math.pi*rotX/180), 0, 10, 0)
glLightfv(GL_LIGHT0, GL_AMBIENT, (GLfloat*4)(0.2,0.2,0.2,1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (GLfloat*4)(0.8,0.8,0.8,1))
glLightfv(GL_LIGHT0, GL_SPECULAR, (GLfloat*4)(1,1,1,1))
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, (GLfloat*1)(100))
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (GLfloat*4)(1,1,1,1))
glBindTexture(GL_TEXTURE_2D, chao.id)
glUseProgram(program)
# chão
glBegin(GL_POLYGON)
glNormal3f(0, 1, 0)
glTexCoord2f(0,0)
glVertex3f(-200,-20,200)
glTexCoord2f(0,10)
glVertex3f(-200,-20,-200)
glTexCoord2f(10,10)
glVertex3f(200,-20,-200)
glTexCoord2f(10,0)
glVertex3f(200,-20,200)
glEnd()
glBindTexture(GL_TEXTURE_2D, parede.id)
# teto
glBegin(GL_POLYGON)
glNormal3f(0, -1, 0)
glTexCoord2f(0,0)
glVertex3f(-200,20,200)
glTexCoord2f(0,10)
glVertex3f(-200,20,-200)
glTexCoord2f(10,10)
glVertex3f(200,20,-200)
glTexCoord2f(10,0)
glVertex3f(200,20,200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(-1, 0, 0)
glTexCoord2f(0,0)
glVertex3f(-200,20,200)
glTexCoord2f(10,0)
glVertex3f(-200,20,-200)
glTexCoord2f(10,1)
glVertex3f(-200,-20,-200)
glTexCoord2f(0,1)
glVertex3f(-200,-20,200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(0, 0, 1)
glTexCoord2f(0,0)
glVertex3f(-200,-20,-200)
glTexCoord2f(10,0)
glVertex3f(200,-20,-200)
glTexCoord2f(10,1)
glVertex3f(200,20,-200)
glTexCoord2f(0,1)
glVertex3f(-200,20,-200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(-1, 0, 0)
glTexCoord2f(0,0)
glVertex3f(200,-20,-200)
glTexCoord2f(10,0)
glVertex3f(200,-20,200)
glTexCoord2f(10,1)
glVertex3f(200,20,200)
glTexCoord2f(0,1)
glVertex3f(200,20,-200)
glEnd()
# parede
glBegin(GL_POLYGON)
glNormal3f(0, 0, 1)
glTexCoord2f(0,0)
glVertex3f(-200,-20,200)
glTexCoord2f(10,0)
glVertex3f(200,-20,200)
glTexCoord2f(10,1)
glVertex3f(200,20,200)
glTexCoord2f(0,1)
glVertex3f(-200,20,200)
glEnd()