Obsah
1. Projekt Vapory: kombinace možností Pythonu a POV-Raye
2. Průběh zpracování celé 3D scény
3. Instalace modulu vapory i raytraceru POV-Ray
4. První testovací scéna napsaná přímo pro POV-Ray
5. Shodná testovací scéna napsaná v Pythonu s využitím Vapory
6. Dočasný soubor vygenerovaný modulem vapory
7. Druhý příklad – použití externích souborů s deklarací barev a textur
8. Varianta naprogramovaná ve Vapory
9. Vylepšení předchozího příkladu – deklarace hodnoty pro gama korekci
10. Konstruktivní geometrie těles v POV-Rayi
11. Třetí příklad – POV-Ray varianta
12. Třetí příklad – varianta používající Vapory
13. Úprava předchozího příkladu: použití samostatných objektů, na něž se aplikují CSG operace
14. Základ tvorby jednoduchých animací
15. Vygenerování série snímků ve Vapory
16. Vytvoření animace ze série snímků
17. Úplný zdrojový kód čtvrtého příkladu
18. Makefile soubor určený pro vykreslení všech scén POV-Rayem
19. Repositář s demonstračními příklady
1. Projekt Vapory: kombinace možností Pythonu a POV-Raye
S raytracerem POV-Ray jsme se již na stránkách Rootu seznámili v poměrně podrobném seriálu. Připomeňme si ve stručnosti, že se v tomto raytraceru pro popis trojrozměrných scén (které mohou být i animované) používá vlastní jazyk, jehož syntaxe je vzdáleně podobná Céčku a od něj odvozených jazyků. Původně byl tento jazyk čistě deklarativní, ovšem s postupným vývojem schopností POV-Raye do něj začaly být přidávány konstrukce pro tvorbu programových smyček apod. Většina aplikací, které POV-Ray využívají jako svůj renderovací engine, tedy všechny 3D scény (světla, kamery, textury, tělesa atd.), nejprve musí exportovat do jazyka POV-Raye a teprve poté je možné provést vlastní vykreslení.
Obrázek 1: Implicitní plocha zapsaná obecným polynomem šestého stupně. I takové plochy je možné v POV-Rayi vykreslit bez nutnosti jejich rozdělení na trojúhelníky.
Do této kategorie nástrojů spadá i dnes popisovaný projekt Vapory, který umožňuje, aby byla celá trojrozměrná scéna popsaná přímo v jazyku Python s tím, že se překlad (transpřeklad) mezi Pythonem a POV-Rayem provede zcela automaticky a prakticky bez zásahu uživatele. Také je možné spojit možnosti Vapory s již popsaným [1] [2] [3] projektem MoviePy, což je poměrně zajímavé téma, kterému se budeme věnovat příště.
Obrázek 2: Příklad terciární struktury biomolekuly vymodelovaný v POV-Ray.
2. Průběh zpracování celé 3D scény
Průběh zpracování celé 3D scény při použití kombinace Vapory s POV-Rayem vypadá následovně:
Obrázek 3: Zpracování 3D scény při použití Vapory a POV-Raye.
V navazujících kapitolách si ukážeme, jak se Vapory může použít, a to nejenom při tvorbě statických 3D scén, ale i při programování jednodušších animací (jednodušších pouze z toho prostého důvodu, že rozsah článku je omezený).
3. Instalace modulu vapory i raytraceru POV-Ray
Nástroj Vapory je distribuován ve formě běžného balíčku pro Python, takže je dostupný i na PyPi. To mj. znamená, že instalace bude velmi jednoduchá a vystačíme si s nástrojem pip, popř. pip3. Instalaci postačuje provést pouze pro právě aktivního uživatele:
$ pip3 install --user vapory Downloading/unpacking vapory Downloading Vapory-0.1.01.tar.gz Running setup.py (path:/tmp/pip_build_tester/vapory/setup.py) egg_info for package vapory warning: no files found matching '*.txt' under directory 'examples' Installing collected packages: vapory Running setup.py install for vapory warning: no files found matching '*.txt' under directory 'examples' Successfully installed vapory Cleaning up...
V případě raytraceru POV-Ray máme dvě možnosti. Buď je možné tento nástroj nainstalovat přímo z balíčku připraveného pro danou distribuci Linuxu, což je nejjednodušší řešení. Druhý způsob je sice nepatrně složitější, ovšem získáte díky němu poslední verzi POV-Raye: naklonujte si repositář https://github.com/POV-Ray/povray/tree/3.7-stable (ideálně právě větev 3.7-stable, na kterou odkaz vede) a instalaci provést následující sérií kroků:
cd unix/ ./prebuild.sh cd ../ ./configure COMPILED_BY="jméno" make make install
Zapotřebí je mít k dispozici překladač C++ a několik knihoven ve vývojářské verzi: Boost, zLib, libpng, libjpeg a libTIFF (většina těchto knihoven se používá pro ukládání výsledných obrázků). Po make install by již měl být POV-Ray připraven pro další použití, takže jen pro rychlé ověření zjistíme jeho verzi:
$ povray --version POV-Ray 3.7.1-beta.7695039.unofficial This is an unofficial version compiled by: Pavel Tisnovsky <ptisnovs@redhat.com> The POV-Ray Team is not responsible for supporting this version. Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Built-in features: I/O restrictions: enabled X Window display: disabled Supported image formats: gif tga iff ppm pgm hdr png jpeg tiff Unsupported image formats: openexr Compilation settings: Build architecture: x86_64-unknown-linux-gnu Built/Optimized for: x86_64-unknown-linux-gnu (using -march=native) Compiler vendor: gnu Compiler version: g++ 4.8 Compiler flags: -pipe -Wno-multichar -Wno-write-strings -fno-enforce-eh-specs -Wno-non-template-friend -s -O3 -ffast-math -march=native -pthread
Obrázek 4: Všimněte si především techniky vymodelování řetězu, z hlediska raytraceru se jedná o velmi složitý objekt.
4. První testovací scéna napsaná přímo pro POV-Ray
Začněme porovnáním způsobu deklarace 3D scény v POV-Rayi a ve Vapory. Jednoduchou scénu, v níž jsou umístěny dva objekty, kamera a světelný zdroj, je možné popsat následovně (úplný zdrojový kód lze nalézt zde):
// ------------------------------------------------------------ // Jednoduchá scéna s jedním uzavřeným objektem, jedním nekonečným // objektem, jedním světlem a jednou kamerou (pozorovatelem) // // rendering lze spustit příkazem: // povray +W800 +H600 +B +FN +D +Iscena2.pov +Oscena2.png // (pro náhled postačí zadat povray scena1.pov) // ------------------------------------------------------------ #version 3.5; // globální nastavení parametrů scény global_settings { assumed_gamma 2.2 max_trace_level 5 } // nastavení kamery (pozorovatele) camera { location <0.0, 2.0,-3.0> // pozice kamery up <0.0, 1.0, 0.0> // vektor směřující vzhůru right <4/3, 0.0, 0.0> // vektor směřující doprava look_at <0.0, 1.0, 2.0> // bod, na který kamera směřuje } // světelný zdroj light_source { <2, 4, -3> // pozice světelného zdroje color <1,1,1> // barva světla } // jediný uzavřený objekt ve scéně - zelená koule sphere { <0, 1, 2>, // souřadnice středu koule 2.00 // poloměr koule texture { // textura - povrch koule pigment { color <1.0, 1.0, 0.0> // barva povrchu } finish { // optické vlastnosti materiálu phong 1 // velikost a síla odlesků phong_size 300 reflection 0.15 // odrazivost } } } // druhý objekt - nekonečná rovina plane { y, // orientace roviny -1.5 // vzdálenost od počátku texture { // textura - vlastnosti povrchu pigment { color <1,1,1> // barva povrchu } finish { // optické vlastnosti materiálu reflection 0.10 } } } // ------------------------------------------------------------ // finito // ------------------------------------------------------------
Vykreslení (rendering) této scény se provede následujícím příkazem (předpokladem samozřejmě je, že máte POV-Ray nainstalovaný nebo přeložený ze zdrojových kódů):
povray +W640 +H480 +B +FN +D +Iscene1.pov +Oscene1.png
Samotný průběh renderingu – maximálně několik sekund – nás nemusí příliš zajímat, ale jen pro jistotu:
Persistence of Vision(tm) Ray Tracer Version 3.7.1-alpha.7695039.unofficial ... ... ... ==== [Parsing...] ========================================================== ---------------------------------------------------------------------------- Parser Statistics ---------------------------------------------------------------------------- Finite Objects: 1 Infinite Objects: 1 Light Sources: 1 Total: 3 ---------------------------------------------------------------------------- Parser Time Parse Time: 0 hours 0 minutes 0 seconds (0.001 seconds) using 1 thread(s) with 0.000 CPU-seconds total Bounding Time: 0 hours 0 minutes 0 seconds (0.000 seconds) using 1 thread(s) with 0.000 CPU-seconds total ---------------------------------------------------------------------------- Render Options Quality: 9 Bounding boxes.......On Bounding threshold: 3 Antialiasing.........Off ==== [Rendering...] ======================================================== ... ... ... ---------------------------------------------------------------------------- Render Statistics Image Resolution 640 x 480 ---------------------------------------------------------------------------- Pixels: 307200 Samples: 0 Smpls/Pxl: 0.00 Rays: 620784 Saved: 5730 Max Level: 3/5 ---------------------------------------------------------------------------- Ray->Shape Intersection Tests Succeeded Percentage ---------------------------------------------------------------------------- Plane 877300 278626 31.76 Sphere 833770 330783 39.67 Bounding Box 877300 612405 69.81 ---------------------------------------------------------------------------- Shadow Ray Tests: 300278 Succeeded: 38040 Shadow Cache Hits: 38032 Reflected Rays: 313584 ---------------------------------------------------------------------------- ---------------------------------------------------------------------------- Render Time: Photon Time: No photons Radiosity Time: No radiosity Trace Time: 0 hours 0 minutes 0 seconds (0.255 seconds) using 4 thread(s) with 0.786 CPU-seconds total POV-Ray finished
Důležitější je výsledek:
Obrázek 5: Výsledek renderingu 3D scény raytracerem POV-Ray.
5. Shodná testovací scéna napsaná v Pythonu s využitím Vapory
Stejnou scénu je možné v Pythonu s využitím modulu/knihovny Vapory zapsat takto. Při zápisu jsem se snažil do co největší míry dodržet strukturu zdrojového kódu POV-Raye:
from vapory import * y = [0, 1, 0] camera = Camera('location', [0.0, 2.0, -3.0], 'up', [0.0, 1.0, 0.0], 'right', [4/3, 0.0, 0.0], 'look_at', [0.0, 1.0, 2.0]) light = LightSource([2, 4, -3], 'color', [1, 1, 1]) sphere = Sphere([0, 1, 2], 2.0, Texture( Pigment('color', [1, 1, 0]), Finish('phong', 1, 'phong_size', 300, 'reflection', 0.15))) plane = Plane(y, -1.5, Texture( Pigment('color', [1, 1, 1]), Finish('reflection', 0.10))) scene = Scene(camera, objects=[light, sphere, plane]) scene.render("scene1_vapory.png", width=640, height=480)
Povšimněte si, že všechny objekty, které tvoří 3D scénu, tj. (nekonečné) plochy, trojrozměrná tělesa, světla i kamera, jsou tvořeny instancemi tříd definovaných ve Vapory. Jedná se o tyto třídy: Camera, LightSource, Sphere a Plane. Následně jsou všechny objekty přidány do scény představované instancí třídy Scene a scéna je ihned poté vykreslena metodou Scene.render(). Není tedy nutné explicitně volat POV-Ray; tento krok za nás Vapory provede automaticky.
Obrázek 6: Porovnání shodné scény – jednou zapsané v jazyku POV-Raye, podruhé v Pythonu.
6. Dočasný soubor vygenerovaný modulem vapory
V případě, že se vám podaří násilím přerušit rendering, můžete si prohlédnout dočasný soubor, který byl vygenerovaný modulem vapory z popisu scény. Tento soubor sice není příliš čitelný kvůli absenci mezer, to ovšem POV-Rayi vůbec nevadí a soubor zpracuje zcela korektně:
light_source { <2,4,-3> color <1,1,1> } sphere { <0,1,2> 2.0 texture { pigment { color <1,1,0> } finish { phong 1 phong_size 300 reflection 0.15 } } } plane { <0,1,0> ( -1.5 ) texture { pigment { color <1,1,1> } finish { reflection 0.1 } } } camera { location <0.0,2.0,-3.0> up <0.0,1.0,0.0> right <1.3333333333333333,0.0,0.0> look_at <0.0,1.0,2.0> right <1.3333333333333333,0,0> } global_settings{ }
7. Druhý příklad – použití externích souborů s deklarací barev a textur
Ve druhém příkladu si ukážeme, jak lze využít externí soubory obsahující deklarace barev, textur popř. i parametrů těles. Těchto souborů obsahuje POV-Ray i ve standardní instalaci poměrně velké množství a lze je do scény snadno vložit příkazem #include:
// načtení všech potřebných externích souborů #include "colors.inc" #include "stones.inc" #include "glass.inc"
Příklad použití (viz zvýrazněné identifikátory):
light_source { <-30, 11, 20> // pozice světelného zdroje color White // barva světla } plane { y, // orientace roviny -1.5 // vzdálenost od počátku texture { // textura - vlastnosti povrchu T_Stone1 // definováno v externím souboru pigment { // vlastní vzorek textury octaves 3 // modifikace procedurálního vzorku rotate 90*z } finish { // optické vlastnosti materiálu reflection 0.10 } } }
Obrázek 7: Druhý demonstrační příklad vykreslený POV-Rayem.
Úplný zdrojový kód druhého příkladu ve variantě přímo pro POV-Ray vypadá takto:
// ------------------------------------------------------------ // Jednoduchá scéna s jedním uzavřeným objektem, jedním nekonečným // objektem, trojicí světel a jednou kamerou (pozorovatelem) // // Založeno na souboru původně vytvořeném Danem Farmerem (leden 2002) // // rendering lze spustit příkazem: // povray +W800 +H600 +B +FN +D +Iscena2.pov +Oscena2.png // (pro náhled postačí zadat povray scena2.pov) // ------------------------------------------------------------ #version 3.5; // globální nastavení parametrů scény global_settings { assumed_gamma 2.2 max_trace_level 5 } // načtení všech potřebných externích souborů #include "colors.inc" #include "stones.inc" #include "glass.inc" // nastavení kamery (pozorovatele) camera { location <1.65, 5.5, -5.0> // pozice kamery up <0.0, 1.0, 0.0> // vektor směřující vzhůru right <4/3, 0.0, 0.0> // vektor směřující doprava look_at <0, 0.5, -1.0> // bod, na který kamera směřuje } // tři světelné zdroje light_source { <-30, 11, 20> // pozice světelného zdroje color White // barva světla } light_source { < 31, 12, -20> // pozice světelného zdroje color White // barva světla } light_source { < 32, 11, -20> // pozice světelného zdroje color LightGray // barva světla } // jediný uzavřený objekt ve scéně - zelená skleněná koule sphere { <0, 0, 0>, // souřadnice středu koule 1.75 // poloměr koule interior { // vlastnosti "vnitřku" koule caustics 1.0 // světelná "prasátka" ior 1.5 // index lomu } texture { // textura - povrch koule T_Glass1 // definováno v externím souboru pigment { color green 0.90 filter 0.85 // barva povrchu } finish { // optické vlastnosti materiálu phong 1 // velikost a síla odlesků phong_size 300 reflection 0.15 // odrazivost } } } // druhý objekt - nekonečná rovina plane { y, // orientace roviny -1.5 // vzdálenost od počátku texture { // textura - vlastnosti povrchu T_Stone1 // definováno v externím souboru pigment { // vlastní vzorek textury octaves 3 // modifikace procedurálního vzorku rotate 90*z } finish { // optické vlastnosti materiálu reflection 0.10 } } } // ------------------------------------------------------------ // finito // ------------------------------------------------------------
8. Varianta naprogramovaná ve Vapory
Při použití Pythonu a knihovny Vapory je nutné v deklaraci scény uvést všechny vkládané soubory v nepovinném parametru included, který se předává konstruktoru třídy Scene. Hodnotou tohoto parametru je seznam vkládaných souborů:
scene = Scene(camera, objects=[light1, light2, light3, sphere, plane], included=["colors.inc", "stones.inc", "glass.inc"])
Úplný zápis druhého příkladu vypadá následovně:
from vapory import * y = [0, 1, 0] z = [0, 0, 1] camera = Camera('location', [1.65, 5.5,-5.0], 'up', [ 0.0, 1.0, 0.0], 'right', [ 4/3, 0.0, 0.0], 'look_at', [ 0.0, 0.5,-1.0]) # tři světelné zdroje light1 = LightSource([-30, 11, 20], 'color', 'White') light2 = LightSource([31, 12, -20], 'color', 'White') light3 = LightSource([32, 11, -20], 'color', 'LightGray') # jediný uzavřený objekt ve scéně - zelená skleněná koule sphere = Sphere([0, 0, 0], 1.75, Interior( 'caustics', 1.0, 'ior', 1.5), Texture( 'T_Glass1', Pigment('color', 'green', 0.9, 'filter', 0.85), Finish('phong', 1, 'phong_size', 300, 'reflection', 0.15))) # druhý objekt - nekonečná rovina plane = Plane(y, -1.5, Texture( 'T_Stone1', Pigment('octaves', 3, 'rotate', [i * 90 for i in z]), Finish('reflection', 0.10))) scene = Scene(camera, objects=[light1, light2, light3, sphere, plane], included=["colors.inc", "stones.inc", "glass.inc"]) scene.render("scene2_vapory.png", width=640, height=480)
9. Vylepšení předchozího příkladu – deklarace hodnoty pro gama korekci
Ve skutečnosti jsou výsledné obrázky vykreslené POV-Rayem odlišné, protože první varianta (vytvořená přímo v jazyku POV-Raye) obsahovala deklaraci hodnoty gmma, kdežto druhá varianta (Vapory) nikoli – viz též Gama korekce na Wiki:
Obrázek 8: Obrázek vykreslený při použití gama=2.2.
Obrázek 9: Obrázek vykreslený při použití výchozí hodnoty gama.
V POV-Rayi je nastavení výchozí hodnoty gama velmi snadné:
// globální nastavení parametrů scény global_settings { assumed_gamma 2.2 }
Ve Vapory musíme použít další nepovinný parametr předávaný do konstruktoru třídy Scene. Tento parametr se jmenuje global_settings a jeho hodnotou je seznam řetězců, které se předávají POV-Rayi:
scene = Scene(camera, objects=[light1, light2, light3, sphere, plane], included=["colors.inc", "stones.inc", "glass.inc"], global_settings=["assumed_gamma 2.2"])
Opět si ukažme úplný zdrojový kód tohoto příkladu:
from vapory import * y = [0, 1, 0] z = [0, 0, 1] camera = Camera('location', [1.65, 5.5,-5.0], 'up', [ 0.0, 1.0, 0.0], 'right', [ 4/3, 0.0, 0.0], 'look_at', [ 0.0, 0.5,-1.0]) # tři světelné zdroje light1 = LightSource([-30, 11, 20], 'color', 'White') light2 = LightSource([31, 12, -20], 'color', 'White') light3 = LightSource([32, 11, -20], 'color', 'LightGray') # jediný uzavřený objekt ve scéně - zelená skleněná koule sphere = Sphere([0, 0, 0], 1.75, Interior( 'caustics', 1.0, 'ior', 1.5), Texture( 'T_Glass1', Pigment('color', 'green', 0.9, 'filter', 0.85), Finish('phong', 1, 'phong_size', 300, 'reflection', 0.15))) # druhý objekt - nekonečná rovina plane = Plane(y, -1.5, Texture( 'T_Stone1', Pigment('octaves', 3, 'rotate', [i * 90 for i in z]), Finish('reflection', 0.10))) scene = Scene(camera, objects=[light1, light2, light3, sphere, plane], included=["colors.inc", "stones.inc", "glass.inc"], global_settings=["assumed_gamma 2.2"]) scene.render("scene2B_vapory.png", width=640, height=480)
10. Konstruktivní geometrie těles v POV-Rayi
POV-Ray, podobně jako mnohé další raytracery, podporuje tzv. CSG. Reprezentace modelů pomocí konstruktivní geometrie těles (Constructive Solid Geometry – CSG) je založena na analytickém popisu těles jejich objemem, tj. podmnožinou trojrozměrného prostoru ležícího uvnitř tělesa. V literatuře se lze občas setkat s tvrzením, že konstruktivní geometrie těles patří mezi metody popisující hranici těles. To však není zcela přesné, protože v CSG můžeme pro libovolný bod jednoduše zjistit, zda leží uvnitř či vně tělesa, což se v POV-Rayi velmi často používá.
Obrázek 10: Jednoduché těleso vytvořené z koule a krychle spojené operací rozdílu (difference).
Na druhou stranu se pro mnohá tělesa složitě zjišťují souřadnice bodů na povrchu těles, mnohdy je dokonce nutné použít numerické metody. Minimálně těmito vlastnostmi se tedy CSG odlišuje od běžně chápané hraniční reprezentace. Vývoj konstruktivní geometrie byl zahájen v roce 1973 s cílem definovat složité útvary pomocí operací sjednocení, průniku, rozdílu a hladkého napojení nad základními tělesy (primitivy).
Obrázek 11: Jednoduché těleso vytvořené z koule a krychle spojené operací průniku (intersection).
Jako primitiva se většinou používají objekty popsatelné pomocí jedné či soustavou několika nerovnic, v nichž se vyskytují polynomy nízkého stupně. Typicky se jedná o následující objekty: koule, válec, kužel, elipsoid (vše jsou to kvadriky), toroid a poloprostor. Model vychází ze skutečnosti, že těleso v prostoru lze popsat jako množinu bodů, které splňují určité vlastnosti. Ty mohou být u jednoduchých objektů popsány jednou nerovnicí či soustavou nerovnic.
Obrázek 12: Jednoduché těleso vytvořené z koule a krychle spojené operací spojení (union).
Popisovat složitý objekt s mnoha nerovnostmi na povrchu pomocí soustavy nerovnic může být velmi obtížné a může vést ke komplikacím při vyhodnocování (vykreslování) scény. Aby k uvedeným problémům nedocházelo, skládají se v CSG reprezentaci složitější objekty z objektů jednoduchých pomocí množinových operací. Množinovými operacemi, které při popisu přicházejí v úvahu, jsou binární nebo n-ární průnik (∩), sjednocení (∪) a rozdíl (-). Často se používá i unární operace doplněk ('), která znamená „převrácení“ tělesa, tedy smyslu bodů ležících uvnitř a vně tělesa se zachováním hranice.
Obrázek 13: Základní 3D tělesa, která lze zkombinovat pomocí CSG.
Složité těleso je tedy v CSG reprezentaci popsáno stromem, který obsahuje ve svých listech geometrické, popř. i doplňkové informace o primitivních tělesech. V uzlech tohoto stromu jsou uloženy množinové operace, popřípadě i transformace. Lineárními transformacemi může být popsána změna polohy, popř. změna měřítka části tělesa ležícího v daném podstromu. Kromě lineárních transformací lze použít i obecnější transformace, které potom mohou reprezentovat například různé deformace buď celého tělesa nebo jeho části (zde se však již jedná o poměrně složitou technologii).
11. Třetí příklad – POV-Ray varianta
V POV-Rayi se CSG zapisuje jednoduše. Následuje ukázka operace rozdílu:
difference { těleso1 těleso2 transformace }
Například pro vytvoření rozdílového tělesa mezi krychlí a koulí použijeme:
difference { box { <-VEL, -VEL, -VEL> // jeden z vrcholů krychle na tělesové úhlopříčce < VEL, VEL, VEL> // druhý z vrcholů krychle na tělesové úhlopříčce texture { // textura - povrch krychle T_Wood23 // definováno v externím souboru finish { // optické vlastnosti materiálu phong 1 // velikost a síla odlesků phong_size 300 reflection 0.15 // odrazivost } } } sphere { <0, 0, 0>, // souřadnice středu koule 1.8 // poloměr koule texture { // textura - povrch koule T_Wood24 // definováno v externím souboru finish { // optické vlastnosti materiálu phong 1 // velikost a síla odlesků phong_size 300 reflection 0.15 // odrazivost } } } rotate <0,45,0> // rotace výsledného "dvojtělesa" }
Obrázek 14: Výsledné rozdílové těleso.
Úplný zdrojový kód třetího příkladu vypadá následovně:
// ------------------------------------------------------------ // Aplikace CSG operace rozdílu koule a krychle // // Založeno na souboru původně vytvořeném Danem Farmerem (leden 2002) // // rendering lze spustit příkazem: // povray +W800 +H600 +B +FN +D +Iscena2.pov +Oscena2.png // (pro náhled postačí zadat povray scena3.pov) // ------------------------------------------------------------ #version 3.5; // globální nastavení parametrů scény global_settings { assumed_gamma 2.2 max_trace_level 5 } // načtení všech potřebných externích souborů #include "colors.inc" #include "stones.inc" #include "glass.inc" #include "woods.inc" // nastavení kamery (pozorovatele) camera { location <1.65, 5.5, -5.0> // pozice kamery up <0.0, 1.0, 0.0> // vektor směřující vzhůru right <4/3, 0.0, 0.0> // vektor směřující doprava look_at <0, 0.5, -1.0> // bod, na který kamera směřuje } // tři světelné zdroje light_source { <-30, 11, 20> // pozice světelného zdroje color White // barva světla } light_source { < 31, 12, -20> // pozice světelného zdroje color White // barva světla } light_source { < 32, 11, -20> // pozice světelného zdroje color LightGray // barva světla } #declare VEL=1.45; // velikost krychle difference { box { <-VEL, -VEL, -VEL> // jeden z vrcholů krychle na tělesové úhlopříčce < VEL, VEL, VEL> // druhý z vrcholů krychle na tělesové úhlopříčce texture { // textura - povrch krychle T_Wood23 // definováno v externím souboru finish { // optické vlastnosti materiálu phong 1 // velikost a síla odlesků phong_size 300 reflection 0.15 // odrazivost } } } sphere { <0, 0, 0>, // souřadnice středu koule 1.8 // poloměr koule texture { // textura - povrch koule T_Wood24 // definováno v externím souboru finish { // optické vlastnosti materiálu phong 1 // velikost a síla odlesků phong_size 300 reflection 0.15 // odrazivost } } } rotate <0,45,0> // rotace výsledného "dvojtělesa" } // druhý objekt - nekonečná rovina plane { y, // orientace roviny -1.5 // vzdálenost od počátku texture { // textura - vlastnosti povrchu T_Stone1 // definováno v externím souboru pigment { // vlastní vzorek textury octaves 3 // modifikace procedurálního vzorku rotate 90*z } finish { // optické vlastnosti materiálu reflection 0.10 } } } // ------------------------------------------------------------ // finito // ------------------------------------------------------------
12. Třetí příklad – varianta používající Vapory
Přepis do Vapory je snadný, protože například rozdíl těles (CSG operace) se zapíše konstruktorem Difference:
csg_object = Difference( Box([-VEL, -VEL, -VEL], [VEL, VEL, VEL], Texture( 'T_Wood23', Finish('phong', 1, 'phong_size', 300, 'reflection', 0.15))), Sphere([0, 0, 0], 1.8, Texture( 'T_Wood24', Finish('phong', 1, 'phong_size', 300, 'reflection', 0.15))) )
Přepis celého demonstračního příkladu do Pythonu/Vapory může vypadat takto:
from vapory import * y = [0, 1, 0] z = [0, 0, 1] camera = Camera('location', [1.65, 5.5,-5.0], 'up', [ 0.0, 1.0, 0.0], 'right', [ 4/3, 0.0, 0.0], 'look_at', [ 0.0, 0.5,-1.0]) # tři světelné zdroje light1 = LightSource([-30, 11, 20], 'color', 'White') light2 = LightSource([31, 12, -20], 'color', 'White') light3 = LightSource([32, 11, -20], 'color', 'LightGray') VEL = 1.45 # velikost krychle csg_object = Difference( Box([-VEL, -VEL, -VEL], [VEL, VEL, VEL], Texture( 'T_Wood23', Finish('phong', 1, 'phong_size', 300, 'reflection', 0.15))), Sphere([0, 0, 0], 1.8, Texture( 'T_Wood24', Finish('phong', 1, 'phong_size', 300, 'reflection', 0.15))) ) # druhý objekt - nekonečná rovina plane = Plane(y, -1.5, Texture( 'T_Stone1', Pigment('octaves', 3, 'rotate', [i * 90 for i in z]), Finish('reflection', 0.10))) scene = Scene(camera, objects=[light1, light2, light3, csg_object, plane], included=["colors.inc", "stones.inc", "woods.inc"], global_settings=["assumed_gamma 2.2"]) scene.render("scene3_vapory.png", width=640, height=480)
13. Úprava předchozího příkladu: použití samostatných objektů, na něž se aplikují CSG operace
Předchozí příklad je možné upravit takovým způsobem, že nejdříve vytvoříme objekty představující samotná 3D tělesa vstupující do CSG:
VEL = 1.45 # velikost krychle box = Box([-VEL, -VEL, -VEL], [VEL, VEL, VEL], Texture( 'T_Wood23', Finish('phong', 1, 'phong_size', 300, 'reflection', 0.15))) sphere = Sphere([0, 0, 0], 1.8, Texture( 'T_Wood24', Finish('phong', 1, 'phong_size', 300, 'reflection', 0.15)))
Teprve poté se na tato dvě tělesa aplikuje vybraná operace. Předností je, že jedno těleso lze použít vícekrát, popř. jednodušší tvorba animací:
csg_object = Difference(box, sphere)
Výsledný kód naleznete na adrese https://github.com/tisnik/vapory-examples/blob/master/scene3_update.py:
from vapory import * y = [0, 1, 0] z = [0, 0, 1] camera = Camera('location', [1.65, 5.5,-5.0], 'up', [ 0.0, 1.0, 0.0], 'right', [ 4/3, 0.0, 0.0], 'look_at', [ 0.0, 0.5,-1.0]) # tři světelné zdroje light1 = LightSource([-30, 11, 20], 'color', 'White') light2 = LightSource([31, 12, -20], 'color', 'White') light3 = LightSource([32, 11, -20], 'color', 'LightGray') VEL = 1.45 # velikost krychle box = Box([-VEL, -VEL, -VEL], [VEL, VEL, VEL], Texture( 'T_Wood23', Finish('phong', 1, 'phong_size', 300, 'reflection', 0.15))) sphere = Sphere([0, 0, 0], 1.8, Texture( 'T_Wood24', Finish('phong', 1, 'phong_size', 300, 'reflection', 0.15))) csg_object = Difference(box, sphere) # druhý objekt - nekonečná rovina plane = Plane(y, -1.5, Texture( 'T_Stone1', Pigment('octaves', 3, 'rotate', [i * 90 for i in z]), Finish('reflection', 0.10))) scene = Scene(camera, objects=[light1, light2, light3, csg_object, plane], included=["colors.inc", "stones.inc", "woods.inc"], global_settings=["assumed_gamma 2.2"]) scene.render("scene3B_vapory.png", width=640, height=480)
14. Základ tvorby jednoduchých animací
Jeden z důvodů, proč používat Vapory namísto přímé dekarace 3D scén v POV-Rayi, spočívá ve snadnější tvorbě animací, protože v Pythonu můžeme provádět různě složité výpočty, pracovat s nelineárním časem atd. atd. Samozřejmě si opět ukážeme příklad, který bude vycházet z příkladu předchozího, tj. i zde se bude využívat CSG (Constructive solid geometry). Ovšem celá scéna bude vytvářena a vykreslována v programové smyčce, v níž se bude postupně měnit souřadnice středu koule, která společně s krychlí tvoří těleso získané právě pomocí CSG. Koule je zpočátku umístěna mimo krychli a v navazujících snímcích postupně krychlí prolétá:
def construct_scene(t): sphere = Sphere([0, 3.3 - 7.0*t, 0], 1.8, Texture( 'T_Wood24', Finish('phong', 1, 'phong_size', 300, 'reflection', 0.15))) csg_object = Difference(box, sphere) return Scene(camera, objects=[light1, light2, light3, csg_object, plane], included=["colors.inc", "stones.inc", "woods.inc"], global_settings=["assumed_gamma 2.2"])
15. Vygenerování série snímků ve Vapory
Pokud výše uvedenou funkci spoustíte ve smyčce:
FRAMES = 100 for frame in range(0, FRAMES): t = frame / float(FRAMES) scene = construct_scene(t) filename = "frame_{:03d}.png".format(frame) scene.render(filename, width=400, height=300)
Vytvoří se série snímků ve formátu PNG:
Obrázek 14: Snímek číslo 0.
Obrázek 15: Snímek číslo 8.
Obrázek 16: Snímek číslo 16.
Obrázek 17: Snímek číslo 24.
Obrázek 18: Snímek číslo 32.
Obrázek 19: Snímek číslo 40.
Obrázek 20: Snímek číslo 48.
Obrázek 21: Snímek číslo 56.
Obrázek 22: Snímek číslo 64.
Obrázek 23: Snímek číslo 72.
Obrázek 24: Snímek číslo 80.
16. Vytvoření animace ze série snímků
Z těchto snímků je nutné vytvořit animaci, k čemuž (prozatím) využijeme nástroj ffmpeg:
ffmpeg -r 10 -i frame_%03d.png -b:v 700k scene4.ogg
Výsledkem by tedy měla být tato animace:
https://tisnik.github.io/moviepy-videos/video10.htm
17. Úplný zdrojový kód čtvrtého příkladu
Úplný zdrojový kód čtvrtého příkladu naleznete na adrese https://github.com/tisnik/vapory-examples/blob/master/scene4.py:
from vapory import * y = [0, 1, 0] z = [0, 0, 1] camera = Camera('location', [1.65, 5.5,-5.0], 'up', [ 0.0, 1.0, 0.0], 'right', [ 4/3, 0.0, 0.0], 'look_at', [ 0.0, 0.5,-1.0]) # tři světelné zdroje light1 = LightSource([-30, 11, 20], 'color', 'White') light2 = LightSource([31, 12, -20], 'color', 'White') light3 = LightSource([32, 11, -20], 'color', 'LightGray') VEL = 1.45 # velikost krychle box = Box([-VEL, -VEL, -VEL], [VEL, VEL, VEL], Texture( 'T_Wood23', Finish('phong', 1, 'phong_size', 300, 'reflection', 0.15))) # druhý objekt - nekonečná rovina plane = Plane(y, -1.5, Texture( 'T_Stone1', Pigment('octaves', 3, 'rotate', [i * 90 for i in z]), Finish('reflection', 0.10))) def construct_scene(t): sphere = Sphere([0, 3.3 - 7.0*t, 0], 1.8, Texture( 'T_Wood24', Finish('phong', 1, 'phong_size', 300, 'reflection', 0.15))) csg_object = Difference(box, sphere) return Scene(camera, objects=[light1, light2, light3, csg_object, plane], included=["colors.inc", "stones.inc", "woods.inc"], global_settings=["assumed_gamma 2.2"]) FRAMES = 100 for frame in range(0, FRAMES): t = frame / float(FRAMES) scene = construct_scene(t) filename = "frame_{:03d}.png".format(frame) scene.render(filename, width=400, height=300)
18. Makefile soubor určený pro vykreslení všech scén POV-Rayem
Pro zajímavost si ještě ukažme soubor Makefile použitý pro vytvoření rastrových obrázků ze všech zdrojových kódů určených přímo pro POV-Ray, tj. ze souborů s koncovkou .pov. Tento soubor je součástí repositáře:
# seznam vsech zdrojovych v POV-Rayi SOURCES := $(wildcard *.pov) # seznam souboru, ktere se maji vygenerovat GENERATED := $(patsubst %.pov,%.png,$(SOURCES)) all: ${GENERATED} clean: rm *.png %.png: %.pov povray +W640 +H480 +B +FN +D +I$< +O$@ .PHONY: clean
19. Repositář s demonstračními příklady
Zdrojové kódy všech dnes popsaných demonstračních příkladů určených pro POV-Ray i Vapory byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/vapory-examples. V případě, že nebudete chtít klonovat celý repositář (ten je ovšem stále velmi malý, stále doslova několik kilobajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:
20. Odkazy na Internetu
- vapory na GitHubu
https://github.com/Zulko/vapory - Seriál na Rootu: Vykreslujeme 3D scény s POV-Ray
https://www.root.cz/serialy/vykreslujeme-3d-sceny-s-pov-ray/ - Animace v POV-Rayi
https://www.root.cz/clanky/animace-v-pov-rayi/ - Tvorba pokročilejších animací v POV-Rayi
https://www.root.cz/clanky/tvorba-pokrocilejsich-animaci-v-pov-rayi/ - The POV-Ray Cyclopedia:
http://www.spiritone.com/~english/cyclopedia/index.html - POV-Ray New Ring:
http://webring.povray.org/ - Animations with POV-Ray:
http://www.f-lohmueller.de/pov_tut/animate/pov_anie.htm - The POV-Ray Objects Collection:
http://objects.povworld.org/ - POV-Ray Texture Library 4.0:
http://texlib.povray.org/ - Galerie modelů vytvořených v Lparseru:
http://home.wanadoo.nl/laurens.lapre/lparser2.html - Charlie Chernohorsky :-) L-systémy ve FractIntu:
http://fractint.oblivion.cz/ - POV-Ray Hall of Fame,
http://hof.povray.org/ - Tekno Frannansa,
http://www.zazzle.com/tekf - Internet Raytracing Competition,
http://www.irtc.org/ - POVRay Short Code Contest – Round 3,
http://local.wasp.uwa.edu.au/~pbourke/exhibition/scc3/final/ - SCC4: POVRay Short Code Contest,
http://local.wasp.uwa.edu.au/~pbourke/exhibition/scc4/final/ - SCC5: POVRay Short Code Contest #5 – The animation round!,
http://local.wasp.uwa.edu.au/~pbourke/exhibition/scc5/final.html - POV-Ray posters,
http://www.povray.org/posters/ - Parametric Constructive Solid Geometry
http://c-csg.com/