Ray-tracing in GrCis library

GrCis library

Basic interfaces and classes are in the common folder: more abstract ones (interfaces, default classes) are in the RayCastingCommon.cs source file, basic implementations are in the RayCastingBasic.cs file (your will sometimes need to expand these classes).

Most of the ray-tracer architecture is covered by the PDF slideshow (video in Czech).

Shared document in Czech language includes detailed instructions, tutorials and Q & A section. You can find it here.

Projects, command-line arguments

Best projects for experimenting with ray-tracing are 048rtmontecarlo and 048rtmontecarlo-script. The later one has a new extension: possibility of defining a scene using a C#-syntax script (see CSharpScript). Script samples (all builtin scenes were rewritten as scripts) can be found in the directory data/rtscenes.

Recommended animation projects are 062animation and 062animation-script. Both are able to pass the text field Param: from the form to a scene-definition function, the later is capable to define a scene (animation) using a CS-script file. Sample script can be found in data/rtscenes/AnimatedScene.cs.

Starting of the 048rtmontecarlo-script executable is a bit more complicated if you are using scripts. You have to use at least one of the following comman-line arguments (changing the working directory is strongly recommended: set it to the directory with the project file – project / Properties / Debug / Working directory:):

  • -nodefault removes all default scenes statically compiled into the executable
  • -dir <directory> (e.g. "-dir ..\data\rtscenes\") scans the given directory and includes all the script names into the list-box. The actual scripts will be read every time the button "Render" is pressed, so you can edit scripts continuously using any external text editor. Scene is refreshed every time rendering is started.
  • -scene <scene-script> uses the specific scene-script (can be used multiple times)
  • -mask <file-mask> sets file-name mask for scene-scripts (default is *.cs)

It is advisable to set a starting directory of the EXE to a Visual Studio project directory (default is usually a directory where a binary is build).

CSharpScript context

CS-script code is formally a sequence of C# commands without any structure or hierarchy (especially there is no need to encapsulate commands into any block or function). Commands will have access to usual "name-spaces" (like initial using directives in a C# source file), additionally there is a set of useful values:

  • IRayScene scene – pre-constructed object, you must fill it with a scene/animation definition
  • string param – textual parameter from a form (command line) if provided, an empty string otherwise
  • Dictionary context – additional parameters passed from/to a script. List of available parameter names and types ("in" means this value is passed to a script, "out" means a script can set this value and affect the run of the R-T framework), quantities set by a script have priority over values set in the GUI/form:
    • bool PropertyName.CTX_PREPROCESSING (in) – present & true if this is the very first runof a script (you can do a pre-processing/simulation) here. All custom values stored in this context will be passed to subsequent script runs...
    • string PropertyName.CTX_SCENE_NAME (in) – scene name
    • string PropertyName.CTX_SCRIPT_PATH (in) – complete file-path to this script (can be used to find more support files in the same directory, etc.)
    • int PropertyName.CTX_WIDTH (in, out) – rendered image/frame width in pixels
    • int PropertyName.CTX_HEIGHT (in, out) – rendered image/frame height in pixels
    • int PropertyName.CTX_SUPERSAMPLING (in, out) – supersampling factor (samples per pixel, 1 ... no anti-aliasing)
    • IImageFunction PropertyName.CTX_ALGORITHM (out) – here you can override the default rendering algorithm (RayTracing)
    • IRenderer PropertyName.CTX_SYNTHESIZER (out) – here you can override the bitmap renderer (IImageFunction to raster-image convertor, default is SupersamplingImageSynthesizer = jittering)
    • string PropertyName.CTX_TOOLTIP (out) – here you can set the tooltip string for the Parameters: text field, use '\r' to separate lines
    • double PropertyName.CTX_START_ANIM (in, out) – animation start in seconds
    • double PropertyName.CTX_END_ANIM (in, out) – animation end in seconds
    • double PropertyName.CTX_FPS (in, out) – FPS (Frames Per Second) of the animation
    • double PropertyName.CTX_TIME (in) – if set, it indicates the renderer is working in a "single frame mode", so you can reduce pre-processing work. The value itself defines the time of the current frame

Important interfaces

  • IIntersectable – any entity able to be intersected by an ray in 3D space (function Intersect() returns a list of the Intersection objects)
  • ICamera – general primary ray generator (e.g. StaticCamera)
  • ILightSource – general light source
  • IReflectanceModel – general local reflectance model (BRDF)
  • IMaterial – material attributes of a specific material (has to be in unity with some concrete IReflectanceModel implementation)
  • ITexture – general texture prototype. Texture is any object able to change (modulate) arbitrary quantity/quantities stored in a Intersection object
  • ITimeDependent – any entity able to change in time (animation via time variable). It must be able to clone itself ("clone on demand" for multi-thread computation)
  • IRayScene – general prototype for ray-tracing rendering job data: scene geometry Intersectable, background color BackgroundColor, ray generator Camera and list of light sources Sources. Individual members can be animated (if they implement interface ITimeDependent)

3D scene definition (scene geometry)

  • ISceneNode – general scene graph node, can have ancestors (hierarchy) and attributed associated (GetAttribute(), SetAttribute(), ..), is able to be intersected by a ray (interface IIntersectable)
  • ISolid – scene hierarchy leaf (CSG-tree leaf) defining geometry of a solid (it has to implement mainly interface IIntersectable). Examples of solids: Plane, Sphere or BezierSurface
  • DefaultSceneNode – default implementation of interface ISceneNode, serves as a predecessor for more classes, e.g. leaves (ISolid)
  • CSGInnerNode – inner CSG-tree node

Important classes

  • Intersection – data object storing all information about single ray-scene intersection. Two-phase evaluation (laisy evaluation), primary instance holds only mandatory data, to complete all the information you need to call CompleteIntersection()..

Ray-based rendering algorithms

  • IImageFunction – abstract concept of image-function with continuous image plane – mapping from continuous image rectangle to a general color space (double[])
  • IRenderer – able to synthesize raster image from associated IImageFunction
  • SimpleImageSynthesizer – implements IRenderer, uses only one sample per pixel (1spp)
  • SupersamplingImageSynthesizer – ancestor of SimpleImageSynthesizer, able to use jittered supersampling in each pixel (independently)
  • RayCasting – implements IImageFunction, ray-casting algorithm
  • RayTracing – ancestor of RayCasting, implements recursive backward ray-tracing (Whitted)


Intersection object

Intersection instance holds information about concrete ray-scene intersection. Two-phase computation is used:

  1. In the 1st phase only the most important data are computed (e.g. 1D coordinate of the intersection = t) and a reference to hit scene object is stored, optionally the object involved could store additional information for later use in the 2nd phase
  2. The 2nd phase means we will actually use this intersection. We need to compute everything – this is what the CompleteIntersection() function is for. Many support procedures, transform matrices, attribute processing, etc. – are already present in the core system and there is no need to reimplement them
Mandatory data items of the Intersection object (assigned in the 1st phase):
  • bool Enter [mandatory] – true if a ray enters an object from outer space ("air-solid" interface)
  • bool Front [mandatory] – true if a ray entered an elementary solid (ISolid) from outside to inside: it is equal to Enter at first but later it might be negated by a CSG set operation (negative CSG operation)
  • double T [mandatory] – parametric coordinate of the intersection point on the ray. Usually we are interested only in positive values T > 0.0 (but generally the system must deal with arbitrary values of T – e.g. for set operation implementation)
  • ISolid Solid [mandatory] – reference to a solid which has generated the intersection (which was intersected first by a ray). The reference will be utilised in the 2nd phase, the Solid.CompleteIntersection(this) will be called.
  • object SolidData [mandatory, can be null] – support data stored here by a solid generating the intersection (for later use in the 2nd phase)

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.


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.


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.


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-2020 J.Pelikán, last change: 2021-06-10 00:45:26 +0200 (Thu, 10 Jun 2021)