Dnešní díl seriálu o multimediální knihovně Pyglet je věnovaný technice mipmappingu, která je často používaná pro zamezení vzniku vizuálních chyb vznikajících v dynamicky se měnících scénách a animacích popř. při použití textur se složitějším vzorkem.
Obsah
1. Multimediální knihovna Pyglet: použití mipmappingu při texturování
2. Texturování bez použití mipmappingu
3. Podvzorkování textury a vznik moaré
4. Vytvoření rastrového obrázku s texturou šachovnice
5. První demonstrační příklad – zobrazení šachovnice v 3D scéně bez použití mipmappingu
7. Podpora mipmappingu v grafické knihovně OpenGL
8. Automatické generování mipmap v nadstavbové knihovně GLU
9. Automatické vygenerování mipmapy v knihovně Pyglet
10. Nastavení filtrů při použití mipmappingu
11. Druhý demonstrační příklad – použití mipmappingu v praxi
12. Ukázka různých nastavení mipmappingu
13. Úplný zdrojový kód druhého demonstračního příkladu
14. Funkce knihovny OpenGL a pomocné knihovny GLU, které byly použity ve zdrojových kódech
15. Repositář s demonstračními příklady
1. Multimediální knihovna Pyglet: použití mipmappingu při texturování
Mipmapping představuje v oblasti 3D grafiky poměrně dobře známou techniku, která je v praxi poměrně často používaná pro odstranění či alespoň pro zmenšení některých vizuálních chyb (resp. přesněji řečeno nežádoucích rozdílů mezi jednotlivými snímky) vzniklých při pohybu těles s nanesenou texturou v trojrozměrné scéně nebo při pohybu celé scény (tj. při změně orientace nebo pozice pozorovatele/kamery). Obraz těles s nanesenou texturou se na obrazovce při pohybu zmenšuje, zvětšuje či jinak deformuje, čímž pochopitelně také dochází k nutnosti zvětšování a zmenšování textury při nanášení texelů (rastrových elementů textury) na zobrazované pixely.
2. Texturování bez použití mipmappingu
Nejprve se podívejme na nám již známé techniky řešení tohoto problému. Již minule jsme si řekli, že při zvětšování a zmenšování textury můžeme pro zamezení některých vizuálních chyb využít filtraci. Nejrychlejšího zobrazení scény však dosáhneme vypnutím filtrace a výběrem vždy pouze jednoho nejbližšího texelu z textury pro každý vykreslovaný pixel:
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MAG_FILTER,
GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER,
GL_NEAREST)
Obrázek 1: Přiblížení textury při použití filtrů GL_NEAREST, tj. barva pixelů se vypočte z nejbližšího texelu.
Předchozí způsob je sice nejrychlejší, současně však nikterak neřeší vznik artefaktů, například takzvaného moaré, způsobeného podvzorkováním obrazu. V knihovně OpenGL a tím pádem i v Pygletu lze využít několika způsobů, které zamezují vznikům těchto artefaktů při zvětšování a zejména zmenšování textur. Pokud se vykresluje statická scéna, je možné použít pouze vhodné filtrace, pracující na principu výběru několika sousedních texelů a jejich bilineární interpolace při výpočtu barvy vykreslovaného pixelu:
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MAG_FILTER,
GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER,
GL_LINEAR);
Obrázek 2: Přiblížení textury při použití filtrů GL_LINEAR, tj. použitím bilineární interpolace.
3. Podvzorkování textury a vznik moaré
Nevýhodou předchozího způsobu je určité zpomalení vykreslování, zejména díky faktu, že se musí provádět více přístupů do texturovací paměti, která v dnešní době stále představuje úzké hrdlo grafických akcelerátorů. V některých případech, zejména při požadavku na vyšší kvalitu obrázků, je možné použít antialiasing, který se v OpenGL provádí tak, že se scéna vykreslí ve vyšším rozlišení, než je rozlišení obrazovky, a poté se provede snížení rozlišení pomocí filtrace s vhodným jádrem filtru (kernelem). Rozdíl mezi scénou vykreslenou bez antialiasingu a s antialiasingem je patrný z dalších dvou screenshotů. Moderní grafické akcelerátory většinou umožňují provádět antialiasing celé scény. Tato technika je nazývaná FSAA neboli Full Scene AntiAliasing. Nevýhodou je samozřejmě nižší rychlost vykreslování.
Obrázek 3: Trojrozměrná scéna vykreslená bez povoleného antialiasingu.
Obrázek 4: Stejná scéna jako na předchozím obrázku vykreslená se zapnutým antialiasingem.
Poznámka: antialiasing implementovaný s použitím takzvaného supersamplingu, se velmi často používá u raytracerů.
Při animacích však kromě moaré vznikají i další artefakty, z nichž nejviditelnější je „problikávání“ pixelů na příliš zmenšených texturách, tj. například texturách nanesených na vzdálených objektech. V těchto případech už běžná filtrace (pracující pouze pro těsné okolí nanášených texelů) není příliš prospěšná, protože s každým pohybem otexturovaného tělesa se může v rovině textury provést posun až o několik desítek texelů, čímž dochází k prudké změně vykreslované barvy.
4. Vytvoření rastrového obrázku s texturou šachovnice
V dnešních dvou demonstračních příkladech budeme používat texturu šachovnice. Abyste si mohli sami vyzkoušet, jak se bude zobrazení takové textury lišit pro různé velikosti políček na šachovnici, bude textura vytvořená následujícím jednoduchým skriptem. Povšimněte si, že rozměry šachovnice jsou 256×256 pixelů, což odpovídá – jak uvidíme dále – požadavkům na rozměry textury, z nichž se bude vytvářet mipmapa:
#!/usr/bin/env python
# Vytvoreni textury sachovnice
from PIL import Image
IMAGE_WIDTH = 256
IMAGE_HEIGHT = 256
SQUARE_SIZE = 16
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
image = Image.new("RGB", (IMAGE_WIDTH, IMAGE_HEIGHT))
for y in range(0, IMAGE_HEIGHT):
for x in range(0, IMAGE_WIDTH):
color = BLACK
xs = x / SQUARE_SIZE
ys = y / SQUARE_SIZE
if (xs + ys) % 2 == 0:
color = WHITE
image.putpixel((x, y), color)
image.save("checker.png")
Obrázek 5: Textura vytvořená výše popsaným skriptem.
5. První demonstrační příklad – zobrazení šachovnice v 3D scéně bez použití mipmappingu
Použití textury šachovnice vytvořené předchozím skriptem je vlastně velmi snadné, protože jen postačuje nepatrně upravit příklady, s nimiž jsme se již seznámili v předchozích částech tohoto seriálu. V 3D scéně bude zobrazeno jen jediné těleso – čtvercová plocha pokrytá šachovnicovou texturou:
def draw_floor():
glBegin(GL_QUADS) # vykresleni podlahy
glTexCoord2f(0.0, 0.0)
glVertex3f(-50.0, -5.0, -50.0)
glTexCoord2f(5.0, 0.0)
glVertex3f(-50.0, -5.0, 50.0)
glTexCoord2f(5.0, 5.0)
glVertex3f(50.0, -5.0, 50.0)
glTexCoord2f(0.0, 5.0)
glVertex3f(50.0, -5.0, -50.0)
glEnd()
Při zobrazení bude možné si zvolit filtry použité při přiblížení či naopak vzdálení textury. Řízení texturovací jednotky provádí tento kód:
def set_filters(minFilterEnabled, magFilterEnabled):
minFilter = GL_LINEAR if minFilterEnabled else GL_NEAREST
magFilter = GL_LINEAR if magFilterEnabled else GL_NEAREST
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter)
Nastavení filtrů pak přibližně následující úryvek kódu, který umožňuje, aby se klávesami I a A filtry zapnuly či vypnuly (každý zvlášť):
minFilterEnabled = True # filtry pouzite pri texturovani
magFilterEnabled = True
if keys[key.I]:
minFilterEnabled = not minFilterEnabled
if keys[key.A]:
magFilterEnabled = not magFilterEnabled
Úplný zdrojový kód dnešního prvního demonstračního příkladu vypadá následovně:
#!/usr/bin/env python
import pyglet
from pyglet.gl import *
from pyglet.window import key
fov = 70.0 # hodnota zorneho uhlu - field of view
nearPlane = 0.1 # blizsi orezavaci rovina
farPlane = 90.0 # vzdalenejsi orezavaci rovina
r1 = 0.0
r2 = 0.0
depthBufferEnabled = False # povoleni ci zakaz Z-bufferu
texturesEnabled = True # povoleni ci zakaz textur
minFilterEnabled = True # filtry pouzite pri texturovani
magFilterEnabled = True
def create_window():
return pyglet.window.Window(width=500,
height=500,
caption="Pyglet library")
window = create_window()
def load_texture(filename):
image_stream = open(filename, 'rb')
image = pyglet.image.load(filename, file=image_stream)
return image.get_texture()
def init():
glClearColor(0.0, 0.0, 0.3, 0.0) # barva pozadi obrazku
glPolygonMode(GL_FRONT, GL_FILL) # nastaveni rezimu vykresleni modelu
glPolygonMode(GL_BACK, GL_FILL)
glDisable(GL_CULL_FACE) # zadne hrany ani steny se nebudou odstranovat
glDepthFunc(GL_LESS) # funkce pro testovani fragmentu
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glBindTexture(GL_TEXTURE_2D, texture.id)
glEnable(GL_TEXTURE_2D) # povoleni texturovani
@window.event
def on_resize(width, height):
init()
glViewport(0, 0, width, height) # viditelna oblast pres cele okno
def draw_floor():
glBegin(GL_QUADS) # vykresleni podlahy
glTexCoord2f(0.0, 0.0)
glVertex3f(-50.0, -5.0, -50.0)
glTexCoord2f(5.0, 0.0)
glVertex3f(-50.0, -5.0, 50.0)
glTexCoord2f(5.0, 5.0)
glVertex3f(50.0, -5.0, 50.0)
glTexCoord2f(0.0, 5.0)
glVertex3f(50.0, -5.0, -50.0)
glEnd()
def set_depth_buffer(depthBufferEnabled):
if depthBufferEnabled:
glEnable(GL_DEPTH_TEST)
else:
glDisable(GL_DEPTH_TEST)
def clear_buffers(depthBufferEnabled):
if depthBufferEnabled: # vymazani i Z/W bufferu
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
else: # vymazani vsech bitovych rovin barvoveho bufferu
glClear(GL_COLOR_BUFFER_BIT)
def set_filters(minFilterEnabled, magFilterEnabled):
minFilter = GL_LINEAR if minFilterEnabled else GL_NEAREST
magFilter = GL_LINEAR if magFilterEnabled else GL_NEAREST
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter)
def set_textures(texturesEnabled):
if texturesEnabled:
glEnable(GL_TEXTURE_2D)
else:
glDisable(GL_TEXTURE_2D)
@window.event
def on_draw():
global depthBufferEnabled
global texturesEnabled
global minFilterEnabled
global magFilterEnabled
if keys[key.Z]:
depthBufferEnabled = not depthBufferEnabled
if keys[key.T]:
texturesEnabled = not texturesEnabled
if keys[key.I]:
minFilterEnabled = not minFilterEnabled
if keys[key.A]:
magFilterEnabled = not magFilterEnabled
clear_buffers(depthBufferEnabled)
set_depth_buffer(depthBufferEnabled)
set_filters(minFilterEnabled, magFilterEnabled)
set_textures(texturesEnabled)
# zacatek kodu modifikujiciho projekcni matici
glMatrixMode(GL_PROJECTION)
glLoadIdentity() # vymazani projekcni matice
gluPerspective(fov, 1.0, nearPlane, farPlane)
# zacatek kodu modifikujiciho modelview matici
glMatrixMode(GL_MODELVIEW)
glLoadIdentity() # nahrat jednotkovou matici
gluLookAt(4.0, 6.0, 18.0, # bod, odkud se kamera diva
0.0, 2.0, 0.0, # bod, kam se kamera diva
0.0, 1.0, 0.0) # poloha "stropu" ve scene
glRotatef(r1, 1.0, 0.0, 0.0) # rotace objektu
glRotatef(r2, 0.0, 1.0, 0.0)
glTranslatef(0, 0, -40) # posun objektu
draw_floor() # vykresleni objektu - podlahy
texture = load_texture('checker.png')
keys = key.KeyStateHandler()
window.push_handlers(keys)
pyglet.app.run()
Obrázek 6: Screenshot prvního příkladu: při přiblížení textury se barva pixelu odvozuje z nejbližšího texelu.
Obrázek 7: Screenshot prvního příkladu: při přiblížení textury je použita bilineární interpolace.
6. Použití mipmappingu
Pro zamezení problikávání se používají textury uložené ve více rozlišeních (tj. úrovních detailu). Při vykreslování otexturovaného povrchu se nejdříve zjistí relativní velikost povrchu vůči celé textuře a poté se vybere vhodné rozlišení textury, která se posléze na vykreslovanou stěnu nanese. Tento postup má nevýhodu v tom, že při postupném zmenšování objektu by docházelo ke skokové změně textury (přešlo by se k menšímu rozlišení textury). Proto se zavádí další úroveň interpolace, kdy se vybere nejbližší větší a nejbližší menší textura a barva pixelů se vypočte interpolací mezi těmito dvěma texturami.
Nyní tedy zbývá pouze volba vhodného rozlišení textur. Z hlediska implementace interpolátoru na grafickém akcelerátoru je nejvýhodnější, aby se rozlišení textury v horizontálním i vertikálním směru snižovalo vždy na polovinu. Počet texelů je v každé následující textuře zmenšen na čtvrtinu až do dosažení textury o velikosti 1×1 pixel. Princip tvorby mipmapy je ukázán na dalším obrázku:
Obrázek 8: Princip tvorby mipmapy.
Obrázek 9: Ukázka textur vhodných pro tvorbu mipmapy
7. Podpora mipmappingu v grafické knihovně OpenGL
V grafické knihovně OpenGL jsou mipmapy samozřejmě také podporovány, protože se jedná o velmi často používanou renderovací (vykreslovací) pomůcku. Pro každé nastavované rozlišení textury je zapotřebí zavolat již dříve popsanou funkci, jejíž céčková hlavička vypadá následovně:
void glTexImage2D(
GLenum target,
GLint level,
GLint components,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
const GLvoid *pixels
);
kde se do parametru nazvaného level zadává úroveň textury v hierarchii. Nulou specifikujeme texturu se základním (tj. nejvyšším) rozlišením, jedničkou texturu s rozlišením polovičním atd. V texturovací paměti grafického akcelerátoru se vytvoří takzvaná mipmapa, tj. textura, ve které jsou uloženy všechny velikosti textur rozdělených na jednotlivé barevné složky RGB. Ukázka mipmapy je zobrazena na následujícím obrázku. Z tohoto obrázku je patrné, že se jedná o hierarchickou strukturu, ve které se dají jednoduše adresovat korespondující pixely v různých rozlišeních. Při adresaci přitom vystačíme pouze s aditivními operacemi a bitovými posuny, což jsou pro grafický akcelerátor ideální operace.
Obrázek 10: Ukázka interní reprezentace mipmapy uložené v texturovací paměti grafického akcelerátoru
8. Automatické generování mipmap v nadstavbové knihovně GLU
Textury s více úrovněmi detailu můžeme buď vytvořit programově s použitím různých filtrů, nebo je možné použít funkce pro automatické generování mipmap. Tyto funkce jsou obsaženy v nadstavbové knihovně GLU a mají tvar:
int gluBuild1DMipmaps(
GLenum target,
GLint components,
GLint width,
GLenum format,
GLenum type,
const GLvoid * data
);
int gluBuild2DMipmaps(
GLenum target,
GLint components,
GLint width,
GLint height,
GLenum format,
GLenum type,
const GLvoid * data
);
Parametry těchto funkcí a jejich význam odpovídá parametrům funkcí glTexImage1D() a glTexImage2D().
9. Automatické vygenerování mipmapy v knihovně Pyglet
V knihovně Pyglet máme situaci značně usnadněnou, protože ve chvíli, kdy je k dispozici obrázek o rozlišení, které je mocninou čísla 2, je možné z takového obrázku přímo získat mipmapu. O všechny přepočty se postará knihovna Pyglet automaticky. Podívejme se nyní, jak se mipmapa vytvoří v praxi. V předchozím příkladu jsme používali uživatelskou funkci nazvanou load_texture(), která načetla rastrový obrázek a vytvořila z něho běžnou texturu:
def load_texture(filename):
image_stream = open(filename, 'rb')
image = pyglet.image.load(filename, file=image_stream)
return image.get_texture()
Pokud namísto volání metody get_texture() použijeme metodu get_mipmapped_texture(), získáme skutečně mipmapu, ovšem jen ve chvíli, kdy jsou rozměry textury rovny 2n×2n pro nějakou celočíselnou konstantu n:
def load_texture(filename):
image_stream = open(filename, 'rb')
image = pyglet.image.load(filename, file=image_stream)
return image.get_mipmapped_texture()
10. Nastavení filtrů při použití mipmappingu
Při použití mipmappingu je také možné specifikovat další typy filtrů použitých při zmenšování textur. Kromě výběru nejbližšího souseda (GL_NEAREST) a interpolace nejbližších sousedů (GL_LINEAR) jsou nově k dispozici i interpolace prováděné mezi dvěma texturami (vybírá se nejbližší menší a nejbližší větší textura):
- Při nastaveném filtru GL_NEAREST_MIPMAP_NEAREST je pro obarvení pixelu vybrán nejbližší texel z nejbližší větší nebo menší textury. Tento filtr poskytuje vizuálně nejhorší výsledky, vykreslování je však nejrychlejší.
- GL_NEAREST_MIPMAP_LINEAR – vybere dva nejbližší texely z obou textur a provede mezi nimi lineární interpolaci. Tímto filtrem se dají jednoduše odstranit nepříjemné skokové změny v obraze, které nastávají v případě, že se zobrazované těleso příliš zvětší nebo zmenší a provede se tak výběr jiné dvojice textur z mipmapy.
- GL_LINEAR_MIPMAP_NEAREST – provádí bilineární interpolaci nejbližších texelů v jedné textuře. Při zmenšování nebo zvětšování tělesa mohou nastat skokové změny ve vykreslované textuře.
- GL_LINEAR_MIPMAP_LINEAR – nejprve se použije interpolace pro výpočet barev texelů v obou texturách a poté se výsledná barva spočte další interpolací mezi dvěma předešlými (ve skutečnosti se tedy provádí takzvaná trilineární interpolace). Tento filtr je sice nejpomalejší, ale na druhou stranu poskytuje nejlepší vizuální výsledky.
11. Druhý demonstrační příklad – použití mipmappingu v praxi
V dnešním druhém demonstračním příkladu bude mipmapping použit a navíc bude i konfigurovatelný. Způsob zobrazení je řízen třemi globálními proměnnými:
minFilterEnabled = True # filtry pouzite pri texturovani
magFilterEnabled = True
minFilterMode = GL_NEAREST_MIPMAP_NEAREST # rezim mipmap
Obsah těchto proměnných je možné modifikovat stiskem kláves I a A (povolení filtrů při texturování) a taktéž klávesami 1 až 4 (čtyři možnosti popsané v desáté kapitole):
if keys[key.I]:
minFilterEnabled = not minFilterEnabled
if keys[key.A]:
magFilterEnabled = not magFilterEnabled
if keys[key._1]:
minFilterMode = GL_NEAREST_MIPMAP_NEAREST
if keys[key._2]:
minFilterMode = GL_NEAREST_MIPMAP_LINEAR
if keys[key._3]:
minFilterMode = GL_LINEAR_MIPMAP_NEAREST
if keys[key._4]:
minFilterMode = GL_LINEAR_MIPMAP_LINEAR
Samotná změna způsobu texturování je implementována ve funkci nazvané set_filters():
def set_filters(minFilterEnabled, magFilterEnabled, minFilterMode):
minFilter = GL_LINEAR if minFilterEnabled else GL_NEAREST
magFilter = GL_LINEAR if magFilterEnabled else GL_NEAREST
if minFilterEnabled:
minFilter = minFilterMode
else:
minFilter = GL_NEAREST
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter)
Zbylé části zdrojového kódu se vlastně neliší od příkladu prvního.
12. Ukázka různých nastavení mipmappingu
Díky tomu, že při běhu příkladu můžeme volit parametry mipmappingu, bylo získání následujících screenshotů velmi snadné:
Obrázek 11: Mipmapping je zakázán, v zadní části obrázku můžeme vidět moaré.
Obrázek 12: Mipmapping je povolen a nastaven na GL_NEAREST_MIPMAP_NEAREST, povšimněte si chyby v zadní části šachovnice.
Obrázek 13: Mipmapping je povolen a nastaven na GL_NEAREST_MIPMAP_LINEAR.
Obrázek 14: Mipmapping je povolen a nastaven na GL_LINEAR_MIPMAP_NEAREST.
Obrázek 15: Mipmapping je povolen a nastaven na GL_LINEAR_MIPMAP_LINEAR (nejkvalitnější výsledek).
13. Úplný zdrojový kód druhého demonstračního příkladu
Úplný zdrojový kód dnešního druhého demonstračního příkladu vypadá takto:
#!/usr/bin/env python
import pyglet
from pyglet.gl import *
from pyglet.window import key
fov = 70.0 # hodnota zorneho uhlu - field of view
nearPlane = 0.1 # blizsi orezavaci rovina
farPlane = 90.0 # vzdalenejsi orezavaci rovina
r1 = 0.0
r2 = 0.0
depthBufferEnabled = False # povoleni ci zakaz Z-bufferu
texturesEnabled = True # povoleni ci zakaz textur
minFilterEnabled = True # filtry pouzite pri texturovani
magFilterEnabled = True
minFilterMode = GL_NEAREST_MIPMAP_NEAREST # rezim mipmap
def create_window():
return pyglet.window.Window(width=500,
height=500,
caption="Pyglet library")
window = create_window()
def load_texture(filename):
image_stream = open(filename, 'rb')
image = pyglet.image.load(filename, file=image_stream)
return image.get_mipmapped_texture()
def init():
glClearColor(0.0, 0.0, 0.3, 0.0) # barva pozadi obrazku
glPolygonMode(GL_FRONT, GL_FILL) # nastaveni rezimu vykresleni modelu
glPolygonMode(GL_BACK, GL_FILL)
glDisable(GL_CULL_FACE) # zadne hrany ani steny se nebudou odstranovat
glDepthFunc(GL_LESS) # funkce pro testovani fragmentu
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glBindTexture(GL_TEXTURE_2D, texture.id)
glEnable(GL_TEXTURE_2D) # povoleni texturovani
@window.event
def on_resize(width, height):
init()
glViewport(0, 0, width, height) # viditelna oblast pres cele okno
def draw_floor():
glBegin(GL_QUADS) # vykresleni podlahy
glTexCoord2f(0.0, 0.0)
glVertex3f(-50.0, -5.0, -50.0)
glTexCoord2f(5.0, 0.0)
glVertex3f(-50.0, -5.0, 50.0)
glTexCoord2f(5.0, 5.0)
glVertex3f(50.0, -5.0, 50.0)
glTexCoord2f(0.0, 5.0)
glVertex3f(50.0, -5.0, -50.0)
glEnd()
def set_depth_buffer(depthBufferEnabled):
if depthBufferEnabled:
glEnable(GL_DEPTH_TEST)
else:
glDisable(GL_DEPTH_TEST)
def clear_buffers(depthBufferEnabled):
if depthBufferEnabled: # vymazani i Z/W bufferu
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
else: # vymazani vsech bitovych rovin barvoveho bufferu
glClear(GL_COLOR_BUFFER_BIT)
def set_filters(minFilterEnabled, magFilterEnabled, minFilterMode):
minFilter = GL_LINEAR if minFilterEnabled else GL_NEAREST
magFilter = GL_LINEAR if magFilterEnabled else GL_NEAREST
if minFilterEnabled:
minFilter = minFilterMode
else:
minFilter = GL_NEAREST
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter)
def set_textures(texturesEnabled):
if texturesEnabled:
glEnable(GL_TEXTURE_2D)
else:
glDisable(GL_TEXTURE_2D)
@window.event
def on_draw():
global depthBufferEnabled
global texturesEnabled
global minFilterEnabled
global magFilterEnabled
global minFilterMode
if keys[key.Z]:
depthBufferEnabled = not depthBufferEnabled
if keys[key.T]:
texturesEnabled = not texturesEnabled
if keys[key.I]:
minFilterEnabled = not minFilterEnabled
if keys[key.A]:
magFilterEnabled = not magFilterEnabled
if keys[key._1]:
minFilterMode = GL_NEAREST_MIPMAP_NEAREST
if keys[key._2]:
minFilterMode = GL_NEAREST_MIPMAP_LINEAR
if keys[key._3]:
minFilterMode = GL_LINEAR_MIPMAP_NEAREST
if keys[key._4]:
minFilterMode = GL_LINEAR_MIPMAP_LINEAR
clear_buffers(depthBufferEnabled)
set_depth_buffer(depthBufferEnabled)
set_filters(minFilterEnabled, magFilterEnabled, minFilterMode)
set_textures(texturesEnabled)
# zacatek kodu modifikujiciho projekcni matici
glMatrixMode(GL_PROJECTION)
glLoadIdentity() # vymazani projekcni matice
gluPerspective(fov, 1.0, nearPlane, farPlane)
# zacatek kodu modifikujiciho modelview matici
glMatrixMode(GL_MODELVIEW)
glLoadIdentity() # nahrat jednotkovou matici
gluLookAt(4.0, 6.0, 18.0, # bod, odkud se kamera diva
0.0, 2.0, 0.0, # bod, kam se kamera diva
0.0, 1.0, 0.0) # poloha "stropu" ve scene
glRotatef(r1, 1.0, 0.0, 0.0) # rotace objektu
glRotatef(r2, 0.0, 1.0, 0.0)
glTranslatef(0, 0, -40) # posun objektu
draw_floor() # vykresleni objektu - podlahy
texture = load_texture('checker.png')
keys = key.KeyStateHandler()
window.push_handlers(keys)
pyglet.app.run()
14. Funkce knihovny OpenGL a pomocné knihovny GLU, které byly použity ve zdrojových kódech
V demonstračních příkladech, které byly uvedeny v dnešním článku, byly použity následující funkce převzaté z knihoven OpenGL a GLU:
- glLoadIdentity
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glLoadIdentity.xml - glRotate
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glRotate.xml - glMatrixMode
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glMatrixMode.xml - glViewport
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glViewport.xml - glColor3f
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glColor.xml - glClearColor
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glClearColor.xml - glClear
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glClear.xml - glTexEnvi
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTexEnv.xml - glTexEnvf
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTexEnv.xml - glTexEnviv
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTexEnv.xml - glTexEnvfv
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTexEnv.xml - glBegin
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glBegin.xml - glEnd
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glBegin.xml - glBindTexture
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glBindTexture.xml - glTexParameteri
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTexParameter.xml - glEnable
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glEnable.xml - glDisable
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glEnable.xml - glDepthFunc
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glDepthFunc.xml - glVertex3f
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glVertex.xml - glTexCoord2f
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTexCoord.xml - gluLookAt
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluLookAt.xml - gluPerspective
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml
15. Repositář s demonstračními příklady
Všechny dnes popsané demonstrační příklady byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/presentations. Příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý repositář. Pro jejich spuštění je nutné mít nainstalovanou jak knihovnu Pyglet, tak i podpůrné grafické knihovny OpenGL a GLU (což se většinou provede automaticky v rámci instalace balíčku s Pygletem, viz též úvodní díl tohoto seriálu):
Příklad | Odkaz |
---|---|
46_make_checker.py | https://github.com/tisnik/presentations/blob/master/pyglet/46_make_checker.py |
47_checker.py | https://github.com/tisnik/presentations/blob/master/pyglet/47_checker.py |
48_checker_mipmap.py | https://github.com/tisnik/presentations/blob/master/pyglet/48_checker_mipmap.py |
Poznámka: nejprve si spusťte první skript, který vytvoří texturu použitou v obou dalších příkladech.
16. Odkazy na Internetu
- Mipmap
https://en.wikipedia.org/wiki/Mipmap - Bilinear filtering
https://en.wikipedia.org/wiki/Bilinear_filtering - Trilinear filtering
https://en.wikipedia.org/wiki/Trilinear_filtering - glTexEnv - příkaz OpenGL
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTexEnv.xml - glGetTexEnv - příkaz OpenGL
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glGetTexEnv.xml - Pyglet Home Page
https://bitbucket.org/pyglet/pyglet/wiki/Home - Dokumentace k verzi 1.2
https://pyglet.readthedocs.io/en/pyglet-1.2-maintenance/ - Dokumentace k verzi 1.2 ve formátu PDF
https://readthedocs.org/projects/pyglet/downloads/pdf/pyglet-1.2-maintenance/ - PyOpenGL
http://pyopengl.sourceforge.net/ - The #! magic, details about the shebang/hash-bang mechanism on various Unix flavours
https://www.in-ulm.de/~mascheck/various/shebang/ - Shebang (Unix)
https://en.wikipedia.org/wiki/Shebang_%28Unix%29 - Domovská stránka systému LÖVE
http://love2d.org/ - Simple DirectMedia Layer (home page)
http://www.libsdl.org/ - Simple DirectMedia Layer (Wikipedia)
https://en.wikipedia.org/wiki/Simple_DirectMedia_Layer - Seriál Grafická knihovna OpenGL
https://www.root.cz/serialy/graficka-knihovna-opengl/ - Pyglet event loop
http://pyglet.readthedocs.io/en/latest/programming_guide/eventloop.html - Decorators I: Introduction to Python Decorators
http://www.artima.com/weblogs/viewpost.jsp?thread=240808 - 3D Programming in Python - Part 1
https://greendalecs.wordpress.com/2012/04/21/3d-programming-in-python-part-1/ - A very basic Pyglet tutorial
http://www.natan.termitnjak.net/tutorials/pyglet_basic.html - Alpha blending
https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending