Switch to PBR Cont.

 

Code so Far

Here is the code for this section

Switch to Physically Based Rendering (PBR) Cont.

Last time I began implementing the Monte Carlo estimator on the ray tracer, but did not complete it. This is what the results looked like from last week.



After realizing my seed was blatantly wrong for my random function I was quickly able to achieve closer results to what I was expecting:


The image above uses 50,000 samples per pixel with 2 bounces. This runs at 1fps. With 100,000 samples per pixel I am able to get an image with almost no noise. 



100,000 Samples

Above is the render with 100,000 samples. Ever with this many samples I am still getting noise. Additionally if you observe the noise in both the 50,000 samples and 100,000 samples, the noise is not uniform. This indicates that either my function that maps a 2d sample over a sphere is incorrect or the generation of the random 2d sample itself is incorrect. After debugging this I was able to observe it was the random seed again and the generation of the 2d sample. This is more or less the random noise I was generating:


I was able to fix the seed function using the equation below.


The seed here generates a random number given the x and y of the image. Also so that the same random number is not generated for each sample and bounce, the sample number and bounce number are both factored into the seed. Using this new seed I was able to achieve more uniform noise and create this image using 50,000 samples. Side note: the image below is only darker because I decrease the light intensity.


The only issue I foresee with this seed still is that I am for sure overflowing the uint which could cause repetition. For now, the noise is more uniform than it was previously and is acceptable for now.

The next thing I added was some some animation to the scene to demonstrate the render isn't just producing a static image. I added a ball that circles the light right below it. The sphere was loaded in from an obj created in blender just like the scene itself. I also created a component for rotating the GameObject's Transform in a circle. This design is akin to Unity's MonoBehavior in that for any logic you want to add for a game object, you would create a class that inherits from Component, and attach that component to the game object. This is what the scene looks like with the added ball.



I also improved quality of life of the application by adding UI that allows you to change parameters for the application. I was able to achieve this through ImGui. I added sample count and bounce count as well as a FPS counter.


Importance Sampling

The Monte Carlo estimator is functional but it is slow. What we want is for the sample number of samples to generate a clearer image. One of the ways the estimator can be improved is instead of generating rays in random directions, generated rays with a higher probability of them pointing to lights. There is many ways to do implement importance sampling but for my renderer I kept it simple. In my implementation I used a step function. A random number is first generated from [0, 1]. If the number is greater than p, than a direction is chosen uniformly around a light source; otherwise a direction is chosen uniformly everywhere else. I exposed p as a configurable parameter through the UI. The next question is what is considered 'close' to a light source. For this I use the cos(atan(lightRadius / lightDistance)) to determine the z to sample from [z, 1] on the unit sphere.

This solution's drawback is that it only works for one light but can expanded for multiple light sources in the future.

The image below shows my implementation of importance sampling with 50 samples and 100,000 samples respectively. Notice without importance sampling the image has a lot more noise.



Lastly, I added some more settings for for enabling and disabling importance sampling and configuring the probability of choosing a direction towards a light in the step function described above. I also added a fps graph as well as vsync and ray tracing enabled indicators. This is the final result:


Up Next

In my last post of the the semester I want to wrap up this project by adding a real time denoiser to the renderer. This in theory should remove the noise from my image without having to increase the number of samples per pixel to an amount that kills FPS.

Comments

Popular posts from this blog

Enabling Raytracing - Part 2

DXR Demo - Introduction

Simple Lighting