Search code examples
pythonopenglpyglettexturingopengl-compat

Texture the 3D figure (cylinder)


I need to texture my cylinder, I have texture.png and i already did a polygonal mesh (with triangles).

Here is the code if you need pastebin

import pyglet
import pyglet.gl as pgl
from pyglet.window import key
import math

win = pyglet.window.Window(1300, 1000, resizable=True)

WINDOW = 1000
tr = 90
INCREMENT = 5
transparant = False
xRotation = -70
zRotation = -30
yRotation = 180
zoom = 1
far = 100
dist = 35
x = -180
y = 70
z = 0
light = False

param = 0
t_prev = -5
start_loop = False
run_loop = False



def run_loop(dt):
    on_draw()


def draw_figure():
    angle = 0
    t = 0
    x = y = z = 0
    a = 50
    b = 100

    if not transparant:
        pgl.glPolygonMode(pgl.GL_FRONT_AND_BACK, pgl.GL_FILL)
    else:
        pgl.glPolygonMode(pgl.GL_FRONT_AND_BACK, pgl.GL_LINE)
    pgl.glBegin(pgl.GL_TRIANGLE_STRIP)
    for i in range(0, tr + 1):
        pgl.glColor3ub(0, 0, 0)
        if i >= 1:
            t1 = a1
            t2 = a2
            t3 = a3
        a1 = x + a * math.cos(i * 2 * math.pi / tr)
        a2 = y + b * math.sin(i * 2 * math.pi / tr)
        a3 = z + 8
        pgl.glVertex3f(a1, a2, a3)
        if i >= 1:
            pgl.glNormal3f((b2 - t2) * (a3 - b3) - (b3 - t3) * (a2 - b2), (b3 - t3) * (a1 - b1) - (b1 - t1) * (a3 - b3),
                           (b1 - t1) * (a2 - b2) - (b2 - t2) * (a1 - b1))
        b1 = x
        b2 = y
        b3 = z + 8
        pgl.glVertex3f(b1, b2, b3)
    pgl.glEnd()
    for j in range(1, 27):
        pgl.glBegin(pgl.GL_TRIANGLE_STRIP)
        pgl.glColor3ub(0, 0, 0)
        x1 = a * math.cos(0)
        y1 = b * math.sin(0)
        a1 = x1 * math.cos(t * math.pi / 360) + y1 * math.sin(t * math.pi / 360)
        a2 = - x1 * math.sin(t * math.pi / 360) + y1 * math.cos(t * math.pi / 360)
        a3 = z + j * 8
        pgl.glVertex3f(a1, a2, a3)
        x1 = a * math.cos(0)
        y1 = b * math.sin(0)
        b1 = x1 * math.cos((t + 16) * math.pi / 360) + y1 * math.sin((t + 16) * math.pi / 360)
        b2 = - x1 * math.sin((t + 16) * math.pi / 360) + y1 * math.cos((t + 16) * math.pi / 360)
        b3 = z + j * 8 + 8
        pgl.glVertex3f(b1, b2, b3)
        for i in range(1, tr + 1):
            pgl.glColor3ub(0, 0, 0)
            x1 = a * math.cos(i * 2 * math.pi / tr)
            y1 = b * math.sin(i * 2 * math.pi / tr)
            t1 = a1
            t2 = a2
            t3 = a3
            a1 = x1 * math.cos(t * math.pi / 360) + y1 * math.sin(t * math.pi / 360)
            a2 = - x1 * math.sin(t * math.pi / 360) + y1 * math.cos(t * math.pi / 360)
            a3 = z + j * 8
            pgl.glNormal3f((b2 - t2) * (a3 - b3) - (b3 - t3) * (a2 - b2), (b3 - t3) * (a1 - b1) - (b1 - t1) * (a3 - b3),
                           (b1 - t1) * (a2 - b2) - (b2 - t2) * (a1 - b1))
            pgl.glVertex3f(a1, a2, a3)
            x1 = a * math.cos(i * 2 * math.pi / tr)
            y1 = b * math.sin(i * 2 * math.pi / tr)
            b1 = x1 * math.cos((t + 16) * math.pi / 360) + y1 * math.sin((t + 16) * math.pi / 360)
            b2 = - x1 * math.sin((t + 16) * math.pi / 360) + y1 * math.cos((t + 16) * math.pi / 360)
            b3 = z + j * 8 + 8
            pgl.glVertex3f(b1, b2, b3)
        t = t + 16
        pgl.glEnd()
    pgl.glBegin(pgl.GL_TRIANGLE_STRIP)
    t = 416
    z = z + 144
    angle = angle + t
    for i in range(0, tr + 1):
        pgl.glColor3ub(0, 0, 0)
        x1 = x + a * math.cos(i * 2 * math.pi / tr)
        y1 = y + b * math.sin(i * 2 * math.pi / tr)
        x2 = x1 * math.cos(t * math.pi / 360) + y1 * math.sin(t * math.pi / 360)
        y2 = - x1 * math.sin(t * math.pi / 360) + y1 * math.cos(t * math.pi / 360)
        if i >= 1:
            t1 = a1
            t2 = a2
            t3 = a3
        a1 = x2
        a2 = y2
        a3 = z + 72
        pgl.glVertex3f(a1, a2, a3)
        if i >= 1:
            pgl.glNormal3f((b2 - t2) * (a3 - b3) - (b3 - t3) * (a2 - b2), (b3 - t3) * (a1 - b1) - (b1 - t1) * (a3 - b3),
                           (b1 - t1) * (a2 - b2) - (b2 - t2) * (a1 - b1))
        b1 = x
        b2 = y
        b3 = z + 72
        pgl.glVertex3f(b1, b2, b3)
        angle = angle + i
    pgl.glEnd()


@win.event
def on_draw():
    global x, y, z, start_loop, run_loop, param, t_prev, zRotation



    pgl.glClearColor(0.3, 0.3, 0.3, 0.0)
    pgl.glEnable(pgl.GL_DEPTH_TEST)
    if light:
        pgl.glEnable(pgl.GL_LIGHTING)
        pgl.glLightModelf(pgl.GL_LIGHT_MODEL_TWO_SIDE, pgl.GL_TRUE)
        pgl.glEnable(pgl.GL_NORMALIZE)
    pgl.glClear(pgl.GL_COLOR_BUFFER_BIT | pgl.GL_DEPTH_BUFFER_BIT)

    pgl.glLoadIdentity()
    pgl.glViewport(0, 0, 1300, 1000)
    pgl.glMatrixMode(pgl.GL_PROJECTION)
    pgl.glLoadIdentity()
    pgl.glOrtho(-1300 / 4, 1300 / 4, -1000 / 4, 1000 / 4, -400, 600)
    pgl.glMatrixMode(pgl.GL_MODELVIEW)
    pgl.glLoadIdentity()

    if light:
        material_diffuse = [1.0, 1.0, 1.0, 1.0]
        pgl.glMaterialfv(pgl.GL_FRONT_AND_BACK, pgl.GL_DIFFUSE,
                         (pgl.GLfloat * len(material_diffuse))(*material_diffuse))

        light5_diffuse = [1.0, 0.0, 0.0];

        light5_position = [0.5, 0.5, 1.0, 0];

        pgl.glEnable(pgl.GL_LIGHT5);

        pgl.glLightfv(pgl.GL_LIGHT5, pgl.GL_DIFFUSE, (pgl.GLfloat * len(light5_diffuse))(*light5_diffuse));

        pgl.glLightfv(pgl.GL_LIGHT5, pgl.GL_POSITION, (pgl.GLfloat * len(light5_position))(*light5_position));

        pgl.glLightf(pgl.GL_LIGHT5, pgl.GL_CONSTANT_ATTENUATION, 0.0);

        pgl.glLightf(pgl.GL_LIGHT5, pgl.GL_LINEAR_ATTENUATION, 0.4);

        pgl.glLightf(pgl.GL_LIGHT5, pgl.GL_QUADRATIC_ATTENUATION, 0.8);

        light6_diffuse = [0.0, 1.0, 0.0];

        light6_position = [0.5 * math.cos(2 * math.pi / 3), 0.5 * math.sin(2 * math.pi / 3), 1.0, 0];

        pgl.glEnable(pgl.GL_LIGHT6);

        pgl.glLightfv(pgl.GL_LIGHT6, pgl.GL_DIFFUSE, (pgl.GLfloat * len(light6_diffuse))(*light6_diffuse));

        pgl.glLightfv(pgl.GL_LIGHT6, pgl.GL_POSITION, (pgl.GLfloat * len(light6_position))(*light6_position));

        pgl.glLightf(pgl.GL_LIGHT6, pgl.GL_CONSTANT_ATTENUATION, 0.0);

        pgl.glLightf(pgl.GL_LIGHT6, pgl.GL_LINEAR_ATTENUATION, 0.4);

        pgl.glLightf(pgl.GL_LIGHT6, pgl.GL_QUADRATIC_ATTENUATION, 0.8);

        light7_diffuse = [0.0, 0.0, 1.0];

        light7_position = [0.5 * math.cos(4 * math.pi / 3), 0.5 * math.sin(4 * math.pi / 3), 1.0, 0];

        pgl.glEnable(pgl.GL_LIGHT7);

        pgl.glLightfv(pgl.GL_LIGHT7, pgl.GL_DIFFUSE, (pgl.GLfloat * len(light7_diffuse))(*light7_diffuse));

        pgl.glLightfv(pgl.GL_LIGHT7, pgl.GL_POSITION, (pgl.GLfloat * len(light7_position))(*light7_position));

        pgl.glLightf(pgl.GL_LIGHT7, pgl.GL_CONSTANT_ATTENUATION, 0.0);

        pgl.glLightf(pgl.GL_LIGHT7, pgl.GL_LINEAR_ATTENUATION, 0.4);

        pgl.glLightf(pgl.GL_LIGHT7, pgl.GL_QUADRATIC_ATTENUATION, 0.8);

    pgl.glPolygonMode(pgl.GL_FRONT_AND_BACK, pgl.GL_FILL)
    pgl.glPushMatrix()
    pgl.glTranslatef(x, y, z)
    pgl.glRotatef(xRotation, 1, 0, 0)
    pgl.glRotatef(yRotation, 0, 1, 0)
    pgl.glRotatef(zRotation, 0, 0, 1)
    pgl.glScalef(zoom, zoom, zoom)

    draw_figure()

    if start_loop:
        start_loop = False
        run_loop = True
        x = ((1 - (param / 100)) ** 3) * (-180) + 3 * (param / 100) * ((1 - (param / 100)) ** 2) * (100) + 3 * (
                    (param / 100) ** 2) * (
                    1 - (param / 100)) * (0) + ((param / 100) ** 3) * (200)
        y = ((1 - (param / 100)) ** 3) * 70 + 3 * (param / 100) * ((1 - (param / 100)) ** 2) * (140) + 3 * (
                    (param / 100) ** 2) * (
                    1 - (param / 100)) * (140) + ((param / 100) ** 3) * (
                70)
        z = ((1 - (param / 100)) ** 3) * 0 + 3 * (param / 100) * ((1 - (param / 100)) ** 2) * (100) + 3 * (
                    (param / 100) ** 2) * (
                    1 - (param / 100)) * (100) + ((param / 100) ** 3) * (
                0)

    elif run_loop:
        if param < 100 and param > t_prev:
            zRotation += INCREMENT
            param = param + 1
            t_prev = t_prev + 1
            if (param == 100):
                t_prev = 105
            x = ((1 - (param / 100)) ** 3) * (-180) + 3 * (param / 100) * ((1 - (param / 100)) ** 2) * (100) + 3 * (
                        (param / 100) ** 2) * (1 - (param / 100)) * (0) + ((param / 100) ** 3) * (200)
            y = ((1 - (param / 100)) ** 3) * 70 + 3 * (param / 100) * ((1 - (param / 100)) ** 2) * (140) + 3 * (
                        (param / 100) ** 2) * (1 - (param / 100)) * (140) + ((param / 100) ** 3) * (
                    70)
            z = ((1 - (param / 100)) ** 3) * 0 + 3 * (param / 100) * ((1 - (param / 100)) ** 2) * (100) + 3 * (
                        (param / 100) ** 2) * (1 - (param / 100)) * (100) + ((param / 100) ** 3) * (
                    0)
            print(param)
            print("плюс")
        if param > 0 and param < t_prev:
            zRotation -= INCREMENT
            param = param - 1
            t_prev = t_prev - 1
            if (param == 0):
                t_prev = -5
            x = ((1 - (param / 100)) ** 3) * (-180) + 3 * (param / 100) * ((1 - (param / 100)) ** 2) * (100) + 3 * (
                    (param / 100) ** 2) * (1 - (param / 100)) * (0) + ((param / 100) ** 3) * (200)
            y = ((1 - (param / 100)) ** 3) * 70 + 3 * (param / 100) * ((1 - (param / 100)) ** 2) * (140) + 3 * (
                    (param / 100) ** 2) * (1 - (param / 100)) * (140) + ((param / 100) ** 3) * (
                    70)
            z = ((1 - (param / 100)) ** 3) * 0 + 3 * (param / 100) * ((1 - (param / 100)) ** 2) * (100) + 3 * (
                    (param / 100) ** 2) * (1 - (param / 100)) * (100) + ((param / 100) ** 3) * (
                    0)
            print(param)
            print("минус")

    pgl.glPopMatrix()


@win.event
def on_text_motion(motion):
    global xRotation, yRotation, INCREMENT
    if motion == key.UP:
        xRotation -= INCREMENT
    elif motion == key.DOWN:
        xRotation += INCREMENT
    elif motion == key.LEFT:
        yRotation -= INCREMENT
    elif motion == key.RIGHT:
        yRotation += INCREMENT


@win.event
def on_key_press(symbol, modifiers):
    global transparant, dist, tr, x, y, z, INCREMENT, zRotation, light, t, start_loop, run_loop
    if symbol == key.T and not transparant:
        transparant = True
    elif symbol == key.T and transparant:
        transparant = False
    elif symbol == key.W:
        x += 2.5
    elif symbol == key.S:
        x -= 2.5
    elif symbol == key.A:
        y -= 2.5
    elif symbol == key.D:
        y += 2.5
    elif symbol == key.Q:
        z -= 2.5
    elif symbol == key.E:
        z += 2.5
    elif symbol == key.L:
        light = not light
    elif symbol == key.Z:
        zRotation += INCREMENT
    elif symbol == key.X:
        zRotation -= INCREMENT
    elif symbol == key.ESCAPE:
        pyglet.app.exit()
    elif symbol == key.P:
        tr += 5
    elif symbol == key.O:
        if tr > 5:
            tr -= 5
    elif symbol == key.SPACE:
        if not run_loop:
            start_loop = True
        else:
            run_loop = False


@win.event
def on_mouse_scroll(x, y, scroll_x, scroll_y):
    global zoom
    if scroll_y < 0:
        zoom += 0.1
    elif scroll_y > 0 and zoom - 0.1 > 0:
        zoom -= 0.1


@win.event
def on_mouse_press(x, y, button, modifiers):
    if button == pyglet.window.mouse.LEFT:
        print(x, y)


pyglet.clock.schedule_interval(run_loop, 0.1)
pyglet.app.run()

Edit:


Solution

  • First you have to load the texture image to a texture object by pyglet.image.load respectively get_texture():

    texture_obj = pyglet.image.load('texture.png').get_texture()
    

    The texture has to be bound by glBindTexture:

    pgl.glBindTexture(pgl.GL_TEXTURE_2D, texture_obj.id)
    

    Two-dimensional texturing is enabled by glEnable(GL_TEXTURE_2D) and can be disabled by glDisable(GL_TEXTURE_2D).
    If texturing is enables then the texture wich is currently bound when the geometry is drawn by the glBegin/glEnd sequence is applied:

    pgl.glEnable(pgl.GL_TEXTURE_2D)
    

    If texturing is enabled, then by default the color of the texel is multiplied by the current color, because by default the texture environment mode (GL_TEXTURE_ENV_MODE) is GL_MODULATE. See glTexEnv.

    This causes that the color of the texels of the texture is "mixed" by the last color which you have set by glColor3ub.

    Set a "white" color before you render the texture, to solve your issue:

    plg.glColor3ub(255, 255, 255)
    

    or

    pgl.glColor3f(1, 1, 1)
    

    Likewise you can change the environment mode to GL_REPLACE, instead:

    pgl.glTexEnvi(pgl.GL_TEXTURE_ENV, pgl.GL_TEXTURE_ENV_MODE, pgl.GL_REPLACE)
    

    When glVertex is called, the the current texture coordinates are associated with the vertex coordinate. The texture coordinate is set by glTexCoord2f.
    You've to set the texture coordinates corresponding to each vertex coordinate. The texture coordinates have to be in range [0, 1]. See also How do opengl texture coordinates work?.

    e.g.

    u = math.cos(i * 2 * math.pi / tr)
    v = math.sin(i * 2 * math.pi / tr)
    pgl.glTexCoord2f(u*0.5+0.5, v*0.5+0.5)
    a1 = x + a * u
    a2 = y + b * v
    a3 = z + 8
    pgl.glVertex3f(a1, a2, a3)
    

    The function draw_figure may look as follows. Note, I don't exactly know how you want to wrap the texture to the mesh, so I calculate the texture coordinates as I thought. You may have to a adapt the calculation of the texture coordinates to your needs:

    texture_obj = None 
    
    def draw_figure():
    
        global texture_obj
    
        # [...]
    
        if texture_obj == None:
            texture_obj = pyglet.image.load('texture.png').get_texture()
        pgl.glBindTexture(pgl.GL_TEXTURE_2D, texture_obj.id)
        pgl.glEnable(pgl.GL_TEXTURE_2D)
        pgl.glTexEnvi(pgl.GL_TEXTURE_ENV, pgl.GL_TEXTURE_ENV_MODE, pgl.GL_REPLACE)
    
        if not transparant:
            pgl.glPolygonMode(pgl.GL_FRONT_AND_BACK, pgl.GL_FILL)
        else:
            pgl.glPolygonMode(pgl.GL_FRONT_AND_BACK, pgl.GL_LINE)
        pgl.glBegin(pgl.GL_TRIANGLE_STRIP)
        for i in range(0, tr + 1):
            pgl.glColor3ub(255, 255, 255)
            if i >= 1:
                t1 = a1
                t2 = a2
                t3 = a3
            u = math.cos(i * 2 * math.pi / tr)
            v = math.sin(i * 2 * math.pi / tr)
            a1 = x + a * u
            a2 = y + b * v
            a3 = z + 8
            pgl.glTexCoord2f(u*0.5+0.5, v*0.5+0.5)
            pgl.glVertex3f(a1, a2, a3)
            if i >= 1:
                pgl.glNormal3f((b2 - t2) * (a3 - b3) - (b3 - t3) * (a2 - b2), (b3 - t3) * (a1 - b1) - (b1 - t1) * (a3 - b3),
                               (b1 - t1) * (a2 - b2) - (b2 - t2) * (a1 - b1))
            b1 = x
            b2 = y
            b3 = z + 8
            pgl.glTexCoord2f(0.5, 0.5)
            pgl.glVertex3f(b1, b2, b3)
        pgl.glEnd()
        for j in range(1, 27):
            pgl.glBegin(pgl.GL_TRIANGLE_STRIP)
            pgl.glColor3ub(255, 255, 255)
            x1 = a * math.cos(0)
            y1 = b * math.sin(0)
            a1 = x1 * math.cos(t * math.pi / 360) + y1 * math.sin(t * math.pi / 360)
            a2 = - x1 * math.sin(t * math.pi / 360) + y1 * math.cos(t * math.pi / 360)
            a3 = z + j * 8
            pgl.glTexCoord2f(0.0, 0.0)
            pgl.glVertex3f(a1, a2, a3)
            b1 = x1 * math.cos((t + 16) * math.pi / 360) + y1 * math.sin((t + 16) * math.pi / 360)
            b2 = - x1 * math.sin((t + 16) * math.pi / 360) + y1 * math.cos((t + 16) * math.pi / 360)
            b3 = z + j * 8 + 8
            u = math.cos((t + 16) * math.pi / 360) + math.sin((t + 16) * math.pi / 360)
            v = (j-1)/26
            pgl.glTexCoord2f(0.0, 0.0)
            pgl.glVertex3f(b1, b2, b3)
            for i in range(1, tr + 1):
                pgl.glColor3ub(255, 255, 255)
                x1 = a * math.cos(i * 2 * math.pi / tr)
                y1 = b * math.sin(i * 2 * math.pi / tr)
                t1 = a1
                t2 = a2
                t3 = a3
                a1 = x1 * math.cos(t * math.pi / 360) + y1 * math.sin(t * math.pi / 360)
                a2 = - x1 * math.sin(t * math.pi / 360) + y1 * math.cos(t * math.pi / 360)
                a3 = z + j * 8
                pgl.glNormal3f((b2 - t2) * (a3 - b3) - (b3 - t3) * (a2 - b2), (b3 - t3) * (a1 - b1) - (b1 - t1) * (a3 - b3),
                               (b1 - t1) * (a2 - b2) - (b2 - t2) * (a1 - b1))
                v = math.cos(t * math.pi / 360) + math.sin(t * math.pi / 360)
                pgl.glTexCoord2f((i-1)/tr, (26-j)/26)
                pgl.glVertex3f(a1, a2, a3)
                x1 = a * math.cos(i * 2 * math.pi / tr)
                y1 = b * math.sin(i * 2 * math.pi / tr)
                b1 = x1 * math.cos((t + 16) * math.pi / 360) + y1 * math.sin((t + 16) * math.pi / 360)
                b2 = - x1 * math.sin((t + 16) * math.pi / 360) + y1 * math.cos((t + 16) * math.pi / 360)
                b3 = z + j * 8 + 8
                v = math.cos((t + 16) * math.pi / 360) + math.sin((t + 16) * math.pi / 360)
                pgl.glTexCoord2f((i-1)/tr, (25-j)/26)
                pgl.glVertex3f(b1, b2, b3)
            t = t + 16
            pgl.glEnd()
        pgl.glBegin(pgl.GL_TRIANGLE_STRIP)
        t = 416
        z = z + 144
        angle = angle + t
        for i in range(0, tr + 1):
            pgl.glColor3ub(255, 255, 255)
            u = math.cos(i * 2 * math.pi / tr)
            v = math.sin(i * 2 * math.pi / tr)
            x1 = x + a * u
            y1 = y + b * v
            x2 = x1 * math.cos(t * math.pi / 360) + y1 * math.sin(t * math.pi / 360)
            y2 = - x1 * math.sin(t * math.pi / 360) + y1 * math.cos(t * math.pi / 360)
            if i >= 1:
                t1 = a1
                t2 = a2
                t3 = a3
            a1 = x2
            a2 = y2
            a3 = z + 72
            pgl.glTexCoord2f(u*0.5+0.5, v*0.5+0.5)
            pgl.glVertex3f(a1, a2, a3)
            if i >= 1:
                pgl.glNormal3f((b2 - t2) * (a3 - b3) - (b3 - t3) * (a2 - b2), (b3 - t3) * (a1 - b1) - (b1 - t1) * (a3 - b3),
                               (b1 - t1) * (a2 - b2) - (b2 - t2) * (a1 - b1))
            b1 = x
            b2 = y
            b3 = z + 72
            pgl.glTexCoord2f(0.5, 0.5)
            pgl.glVertex3f(b1, b2, b3)
            angle = angle + i
        pgl.glEnd()