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 Material
Fields
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::RBG
the 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
col
number of horizontal subdivisionsrow
number of vertical subdivisionsdark
color of the dark squaresbright
color 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::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
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
.
Fields
Pigment::AbstractPigment
: the pigment used for the BRDF.
Functional Usage
DiffusiveBRDF(pcg::PCG, in_dir::Vec, p::Point, normal::Normal, depth::Int64)
returns a Ray sampled with diffusion.
jujutracer.SpecularBRDF
— TypeSpecularBRDF(Pigment::AbstractPigment)
Specular BRDF with reflective pigment Pigment
.
Fields
Pigment::AbstractPigment
: the pigment used for the BRDF.
Functional Usage
SpecularBRDF(pcg::PCG, in_dir::Vec, p::Point, normal::Normal, depth::Int64)
returns a Ray sampled with specular reflection. Can also be called withtout pcg
.
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 <: 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 whereM
andinv
are both 4x4 identity matrices.Transformation(M::Matrix{Float64}, inv::Matrix{Float64})
: Creates a transformation with the givenM
andinv
matrices.Transformation(M::Matrix{Float64}, inv::Matrix{Float64}, unsafe::Unsafe)
: Creates a transformation with the givenM
andinv
matrices, without veryfing the inputs.
Throws an ArgumentError
if:
M
orinv
are not 4x4 matrices.- The last element of
M
orinv
is not1.0
. M
andinv
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
andinv
must be approximately equal to the 4x4 identity matrix.
jujutracer.Translation
— Typestruct 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 aTranslation
object with translation offsetsdx
,dy
, anddz
along the x, y, and z axes, respectively.Translation(v::Vec)
: Creates aTranslation
object using aVec
object.
jujutracer.Rx
— Typestruct 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 anRx
instance for a given rotationθ
(in radians).
See also
jujutracer.Ry
— Typestruct 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 anRy
instance for a given rotationθ
(in radians).
See also
jujutracer.Rz
— Typestruct 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 anRz
instance for a given rotationθ
(in radians).
See also
jujutracer.Scaling
— Typestruct 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 a
Scalinginstance with scaling factors
x,
y, and
zalong the x, y, and z axes, respectively. Throws an
ArgumentError` 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 <: 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
jujutracer.Box
— Typestruct 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) in the Box's local coordinate system.P2::Point
: The opposite corner of the box (maximum x, y, z) in the Box's local coordinate system.Mat::Material
: The material of the box.
Constructors
Box()
: Creates a new box with default transformation and 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)
: Creates a new box with the specified transformation and default 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 <: 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
jujutracer.Cylinder
— Typestruct 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.
CSG Shapes
Set operations are defined as methods on the AbstractSolid
` type. The available operations are:
jujutracer.CSGUnion
— Typestruct 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
CSGDifference
: Represents the difference of two solid shapes.CSGIntersection
: Represents the intersection of two solid shapes.
jujutracer.CSGIntersection
— Typestruct 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.
jujutracer.CSGDifference
— Typestruct 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 whereSh1 - Sh2
is 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 <: AbstractShape
A 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 <: AbstractShape
Triangle.
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 IdentityTransformation
and vertices (0,0,0), (1,0,0), (0,1,0) and a default material.Triangle(Tr::AbstractTransformation)
: creates a triangle withTr
Transformation
and vertices (0,0,0), (1,0,0), (0,1,0) and a default material.Triangle(Mat::Material)
: creates a triangle with IdentityTransformation
and vertices (0,0,0), (1,0,0), (0,1,0) and aMat
material.Triangle(Tr::AbstractTransformation, Mat::Material)
: creates a triangle withTr
Transformation
and vertices (0,0,0), (1,0,0), (0,1,0) and aMat
material.Triangle(A::Point, B::Point, C::Point)
: creates a triangle with IdentityTransformation
and verticesA
,B
,C
and a default material.Triangle(A::Point, B::Point, C::Point, Mat::Material)
: creates a triangle with IdentityTransformation
and verticesA
,B
,C
and aMat
material.
jujutracer.Parallelogram
— Typestruct 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'sMat::Material
: the material of the shape
Constructor
Parallelogram()
: creates a parallelogram with IdentityTransformation
and vertices (0,0,0), (1,0,0), (0,1,0) and a default material.Parallelogram(Tr::AbstractTransformation)
: creates a parallelogram withTr
Transformation
and vertices (0,0,0), (1,0,0), (0,1,0) and a default material.Parallelogram(Mat::Material)
: creates a parallelogram with IdentityTransformation
and vertices (0,0,0), (1,0,0), (0,1,0) and aMat
material.Parallelogram(Tr::AbstractTransformation, Mat::Material)
: creates a parallelogram withTr
Transformation
and vertices (0,0,0), (1,0,0), (0,1,0) and aMat
material.Parallelogram(A::Point, B::Point, C::Point)
: creates a parallelogram with IdentityTransformation
and verticesA
,B
,C
and a default material.Parallelogram(A::Point, B::Point, C::Point, Mat::Material)
: creates a parallelogram with IdentityTransformation
and verticesA
,B
,C
and aMat
material.Parallelogram(A::Point, AB::Vec, AC::Vec)
: creates a parallelogram with IdentityTransformation
and verticesA
,A + AB
,A + AC
and a default material.
jujutracer.Rectangle
— Typestruct Rectangle <: AbstractShape
1x1 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 <: 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.
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 <: AbstractShape
mesh.
Fields
file::String
: the sourcefile.obj
of the meshshape::Vector{Triangle}
: the triangles of the mesh
Keywords
order::String
: the order of the coordinates in the file, default is "dwh" (depth, width, height). If the order is different, you can specify it with this keyword argument.
Constructor
mesh(shapes::Vector{Triangle})
: creates a mesh frome theVector{Triangle}
mesh(file::String)
: creates a mesh fromfile
mesh(file::String, Tr::AbstractTransformation)
: creates a mesh fromfile
with a transformationTr
mesh(file::String, Mat::Material)
: creates a mesh withMat
material fromfile
mesh(file::String, Tr::AbstractTransformation, Mat::Material)
: creates a mesh withTr
transformation and aMat
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.
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.obj
Tr::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 <: 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 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 cornersP1
andP2
for 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 <: 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 newBVHShape
with 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 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.
jujutracer.SpotLight
— Typestruct 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.
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)
: 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 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 newWorld
with an empty vector of shapes.World(S::Vector{AbstractShape})
: creates a newWorld
with the specified vector of shapes. Lights are initialized to an empty vector.World(S::Vector{AbstractShape}, L::Vector{AbstractLight})
: creates a newWorld
with the specified vector of shapes and light sources.
See also
AbstractShape
: the abstract type for all shapes.Sphere
: a concrete implementation ofAbstractShape
representing a sphere.Plane
: a concrete implementation ofAbstractShape
representing 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)