Search code examples
pythonpython-3.xopenglpygletopengl-compat

Why does my pyglet application draw funny?


My pyglet application to view 3-d objects in STL format is acting funny. when I load a stl file, it works fine, but then when I try to draw it, it acts funny. code doesn't crash, but the test file I loaded for a cube doesn't look right. I think it might be joining all of the points in the draw code that I don't want to join. the test file should appear 30 pixels by 30 instead of the whole upper right corner:

a picture showing that a chunk of the display is the cube.

at 150 degrees, looks almost right... the 150 degree attempt...

the red lines are the wireframe, green dots vertices, and gray is a face of the cube.

here is my code:

print("starting Wireframe Viewer")
import pyglet, wireframe
from pyglet.gl import *

verticeColor = (0, 100, 0)
verticeSize = 4
lineColor = (100, 0, 0)
lineSize = 2
faceColor = (200, 200, 200)
menuColor = (0, 0, 100)
backgroundColor = (0, 0, 50)
gridColor = (255, 255, 255)
mode = 'OBJ'  # normal viewing - see all faces and such

pos = [0, 0, -20]
rot_y = 0
rot_x = 0
rot_z = 0

if __name__ == "__main__":
    # good
    window = pyglet.window.Window(640, 480, resizable=True)
    wf = wireframe.Wireframe()

    # good
    wf.importStl('test.stl')
    wf.dumpData()


    @window.event
    def on_draw():
        # creating 3D viewport
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(10, 1, 0.1, 100)

        glTranslatef(*pos)
        glRotatef(rot_y, 0, 1, 0)
        glRotatef(rot_x, 1, 0, 0)
        glRotatef(rot_z, 0, 0, 1)

        glClearColor(0.0, 0.0, 0.15, 0.0)
        window.clear()

        # load line width and point size
        glLineWidth(lineSize)
        glPointSize(verticeSize)
        stlDrawDat = []
        for dat in wf.stlMesh:
            stlDrawDat.append([[dat[0], dat[1], dat[2]],
                               [dat[3], dat[4], dat[5]],
                               [dat[6], dat[7], dat[8]]])
        # drawing the image
        for dat in stlDrawDat:
            pyglet.graphics.draw(3, GL_TRIANGLES,
                                 ('v3f', [*dat[0], *dat[1], *dat[2]]), ('c3B', faceColor * 3))
            pyglet.graphics.draw(3, GL_LINES,
                                 ('v3f', [*dat[0], *dat[1], *dat[2]]), ('c3B', lineColor * 3))
            pyglet.graphics.draw(3, GL_POINTS,
                                 ('v3f', [*dat[0], *dat[1], *dat[2]]), ('c3b', verticeColor * 3))

        glFlush()


    @window.event
    def on_key_press(s, m):
        # good
        global pos, rot_y, rot_x, rot_z

        if m:
            pass
        if s == pyglet.window.key.W:
            rot_x += 5  # pos[2] -= 1
        if s == pyglet.window.key.S:
            rot_x -= 5  # pos[2] += 1
        if s == pyglet.window.key.A:
            rot_y += 5
        if s == pyglet.window.key.D:
            rot_y -= 5
        if s == pyglet.window.key.Q:
            rot_z += 5
        if s == pyglet.window.key.E:
            rot_z -= 5
        if s == pyglet.window.key.MINUS:
            pos[2] -= 1
        if s == pyglet.window.key.EQUAL:
            pos[2] += 1
        if s == pyglet.window.key.LEFT:
            pos[0] -= 1
        if s == pyglet.window.key.RIGHT:
            pos[0] += 1
        if s == pyglet.window.key.UP:
            pos[1] += 1
        if s == pyglet.window.key.DOWN:
            pos[1] -= 1


    pyglet.app.run()

and my outer file wireframe.py I can add if needed:

import numpy
from stl import mesh


class Wireframe:
    def __init__(self):
        self.stlMesh = numpy.zeros((0, 9))
        self.originalMesh = numpy.zeros((0, 9))
        self.backupMesh = numpy.zeros((0, 9))

    def importStl(self, fileName):
        print("importing ", fileName)
        self.stlMesh = mesh.Mesh.from_file(fileName)
        self.originalMesh = mesh.Mesh.from_file(fileName)
        self.backupMesh = mesh.Mesh.from_file(fileName)

    def dumpData(self):
        print('\nstl data:')
        for x in self.stlMesh:
            print(x)


if __name__ == "__main__":
    wf = Wireframe()
    wf.importStl('test.stl')
    wf.dumpData()

if someone could help me figure out the problem, I would be happy. I think the problem is somewhere in the drawing functions. if I need to shorten my code, tell me! it was working till I added the 3-D view code from another post: How do I make 3D in pyglet?

modules needed to run code:

python-utils
pyglet
numpy
numpy-stl

Solution

  • gluPerspective defines a Viewing frustum.

    In view space the origin of the view is the camera positions and all the points with the x and y coordinate (0, 0) are on the line of sight in the center of the view.
    The 1st parameter of gluPerspective is the filed of view angle along the y axis in degrees. The angle has to 0° < fovAngle < 180°. Hence 0° and 180° a re not valid angles.

    The 2nd parameter is the aspect ratio.

    A field of view of 10° seems to be far to small. Since the size of the window is 640x480, the aspect ration has to be 640.0/480.0:

    gluPerspective(10, 1, 0.1, 100)

    gluPerspective(120.0, 640.0/480.0, 0.1, 100)
    

    Furthermore I recommend to enable the Depth Test:

    glEnable(GL_DEPTH_TEST)