Ray-tracing v knihovně GrCis

Knihovna GrCis

Základní definice interface a tříd pro paprskové zobrazovací metody najdete v adresáři common. Abstraktnější definice (interface, default třídy) jsou obsaženy ve zdrojovém souboru RayCastingCommon.cs, jednoduché varianty implementací pak v souboru RayCastingBasic.cs (Váš kód bude některé tyto třídy doplňovat, tyto jsou zatím označeny partial).

Některé části architektury ray-traceru v GrCis jsou popsány v této prezentaci (bude průběžně aktualizována).

Důležité obecné interface

  • IIntersectable - jakýkoli objekt, který umí být protnut paprskem (metoda Intersect() vracející seznam objektů Intersection)
  • ICamera - generátor primárních paprsků (např. StaticCamera)
  • ILightSource - světelný zdroj
  • IReflectanceModel - lokální model odrazu světla na povrchu tělesa
  • IMaterial - parametry konkrétního materiálu (musí být v souladu s použitým modelem odrazu světla)
  • ITexture - obecný prototyp textury jako objektu schopného měnit (modulovat) libovolné hodnoty uložené v objektu Intersection
  • ITimeDependent - objekt schopný reagovat na změny v čase (tj. animovat se v čase). Musí mít schopnost se naklonovat (pro výpočty ve více vláknech)
  • IRayScene - objekt sdružující všechny komponenty zobrazované CSG scény: vlastní geometrii scény Intersectable, barvu pozadí BackgroundColor, generátor primárních paprsků Camera a seznam světelných zdrojů Sources. Jednotlivé komponenty mohou být animovatelné (viz interface ITimeDependent)

Datová struktura scény (geometrie)

  • ISceneNode - obecný uzel stromu hierarchie scény, může mít potomky (hierarchie) a přiřazené atributy (GetAttribute(), SetAttribute(), ..), umí se protnout paprskem (interface IIntersectable)
  • ISolid - list CSG stromu obsahující těleso (hlavně musí implementovat interface IIntersectable). Příklady těles: Plane, Sphere nebo BezierSurface
  • DefaultSceneNode - implicitní implementace základních funkcí interface ISceneNode, slouží jako předek všech dalších uzlů, mj. i listů (ISolid)
  • CSGInnerNode - implementace vnitřního uzlu CSG stromu

Další důležité objekty

  • Intersection - datový objekt obsahující všechny údaje o nalezeném průsečíku paprsku s povrchem tělesa/scény. Dvoufázový výpočet, primárně vznikne instance objektu obsahující pouze nejnutnější údaje, k doplnění slouží metoda CompleteIntersection()..

Algoritmy paprskového zobrazování

  • IImageFunction - abstraktní koncept obrazové funkce se spojitou průmětnou - zobrazení ze spojitého obdélníka do prostoru barev (double[])
  • IRenderer - z připojeného objektu typu IImageFunction umí vyrábět výstupní rastrový obrázek
  • SimpleImageSynthesizer - implementuje IRenderer, nechává počítat jenom jeden vzorek na každý pixel
  • SupersamplingImageSynthesizer - potomek SimpleImageSynthesizer, v každém pixelu umí spočítat a zprůměrovat více vzorků
  • RayCasting - implementuje IImageFunction, obsahuje základ algoritmu ray-casting
  • RayTracing - potomek RayCasting, implementace rekurzivního sledování paprsku

Detaily

Objekt Intersection

Instance třídy Intersection slouží k uchování informací o konkrétním průsečíku paprsku se scénou (s povrchem tělesa). Je implementován dvoufázový výpočet:

  1. V první fázi jsou spočítány jenom ty nejdůležitější údaje (např. souřadnice průsečíku v 1D systému paprsku) a objekt scény, který průsečík vytvořil (uzel grafu scény), si do něj uloží případné mezivýsledky pro druhou fázi
  2. Druhá fáze znamená, že průsečík bude skutečně použit, a že tedy potřebujeme všechny detailní informace o něm. Zavolá se funkce CompleteIntersection(), která dopočítá vše potřebné. Mnohé pomocné výpočty, např. transformační matice, akumulace atributů,.. jsou již vestavěny do systému a není třeba je explicitně implementovat
Výčet důležitých položek datového objektu Intersection, nejdříve ty z první fáze (povinné):
  • bool Enter [povinná] - příznak, že paprsek v tomto bodě vstupuje dovnitř tělesa (rozhraní "vzduch-těleso")
  • bool Front [povinná] - příznak, že paprsek vstoupil dovnitř elementárního tělesa (ISolid): při výpočtu průsečíku je to zatím hodnota totožná s Enter, později se však může začít lišit (negativní CSG operace)
  • double T [povinná] - parametrická souřadnice průsečíku na přímce paprsku. Pro pozitivní směr od počítku paprsku je T > 0.0 (výpočet průsečíku paprsku se scénou však musí udržovat i průsečíky na negativní polopřímce)
  • ISolid Solid [povinná] - odkaz na těleso, které průsečík vytvořilo (je potřeba pro druhou fázi - bude se volat jeho matoda Solid.CompleteIntersection( this ))
  • object SolidData [povinná, může být null] - pomocná data, která si potřebovalo těleso Solid odložit pro pozdější kompletaci průsečíku

Datové položky počítané typicky až při kompletaci průsečíku:
  • Vector3d CoordWorld [odložená] - světové souřadnice průsečíku
  • Vector3d CoordObject [odložená] - relativní souřadnice v rámci objektu (animační jednotka, objekt se ve scéně hýbe jako jeden celek)
  • Vector3d CoordLocal [odložená] - lokální souřadnice průsečíku (v rámci elementárního tělesa)
  • Vector2d TextureCoord [odložená] - 2D texturové souřadnice na poverchu tělesa
  • Vector3d Normal [odložená] - normálový vektor (ve světových souřadnicích)
  • Matrix4d LocalToWorld, WorldToLocal [odložená] - transformační matice mezi lokálním (Solid) a světovým souřadným systémem
  • Matrix4d LocalToObject [odložená] - transformační matice z lokálního do objektového (animačního) prostoru
  • double [] SurfaceColor [odložená] - pracovní kopie barvy povrchu tělesa (může se mnohokrát přepisovat, proto se musí okopírovat ze sdílených datových struktur)
  • IReflectanceModel ReflectanceModel [odložená] - platný model odrazu světla (= světelný model)
  • IMaterial Material [odložená] - materiálové konstanty pro aktuální světelný model
  • LinkedList<ITexture> Textures [odložená] - seznam textur v pořadí, ve kterém se mají aplikovat (tj. od nižších priorit k vyšším)

Interface IIntersectable

Každá třída, která se umí protnout daným paprskem.

  • LinkedList<Intersection> Intersect ( Vector3d p0, Vector3d p1 ) - výpočet průsečíků daného paprsku s objektem. Vrací jen průsečíky s vyplněnými povinnými položkami (první fáze). Souřadnice paprsku jsou lokální = přizpůsobené elementárnímu tělesu!
  • CompleteIntersection ( Intersection inter ) - kompletace daného průsečíku (druhá fáze), je třeba dopočítat všechny odložené položky

Interface ICamera

Ve skutečnosti se v zobrazovači používá jako generátor primárních paprsků, to je jediná funkce objektů tohoto typu. Vstupem je souřadnice bodu v průmětně, výstupem paprsek zadaný počátečním bodem a směrovým vektorem:

  • bool GetRay ( double x, double y, out Vector3d p0, out Vector3d p1 ) - vrací true, pokud zadaná poloha bodu v průmětně ([x,y]) byla přípustná (výjimky např. objektiv typu "rybí oko")
  • double Width, Height, AspectRatio - parametry oblasti průmětny, která se má používat pro zobrazení. Tato tři čísla jsou na sobě závislá: AspectRatio = Width / Height

Interface ITimeDependent

Každá třída implementující tento interface se umí měnit v čase (animovat). Obsahuje vlastnosti:

  • double Start - počáteční čas ve sekundách, spíše informativní údaj říkající, v jakém intervalu je akceptován čas (Time).
  • double End - koncový čas ve sekundách (délka cyklu animace), spíše informativní údaj říkající, v jakém intervalu (periodě) je akceptován čas (Time).
  • double Time - vlastní nastavení vnitřního času instance. Pokud objekt obsahuje odkazy na další podobjekty (komponenty), musí se do nich čas propagovat!
Interface ITimeDependent je potomkem ICloneable. Význam je následující: pokud je výpočet obrázku prováděn ve více vláknech, musí se naklonovat všechny datové struktury, které by se případně v jednotlivých vláknech mohly individuálně modifikovat. Například při výpočtu animace má každé vlákno za úkol počítat jiný snímek animační sekvence. K tomu se používá vlastnost Time, při jejím nastavování by tudíž docházelo ke konfliktu.
Implementace metody Clone() musí být přítomna u všech objektů, které se v průběhu výpočtu mění a do kterých se ukládají nějaké mezivýsledky (stavové API). Musí se jednat o tzv. "deep-copy", to znamená, že se objekt musí při klonování postarat o to, aby všechny jeho komponenty implementující interface ITimeDependent byly rovněž naklonovány!

Konkrétní třídy

Nejdříve několik elementárních těles, všechna implementují ISolid (tj. nepřímo i interface IIntersectable) a jsou potomky DefaultSceneNode, to znamená, že mají implicitně implementované všechny funkce potřebné pro začlenění do grafu scény.

Sphere

Jednotlová koule se středem v pořátku. Prototyp elementárního tělesa, obsahuje všechny potřebné implementace v metodách Intersect() i CompleteIntersection().

Plane, Cube, Cylinder, Torus

Další jednoduchá tělesa, jejichž průsečíky lze spočítat analyticky.

TriangleMesh

Trojúhelníková síť uložená v datovém objektu SceneBrep (Corner Table, lze ji načíst z OBJ formátu, ...). Výpočet průsečíků je naivní, bez urychlovacích metod, není to tedy prakticky použitelný objekt.

BezierSurface

Síť bikubických Bézierových plátů. Ukázka optimalizovaného výpočtu průsečíků - pláty se dělí (subdivision) a výsledné menší pláty jsou ukládány do R-tree pro větší efektivitu při hledání průsečíku.


Následuje několik základních implementačních tříd, většinou realizují nejjednodušší variantu daného interface. Při rozšiřování ray-traceru je vhodné z jejich implementace vycházet, protože je přímočará a ověřená.

StaticCamera : ICamera

Nejjednodušší implementace generátoru primárních paprsků (interface ICamera). Simulace ideálního objektivu pro středové promítání do rovinné průmětny (lineární perspektiva). Geometrie je zadána středem projekce, směrem pohledu a Up vektorem. Dále je definován zorný úhel pomocí třech na sobě závislých parametrů: Width, Height a AspectRatio.


Copyright (C) 2011-2015 J.Pelikán, last change: 2016-03-09 12:23:47 +0100 (Wed, 09 Mar 2016)