LuxMancer: Mastering Light and Shadow- MINIRT: PART 1

B.R.O.L.Y
7 min readDec 18, 2023

--

0 — Authors: A Collaborative Endeavor:

This blog post is the result of a collaborative effort between RIDWANE EL FILALI and MOHCINE GHALMI, we together navigated the intricacies of vector mathematics, graphics, and ray tracing. The synergy of their insights and expertise brings you this exploration into the world of vectors and their applications.

Feel free to connect with Mohcine Ghalmi on Medium to explore more of his contributions and insights.

1 — Introduction:

Welcome aboard as we set sail into the captivating realm of ray tracing — a journey where pixels transform into breathtaking landscapes, shadows dance with light, and realism meets imagination. This blog marks the genesis of a series, a chronicle of my endeavors in crafting a simple yet powerful ray tracer, unlocking the secrets behind the scenes of realistic computer-generated imagery.

2 — What is a Vectors :

At its core, a vector is more than a mere collection of numbers; it is a mathematical entity with both magnitude and direction. Imagine an arrow pointing in space; the length of the arrow represents its magnitude, and the direction it points captures its essence.

Magnitude: The numerical measure of a vector’s length, often denoted by |v| or ||v||.

Direction: The orientation of the vector in space, indicating where it points.

2 — Extending into 3D :

In three-dimensional space, vectors take on a richer form. No longer confined to the simplicity of a plane, they stretch and reach, defining points, directions, and movements within a volumetric expanse.

Coordinate Systems in 3D:

  • Introduce the Cartesian coordinate system in 3D, where each point is described by an ordered triplet (x, y, z). Vectors in this space are represented similarly, with each component corresponding to movement along a specific axis.

Vector Representation in 3D:

  • Visualize a 3D vector as an arrow extending from the origin to a specific point in space. The vector’s components (x, y, z) denote the distances along each coordinate axis.

Magnitude in 3D space:

  • so to calculate the magnitude in 3d we just need to use the same mathematical formula of 2d space and add the 3rd dimension
double      vlength2(t_vector vec)
{
return (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z);
}


double vlength(t_vector vec)
{
return (sqrt(vlength2(vec)));
}

3 — Vector operations :

* Vector Addition: Combining Forces in Space

  • Vector addition is the fundamental operation that allows us to combine two vectors, unleashing the power to represent complex movements or displacements in three-dimensional space. The formula for vector addition is quite intuitive:

now let’s code the addition part, we know that the vector a point and even the color have the same elements (x, y, z) so we’re gonna create one struct aliased to three elements, if you’re scared you’ll miss things up passing a point instead of a vector worry not because with you implementing a little cautious and patients you’ll get things running but we will always choose the shortcode part just for logic and course purposes

/*define vector*/
struct vector
{
double x;
double y;
double z;
};

// 3 alias for color and point color
typedef struct vector t_vector;
typedef struct vector t_point;
typedef struct vector t_color;

now let’s create a function handling vector addition

t_vector      vplus(t_vector vec, t_vector vec2)
{
vec.x += vec2.x;
vec.y += vec2.y;
vec.z += vec2.z;
return (vec);
}

t_vector vplus_(t_vector vec, double x, double y, double z)
{
vec.x += x;
vec.y += y;
vec.z += z;
return (vec);
}

* Vector Subtraction: Unraveling Spatial Displacements

  • Vector subtraction is a mathematical operation that unveils the intricacies of spatial displacements, offering insights into the changes or differences between two points in three-dimensional space

now let’s talk subtraction logic, its nature is just addition with extra steps hhh, in fact it’s like this

now this most people know but it will help us image it in 3d

t_vector      vminus(t_vector vec, t_vector vec2)
{
vec.x -= vec2.x;
vec.y -= vec2.y;
vec.z -= vec2.z;
return (vec);
}

t_vector vminus_(t_vector vec, double x, double y, double z)
{
vec.x -= x;
vec.y -= y;
vec.z -= z;
return (vec);
}

* Vector Multiplication: Scaling and Component-Wise Interaction

  • Vector multiplication, a versatile operation in the realm of vector mathematics, comes in two distinct forms: scalar multiplication and component-wise multiplication of two vectors.

→ Scalar Multiplication:

When scaling a vector V by a scalar t, each component of the vector is multiplied by the scalar:

Scalar multiplication allows us to stretch or shrink a vector, influencing its magnitude while preserving its directions

→ Component-Wise Multiplication:

The component-wise multiplication of two vectors V and W involves multiplying corresponding components:

This operation results in a new vector whose components represent the element-wise product of the original vectors

t_vector      vmult(t_vector vec, double t)
{
vec.x *= t;
vec.y *= t;
vec.z *= t;
return (vec);
}


t_vector vmult_(t_vector vec, t_vector vec2)
{
vec.x *= vec2.x;
vec.y *= vec2.y;
vec.z *= vec2.z;
return (vec);
}

* Vector Division: Scaling and Component-Wise Interaction in Reverse

  • Vector division, while not as common as multiplication in many contexts, involves two distinct operations: scalar division and component-wise division of two vectors.

→ Scalar Division:

Scalar division of a vector V by a scalar t is executed by dividing each component of the vector by the scalar:

The scalar division allows for the adjustment of a vector’s magnitude while maintaining its direction.

  • In standard vector mathematics, the division between two vectors isn’t a defined operation. Vector division is not a common operation in vector spaces like addition, subtraction, or scalar multiplication.
t_vector      vdivide(t_vector vec, double t)
{
vec.x *= 1 / t;
vec.y *= 1 / t;
vec.z *= 1 / t;

return vec;
}

* Unit Vectors: Navigating Magnitudes with Precision

  • Unit vectors, the unsung heroes of vector mathematics, play a crucial role in providing direction without altering magnitude. A unit vector, denoted as U, is derived by dividing a vector V by its own magnitude, forming a vector with a length of 1:

Here, ∥v∥ represents the magnitude of V. Unit vectors provide a convenient way to express direction, making them essential in normalized calculations. In computer graphics, physics simulations, and various mathematical models, unit vectors act as navigators, ensuring precise directionality without impacting the scale of operations. Whether illuminating the path of a ray in ray tracing or normalizing forces in physics simulations, unit vectors are the compass guiding vectors through the vast spaces of numerical exploration.

t_vector      vunit(t_vector vec)
{
double len = vlength(vec);
if (len == 0)
{
printf("Error\n:Devider is 0");
exit(1);
}
vec.x /= len;
vec.y /= len;
vec.z /= len;
return (vec);
}

* Dot Product: Unveiling Spatial Alignment

  • The dot product, a fundamental operation in vector mathematics, serves as a compass guiding us through the intricacies of spatial relationships. Given two vectors V and W, the dot product vw is calculated by multiplying corresponding components and summing them:

This operation yields a scalar value, representing the projection of one vector onto the other. Geometrically, it reveals the extent to which two vectors align, with a positive dot product signifying similarity in direction, a negative dot product indicating opposition, and a dot product of zero denoting orthogonality. The dot product finds wide applications in physics, computer graphics, and engineering, providing insights into the alignment of forces, angles between vectors, and the determination of projections in multidimensional spaces.

double      vdot(t_vector vec, t_vector vec2)
{
return (vec.x * vec2.x + vec.y * vec2.y + vec.z * vec2.z);
}

* Cross Product: The Vector Alchemy of Orthogonality and Magnitude

  • The cross product, a transformative operation in vector calculus, unveils the art of generating a vector that is perpendicular to two given vectors. For two vectors V and W, their cross product v×w is calculated as follows:

The result is a vector that is perpendicular to both v and w. The magnitude of the cross-product is proportional to the area of the parallelogram formed by v and w, revealing a geometric insight into their mutual orthogonality.

t_vector      vcross(t_vector vec, t_vector vec2)
{
t_vector new;

new.x = vec.y * vec2.z - vec.z * vec2.y;
new.y = vec.z * vec2.x - vec.x * vec2.z;
new.z = vec.x * vec2.y - vec.y * vec2.x;
return (new);
}

and this gets us to the end of part 1, but keep your seat warm because there will be a part 2 soon

--

--

B.R.O.L.Y

"1337 student and open-source advocate. Enthusiastic about Linux kernel hacking and crafting web apps that push boundaries."