*** Wartungsfenster jeden ersten Mittwoch vormittag im Monat ***

Skip to content
Snippets Groups Projects
Commit e67ee218 authored by Adam Celarek's avatar Adam Celarek
Browse files

wokr on assignment 1 / mc and path tracing

parent 4cea8187
No related branches found
No related tags found
No related merge requests found
......@@ -2,11 +2,12 @@
\usepackage{graphicx}
\usepackage{xspace}
\usepackage{xcolor}
\usepackage{subcaption}
\newcommand{\OpenGL}{OpenGL\xspace}
\newcommand*\diff{\mathop{}\!\mathrm{d}}
\newcommand{\f}[1]{\operatorname{#1}}
\newcommand{\todo}[1]{\color[red]{\textbf{#1}}}
\newcommand{\todo}[1]{\textcolor{red}{\textbf{#1}}}
\title{Assignment 1: Monte Carlo Integration and Path Tracing}
\deadline{2020-05-24 23:59}%2020-05-13 23:59
......@@ -44,7 +45,7 @@ git pull upstream master
git push
\end{verbatim}
\section{Completing Nori's MC Intestines (1 easy point)}
\section{Completing Nori's MC Intestines}
Nori is an almost complete Monte Carlo integrator.
We have left out some crucial parts for you to complete.
At the same time you'll get a short tour of the MC machinery.
......@@ -64,50 +65,42 @@ for (y=0; y<height; ++y) {
}
\end{verbatim}
\todo{Iirc there is still the box filter in the code. we want to remove it and have the samples only in the pixel centre.}
Obviously the code will be longer in practise due to parallelisation, filtering (something we will learn later) and general architectural design.
Look into the code, try to understand how things are done and complete the following functions (all changes are a single line):
\begin{description}
\item[main.cpp, renderBlock()] (iterate over all samples)
\item[block.cpp, ImageBlock::put(Point2f, Color3f)] (accumulate samples and sample count)
\item[block.cpp, ImageBlock::toBitmap()] divide by sample count (look at Color4f, there is a function you can use)
\item[any scene from assignment1] increase the sample count.
\end{description}
With the normals integrator you shouldn't see a difference, but the AO renderer will not work properly without these changes.
With the normals renderer you shouldn't see a difference, but the AO integrator will not work properly without these changes.
You do not need another sample generating loop inside the integrators.
If you would do that, there would be the problem of ever exploding number of samples (curse of dimensionality).
If you would do that in a path tracer, there would be the problem of ever exploding number of samples (curse of dimensionality).
\section{Ambient occlusion (10 easy points)}
\section{Ambient occlusion (3 easy points)}
Implement ambient occlusion!
The rendering equation is
\begin{align}
L_e(x) = \int_{\Omega} \f{V}(x, x + \alpha \omega) \frac{\cos(\theta)}{\pi} \diff \omega,
L_e(x) = \int_{\Omega} \frac{1}{\pi} \f{V}(x, x + \alpha \omega) \cos(\theta) \diff \omega,
\end{align}
where $L_e$ is the brightness, $x$ a position on the surface, $\f{V}$ the visibility function, $\alpha$ a constant, and $\theta$ the angle between the normal and $\omega$.
The visibility function is 1 or 0, depending on whether the ray reaches the destination, it's also called a shadow ray.
$\alpha$ should default to \texttt{scene->getBoundingBox().getExtents().norm()}, and be configurable via XML (experiment with it!).
The division by $\pi$ is exactly what we explained in the lecture about light when we talked about the furnace test.
$\frac{1}{\pi}$ is a white diffuse BRDF, as we explained in the lecture about light when we talked about the furnace test.
You will need a function that turns a 2d uniform sample between 0 and 1 into a uniform hemisphere sample.
This transformation is called warping.
Look at \texttt{Vector3f Warp::squareToUniformHemisphere(const Point2f \&sample)} inside \texttt{warp.cpp} and \texttt{warp.h}.
Be careful with all the factors (including those inside $\f{p}(x)$), some of them cancel out and don't need to be computed!
Altogether, this should be about 20 lines in a new \texttt{ao.cpp} file (not counting boiler plate code).
Implement 2 variants, one using uniform hemisphere sampling and the other with cosine-weighted hemisphere sampling (that is an importance sampling method).
You should make that configurable as well.
Altogether, this should be about 20 lines in a new \texttt{integrator\_ao.cpp} file (not counting boiler plate code).
Compare results with different sample counts (16, 64, 256...), do you see an improvement?
\begin{verbatim}
<integrator type="ao">
<float name="alpha" value="4"/>
<boolean name="cosine_sampling" value="true"/>
</integrator>
\end{verbatim}
\section{Direct lighting}
This will require the largest amount of coding :)
\section{Direct lighting (9 Points)}
Check the slides about light and the recap in Monte Carlo integration for the correct integrals.
There are two possibilities on how to implement direct lighting: hemisphere sampling and the light source sampling.
There are two possibilities on how to implement direct lighting: hemisphere sampling and light source sampling.
Hemisphere sampling works well only for very large lights (sky), while light source sampling works especially well with small lights.
If we had point or directional lights, we could sample them only directly.
All these sampling methods can be combined using MIS (you will learn about that later).
......@@ -117,33 +110,34 @@ Once you have that and you start with light source sampling, you can test whethe
If they don't, you have a bug.
You can also use our provided unit tests locally (maybe you have to edit the python script to correct the path).
\subsection{Hemisphere sampling (9 easy points)}
You should base your code on \texttt{ao.cpp} and implement it in \texttt{direct\_lighting.cpp}.
\subsection{Hemisphere sampling (3 easy points)}
You should base your code on \texttt{integrator\_ao.cpp} and implement it in \\
\texttt{integrator\_direct\_lighting.cpp}.
\paragraph*{Task 1} Implement the emitter interface (make either a \texttt{parallelogram\_emitter} or \texttt{mesh\_emitter}) and the supporting machinery.
Emitters need to read their brightness (radiance) and colour from the scene file and store it (this is the least).
A name and debug info might also be good.
If you don't plan to implement the bonus points, you can use a dummy implementation for Emitter::pdf() and Emitter::sample().
If you don't plan to implement the direct sampling, you can use a dummy implementation for Emitter::pdf() and Emitter::sample().
\paragraph*{Task 2}
Implement the integrator.
First, you need to check whether the camera ray hits a light (emitter).
If so, return its colour and be done.
This is not completely correct, but you can ignore direct illumination of light sources for now.
If you hit a regular surface instead, make a random ray cast using cosine-weighted importance sampling, similar to ambient occlusion (no maximum length this time!).
If you hit a regular surface instead, make a random ray cast using uniform hemisphere sampling, similar to ambient occlusion (no maximum length this time!).
If the closest intersected object is a light, compute its contribution using the equations from the lecture, otherwise return zero (black).
This is only a small edit from the \texttt{ao} integrator.
\subsection{Direct light sampling (20 points)}
\subsection{Direct light sampling (6 points)}
Direct light sampling, is also important for performant path tracers (it's called "next event estimation" there).
You will need to sample area lights directly, i.e., you need a function to randomly pick points on the surface of the light.
There are 2 options here:
\begin{enumerate}
\item \textbf{Parallelogram lights (10 points)}
\item \textbf{Parallelogram lights (3 points)}
Parallelograms are very easy to sample (just take the linear combination of its side vectors with 0 < random factor < 1).
Another advantage is that you can apply sampling patterns (stratified, Halton, we'll cover those later).
\item \textbf{Triangle mesh lights (20 points)}
\item \textbf{Triangle mesh lights (6 points)}
This can give very cool results, i.e., imagine a glowing mesh.
Mesh sampling is not that hard either: Select the triangle according to its surface area (larger triangles are more often selected).
The implementation in \texttt{nori/dpdf.h} will be useful here.
......@@ -158,19 +152,19 @@ There are 2 options here:
More complex samplers would be needed for large meshes, for instance such that do importance sampling based on distance, cosine, etc.
Please don't go that far for now.
\end{enumerate}
You can get either 10 points for parallelogram lights or 20 points for triangle mesh.
You can get either 3 points for parallelogram lights or 6 points for triangle mesh.
\paragraph*{Task 3}
Implement sampling.
The parallelogram, mesh, or emitter classes would be good places (your design).
You need to implement something like \texttt{samplePosition} (taking random numbers, returning a position and its normal) and \texttt{pdf} (taking a position and returning the sample probability).
This is similar to the warping functions that you wrote in the first sub-assignment.
This is similar to warping functions.
\paragraph*{Task 4}
You will need a list of emitters in the scene.
Hook into \texttt{Scene::addChild}.
In our assignments, surface emitters are children of meshes.
The switch emitter case is for point lights or other emitters without physical surface (that code was made for EPFL, we have slightly different assignments).
The switch emitter case is for point lights or other emitters without physical surface (that code was made for EPFL, we have different assignments).
Additionally, the emitter object needs a pointer to the geometry (mesh or parallelogram, otherwise the sampling code wouldn't have any data).
Don't be afraid of adding stuff to the headers or create new ones, it's your design now.
......@@ -182,13 +176,13 @@ When you have a point, you then cast a shadow ray, and compute the contribution
Use a boolean property to switch between hemisphere sampling and surface sampling.
It shouldn't be hard to see the difference in quality.
\section{Simple Path Tracing}
\subsection{Implement the recursive path tracing algorithm (10 Points)}
\section{Simple Path Tracing (15 Points)}
\subsection{Implement the recursive path tracing algorithm (8 points)}
Create a new integrator and call it \texttt{path\_tracer\_recursive}(\texttt{.cpp}).
Start with a copy of the direct lighting integrator.
It might pay off to keep your code clean and make small refactorings while working on it.
\paragraph*{Task 1, starter code (4 easy points)}
\paragraph*{Task 1, starter code (5 easy points)}
Create an additional \texttt{Li} function, that also keeps track of the current depth.
Now you can use the pseudo code from the lecture as a template to implement a simple path tracer.
\begin{verbatim}
......@@ -207,10 +201,10 @@ value += getLightRadiance(its);
if(depth >= 3)
return value;
// Generally, the BRDF should decide on the next ray (e.g. for specular
// reflections). For now you can assume white diffuse BRDF and uniform
// hemisphere sampling. Therefore, replace the code as you see fit.
BRDF brdf = getBRDF(its);
// BRDF should decide on the next ray
// (It has to, e.g. for specular reflections)
Color brdfValue = sampleBrdf(brdf, -ray, wo);
// Call recursively for indirect lighting
......@@ -229,7 +223,7 @@ But the proper way to do it is to keep track of the \textit{throughput}.
With every bounce, the importance emitted from the camera is attenuated, and the probability for continuation should become lower.
You should keep track of this throughput in a Color3f vector, and use its largest coefficient for Russian Roulette (2 Points).
\subsection{Implement path tracing in a loop (5 point)}
\subsection{Implement path tracing in a loop (5 bonus point)}
Every recursive algorithm can be written in a loop as well.
Sometimes a stack is needed, but in the path tracer that is not necessary.
The loop form is much friendlier to the processor, and you can't get stack overflows (which could happen with deep refractions).
......@@ -261,6 +255,10 @@ return value;
You might \textit{break}, or add things to \textit{value} in more than one place, or in a different order.
This is just the basic idea.
\subsection{Use the BRDF / BSDF interface (2 bonus point)}
You will have to implement that later anyway, but you can do it early and gather bonus points.
These 2 bonus points are only available in conjunction with a working path tracer.
\subsection*{Submission format}
%To be announced.
......@@ -269,7 +267,7 @@ This is just the basic idea.
\subsection*{Words of wisdom}
\begin{itemize}
\item Remember that you don't need all points to get the best grade. The workload of 3 ECTS counts on taking the exam, which gives a lot of points.
\item Nori provides you with a \texttt{Sampler} that is passed in to the functions that produce the integrator input. Use this class to draw values from a canonic random variable.
\item Be careful of so-called "self-intersections". These happen when due to
inaccuracies in floating point computations, you immediately hit the
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment