This article is a summary of my self-study about Ray-Tracing.
In the traditional rendering pipeline, every object, primitive, and pixel are calculated lighting independently. They know less or even nothing about nearby objects. As a result, it’s hard to calculate indirect illumination. For example, those objects out of view frustum will be culled. But in reality, they make great contributions to the scene. Though, these years many methods have be proposed, they are more like some tricks.
The theory of Ray-Tracing has been advanced for almost 40 years, but due to its giant amount of calculation, it has not been widely applied. Recently, the breakthrough of graphics technology makes it possible to apply this technology in real-time rendering and greatly improves the rendering quality.
Introduction
Ray-Tracing is a recursive process. Firstly, cast a ray from the view point to a pixel in the screen, then get the closest intersection object in this direction, calculate the lighting in the intersection point. Next, reflect or refract the ray and repeat the Ray Casting, Closest Intersection Object, Reflect and Refract until the ray reach the light source or exceed the maximum recursion depth.
Ray Casting
1 | class ray { |
A ray is defined by an origin point and a casting direction. Every point in this ray can be defined by \(p = orig + t *dirp=orig+t∗dir\).
Object Intersection
Now, we have the representation of the ray and the surface \(f(p) = 0\). By replacing the \(p\) in the surface equation, we get a new equation in terms of \(t\), \(f(orig + t * dir) = 0\). If this equation has no solution means not intersecting, and the smallest solution is the intersection point.
Intersection Equation
- Sephere Equation A sephere with the center \(c(x_{c}, y_{c}, z_{c})\)and radius \(R\) can be represented by: \[\begin{align} (x-x_c)^2+(y-y_c)^2+(z-z_c)^2-R^2=0 \nonumber \end{align}\] Rewrite the equation in vector form: \[\begin{align} (p-c)\cdot(p-c)-R^2=0 \nonumber \end{align}\] Replace pp by equation \(p = orig + t*dir\): \[\begin{align} (orig + t * dic - c)\cdot(orig + t * dic - c)-R^2=0 \nonumber \\ (dir\cdot dir)t^2 + 2dir\cdot(orig-c)t + (orig - c)\cdot(orig - c)-R^2=0 \nonumber \end{align}\] It’s a Quadratic Polynomial, \(At^2+Bt+C=0\): \[\begin{align} A=dir\cdot dir \nonumber \\ B=2dir\cdot(orig - c) \nonumber \\ C=(orig-c)\cdot(orig-c)-R^2 \nonumber \\ t=(-B\pm \sqrt{B^2-4AC}\over 2A \nonumber \\ t=(-B/2\pm \sqrt{(B/2)^2-AC}\over A \nonumber \\ \end{align}\]
1 | bool sphere::hit(const ray& r, double tmin, double tmax) const |
- Triangle Equation Giving a triangle with vertices \(a, b, c\) the ray intersects with the triangle surface at: \[\begin{align} orig + t * dir=\alpha + \beta(b-a) +\gamma(c-a) \nonumber \end{align}\]
Only if \(\beta>0\), \(\gamma>0\), \(\beta+\gamma<1\), the intersection is inside the triangle.
Materials
- Diffuse Surfaces don’t emit light but only scatter
light equality in all directions.
1
2vec3 scatter_direction = hit_record.normal + random_in_hemisphere(hit_record.normal);
scattered = ray(hit_record.p, scatter_direction); - Reflection The smooth surfaces will scatter light in a specific direction. The relationship between incident light and reflected light is shown in the following figure:
As shown in the figure, we can get the reflected light direction
equation: 1
2
3
4vec3 reflect(const vec3& v, const vec3 n)
{
return v - 2 * dot(v, n) * n;
}
We assume that the incident ray \(R\), and the refrated ray \(R'\) are unit vectors. The reflacted ray \(R'\) can be splited into parts \(R_{\parallel}'\) which parallels to \(n\) and \(R'_{\perp}\) which is perpendicular to \(n\). \[\begin{align} |R_\perp|=|R|*sin\theta_i \nonumber \\ |R'_\perp|=|R'|*sin\theta_r \nonumber \\ |R'_\perp|={ {sin\theta_r * |R_\perp|} \over {sin\theta_i} } \nonumber \\ R'_{\perp} = {-{n_1*R_{\perp}\over n_2}} \nonumber \\ R_{\perp}=-(R+|R|cos\theta_i n) \nonumber \\ R'_\perp={n_1\over n_2}(R+cos\theta_i n) \nonumber \\ R'_\parallel = -\sqrt{1-|{R'_\perp}^2n} \nonumber \end{align}\]
1 | vec3 unit_direction = unit_vector(r_in.direction()); |