OpenGL, PyOpenGL
3 boyutlu simülasyonlar için OpenGL ünlü bir paket. Çeşitli objeler, satıhlar, onları gösteren bir kamera gibi kavramların kodlaması basit. Birkaç örnek C++ kodunu SPH yazısında gördük. Ek bazı kodlar [2]'den alınmıştır,
bouncingballs.cpp, checkeredtriangles.cpp, colorcube.cpp, cometride.cpp, fish.cpp, litsolids.cpp, moon.cpp, robotarm.cpp, sierpinski2d.cpp, sierpinski3d.cpp, spinningsquare.cpp, tetrahedron.cpp, torus.cpp, triangle.cpp
Derlemek icin
sudo apt-get install mesa-common-dev libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev
Sonra
g++ dosya.cpp -lX11 -lGL -lGLU -lglut -g -Wall -O2 -o islet.exe
Alttaki kodlarda [2]'den alınan bir uçuş simulatörü var
fly.cpp geometry.h landscape.cpp landscape.h ship.h
Derlemek icin
g++ -c landscape.cpp -o landscape.o -lX11 -lGL -lGLU -lglut -g -Wall -O2
g++ fly.cpp -g -Wall -O2 -o r.exe -lX11 -lGL -lGLU -lglut landscape.o
Python
Kurulus
pip install PyOpenGL==3.1.0
[1] kodu baz alınarak bir topun düşüşünü, duvarlara, yere çarpmasını
simüle eden bir kod altta görülüyor. Top sayısını self.n
ile
arttırabiliriz.
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from random import random
from PIL import Image
from PIL import ImageOps
import sys
class Simulation:
def __init__(self):
self.i = 0
self.n = 1
self.r = 0.1
self.g = 9.8
self.dt = 0.01
self.cor = 0.6
self.balls = []
self.tm = 0.0
self.th = 0.0
self.mmax = 1.0-self.r
self.mmin = -1.0+self.r
self.right = False
self.left = False
def init(self):
for i in range(self.n):
p = [
self.mmin + random()*(self.mmax-self.mmin),
self.mmin + random()*(self.mmax-self.mmin),
0.9]
v = [
-1.5 + random()*3.0,
-1.5 + random()*3.0,
-1.0 + random()*2.0]
self.balls.append({'pos':p,'vel':v})
tm = 0.0
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_DEPTH_TEST)
glClearColor(1.0,1.0,1.0,1.0)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60.0,1.0,1.0,50.0)
glTranslatef(0.0,0.0,-3.5)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
def update(self):
for b in self.balls:
b['vel'][2] += -self.g*self.dt
b['pos'][0] += b['vel'][0]*self.dt
b['pos'][1] += b['vel'][1]*self.dt
b['pos'][2] += b['vel'][2]*self.dt
if (abs(b['pos'][0]) >= self.mmax):
b['vel'][0] *= -self.cor
if b['pos'][0] < 0:
b['pos'][0] = self.mmin
else:
b['pos'][0] = self.mmax
if (abs(b['pos'][1]) >= self.mmax):
b['vel'][1] *= -self.cor
if b['pos'][1] < 0:
b['pos'][1] = self.mmin
else:
b['pos'][1] = self.mmax
if (abs(b['pos'][2]) >= self.mmax):
b['vel'][2] *= -self.cor
if b['pos'][2] < 0:
b['pos'][2] = self.mmin
else:
b['pos'][2] = self.mmax
# kamerayi saga sola dondurmek icin
if self.right:
self.th += 0.2
if self.th>360.0:
self.th -= 360.0
if self.left:
self.th -= 0.2
if self.th>360.0:
self.th -= 360.0
glutPostRedisplay()
def display(self):
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glPushMatrix()
glRotatef(self.th,0.0,1.0,0.0)
glRotatef(90.0,-1.0,0.0,0.0)
glutWireCube(2.0)
for b in self.balls:
glPushMatrix()
glTranslatef(b['pos'][0],b['pos'][1],b['pos'][2])
glutSolidSphere(self.r,50,50)
glPopMatrix()
glPopMatrix()
glutSwapBuffers()
# her 40'inci resmi diske png olarak yaz
if self.i % 40 == 0:
width,height = 640,480
data = glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE)
image = Image.frombytes("RGBA", (width, height), data)
image = ImageOps.flip(image)
image.save('/tmp/glutout-%03d.png' % self.i, 'PNG')
self.i += 1
def mouse(self,button,state,x,y):
if button == GLUT_LEFT_BUTTON:
self.right = not state
elif button == GLUT_RIGHT_BUTTON:
self.left = not state
if __name__ == '__main__':
s = Simulation()
glutInit(())
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
glutInitWindowSize(500,500)
glutCreateWindow("GLUT Bouncing Ball in Python")
glutDisplayFunc(s.display)
glutIdleFunc(s.update)
glutMouseFunc(s.mouse)
s.init()
glutMainLoop()
Sonuc
Dikkat üstteki kodda duvar çarpım fiziği var fakat topların birbirine çarpma fiziği yok.
Görüntüsüz (Headless) İsletmek
Bazen uzun sürebilecek, ya da otomize şekilde script içinden grafik
rutinleri çağırmak isteyebiliriz, ve program işlerken bir pencere
açılip görüntü gösterilsin istemiyoruz. Bu durumda normal bir Unix
script çağırır gibi OpenGL ya da PyOpenGL çağrıları yapabiliriz,
görüntüyü işletim sistemi seviyesine yakalayıp göstermemek
lazım. xvfb
ile bunu yapabiliriz, Ubuntu'da
sudo apt-get install xvfb
İşletmek için
xvfb-run -s "-screen 0 1x1x24" python -u script.py
Görüntü gösterilmeyecek fakat program işleyecek, eğer kod içinde png dosyaları yazıyorsak mesela bunların normal olduğu gibi üretildiğini göreceğiz. .
Kaynaklar
[1] http://fab.cba.mit.edu/classes/864.05/people/knorton/01-balls/
[2] https://cs.lmu.edu/~ray/notes/openglexamples/
Yukarı