То, что вы хотите сделать, невозможно, из-за gouraud shading модели освещения с фиксированной функцией. См. Также OpenGL Освещение на плоскости текстуры не работает , что является вопросом о подобной проблеме. Вам придется тесселировать поверхности (стены и полы) на меньшие плитки, потому что свет рассчитывается только для координат вершин и интерполируется на поверхности. Зеркальные блики в середине поверхности не появятся.
Я знаю, что вас это не удовлетворит. Но обратите внимание, что рисование с помощью glBegin
/ glEnd
последовательностей, набора матриц с фиксированными функциями и фиксированной функции для каждой модели освещения вершин устарело с десятилетий. См. конвейер с фиксированными функциями и Legacy OpenGL .
Прочитайте о Vertex Specification и Shader , чтобы узнать о современном способе рендеринга.
Если вы хотите что-то «увидеть», вам нужно пропустить прожектор, потому что он не будет работать с вашей геометрией:
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
), то положение освещения относительно камеры (положение в пространстве просмотра).
Если он установлен после того, как была установлена матрица вида, то положение источника света должно быть в мировых координатах, поскольку оно преобразуется матрицей вида.
Если вы хотите, чтобы источник света находился в положении камеры, вам нужно установить свет в положение (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))
Другой возможностью было бы реализовать простую шейдерную программу освещения :
Создание исходного кода программы шейдера:
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);
}
"""
Скомпилируйте и скомпонуйте программу:
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()