فهرست بستن

برنامه نویسی گرافیک سه بعدی در پایتون

ابتدای مسیر توسعه کامپیوترها، رابط گرافیکی مفهومی نداشت و تمامی وظایف در محیط رابط متنی خیلی ساده انجام می‌گرفت. با پیشرفت قدرت پردازشی کامپیوترها و همزمان پیدایش تکنولوژی‌های جدید صفحات نمایش که هزینه این ادوات را کاهش می‌داد، رابطهای گرافیکی به دنیای کامپیوتر معرفی شدند. روند توسعه گرافیکی با ورود به قرن بیست و یکم سرعت بیشتری پیدا کرد و گرافیک سه بعدی مورد اقبال کاربران قرار گرفت. بسته‌های نرم افزاری مختلفی برای کارهای گرافیکی و شتاب بخشی به آن‌ها که رابط بین کدهای نوشته شده توسط کاربر و سخت افزار پردازش‌گر گرافیکی می‌باشند نیز شروع به توسعه پیدا کردند. یکی از این رابطهای برنامه‌نویسی نرم‌افزارهای کاربردی OpenGL می‌باشد. اولین انتشار این رابط در سال ۱۹۹۲ اتفاق افتاد و تا امروز یکی از رابطهای برنامه‌نویسی گرافیکی دو بعدی و سه بعدی محبوب می‌باشد. در این نوشته به نحوه استفاده از این رابط با استفاده از زبان برنامه‌نویسی پایتون پرداخته خواهد شد.

بسم الله الرحمن الرحیم

هدف این متن در نهایت رسم یک مکعب با دوران مورد نظر در فضای سه بعدی می‌باشد. پس ابتدا به سراغ نصب کتابخانه‌های مورد نیاز می‌رویم. اگر کاربر لینوکس (توسعه‌هایی که بر مبنای دبیان می‌باشند مثل اوبونتو) هستید کارتان آسوده است و با دستور زیر در ترمینال لینوکس می‌توان در اولین قدم GLUT را نصب نمایید:

sudo apt-get install freeglut3-dev

در صورتی که کاربر ویندوز هستید بایستی از لینک زیر مراحل نصب GLUT را دنبال کرده:

http://web.eecs.umich.edu/~sugih/courses/eecs487/glut-howto/#win

بعد از نصب در ویندوز فایل glut32.dll را باید به آدرس زیر کپی نمایید:

python-installation-directory/Lib/site-packages/OpenGL/DLLS

بعد از نصب GLUT برای کار با OpenGL در پایتون باید کتابخانه pyopengl نصب گردد که برای آن از دستور زیر در ترمینال (یا خط فرمان) استفاده می‌شود:

pip install numpy scipy pyopengl

خب حالا آماده ایم اولین برنامه گرافیک سه بعدی را بنویسیم. با توجه به علاقه خودم به فهمیدن نتیجه قبل از تحلیل راه رسیدن به آن، ابتدا کد را قرار داده خروجی را دیده و بعد از آن به تحلیل کدها پرداخته می‌شود:

#!/usr/bin/env python

"""This demonstrates a simple rotating cube in 3D using OpenGL.
"""

import sys
import os
import linecache
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *

ROTATE_X = 30.0
ROTATE_Y = -30.0
ROTATE_Z = 0.0


def InitGL(Width, Height):

    glClearColor(0.0, 0.0, 0.0, 0.0)
    glClearDepth(1.0)
    glDepthFunc(GL_LESS)  # glDepthFunc(GL_LEQUAL)
    #glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glEnable(GL_DEPTH_TEST)
    glEnable(GL_POLYGON_SMOOTH)
    glEnable(GL_BLEND)
    # Wire frame:  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    glShadeModel(GL_SMOOTH)  # glShadeModel(GL_FLAT)
    ReSizeGLScene (Width,Height)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)


def ReSizeGLScene (width, height):

    if height==0:
        height=1
    glViewport (0,0,width,height)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    # set perspective and aspect ratio.
    gluPerspective(45.0, float(width)/float(height), 0.1, 100.0)
    glMatrixMode(GL_MODELVIEW)
#    glLoadIdentity()


def DrawGLScene():

    global ROTATE_X,ROTATE_Y,ROTATE_Z

    glClearColor(0.0, 0.0, 0.0, 0.0)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glLoadIdentity()
    glMatrixMode(GL_MODELVIEW)

    glTranslatef(0.0,0.0,-6.0)
    glRotatef(ROTATE_X,1.0,0.0,0.0)
    glRotatef(ROTATE_Y,0.0,1.0,0.0)
    glRotatef(ROTATE_Z,0.0,0.0,1.0)

    glPushMatrix()
    glBegin(GL_QUADS)
    glColor4f(0.4,0.4,0.4,1.0) # 0.666)
    glVertex3f( 1.5, 1.5,-1.5)
    glVertex3f( 1.5, 1.5, 1.5)
    glVertex3f( 1.5,-1.5, 1.5)
    glVertex3f( 1.5,-1.5,-1.5)

    # side 1: blue
    glColor4f(0.0,0.0,1.0,1.0) # 0.666)
    # upper right -> upper left -> lower left -> lower right
    glVertex3f( 1.0, 1.0,-1.0)
    glVertex3f(-1.0, 1.0,-1.0)
    glVertex3f(-1.0, 1.0, 1.0)
    glVertex3f( 1.0, 1.0, 1.0)

    # side 2: green
    glColor4f(0.0,1.0,0.0,1.0) # 0.666)
    # upper right -> upper left -> lower left -> lower right
    glVertex3f( 1.0,-1.0, 1.0)
    glVertex3f(-1.0,-1.0, 1.0)
    glVertex3f(-1.0,-1.0,-1.0)
    glVertex3f( 1.0,-1.0,-1.0)

    # side 3: red
    glColor4f(1.0,0.0,0.0,1.0) # 0.666)
    # upper right -> upper left -> lower left -> lower right
    glVertex3f( 1.0, 1.0, 1.0)
    glVertex3f(-1.0, 1.0, 1.0)
    glVertex3f(-1.0,-1.0, 1.0)
    glVertex3f( 1.0,-1.0, 1.0)

    # side 4: yellow
    glColor4f(1.0,1.0,0.0,1.0) # 0.666)
    # upper right -> upper left -> lower left -> lower right
    glVertex3f( 1.0,-1.0,-1.0)
    glVertex3f(-1.0,-1.0,-1.0)
    glVertex3f(-1.0, 1.0,-1.0)
    glVertex3f( 1.0, 1.0,-1.0)

    # side 5: white
    glColor4f(1.0,1.0,1.0,1.0) # 0.666)
    # upper right -> upper left -> lower left -> lower right
    glVertex3f(-1.0, 1.0, 1.0)
    glVertex3f(-1.0, 1.0,-1.0)
    glVertex3f(-1.0,-1.0,-1.0)
    glVertex3f(-1.0,-1.0, 1.0)

    # side 6: cyan
    glColor4f(0.0,1.0,1.0,1.0) # 0.666)
    # upper right -> upper left -> lower left -> lower right
    glVertex3f( 1.0, 1.0,-1.0)
    glVertex3f( 1.0, 1.0, 1.0)
    glVertex3f( 1.0,-1.0, 1.0)
    glVertex3f( 1.0,-1.0,-1.0)

    glEnd()
    glPopMatrix()
    glutSwapBuffers()


def main():

    glutInit(sys.argv)
    # pyopengl bug causes a "Segmentation fault" when glutCreateWindow is called after glutInitDisplayMode.
    window = glutCreateWindow('cube')
    glutInitWindowSize(480,272)
    glutInitWindowPosition(0,0)
    # Setting only GLUT_DOUBLE seems to have the same effect. What are the others good for?
    glutInitDisplayMode(GLUT_RGBA | GLUT_ALPHA | GLUT_DOUBLE | GLUT_DEPTH)
    glutDisplayFunc(DrawGLScene)
    #glutIdleFunc uses 50% of the CPU while "idle". Seems to run fine without it.
    #glutIdleFunc(DrawGLScene)
    glutReshapeFunc(ReSizeGLScene)
    #glutFullScreen()
    InitGL(480,272)
    glutMainLoop()


if __name__ == "__main__":

    main()

و اما خروجی:

حالا ببینیم در این برنامه چه اتفاقی می‌افتد …