This repository has been archived on 2024-12-30. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
2024CG-project-render/02_RayTracing.html
github-classroom[bot] 6eef377959
Initial commit
2024-10-11 10:27:35 +00:00

270 lines
11 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<link type="text/css" rel="stylesheet" href="css/github-markdown.css"/>
<link rel="stylesheet" href="css/github-markdown.css">
<style>
.markdown-body {
box-sizing: border-box;
min-width: 200px;
max-width: 980px;
margin: 0 auto;
padding: 45px;
}
</head>
<body>
<pre><code>@media (max-width: 767px) {
.markdown-body {
padding: 15px;
}
}
</code></pre>
<p></style>
<article class="markdown-body"></p>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({ TeX: { equationNumbers: {autoNumber: "all"} } });
</script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<div style="display:none">
$\newcommand{\A}{\mat{A}}$
$\newcommand{\B}{\mat{B}}$
$\newcommand{\C}{\mat{C}}$
$\newcommand{\D}{\mat{D}}$
$\newcommand{\E}{\mat{E}}$
$\newcommand{\F}{\mat{F}}$
$\newcommand{\G}{\mat{G}}$
$\newcommand{\H}{\mat{H}}$
$\newcommand{\I}{\mat{I}}$
$\newcommand{\J}{\mat{J}}$
$\newcommand{\K}{\mat{K}}$
$\newcommand{\L}{\mat{L}}$
$\newcommand{\M}{\mat{M}}$
$\newcommand{\N}{\mat{N}}$
$\newcommand{\One}{\mathbf{1}}$
$\newcommand{\P}{\mat{P}}$
$\newcommand{\Q}{\mat{Q}}$
$\newcommand{\Rot}{\mat{R}}$
$\newcommand{\R}{\mathbb{R}}$
$\newcommand{\S}{\mathcal{S}}$
$\newcommand{\T}{\mat{T}}$
$\newcommand{\U}{\mat{U}}$
$\newcommand{\V}{\mat{V}}$
$\newcommand{\W}{\mat{W}}$
$\newcommand{\X}{\mat{X}}$
$\newcommand{\Y}{\mat{Y}}$
$\newcommand{\argmax}{\mathop{\text{argmax}}}$
$\newcommand{\argmin}{\mathop{\text{argmin}}}$
$\newcommand{\a}{\vec{a}}$
$\newcommand{\b}{\vec{b}}$
$\newcommand{\c}{\vec{c}}$
$\newcommand{\d}{\vec{d}}$
$\newcommand{\e}{\vec{e}}$
$\newcommand{\f}{\vec{f}}$
$\newcommand{\g}{\vec{g}}$
$\newcommand{\mat}[1]{\mathbf{#1}}$
$\newcommand{\min}{\mathop{\text{min}}}$
$\newcommand{\m}{\vec{m}}$
$\newcommand{\n}{\vec{n}}$
$\newcommand{\p}{\vec{p}}$
$\newcommand{\q}{\vec{q}}$
$\newcommand{\r}{\vec{r}}$
$\newcommand{\transpose}{{\mathsf T}}$
$\newcommand{\tr}[1]{\mathop{\text{tr}}{\left(#1\right)}}$
$\newcommand{\s}{\vec{s}}$
$\newcommand{\t}{\vec{t}}$
$\newcommand{\u}{\vec{u}}$
$\newcommand{\vec}[1]{\mathbf{#1}}$
$\newcommand{\x}{\vec{x}}$
$\newcommand{\y}{\vec{y}}$
$\newcommand{\z}{\vec{z}}$
$\newcommand{\0}{\vec{0}}$
$\renewcommand{\v}{\vec{v}}$
<!-- https://github.com/mathjax/MathJax/issues/1766 -->
$\renewcommand{\hat}[1]{\widehat{#1}}$
</div>
<h1 id="computergraphicsraytracing">Computer Graphics - Ray Tracing</h1>
<p>Deadline: Oct. 25 2024, 22:00</p>
<p>Any questions or comments are welcome at julie.artois@ugent.be and in CC glenn.vanwallendael@ugent.be and bert.ramlot@ugent.be </p>
<h2 id="background">Background</h2>
<h3 id="readsections4.5-4.9offundamentalsofcomputergraphics4thedition.">Read Sections 4.5&#8211;4.9 of <em>Fundamentals of Computer Graphics (4th Edition)</em>.</h3>
<p>Many of the classes and functions of this assignment are <strong>reused
from the previous ray casting assignment</strong>. For example <code>viewing_ray()</code>,<code>first_hit()</code> and many more. Check the README for more info on this.</p>
<p>Unlike the previous assignment, this <a href="https://en.wikipedia.org/wiki/Ray_tracing_(graphics)">ray
tracer</a> will produce
<em>approximately</em> accurate renderings of scenes illuminated with light.
Ultimately, the shading and lighting models here are <em>useful</em> hacks. The basic
<a href="https://en.wikipedia.org/wiki/Ray_tracing_(graphics)#Recursive_ray_tracing_algorithm">recursive</a>
structure of the program is core to many methods for rendering with <a href="https://en.wikipedia.org/wiki/Global_illumination">global
illumination</a> effects (e.g.,
shadows, reflections, etc.).</p>
<figure>
<img src="css/sphere-and-plane.png" alt="Running ./raytracing ../data/sphere-and-plane.json should produce this image." />
</figure>
<h2 id="floatingpointnumbers">Floating point numbers</h2>
<p>For this assignment we will use the <code>Eigen::Vector3d</code> to represent points and
vectors, but <em>also</em> RGB colors. For all computation (before finally writing the
.ppm file) we will use double precision floating point numbers and <code>0</code> will
represent no light and <code>1</code> will represent the brightest color we can display.</p>
<p><a href="https://en.wikipedia.org/wiki/Floating-point_arithmetic">Floating point
numbers</a> <span class="math">\(≠\)</span> <a href="https://en.wikipedia.org/wiki/Real_number">real
numbers</a>, they don&#8217;t even cover all
of the <a href="https://en.wikipedia.org/wiki/Rational_number">rational numbers</a>. This
creates a number of challenges in numerical method and rendering is not immune
to them. We see this in the need for a <a href="https://en.wikipedia.org/wiki/Fudge_factor">fudge
factor</a> (for example 1e-6) to discard ray-intersections
when computing shadows or reflections that are too close to the originating
surface (i.e., false intersections due to numerical error).</p>
<h3 id="dynamicrangeburning">Dynamic Range &amp; Burning</h3>
<p>Light obeys the <a href="https://en.wikipedia.org/wiki/Superposition_principle">superposition
principle</a>. Simply put,
the light reflected of some part of an objects is the <em>sum</em> of contributions
from light coming in all directions (e.g., from all light sources). If there are
many bright lights in the scene and the object has a bright color, it is easy
for this sum to add up to more than one. At first this seems counter-intuitive:
How can we exceed 100% light? But this premise is false, the <span class="math">\(1.0\)</span> does not mean
the physically brightest possible light in the world, but rather the brightest
light our screen can display (or the brightest color we can store in our chosen
image format). <a href="https://en.wikipedia.org/wiki/High-dynamic-range_imaging">High dynamic range (HDR)
images</a> store a larger
range beyond this usual [0,1]. For this assignment, we will simply <em>clamp</em> the
total light values at a pixel to 1.</p>
<p>This issue is compounded by the problem that the <a href="https://en.wikipedia.org/wiki/BlinnPhong_shading_model">Blinn-Phong
shading</a> does not
correctly <a href="https://en.wikipedia.org/wiki/Energy_conservation">conserve energy</a>
as happens with light in the physical world.</p>
<p>Once you have finished the assignment, running <code>./raytracing ../data/bunny.json</code> (Linux/Macos) or <code>raytracing.exe ..\..\..\data\bunny.json</code> (Windows) should result in a PNG file similar to the one below. This might take a few minutes (e.g. 5 minutes in Release mode on a decent CPU). Notice the <a href="https://en.wikipedia.org/wiki/Burned_(image)">&#8220;burned out&#8221;</a> white
regions where the collected light has been clamped to [1,1,1]
(white).</p>
<figure>
<img src="css/bunny.png"/>
</figure>
<blockquote>
<p><strong>Question:</strong> Can we ever get a pixel value <em>less than zero</em>?</p>
<p><strong>Hint:</strong> Can a light be more than off?</p>
<p><strong>Side note:</strong> This doesn&#8217;t stop crafty visual effects artists from using
&#8220;negative lights&#8221; to manipulate scenes for aesthetic purposes.</p>
</blockquote>
<h2 id="whitelist">Whitelist</h2>
<p>There are many ways to &#8220;multiply&#8221; two vectors. One way is to compute the
<a href="https://en.wikipedia.org/wiki/Hadamard_product_(matrices)">component-wise</a>
multiplication: <span class="math">\(\mathbf{c} = \mathbf{a} \circ \mathbf{b}\)</span> or in index notation:
<span class="math">\(c_i = a_i b_i\)</span>. That is, multiply each corresponding component and store the
result in the corresponding component of the output vector. Using the Eigen
library this is accomplished by telling Eigen to treat each of the vectors as
&#8220;array&#8221; (where <a href="">matrix multiplication</a>, <a href="">dot product</a>, <a href="">cross product</a>
would not make sense) and then using the usual <code>*</code> multiplication:</p>
<pre><code>Eigen::Vector3d a,b;
...
// Component-wise multiplication
Eigen::Vector3d c = (a.array() * b.array()).matrix();
</code></pre>
<p>The <code>.matrix()</code> converts the &#8220;array&#8221; view of the vector back to a &#8220;matrix&#8221;
(i.e., vector) view of the vector.</p>
<p>Eigen also has a built in way to normalize a vector (divide a vector by its
length): <code>a.normalized()</code>.</p>
<p>C++ standard library includes a value for <span class="math">\(∞\)</span> via <code>#include &lt;limits&gt;</code>. For
example, for <code>double</code> floating point, use <code>std::numeric_limits&lt;double&gt;::infinity()</code>.</p>
<h2 id="tasks">Tasks</h2>
<h3 id="pointlight::directioninsrcpointlight.cpp"><code>PointLight::direction</code> in <code>src/PointLight.cpp</code></h3>
<p>Compute the direction to a point light source and its <em>parametric</em> distance from
a query point.</p>
<h3 id="directionallight::directioninsrcdirectionallight.cpp"><code>DirectionalLight::direction</code> in <code>src/DirectionalLight.cpp</code></h3>
<p>Compute the direction to a direction light source and its <em>parametric</em> distance from a
query point (infinity).</p>
<h3 id="srcraycolor.cpp"><code>src/raycolor.cpp</code></h3>
<p>Make use of <code>first_hit.cpp</code> to shoot a ray into the scene, collect hit
information and use this to return a color value. Use recursion to add mirror reflections.</p>
<h3 id="srcblinn_phong_shading.cpp"><code>src/blinn_phong_shading.cpp</code></h3>
<p>Compute the lit color of a hit object in the scene using <a href="https://en.wikipedia.org/wiki/BlinnPhong_shading_model">Blinn-Phong shading
model</a>. This function
should also shoot an additional ray to each light source to check for shadows.</p>
<p><b>Important:</b> On slide 39 of lecture CG_02_raytracing-split.pdf, the formula for the diffuse shading component is given: <br/>
<img src="css/diffuse_formula.png" width="300" /> <br/>
However, in your code, you should <b>omit the division by r²</b>. Otherwise your scenes will appear dim.
</p>
<h3>Running raytracing on sphere-and-plane.json</h3>
<figure>
<img src="css/sphere-and-plane.gif" />
<figcaption>It is recommended to add and debug each term in your shading model. The
ambient term will look like a faint object-ID image. The diffuse term will
illuminate the scene, and create a dull, Lambertian look to each object. The
specular term will add shiny highlights. Then, mask the diffuse and specular
terms by checking for shadows. Finally, add a recursive call to account for
mirror reflections.</figcaption>
</figure>
<h3 id="srcreflect.cpp"><code>src/reflect.cpp</code></h3>
<p>Given an &#8220;incoming&#8221; vector and a normal vector, compute the mirrored, reflected
&#8220;outgoing&#8221; vector.</p>
<h3>Running raytracing on sphere-packing.json</h3>
<figure>
<img src="css/sphere-packing.png" alt="./raytracing ../data/sphere-packing.json should produce this
image of highly reflective, metallic looking
surfaces." />
<figcaption>This should produce an image of highly reflective, metallic looking surfaces.</figcaption>
</figure>
<hr />
<blockquote>
<p><strong>Pro Tip:</strong> After you&#8217;re confident that your program is working <em>correctly</em>,
you can dramatically improve the performance simply by enabling <a href="https://en.wikipedia.org/wiki/Optimizing_compiler">compiler
optimization</a>: </p>
<pre><code>cmake .. -DCMAKE_BUILD_TYPE=Release
make
</code></pre>
</blockquote>
</body>
</html>