2

How do I make specular lighting in OpenGL work? I use python and I have been trying to learn how it works the same, I've already been able to make texturing work, depth, create a basic gameplay, but now I was trying to make the specular lighting work like a flashlight, so I change the position of it constantly to the same of the player and the direction to where the player is looking, but it does not work!

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()

I already tried to change the glMaterial, or change different things in the lighting but nothing worked right, I just want the lighting to work like a flashlight, please give answers with code

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Arthur Sally
  • 134
  • 1
  • 10
  • 1
    You are using an obsolete OpenGL interface, just so you know. – Yakov Galka Mar 25 '19 at 17:03
  • There are several issues. A: you seem to confuse `specular reflections` with `spotlights`, a specular-only light source does not really make much sense under normal circumstances, B: your geometry is lacking normal vectors, so lighting will not work, C: with fixed-function GL's flat or gouraud shading, flashlights will really look odd unless you use some insanely high level of tesselation in your models, _even more so_ for the specular lighting. D: All of this is outdated since at least 15 years. – derhass Mar 25 '19 at 17:32

1 Answers1

4

What you want to do is not possible, because of the gouraud shading of the fixed function light model. See also OpenGL Lighting on texture plane is not working, which is a question about a similar issue. You would've to tessellate the surfaces (walls and floors) to smaller tiles, because the light is only calculated for the vertex coordinates and interpolate on the surface. Specular highlights in the middle of a surface won't appear.

I know that will not satisfy you. But note, that drawing by 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. Read about Vertex Specification and Shader for a state of the art way of rendering.

If you want to "see" anything, the you've to skip the spot light, because it won't work with your geometry:

glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, (GLfloat*1)(45))

but activate the ambient an diffuse light:

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)

For the calculation of the light, the normal vector of the surface is required.

Activate light model GL_LIGHT_MODEL_TWO_SIDE side:

glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE)

Set the normal vectors by 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()

When the light position is set by glLightfv(GL_LIGHT0, GL_POSITION, pos), then position is multiplied by the current model view matrix.
This means if the position is set before the view matrix is set (gluLookAt), then the light position is relative to the camera (view space position).
If it is set after the view matrix was set, then the light position has to be in world coordinates, because it is transformed by the view matrix.

If you want that the light source is a the camera position, then you've to set the light to the position (0, 0, 0), before the view matrix is set by 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) 

If you want to make the spotlight (more or less) work, then the only possibility is to use a very small GL_SHININESS parameter (e.g. 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))


The other possibility would be to implement a simple Per Fragment Lighting shader program:

Create the shader program sources code:

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);     
}
"""

Compile and link the program:

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)

Load the textures before the main loop of the program:

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)

Use the program when drawing the scene:

@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()

Rabbid76
  • 202,892
  • 27
  • 131
  • 174