Skip to content

flarive/Cortex-Raytracer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cortex-Raytracer

Cortex RT is a self made CPU based monte carlo path tracer created from scratch in C++.

Screenshot

Primitives

Cortex supports an extended list of builtin uv mapped primitives mostly for testing purposes :

  • Plane
  • Cylinder
  • Disk
  • Cone
  • Box
  • Torus
  • Sphere
Primitives with test UV texture Primitives with stone texture
Screenshot of all builtin primitives Screenshot of all builtin primitives

extended_primitives.scene

Meshes

Cortex RT supports loading Wavefront .obj files.

obj is a kind of old legacy plain text 3D file format but it is still widely used by 3D software (blender, 3ds max, maya...) as an export file format.

  • .obj file contains vertex, faces, normals, uv mapping and smmothing groups definition
  • .mtl (Material template library) additional file contains materials definition (color, textures, ambient, diffuse, specular, bump...)

If you want to knowm more about obj and mtl files : https://en.wikipedia.org/wiki/Wavefront_.obj_file

teapot.obj solid color teapot.obj textured 3ds max obj exporter
Screenshot of 3ds max OBJ file exporter

Scenes

Cortex RT comes with a convenient .scene configuration file system to describe the scene to be rendered (primitives, meshes, camera, lights, materials, textures, rendering quality...)

# teapot_mesh.scene

image:
{
    width = 512;
    height = 388;
    maxDepth = 100;
    samplesPerPixel = 100;
    background = 
    {
        color = { r = 0.0; g = 0.0; b = 0.0; };
    };
};

# Configuration of the camera
camera:
{
    aspectRatio = "16:9";
    lookFrom = { x = 0.0; y = 4.0; z = 9.0; };
    lookAt = { x = 0.0; y = 0.0; z = 0.0; };
    upAxis = { x = 0.0; y = 1.0; z = 0.0; };
    fov = 18.0;
};

# Lights in the scene
lights:
{
    sphereLights: (
        {
            name = "MySphereLight";
            position = { x = 0.0; y = 8.0; z = 5.0; };
            radius = 3.0;
            intensity = 3.0;
            color = { r = 1.0; g = 1.0; b = 1.0; };
            invisible = true;
        }
    )
}

textures:
{
    solidColor: (
        {
            name = "ground_texture";
            color = { r = 0.7; g = 0.8; b = 1.0; };
        },
    ),
    image: (
        {
            name = "teapot_diffuse_texture";
            filepath = "../../data/models/rusted_metal1.jpg";
        }
    )
}

materials:
{
    lambertian: (
        {
            name = "ground_material";
            texture = "ground_texture";
        }
    ),
    phong: (
        {
            name = "teapot_material";
            diffuseTexture = "teapot_diffuse_texture";
            ambientColor = { r = 0.0; g = 0.0; b = 0.0; };
            shininess = 0.9;
        }
    )
}

# Meshes in the scene
meshes:
{
    obj: (
        {
            name = "MyTeapotModel"
            filepath = "../../data/models/teapot.obj";
            position = { x = 0.0; y = 0.0; z = 0.0; };
            material = "teapot_material"
            use_mtl = false;
            use_smoothing = true;
            transform =
            {
                translate = { x = 0.0; y = 0.0; z = 0.0; };
                rotate = { x = 0.0; y = 0.0; z = 0.0; };
                scale = { x = 0.02; y = 0.02; z = 0.02; };
            };
        }
    );
};

# Primitives in the scene
primitives:
{
    # List of boxes
    boxes: (
        {
            name = "MyGround";
            position = { x = 0.0; y = -1.0; z = 0.0; };
            size = { x = 40.0; y = 0.5; z = 40.0; };
            material = "ground_material";
            uvmapping = { scale_u = 1.0; scale_v = 1.0; offset_u = 0.0; offset_v = 0.0; repeat_u = 2.0; repeat_v = 2.0; };
        }
    );
};

Materials

Screenshot of all suported materials

Cortex RT mostly support following materials :

  • Phong
  • Oren Nayar
  • Anisotropic (for wood, slate, ice, velvet...)
  • Isotropic (for glass, crystals with cubic symmetry, diamonds, plastic, metal...)
  • Dielectric (for water, glass, diamond...)
  • Lambertian (simple diffuse material without any specular relection)
  • Metal (for metals, mirrors...)
  • Emissive (WIP)
crate.obj (diffuse + specular + bump textures) cushion.obj (diffuse + specular + normal textures)
Screenshot of phong crate model with diffuse + specular + bump textures Screenshot of phong cushion model with diffuse + specular + normal textures
Screenshot of crate textures Screenshot of cushion textures

The phong reflection model is a full featured material that combines ambient + diffuse + specular. https://en.wikipedia.org/wiki/Phong_reflection_model

On top of that, Cortex RT phong material also support a lot of possible textures (solid color, gradient, image, bump, normal, displacement, alpha...)

# Sample materials section in scene file
materials:
{
    lambertian: (
        {
            name = "ground_material";
            texture = "ground_texture";
        }
    ),
    phong: (
        {
            name = "crate_material";
            diffuseTexture = "crate_diffuse_texture";
            specularTexture = "crate_specular_texture";
            #bumpTexture = "crate_bump_texture";
            normalTexture = "crate_normal_texture";
            ambientColor = { r = 0.0; g = 0.0; b = 0.0; };
            shininess = 0.0;
        }
    )
}

all_materials_spheres.scene

Textures

Screenshot of all suported materials

Cortex RT supports quite a lot of textures you can combine in a material :

  • Solid color texture
  • Gradient color texture
  • Image texture
  • Bump texture
  • Normal texture
  • Displacement texture (WIP)
  • Alpha texture (transparency texture)
  • Perlin texture (procedural noise)
  • Checker (procedural checkboard pattern texture)
  • Emissive texture (WIP)
# Sample textures section in scene file
textures:
{
    image: (
        {
            name = "ground_texture";
            filepath = "../../data/textures/scifi_floor2.png";
        },
        {
            name = "crate_diffuse_texture";
            filepath = "../../data/models/crate_diffuse.jpg";
        },
        {
            name = "crate_specular_texture";
            filepath = "../../data/models/crate_specular.jpg";
        },
        {
            name = "crate_bump_texture";
            filepath = "../../data/models/crate_bump.jpg";
        }
    ),
    normal: (
        {
            name = "crate_normal_texture";
            filepath = "../../data/models/crate_normal.jpg";
            strength = 0.005;
        }
    )
}

all_textures_spheres.scene

Bump texture Normal texture
Screenshot of bump texture Screenshot of normal texture

Camera

Cortex RT provides 2 kinds of camera : perspective (default) and orthographic (no perception of depth)

Perspective camera Orthographic camera
# Configuration of a perspective camera
camera:
{
    aspectRatio = "16:9";
    lookFrom = { x = 0.0; y = 2.0; z = 9.0; };
    lookAt = { x = 0.0; y = 0.6; z = 0.0; };
    upAxis = { x = 0.0; y = 1.0; z = 0.0; };
    fov = 18.0; // Field Of View (zoom level in degrees)
};
# Configuration of an orthographic camera
camera:
{
    aspectRatio = "16:9";
    lookFrom = { x = 0.0; y = 2.0; z = 9.0; };
    lookAt = { x = 0.0; y = 0.6; z = 0.0; };
    upAxis = { x = 0.0; y = 1.0; z = 0.0; };
    orthographic = true;
    orthoHeight = 2.0; // Orthographic viewport height (height of the viewport in world space units)
};

Rendering parameters

The image section in .scene files defines some usefull render settings :

  • width/height : The size in pixels of the final rendered image (according to the camera aspect ratio)
  • maxDepth : The max number of ray bounces (50 should be more than enough)
  • samplesPerPixel (spp) : The max number of samples calculated to generate each pixel of the rendered image (50 is very fast but very noisy, 500-1000 is high quality, 5000+ is extra high quality but very slow)
  • background : The background to use while rendering the scene (color, simple image or hdr skybox image)
# Configuration of the rendered image quality
image:
{
    width = 512;
    height = 388;
    maxDepth = 50;
    samplesPerPixel = 500;
    background = 
    {
        #color = { r = 0.1; g = 0.1; b = 0.1; };
        filepath = "../../data/backgrounds/hdr/christmas_photo_studio_02_2k.hdr";
        is_skybox = true;
    };
};
50 spp 500 spp 1000 spp 5000 spp 10000 spp

Lights

Cortex RT supports 3 different kinds of lights :

  • Omni light : Also known as a point light, an omni light emits light equally in all directions from a single point in space, similar to a light bulb.

  • Directional light : Simulates light coming from a specific direction, as if it were emitted from an infinitely large source, such as the sun.

  • Spot light : More focused light source that emits light in a specific direction within a cone.

Lights are produced by hidden objects (quad or sphere) with an emissive material.
Such objects can be displayed for debug lightning purpose.

Omni light Omni light debug (emissive sphere)
Directional light Directional light debug (emissive quad)
Spot light Spot light debug (emissive sphere)

all_lights_types.scene

Transforms and groups

Cortex RT supports applying transforms to primitives and meshes (translate, rotate, scale). Transform attribute overrides the object position and size already defined.

# Transform applied on a box primitive
primitives:
{
    boxes: (
        {
            name = "MyGround";
            position = { x = 0.0; y = -0.28; z = 0.0; };
            size = { x = 10.0; y = 0.5; z = 40.0; };
            material = "ground_material";
        },
        {
            name = "MyBox"
            position = { x = 0.0; y = 0.35; z = 0.0; };
            size = { x = 0.7; y = 0.7; z = 0.7; };
            material = "uvmapper_material";
            uvmapping = { scale_u = 0.5; scale_v = 0.5; offset_u = 0.0; offset_v = 0.0; };
            transform =
            {
                translate = { x = 0.0; y = 0.0; z = 0.0; };
                rotate = { x = 0.0; y = 45.0; z = 0.0; };
                scale = { x = 2.0; y = 2.0; z = 2.0; };
            };
        }
    );
};

# Transform applied on a custom mesh
meshes:
{
    obj: (
        {
            name = "MyMesh"
            filepath = "../../data/models/smooth_sphere.obj";
            use_mtl = true;
            use_smoothing = true;
            transform =
            {
                translate = { x = -1.3; y = 0.0; z = 0.0; };
                rotate = { x = 0.0; y = 45.0; z = 0.0; };
                scale = { x = 1.2; y = 1.2; z = 1.2; };
            };
        }
    );
};

In a scene objects (primitives and meshes) can be grouped by using groups. A transform can also be applied to a group.

primitives:
{
    boxes: (
        {
            name = "MyBox1"
            position = { x = 0.0; y = 0.0; z = 0.0; };
            size = { x = 0.7; y = 0.7; z = 0.7; };
            material = "uvmapper_material";
            group = "MyGroup";
        },
        {
            name = "MyBox2"
            position = { x = 0.0; y = 0.0; z = 0.0; };
            size = { x = 0.7; y = 0.7; z = 0.7; };
            material = "uvmapper_material";
            group = "MyGroup";
        }
    );
};

# Definition of groups
groups: (
    {
        name = "MyGroup";
        transform =
        {
            translate = { x = -100.0; y = 270.0; z = 395.0; };
            rotate = { x = 0.0; y = 15.0; z = 0.0; };
            scale = { x = 2.0; y = 2.0; z = 2.0; };
        };
    }
);

transforms.scene

Anti aliasing

Performances and optimizations

Command line exe

CortexRT is a lightweight standalone executable (CortexRTCore.exe) that can be called with command line arguments :

CortexRTCore.exe -width 512 -height 512 -ratio 1:1 -spp 250 -maxdepth 50 -gamma 1 -aa 1 -mode 8
-scene ..\..\data\scenes\buddha1_mesh.scene
-save ..\..\data\renders\buddha1_mesh.png
Argument Type Explanations
width int width in pixels of the output
height int height in pixels of the output
ratio string image ratio of the output (ex : 16:9, 9:16, 1:1...)
spp int number of sample per pixel (50 and less = fast but low quality with a lot of noise, between 100 and 250 is a good quality/time compromise, 500 and more = slower but high quality with very few noise)
maxdepth int maximum number of bounce for a ray (you shouldn't need to change this value)
gamma boolean int apply gamma correction to the output (0 = no correction, 1 = gamma correction)
aa int anti aliasing method (0 = no anti aliasing, 1 = random method (fast), 2 = msaa (slower))
mode int number of CPU core to use for multithreaded rendering (0 = mono threaded, 2 = multi threaded with 2 cores, 8 = 8 cores and so on...)
scene string relative or absolute path to the .scene file to render
save string relative or absolute path to the rendered output

If you want to run the denoiser (CortexRTDenoiser.exe) after rendering, you can call it like that :

CortexRTDenoiser.exe -input ..\..\data\renders\buddha1_mesh.png -output ..\..\data\renders\buddha1_mesh_denoised.png -hdr 0

Graphical User Interface

CortexRT also comes with a GUI (CortexRT.exe) to easily adjust parameters and have a preview of a the rendered image.

Screenshot

Supported platforms

CortexRT is using mostly std and modern C++ (compiled for C++ 20) but is limited to Windows platform for the moment. With few changes it should be possible to compile for mac or linux (I will see later).

Dependencies

CortexRT is using following libs :

  • GLM (OpenGL Mathematics)
  • Eigen (for linear algebra)
  • LibConfig (for parsing .scene files)
  • TinyObjLoader (for loading .obj 3D models)
  • PCG (for high quality random number generation)
  • stb (for loading/saving images)
  • Oidn (Intel Open Image Denoiser)
  • imGUI (well known UI lib)
  • GLFW (multi-platform library for OpenGL)

Thanks to

Following sites and people helped a lot to create Cortex Raytracer :

Gallery

What's next ?