World

To define a scene, you will need to place some shapes in the world. All shapes are a subtype of AbstractShape. Moreover, shapes which are considerer "solid" or "closed" are a subtype of AbstractSolid. In addition to standard shapes there are auxiliary shapes such as AABB and BVHShape which are used as acceleration structures.

Every shape needs a material and a transformation.

Materials

Materials are defined in a concrete type:

jujutracer.MaterialType
struct Material

Fields

  • Emition::AbstractPigment: the pigement with which the radiation is emitted.
  • BRDF::AbstractBRDF: the BRDF of the material.
source

Pigments

The emission of the material can be defined as a pigment, which is a subtype of AbstractPigment.

They are based on the ColorTypes.jl package, of which we use the RGB type.

There are three types of pigments:

jujutracer.UniformPigmentType
UniformPigment()

Uniform Pigment for Shapes

Fields

  • color::RBG the uniform color

Functional Usage

UniformPigment(p::SurfacePoint) return the RGB associated to the (u, v) coordinates of the SurfacePoint

source
jujutracer.CheckeredPigmentType
CheckeredPigment(col::Int32, row::Int32, dark::RGB, bright::RGB)

Checkered pigment for a Shape, subdiveded in row rows and col columns with alternate dark and bright color

Fields

  • col number of horizontal subdivisions
  • row number of vertical subdivisions
  • dark color of the dark squares
  • bright color of the bright squares

Functional Usage

CheckeredPigment(p::SurfacePoint) return the RGB associated to the (u, v) coordinates of the SurfacePoint

source
jujutracer.ImagePigmentType
ImagePigment(img::hdrimg)

Print the image img as pigment of the surface

Fields

  • img::hdrimg the image in hdr format

Functional Usage

ImagePigment(p::SurfacePoint) return the RGB of to the (u, v) coordinates of the SurfacePoint associated to the corresponding element of img

source

BRDFs

The BRDF of the material is defined as a subtype of AbstractBRDF. The available BRDFs are

A complete material can be defined as follows:

mat = Material(
    ImagePigment("asset/sky.pfm"),
    DiffuseBRDF(UniformPigment(RGB(0.1, 0.7, 0.3)))
)

Transformations

Transformations are defined as a subtype of AbstractTransformation. They are structs thah hold a transformation matrix and its inverse for fast change of basis from world to local coordinates. The available transformations are:

jujutracer.TransformationType
struct Transformation <: AbstractTransformation

Represents a transformation in 3D space with homogeneous coordinates. This structure is a subtype of AbstractTransformation.

Fields

  • M::Matrix{Float64}: The 4x4 transformation matrix.
  • inv::Matrix{Float64}: The 4x4 inverse of the transformation matrix.

Constructors

  • Transformation(): Creates an identity transformation where M and inv are both 4x4 identity matrices.
  • Transformation(M::Matrix{Float64}, inv::Matrix{Float64}): Creates a transformation with the given M and inv matrices.
  • Transformation(M::Matrix{Float64}, inv::Matrix{Float64}, unsafe::Unsafe): Creates a transformation with the given M and inv matrices, without veryfing the inputs.

Throws an ArgumentError if:

  • M or inv are not 4x4 matrices.
  • The last element of M or inv is not 1.0.
  • M and inv are not inverses of each other.

Notes

The M and inv matrices must satisfy the following conditions:

  • Both must be 4x4 matrices.
  • The last element of both matrices must be 1.0.
  • The product of M and inv must be approximately equal to the 4x4 identity matrix.
source
jujutracer.TranslationType
struct Translation <: AbstractTransformation

Represents a translation in 3D space with homogeneous coordinates. This structure is a subtype of AbstractTransformation.

Fields

  • M::Matrix{Float64}: The 4x4 transformation matrix.
  • inv::Matrix{Float64}: The 4x4 inverse transformation matrix.

Constructors

  • Translation(dx::Float64, dy::Float64, dz::Float64): Creates a Translation object with translation offsets dx, dy, and dz along the x, y, and z axes, respectively.

  • Translation(v::Vec): Creates a Translation object using a Vec object.

source
jujutracer.RxType
struct Rx <: AbstractTransformation

Represents a rotation transformation around the x-axis in 3D space. This structure is a subtype of AbstractTransformation.

Fields

  • M::Matrix{Float64}: The 4x4 transformation matrix.
  • inv::Matrix{Float64}: The 4x4 inverse of the transformation matrix.

Constructor

  • Rx(θ): Creates an Rx instance for a given rotation θ (in radians).

See also

  • Ry: For rotation around the y-axis.
  • Rz: For rotation around the z-axis.
source
jujutracer.RyType
struct Ry <: AbstractTransformation

Represents a rotation transformation around the y-axis in 3D space. This structure is a subtype of AbstractTransformation.

Fields

  • M::Matrix{Float64}: The 4x4 transformation matrix.
  • inv::Matrix{Float64}: The 4x4 inverse of the transformation matrix.

Constructor

  • Ry(θ): Creates an Ry instance for a given rotation θ (in radians).

See also

  • Rx: For rotation around the x-axis.
  • Rz: For rotation around the z-axis.
source
jujutracer.RzType
struct Rz <: AbstractTransformation

Represents a rotation transformation around the z-axis in 3D space. This structure is a subtype of AbstractTransformation.

Fields

  • M::Matrix{Float64}: The 4x4 transformation matrix.
  • inv::Matrix{Float64}: The 4x4 inverse of the transformation matrix.

Constructor

  • Rz(θ): Creates an Rz instance for a given rotation θ (in radians).

See also

  • Rx: For rotation around the x-axis.
  • Ry: For rotation around the y-axis.
source
jujutracer.ScalingType
struct Scaling <: AbstractTransformation

Represents a scaling transformation in 3D space. This structure is a subtype of AbstractTransformation.

Fields

  • M::Matrix{Float64}: The 4x4 transformation matrix.
  • inv::Matrix{Float64}: The 4x4 inverse of the transformation matrix.

Constructor

  • Scaling(x::Float64, y::Float64, z::Float64): Creates aScalinginstance with scaling factorsx,y, andzalong the x, y, and z axes, respectively. Throws anArgumentError` if any of the scaling factors are zero.
source

Shapes

Shapes are defined as a subtype of AbstractShape. There are two categories of shapes:, the ones that can be used in CSG operations and the ones that cannot, such as flat shapes.

Water-tight Shapes

jujutracer.SphereType
struct Sphere <: AbstractSolid

A sphere. Unit radius sphere centered at the origin. This structure is a subtype of AbstractSolid.

Fields

  • t::Transformation: the transformation applied to the sphere.
  • Mat::Material: the material of the shape
source
jujutracer.BoxType
struct Box <: AbstractSolid

An axis-aligned box (rectangular cuboid) defined by two opposite corners.

Fields

  • Tr::AbstractTransformation: The transformation applied to the box.
  • P1::Point: One corner of the box (minimum x, y, z).
  • P2::Point: The opposite corner of the box (maximum x, y, z).
  • Mat::Material: The material of the box.

Constructors

  • Box(): Creates a new box with default transformation and material.
  • Box(Tr::AbstractTransformation): Creates a new box with the specified transformation and default material.
  • Box(P1::Point, P2::Point): Creates a new box with the specified corners and default transformation and material.
  • Box(P1::Point, P2::Point, Mat::Material): Creates a new box with the specified corners and material.
  • Box(Tr::AbstractTransformation, P1::Point, P2::Point): Creates a new box with the specified transformation and corners.
  • Box(Tr::AbstractTransformation, P1::Point, P2::Point, Mat::Material): Creates a new box with the specified transformation, corners, and material.
  • Box(Mat::Material): Creates a new box with the default transformation and the specified material.
  • Box(Tr::AbstractTransformation, Mat::Material): Creates a new box with the specified transformation and material.
source
jujutracer.ConeType
struct Cone <: AbstractSolid

A cone of unitary radiuos and height resting on the xy plane. This structure is a subtype of AbstractSolid.

Fields

  • Tr::Transformation: the transformation applied to the sphere.
  • Mat::Material: the material of the shape
source
jujutracer.CylinderType
struct Cylinder <: AbstractSolid

A cylinder of unitary radius and height centered in the origin. This structure is a subtype of AbstractSolid.

Fields

  • Tr::Transformation: the transformation applied to the sphere.
  • Mat::Material: the material of the shape

Constructors

  • Cylinder(): Creates a new cylinder with default transformation and material.
  • Cylinder(Tr::AbstractTransformation): Creates a new cylinder with the specified transformation and default material.
  • Cylinder(Mat::Material): Creates a new cylinder with the default transformation and the specified material.
  • Cylinder(Tr::AbstractTransformation, Mat::Material): Creates a new cylinder with the specified transformation and material.
source

CSG Shapes

Set operations are defined as methods on the AbstractSolid` type. The available operations are:

jujutracer.CSGUnionType
struct CSGUnion <: AbstractSolid

Represents the union of two solid shapes.

Fields

  • Tr::AbstractTransformation: The transformation applied to the union.
  • Sh1::AbstractSolid, Sh2::AbstractSolid: The two solid shapes being united.

See also

source
jujutracer.CSGIntersectionType
struct CSGIntersection <: AbstractSolid

Represents the intersection of two solid shapes.

Fields

  • Tr::AbstractTransformation: The transformation applied to the intersection.
  • Sh1::AbstractSolid, Sh2::AbstractSolid: The two solid shapes being intersected.

See also

  • CSGUnion: Represents the union of two solid shapes.
  • CSGDifference: Represents the difference of two solid shapes.
source
jujutracer.CSGDifferenceType
struct CSGDifference <: AbstractSolid

Represents the difference of two solid shapes.

Fields

  • Tr::AbstractTransformation: The transformation applied to the difference.
  • Sh1::AbstractSolid, Sh2::AbstractSolid: The two solid shapes where Sh1 - Sh2 is computed.

See also

  • CSGUnion: Represents the union of two solid shapes.
  • CSGIntersection: Represents the intersection of two solid shapes.
source

Flat Shapes

jujutracer.PlaneType
struct Plane <: AbstractShape

A plane. This structure is a subtype of AbstractShape.

Fields

  • t::Transformation: the transformation applied to the plane
  • Mat::Material: the material of the shape
source
jujutracer.TriangleType
struct Triangle <: AbstractShape

Triangle.

Fields

  • t::Transformation: the transformation applied to the triangle
  • A, B, C::Point: the vertices of the triangle
  • Mat::Material: the material of the shape

Constructor

  • Triangle(): creates a triangle with Identity Transformation and vertices (0,0,0), (1,0,0), (0,1,0) and a default material.
  • Triangle(Tr::AbstractTransformation): creates a triangle with Tr Transformation and vertices (0,0,0), (1,0,0), (0,1,0) and a default material.
  • Triangle(Mat::Material): creates a triangle with Identity Transformation and vertices (0,0,0), (1,0,0), (0,1,0) and a Mat material.
  • Triangle(Tr::AbstractTransformation, Mat::Material): creates a triangle with Tr Transformation and vertices (0,0,0), (1,0,0), (0,1,0) and a Mat material.
  • Triangle(A::Point, B::Point, C::Point): creates a triangle with Identity Transformation and vertices A, B, C and a default material.
  • Triangle(A::Point, B::Point, C::Point, Mat::Material): creates a triangle with Identity Transformation and vertices A, B, C and a Mat material.
source
jujutracer.ParallelogramType
struct Parallelogram <: AbstractShape

Parallelogram

   C-----p
  /     /
 /     /
A-----B

Fields

  • t::Transformation: the transformation applied to the Parallelogram.
  • A, B, C::Point: the vertices defining the quadrilateral's
  • Mat::Material: the material of the shape

Constructor

  • Parallelogram(): creates a parallelogram with Identity Transformation and vertices (0,0,0), (1,0,0), (0,1,0) and a default material.
  • Parallelogram(Tr::AbstractTransformation): creates a parallelogram with Tr Transformation and vertices (0,0,0), (1,0,0), (0,1,0) and a default material.
  • Parallelogram(Mat::Material): creates a parallelogram with Identity Transformation and vertices (0,0,0), (1,0,0), (0,1,0) and a Mat material.
  • Parallelogram(Tr::AbstractTransformation, Mat::Material): creates a parallelogram with Tr Transformation and vertices (0,0,0), (1,0,0), (0,1,0) and a Mat material.
  • Parallelogram(A::Point, B::Point, C::Point): creates a parallelogram with Identity Transformation and vertices A, B, C and a default material.
  • Parallelogram(A::Point, B::Point, C::Point, Mat::Material): creates a parallelogram with Identity Transformation and vertices A, B, C and a Mat material.
  • Parallelogram(A::Point, AB::Vec, AC::Vec): creates a parallelogram with Identity Transformation and vertices A, A + AB, A + AC and a default material.
source
jujutracer.RectangleType
struct Rectangle <: AbstractShape

1x1 Rectangle on xy plane, centered in the origin

Fields

  • t::Transformation: the transformation applied to the plane
  • Mat::Material: the material of the shape
source
jujutracer.CircleType
struct Circle <: AbstractShape

A unit circle in the xy-plane, centered at the origin.

Fields

  • Tr::AbstractTransformation: the transformation applied to the circle.
  • Mat::Material: the material of the shape.

Constructors

  • Circle(): Creates a new circle with default transformation and material.
  • Circle(Tr::AbstractTransformation): Creates a new circle with the specified transformation and default material.
  • Circle(Mat::Material): Creates a new circle with the default transformation and the specified material.
  • Circle(Tr::AbstractTransformation, Mat::Material): Creates a new circle with the specified transformation and material.
source

Meshes

Meshes are defined as structs that hold a vector of triangles, a vector of points and the file from which the mesh was loaded.

jujutracer.meshType
struct mesh <: AbstractShape

mesh.

Fields

  • file::String: the source file.obj of the mesh
  • shape::Vector{Triangle}: the triangles of the mesh
  • points::Vector{Point}: the vertices of the triangles of the shape

Constructor

  • mesh(shapes::Vector{Triangle}): creates a mesh frome the Vector{Triangle}
  • mesh(file::String): creates a mesh from file
  • mesh(file::String, Tr::AbstractTransformation): creates a mesh from file with a transformation Tr
  • mesh(file::String, Mat::Material): creates a mesh with Mat material from file
  • mesh(file::String, Tr::AbstractTransformation, Mat::Material): creates a mesh with Tr transformation and a Mat material.

For all constructors from obj files, the order of the coordinates in the file is assumed to be "dwh" (depth, width, height) by default. If the order is different, you can specify it with the order keyword argument.

source
jujutracer.read_obj_fileFunction
read_obj_file(io::IOBuffer; Tr::AbstractTransformation = Transformation(), Mat::Material = Material(); order = "dwh")

Method for constructing vectors and points from a buffer.

Fields

  • io::IOBuffer: the buffer
  • Tr::AbstractTransformation: an hypotetical transformation to be applied to all the shapes and points
  • Mat::Material: an hypotetical material to be applied to all the triangles

Keywords

  • order::String: the order of the coordinates in the file, default is "dwh" (depth, width, height).

Returns

  • shape::Vector{Triangle}
  • points:Vector{Points}
source
read_obj_file(io::IOBuffer; Tr::AbstractTransformation = Transformation(), Mat::Material = Material(); order = "dwh")

Method for constructing vectors and points from a file

Fields

  • filename::String: the name of the file.obj
  • Tr::AbstractTransformation: an hypotetical transformation to be applied to all the shapes and points
  • Mat::Material: an hypotetical material to be applied to all the triangles

Keywords

  • order::String: the order of the coordinates in the file, default is "dwh" (depth, width, height).

Returns

  • shape::Vector{Triangle}
  • points:Vector{Points}
source
jujutracer.trianglizeFunction
trianglize(P::Vector{Points}, Tr::AbstractTransformation, Mat::Material)

Triangulation method, working only with ordered verteces

Arguments

  • P::Vector{Point}: the vector of points to be triangulated
  • Tr::AbstractTransformation: an hypotetical transformation to be applied to all the shapes and points
  • Mat::Material: a material to be applied to all the triangles

Returns

  • tr::Vector{Triangle}: a vector of triangles created from the points in P
source

Acceleration Structures

Acceleration structures are used to speed up the ray tracing process by reducing the number of intersection tests.

The most basic acceleration structure is the AABB, which is an axis-aligned bounding box that contains a shape. It is used to quickly eliminate shapes that are not intersected by a ray.

jujutracer.AABBType
struct AABB <: AbstractShape

Axis-Aligned Bounding Box (AABB) for a set of shapes.

Fields

  • S::Vector{AbstractShape}: the vector of shapes contained within the AABB.
  • P1::Point: the minimum corner of the AABB.
  • P2::Point: the maximum corner of the AABB.

Constructor

  • AABB(S::Vector{AbstractShape}): creates an AABB for the shapes in S, calculating the minimum and maximum corners based on the bounding boxes of the shapes.
  • AABB(S::Vector{AbstractShape}, P1::Point, P2::Point): creates an AABB with the specified minimum and maximum corners P1 and P2 for the shapes in S.
  • AABB(csg::Union{CSGDifference, CSGUnion, CSGIntersection}): creates an AABB for a CSG shape, extracting the shapes and their bounding box.
source

Otherwise, jujutracer provides the means to build a binary tree of shapes using Boundary Volume Hierarchy (BVH) algorithm. The BVH is a tree structure that allows to quickly find the closest intersection between a ray and a shape. The BVH is built from a vector of shapes, which wil be divided into nodes with two possible methods:

  • simple: the shapes are divided into two groups based on their centroids
  • surface area heuristic (SAH): the shapes are divided into two groups based on their surface area, which is a more efficient method.

After that, the BVH is held in a BVHShape, which is a subtype of AbstractShape.

jujutracer.BuildBVH!Function
BuildBVH!(shapes::Vector{AbstractShape}; use_sah::Bool=false, max_shapes_per_leaf::Int64=2, n_buckets::Int64=12)

Build a Boundary Volume Hierarchy (BVH) tree from a vector of shapes.

Arguments

  • shapes::Vector{AbstractShape}: The vector of shapes to build the BVH from. Note: it will be modified in place.

Keyword Arguments

  • use_sah::Bool=false: Whether to use the Surface Area Heuristic (SAH) for subdivision.
  • max_shapes_per_leaf::Int64=2: The maximum number of shapes allowed in a leaf node.
  • n_buckets::Int64=12: The number of buckets to use for SAH.

Returns

  • (BVHNode, Int64): A tuple containing the root node of the BVH tree and the maximum depth of the tree.
source
jujutracer.Subdivide!Function
Subdivide!(node::BVHNode, shapes::Vector{AbstractShape}, centroids::Vector{Point}, depth::Int64; max_shapes_per_leaf::Int64=2)

Subdivide a BVH node into left and right child nodes based on the centroids of the shapes. Recursive method.

Arguments

  • node::BVHNode: The BVH node to subdivide.
  • shapes::Vector{AbstractShape}: The vector of shapes used by the BVH Tree. Note: it will be modified in place.
  • centroids::Vector{Point}: The centroids of the shapes.
  • depth::Int64: The current depth of the BVH tree.

Keyword Arguments

  • max_shapes_per_leaf::Int64=2: The maximum number of shapes allowed in a leaf node.

Returns

  • Int64: The maximum depth of the BVH tree after subdivision.
source
jujutracer.SubdivideSAH!Function
SubdivideSAH!(node::BVHNode, shapes::Vector{AbstractShape}, centroids::Vector{Point}, depth::Int64; max_shapes_per_leaf::Int64=2, n_buckets::Int64=12)

Subdivide a BVH node using the Surface Area Heuristic (SAH) method. Recursive method.

Arguments

  • node::BVHNode: The BVH node to subdivide.
  • shapes::Vector{AbstractShape}: The vector of shapes used by the BVH Tree. Note: it will be modified in place.
  • centroids::Vector{Point}: The centroids of the shapes.
  • depth::Int64: The current depth of the BVH tree.

Keyword Arguments

  • max_shapes_per_leaf::Int64=2: The maximum number of shapes allowed in a leaf node.
  • n_buckets::Int64=12: The number of buckets to use for SAH.

Returns

  • Int64: The maximum depth of the BVH tree after subdivision.
source
jujutracer.BVHShapeType
struct BVHShape <: AbstractShape

Shape that holds a BVH tree and the relative shapes.

Fields

  • bvhroot::BVHNode: The root node of the BVH tree.
  • shapes::Vector{AbstractShape}: The vector of shapes used by the BVH Tree.

Constructor

  • BVHShape(bvhroot::BVHNode, shapes::Vector{AbstractShape}): Creates a new BVHShape with the specified BVH root and shapes.
source
BVHs and large shapes

When using BVHs, and in particular when using the SAH method, adding to the accelerated shapes a large shape which cointains other shapes (such as a box or a sphere used as sky) can lead to a large leaf node, when the first split occurs. This can lead to a very slow rendering time, as the ray tracing algorithm will have to check every shape in the leaf node for intersection.

An example of using a BVH is when accelerating a mesh object:

m_tree = mesh("asset/tree.obj"; order = "whd") # Beware that the mesh holds triangles, and not AbstractShapes.

shapes = Vector{AbstractShape}()
for t in m_tree.shapes
    push!(shapes, t)
end

bvh, bvhdepth = BuildBVH!(shapes; use_sah=true) # Returns the root node of the BVH and its depth.
# `shapes` is rearranged according to the BVH intersection order.
bvhshape = BVHShape(bvh, shapes)

Light Sources

Light sources are defined as a subtype of AbstractLight. They are used to illuminate the scene.

jujutracer.LightSourceType
struct LightSource

A struct representing a point light source.

Fields

  • position::Point: the position of the light source in 3D space.
  • emission::RGB: the color of the light emitted by the source.
  • scale::Float64: the scale factor for the light source, affecting its intensity.

Constructors

  • LightSource(position::Point, emission::RGB=RGB(1.0, 1.0, 1.0), scale::Float64=1.0): Creates a new light source with the specified position, emission color, and scale factor.
source
jujutracer.SpotLightType
struct SpotLight <: AbstractLight

A struct representing a spotlight source.

Fields

  • position::Point: the position of the spotlight in 3D space.
  • direction::Vec: the direction in which the spotlight is pointing.
  • emission::RGB: the color of the light emitted by the spotlight.
  • scale::Float64: the scale factor for the spotlight, affecting its intensity.
  • cos_total::Float64: the cosine of the angle that defines the total light cone.
  • cos_falloff::Float64: the cosine of the angle that defines the falloff region of the spotlight.
  • cos_start::Float64: the cosine of the angle that defines the start of the falloff region.

Constructors

  • SpotLight(position::Point, direction::Vec, emission::RGB=RGB(1.0, 1.0, 1.0), scale::Float64=100.0, cos_total::Float64=0.9, cos_falloff::Float64=0.93, cos_start::Float64=0.95): Creates a new spotlight with the specified parameters.
source

World

Once the shapes are defined (and lights), they can be added to the world. A vector of shapes and lights need to be prepared, from which the world will be created.

jujutracer.WorldType
struct World

A struct representing a collection of shapes (and lights) in a 3D world.

Fields

  • shapes::Vector{AbstractShape}: the vector containing the shapes in the world.
  • lights::Vector{AbstractLight}: the vector containing the light sources in the world.

Constructor

  • World(): creates a new World with an empty vector of shapes.
  • World(S::Vector{AbstractShape}): creates a new World with the specified vector of shapes. Lights are initialized to an empty vector.
  • World(S::Vector{AbstractShape}, L::Vector{AbstractLight}): creates a new World with the specified vector of shapes and light sources.

See also

  • AbstractShape: the abstract type for all shapes.
  • Sphere: a concrete implementation of AbstractShape representing a sphere.
  • Plane: a concrete implementation of AbstractShape representing a plane.
source

An example of creating a world is as follows:

shapes = Vector{AbstractShape}()
lights = Vector{AbstractLight}()

push!(shapes, sphere)
push!(shapes, ground)
push!(lights, light1)
push!(lights, spot1)

world = World(shapes, lights)