CS148 Final Project 12/13/2017 Bryce Long (molohov) I-Sheng Yang (ishengy) Theme of the scene: A chess battle in the snowy North Pole amidst an Aurora Borealis. SCENE ASSETS: + Chess pieces (all modeled by us) - Black marble texture (found on Google) - Red marble texture (found on Google) - Clear pieces are pure transmissive pieces with IOR 1.6, no textures set + Ground mesh (modeled by Bryce) - Snow texture on ground mesh (found on Google) + Wall plane (modeled by us) - Background image texture on wall plane (found on Google, Photoshopped by Bryce to give depth of field without implementing real depth of field :D) TECHNICAL CONTRIBUTIONS: +++ Photon mapping with importance sampling (I-Sheng) We extended assignment 8's framework for photon gathering and radiance contribution calculation. For generic light map (completely random photon direction generation), we tried up to 36 million photons, but we found the effect at 6 million to be what we are after. Additionally, we implemented importance sampling, in the form of 3 "virtual" light sources, one for each channel of RGB. For the red and the blue lights, we shot and additional 8 million photons at the backwall. For the green light, we shot an additional 20 million photons at the backwall to get a more pronouonced effect of the aurora reflecting onto the main scene. We experimented with implementing importance sampling on the bounce when photons hit an object so that it will always bounce towards another mesh of interest, but that created a rather unnatural distribution of the green hue in the final image, mostly concentrated around the chess pieces. +++ Diffuse color bleeding (I-Sheng) The assignment8 framework deals with pure white photons and calculates the probability of bounce or absorption by the Russian roulette method, which looks at the diffuse response on all three channels. In order to implement color bleeding, we only fired photons of each color channel (meaning, either pure red, pure green, or pure blue). Note that when we did this, we gave the photon the full intensity of the respective color, and not a divided power based on the number of photons shot. If we divided photon power by number of photons, we found that the contribution in the gathering step was too low. When calculating the Russian roulette, we only 'gamble' in the channel that the photon exists on (that means comparing with the R, G or B channel of the diffuse response). If the photon is absorbed, it means that this color isn't bleeding into the scene because it is absorbed by the material. But if this photon bounces according to the roulette, that means the color of the material will have 'bled' onto other parts of the scene. In order to avoid wasted photons, we skewed the probability of bouncing to be more likely. This is because the scene is naturally low in BRDF values, so by skewing the probability we waste less photons as they are less likely to be absorbed. +++ Photon gathering for final color calculation (I-Sheng + Bryce) At each diffuse intersection, we look for nearby photons from the photon map. We look for at least 25 photons within a radius of 0.01. If less than 25 photons are found within the 0.01 radius, then we conclude the intensity of the light in the area must be low. If we find more than 25 photons in the radius then we divide it by the actual number found (this part is consistent with Jensen's area averaging method). We then average each photon's power multiplied by the material's BRDF response to give it a color. When gathering, the neighboring photons powers are all combined and multiplied by the camera ray material's BRDF response. The result in our scene are the green halos at the bottom of the transparent chess pieces, and green patches on the black pieces themselves. We found the dividing by area method produced a significantly less pronounced effect on photon contribution. Additionally, the Manhatten method implemented in the KD tree class is extremely inefficient and slow when searching for nearby photons, causing us to look for an alternative method to speed up the performance, as we have a lot of photons to go through. We fire pure red, green, or blue photons into scene to emulate separate photon maps for each channel. +++ Parallelized backward ray tracer (I-Sheng) Adding OMP pragmas + compiler options was enough to use all available cores for the backward ray tracer. We parallelized over rows rather than pixels to reduce time spent creating and destroying the thread, and this proved to provide the highest performance. It also serves as an useful indicator on the rendering progress. +++ Non-refractive transmissive shadow rays (Bryce) We had gotten true refractive shadow rays (backward path traced) implemented in a testbench but it didn't look good on the final scene, so we settled for non-refractive shadow rays :'( Caustic photon mapping would have given a better and more efficient solution but we didn't get around to it. Our photon map is diffuse bounce only.