270 lines
11 KiB
HTML
270 lines
11 KiB
HTML
<!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="computergraphics–raytracing">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–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’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 & 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/Blinn–Phong_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)">“burned out”</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’t stop crafty visual effects artists from using
|
||
“negative lights” to manipulate scenes for aesthetic purposes.</p>
|
||
</blockquote>
|
||
|
||
<h2 id="whitelist">Whitelist</h2>
|
||
|
||
<p>There are many ways to “multiply” 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
|
||
“array” (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 “array” view of the vector back to a “matrix”
|
||
(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 <limits></code>. For
|
||
example, for <code>double</code> floating point, use <code>std::numeric_limits<double>::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/Blinn–Phong_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 “incoming” vector and a normal vector, compute the mirrored, reflected
|
||
“outgoing” 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’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>
|