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.Material — Typestruct MaterialFields
Emition::AbstractPigment: the pigement with which the radiation is emitted.BRDF::AbstractBRDF: the BRDF of the material.
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.UniformPigment — TypeUniformPigment()Uniform Pigment for Shapes
Fields
color::RBGthe uniform color
Functional Usage
UniformPigment(p::SurfacePoint) return the RGB associated to the (u, v) coordinates of the SurfacePoint
jujutracer.CheckeredPigment — TypeCheckeredPigment(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
colnumber of horizontal subdivisionsrownumber of vertical subdivisionsdarkcolor of the dark squaresbrightcolor of the bright squares
Functional Usage
CheckeredPigment(p::SurfacePoint) return the RGB associated to the (u, v) coordinates of the SurfacePoint
jujutracer.ImagePigment — TypeImagePigment(img::hdrimg)Print the image img as pigment of the surface
Fields
img::hdrimgthe 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
BRDFs
The BRDF of the material is defined as a subtype of AbstractBRDF. The available BRDFs are
jujutracer.DiffusiveBRDF — TypeDiffusiveBRDF(Pigment::AbstractPigment)Diffusive BRDF with reflective pigment Pigment.
jujutracer.SpecularBRDF — TypeSpecularBRDF(Pigment::AbstractPigment)Specular BRDF with reflective pigment Pigment.
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.Transformation — Typestruct Transformation <: AbstractTransformationRepresents 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 whereMandinvare both 4x4 identity matrices.Transformation(M::Matrix{Float64}, inv::Matrix{Float64}): Creates a transformation with the givenMandinvmatrices.Transformation(M::Matrix{Float64}, inv::Matrix{Float64}, unsafe::Unsafe): Creates a transformation with the givenMandinvmatrices, without veryfing the inputs.
Throws an ArgumentError if:
Morinvare not 4x4 matrices.- The last element of
Morinvis not1.0. Mandinvare 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
Mandinvmust be approximately equal to the 4x4 identity matrix.
jujutracer.Translation — Typestruct Translation <: AbstractTransformationRepresents 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 aTranslationobject with translation offsetsdx,dy, anddzalong the x, y, and z axes, respectively.Translation(v::Vec): Creates aTranslationobject using aVecobject.
jujutracer.Rx — Typestruct Rx <: AbstractTransformationRepresents 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 anRxinstance for a given rotationθ(in radians).
See also
jujutracer.Ry — Typestruct Ry <: AbstractTransformationRepresents 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 anRyinstance for a given rotationθ(in radians).
See also
jujutracer.Rz — Typestruct Rz <: AbstractTransformationRepresents 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 anRzinstance for a given rotationθ(in radians).
See also
jujutracer.Scaling — Typestruct Scaling <: AbstractTransformationRepresents 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.
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.Sphere — Typestruct Sphere <: AbstractSolidA 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
jujutracer.Box — Typestruct Box <: AbstractSolidAn 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.
jujutracer.Cone — Typestruct Cone <: AbstractSolidA 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
jujutracer.Cylinder — Typestruct Cylinder <: AbstractSolidA 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.
CSG Shapes
Set operations are defined as methods on the AbstractSolid` type. The available operations are:
jujutracer.CSGUnion — Typestruct CSGUnion <: AbstractSolidRepresents 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
CSGDifference: Represents the difference of two solid shapes.CSGIntersection: Represents the intersection of two solid shapes.
jujutracer.CSGIntersection — Typestruct CSGIntersection <: AbstractSolidRepresents 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.
jujutracer.CSGDifference — Typestruct CSGDifference <: AbstractSolidRepresents the difference of two solid shapes.
Fields
Tr::AbstractTransformation: The transformation applied to the difference.Sh1::AbstractSolid,Sh2::AbstractSolid: The two solid shapes whereSh1 - Sh2is computed.
See also
CSGUnion: Represents the union of two solid shapes.CSGIntersection: Represents the intersection of two solid shapes.
Flat Shapes
jujutracer.Plane — Typestruct Plane <: AbstractShapeA plane. This structure is a subtype of AbstractShape.
Fields
t::Transformation: the transformation applied to the planeMat::Material: the material of the shape
jujutracer.Triangle — Typestruct Triangle <: AbstractShapeTriangle.
Fields
t::Transformation: the transformation applied to the triangleA, B, C::Point: the vertices of the triangleMat::Material: the material of the shape
Constructor
Triangle(): creates a triangle with IdentityTransformationand vertices (0,0,0), (1,0,0), (0,1,0) and a default material.Triangle(Tr::AbstractTransformation): creates a triangle withTrTransformationand vertices (0,0,0), (1,0,0), (0,1,0) and a default material.Triangle(Mat::Material): creates a triangle with IdentityTransformationand vertices (0,0,0), (1,0,0), (0,1,0) and aMatmaterial.Triangle(Tr::AbstractTransformation, Mat::Material): creates a triangle withTrTransformationand vertices (0,0,0), (1,0,0), (0,1,0) and aMatmaterial.Triangle(A::Point, B::Point, C::Point): creates a triangle with IdentityTransformationand verticesA,B,Cand a default material.Triangle(A::Point, B::Point, C::Point, Mat::Material): creates a triangle with IdentityTransformationand verticesA,B,Cand aMatmaterial.
jujutracer.Parallelogram — Typestruct Parallelogram <: AbstractShapeParallelogram
C-----p
/ /
/ /
A-----BFields
t::Transformation: the transformation applied to the Parallelogram.A, B, C::Point: the vertices defining the quadrilateral'sMat::Material: the material of the shape
Constructor
Parallelogram(): creates a parallelogram with IdentityTransformationand vertices (0,0,0), (1,0,0), (0,1,0) and a default material.Parallelogram(Tr::AbstractTransformation): creates a parallelogram withTrTransformationand vertices (0,0,0), (1,0,0), (0,1,0) and a default material.Parallelogram(Mat::Material): creates a parallelogram with IdentityTransformationand vertices (0,0,0), (1,0,0), (0,1,0) and aMatmaterial.Parallelogram(Tr::AbstractTransformation, Mat::Material): creates a parallelogram withTrTransformationand vertices (0,0,0), (1,0,0), (0,1,0) and aMatmaterial.Parallelogram(A::Point, B::Point, C::Point): creates a parallelogram with IdentityTransformationand verticesA,B,Cand a default material.Parallelogram(A::Point, B::Point, C::Point, Mat::Material): creates a parallelogram with IdentityTransformationand verticesA,B,Cand aMatmaterial.Parallelogram(A::Point, AB::Vec, AC::Vec): creates a parallelogram with IdentityTransformationand verticesA,A + AB,A + ACand a default material.
jujutracer.Rectangle — Typestruct Rectangle <: AbstractShape1x1 Rectangle on xy plane, centered in the origin
Fields
t::Transformation: the transformation applied to the planeMat::Material: the material of the shape
jujutracer.Circle — Typestruct Circle <: AbstractShapeA 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.
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.mesh — Typestruct mesh <: AbstractShapemesh.
Fields
file::String: the sourcefile.objof the meshshape::Vector{Triangle}: the triangles of the meshpoints::Vector{Point}: the vertices of the triangles of the shape
Constructor
mesh(shapes::Vector{Triangle}): creates a mesh frome theVector{Triangle}mesh(file::String): creates a mesh fromfilemesh(file::String, Tr::AbstractTransformation): creates a mesh fromfilewith a transformationTrmesh(file::String, Mat::Material): creates a mesh withMatmaterial fromfilemesh(file::String, Tr::AbstractTransformation, Mat::Material): creates a mesh withTrtransformation and aMatmaterial.
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.
jujutracer.read_obj_file — Functionread_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 bufferTr::AbstractTransformation: an hypotetical transformation to be applied to all the shapes and pointsMat::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}
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 thefile.objTr::AbstractTransformation: an hypotetical transformation to be applied to all the shapes and pointsMat::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}
jujutracer.trianglize — Functiontrianglize(P::Vector{Points}, Tr::AbstractTransformation, Mat::Material)Triangulation method, working only with ordered verteces
Arguments
P::Vector{Point}: the vector of points to be triangulatedTr::AbstractTransformation: an hypotetical transformation to be applied to all the shapes and pointsMat::Material: a material to be applied to all the triangles
Returns
tr::Vector{Triangle}: a vector of triangles created from the points inP
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.AABB — Typestruct AABB <: AbstractShapeAxis-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 inS, 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 cornersP1andP2for the shapes inS.AABB(csg::Union{CSGDifference, CSGUnion, CSGIntersection}): creates an AABB for a CSG shape, extracting the shapes and their bounding box.
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! — FunctionBuildBVH!(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.
jujutracer.Subdivide! — FunctionSubdivide!(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.
jujutracer.SubdivideSAH! — FunctionSubdivideSAH!(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.
jujutracer.BVHShape — Typestruct BVHShape <: AbstractShapeShape 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 newBVHShapewith the specified BVH root and 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.LightSource — Typestruct LightSourceA 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.
jujutracer.SpotLight — Typestruct SpotLight <: AbstractLightA 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.
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.World — Typestruct WorldA 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 newWorldwith an empty vector of shapes.World(S::Vector{AbstractShape}): creates a newWorldwith the specified vector of shapes. Lights are initialized to an empty vector.World(S::Vector{AbstractShape}, L::Vector{AbstractLight}): creates a newWorldwith the specified vector of shapes and light sources.
See also
AbstractShape: the abstract type for all shapes.Sphere: a concrete implementation ofAbstractShaperepresenting a sphere.Plane: a concrete implementation ofAbstractShaperepresenting a plane.
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)