مقدمه‌ای کوتاه بر OpenGL در Python با استفاده از PyOpenGL

شبیه‌سازی سه‌بعدی صدا با استفاده از OpenGL (تصویر از ccrma.stanford.edu)
شبیه‌سازی سه‌بعدی صدا با استفاده از OpenGL (تصویر از ccrma.stanford.edu)

مقدمه

در این آموزش، خواهیم آموخت که چگونه از کتابخانه PyOpenGL در پایتون استفاده کنیم. OpenGL یک کتابخانه گرافیکی است که توسط سیستم‌عامل‌های گوناگون - اعم از ویندوز، لینوکس و MacOS - پشتیبانی می‌شود. این کتابخانه همچنین برای استفاده در زبان‌های برنامه‌نویسی گوناگون در دسترس است؛ با این حال، این آموزش به نحوه استفاده از آن در زبان برنامه‌نویسی پایتون محدود خواهد بود.

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

نصب

آسان‌ترین روش نصب OpenGL برای استفاده در پایتون، از طریق مدیر بسته pip صورت می‌گیرد. اگر pip را در سیستم‌تان نصب دارید، دستور زیر را برای دانلود و نصب OpenGL اجرا کنید:

$ pip3 install PyOpenGL PyOpenGL_accelerate

توصیه می‌کنیم دستور بالا را کپی کنید تا از خطاهای تایپی احتمالی جلوگیری شود.

اگر نصب با موفقیت انجام شود، به محض اینکه اجرای دستور فوق به پایان رسید، در نهایت باید چیزی شبیه خروجی زیر را دریافت کنید:

Successfully installed PyOpenGL-3.1.5 PyOpenGL-accelerate-3.1.5

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

$ python3 setup.py

لازم به ذکر است که شما به منظور کار با کتابخانه‌های OpenGL در پایتون، نیاز خواهید داشت تا Visual C++ 14.0 build tools را بر روی سیستم خود نصب داشته باشید.

حالا OpenGL را با موفقیت روی سیستم‌مان نصب کرده‌ایم؛ بیایید کمی با آن کار کنیم.

تمرین کدنویسی

اولین چیزی که برای استفاده از OpenGL در کدمان نیاز داریم ایمپورت کردن آن است. برای این کار، دستور زیر را اجرا کنید:

import OpenGL

پیش از اینکه ادامه دهیم، باید بدانید که برای استفاده از OpenGL در برنامه‌مان، نیاز داریم تا چند کتابخانه دیگر را نیز ایمپورت کنیم. کد زیر این ایمپورت‌ها را انجام می‌دهد:

import OpenGL.GL
import OpenGL.GLUT
import OpenGL.GLU
print(&quotImports successful!&quot) #اگر این پیام در کنسول نمایش داده شود نصب با موفقیت انجام شده است.

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

def showScreen():
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # همه چیز را از صفحه نمایش پاک می‌کند.

glutInit() # نمونه‌ای از glut را مقداردهی اولیه می‌کند که به ما اجازه می‌دهد تا پنجره را شخصی‌سازی کنیم.
glutInitDisplayMode(GLUT_RGBA) # صفحه را قابل رنگ‌آمیزی می‌کند.
glutInitWindowSize(500, 500) # طول و عرض پنجره را تنظیم می‌کند.
glutInitWindowPosition(0, 0) # مکانی که این پنجره نمایان خواهد شد را تنظیم می‌کند.
wind = glutCreateWindow(&quotOpenGL Coding Practice&quot) # به پنجره شما یک عنوان می‌دهد.
glutDisplayFunc(showScreen) # به OpenGL می‌گوید که به‌طور پیوسته متد showScreen را فراخوانی کند.
glutIdleFunc(showScreen) # اشکال گرافیکی موجود در تابع showScreen را در هر زمان رسم می‌کند.
glutMainLoop() # پنجره ساخته شده فوق را در یک حلقه در حالت اجرا و نمایش نگه می‌دارد.

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

بیایید تلاش کنیم تا با استفاده OpenGL یک مربع بسازیم؛ ولی پیش از آن ما نیاز داریم تا با دستگاه مختصاتی (coordinate system) که OpenGL استفاده می‌کند آشنا شویم.

نقطه (0 ,0) نقطه «پایین سمت چپ» پنجره شما است؛ اگر از آنجا به سمت بالا بروید در امتداد محور yها (y-axis) حرکت می‌کنید و چنانچه از آنجا به سمت راست بروید در امتداد محور xها (x-axis) حرکت خواهید کرد. بنابراین نقطه «بالا سمت چپ» (500 ,0)، نقطه «بالا سمت راست» (500 ,500) و نقطه «پایین سمت راست» (0 ,500) خواهد بود.

نکته: ما درباره پنجره‌ای که در بالا ساختیم صحبت می‌کنیم؛ این پنجره در مثال ما ابعاد 500 × 500 را دارد. آن را با ابعاد صفحه نمایش‌تان اشتباه نگیرید.

حالا که این را متوجه شدیم، بیایید یک مربع را کدنویسی کنیم. توضیح کد در کامنت‌ها موجود است.

from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *

w, h = 500, 500

# ---بخش اول---
def square():
    # باید نقاط را با این ترتیب تعریف کنیم: پایین سمت چپ، پایین سمت راست، بالا سمت راست، بالا سمت چپ
    glBegin(GL_QUADS) # طرح‌ریزی را شروع می‌کند.
    glVertex2f(100, 100) # مختصات برای نقطه پایین سمت چپ
    glVertex2f(200, 100) # مختصات برای نقطه پایین سمت راست
    glVertex2f(200, 200) # مختصات برای نقطه بالا سمت راست
    glVertex2f(100, 200) # مختصات برای نقطه بالا سمت چپ
    glEnd() # پایان یافتن رسم را مشخص می‌کند.

# این به تنهایی برای رسم مربع ما کافی نیست.

# ---بخش دوم---
def showScreen():
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # همه چیز را از صفحه پاک می‌کند.
    glLoadIdentity() # مکان‌های همه اشکال گرافیکی را دوباره تنظیم می‌کند.
    square() # با استفاده از تابع ما یک مربع رسم می‌کند.
    glutSwapBuffers()

#---بخش سوم---
glutInit()
glutInitDisplayMode(GLUT_RGBA) # صفحه را قابل رنگ‌آمیزی می‌کند.
glutInitWindowSize(500, 500)   # طول و عرض پنجره را تنظیم می‌کند.
glutInitWindowPosition(0, 0)   # مکانی که این پنجره نمایان خواهد شد را تنظیم می‌کند.
wind = glutCreateWindow(&quotOpenGL Coding Practice&quot) # به پنجره یک عنوان می‌دهد.
glutDisplayFunc(showScreen)
glutIdleFunc(showScreen) # پنجره را باز نگه می‌دارد.
glutMainLoop()  # پنجره ساخته شده فوق را در یک حلقه در حالت اجرا و نمایش نگه می‌دارد.

اگر کد بالا را اجرا کنید یک مربع رسم می‌شود، اما قابل مشاهده نخواهد بود؛ زیرا مربع ما همرنگ پنجره خواهد بود. بنابراین باید رنگ متفاوتی به آن نسبت دهیم. برای این کار ما تغییراتی را در «بخش دوم» کد بالا (یعنی همان تابع showScreen) ایجاد می‌کنیم. خط زیر را پس از glLoadIdentity و پیش از square وارد کنید:

glColor3f(1.0, 0.0, 3.0) # رنگ را به صورتی تغییر می‌دهد.

با این حال، کد ما هنوز کامل نیست. این کد مربع را یک بار رسم می‌کند و سپس صفحه نمایش را دوباره پاک می‌کند. ما این را نمی‌خواهیم. در واقع ما حتی نمی‌توانیم لحظه‌ای را که مربع رسم می‌شود تشخیص دهیم؛ چرا که مربع نمایان شده و سپس در کسری از ثانیه ناپدید می‌شود. بیایید تابعی دیگر بنویسیم تا از این مشکل جلوگیری کند.

def iterate():
    # این تابع را پیش از بخش دوم کد بالا (یعنی تابع showScreen) اضافه کنید.
    glViewport(0, 0, 500,500)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glOrtho(0.0, 500, 0.0, 500, 0.0, 1.0)
    glMatrixMode (GL_MODELVIEW)
    glLoadIdentity()

تابع iterate را در «بخش دوم» کد فوق فراخوانی کنید. این فراخوانی را در تابع showScreen - پس از glLoadIdentity و پیش از glColor3d - انجام دهید.

حالا بیایید همه این مراحل را در یک کد واحد قرار دهیم تا از ابهامات جلوگیری شود:

from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *

w,h= 500,500
def square():
    glBegin(GL_QUADS)
    glVertex2f(100, 100)
    glVertex2f(200, 100)
    glVertex2f(200, 200)
    glVertex2f(100, 200)
    glEnd()

def iterate():
    glViewport(0, 0, 500, 500)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glOrtho(0.0, 500, 0.0, 500, 0.0, 1.0)
    glMatrixMode (GL_MODELVIEW)
    glLoadIdentity()

def showScreen():
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glLoadIdentity()
    iterate()
    glColor3f(1.0, 0.0, 3.0)
    square()
    glutSwapBuffers()

glutInit()
glutInitDisplayMode(GLUT_RGBA)
glutInitWindowSize(500, 500)
glutInitWindowPosition(0, 0)
wind = glutCreateWindow(&quotOpenGL Coding Practice&quot)
glutDisplayFunc(showScreen)
glutIdleFunc(showScreen)
glutMainLoop()

هنگامی که این کد را اجرا کنید، باید مشابه تصویر زیر پنجره‌ای حاوی یک مربع صورتی‌رنگ نمایان شود.

خروجی کد نهایی (تصویر از stackabuse.com)
خروجی کد نهایی (تصویر از stackabuse.com)

جمع‌بندی

در این آموزش، کمی درباره OpenGL آموختیم؛ اینکه چگونه آن را دانلود و نصب کرده و از آن در قالب یک مثال کوتاه استفاده کنیم. در این مثال، همچنین ایجاد یک شکل پایه‌ای را با استفاده از OpenGL یاد گرفتیم که به ما دیدی درباره اشکال پیچیده‌تر فراخوانی توابع - که برای رسم اشکال با استفاده از این کتابخانه لازم‌اند - می‌دهد. و در پایان اینکه OpenGL بسیار زیرک است؛ هر چه در آن عمیق شوید بیشتر و بیشتر پیچیده می‌شود.

مقاله فوق (+) توسط اینجانب ترجمه شده است. خوشحال می‌شوم نظرات، پیشنهادات و انتقادات شما عزیزان را بشنوم. همچنین چنانچه در رابطه با این آموزش به مشکلی برخوردید یا سؤالی داشتید، در خدمت هستم.