Implementation effect

All the elements in the figure below are code generated. The title is from modern Graphics Assignment 5- Yan Lingqi. This picture is seen in many places, and I wonder who first proposed the model.

Complete code: github.com/summer-go/g…

Welcome to follow the public account: Sumsmile/focus on image processing mobile development veterans ~~

What is raytracing

Let’s review rasterization

Mapping objects in stereo space onto a 2D screen is essentially a sampling process

The image above shows the simplest example – triangular rasterization. In fact, rasterization can also render more complex scenes.

But for a more realistic effect, you have to use raytracing

Ray tracing

To approximate the sense of reality, it is necessary to simulate the path of light propagation from the perspective of energy conservation. One ray of light is emitted from each pixel on the screen, hits the first object, and bounces off, reversely simulating the effects of light transmission (specular, diffuse, refraction). In the above image, the color of a point on the sphere is actually a combination of light from multiple sources and reflected light from other objects.

Whitted-style ray tracing implementation

The basic principle of raytracing is simple, but there are many details to implement. Whitted-style raytracing is implemented below.

John Turner Whitted, an electrical engineer and computer scientist, introduced recursive ray tracing to computer graphics in his 1979 paper, “An Improved Illumination Model for Shadow Display.

Whitted-style Ray tracing, starting from the “human eye”, reversely tracks the source of light hitting the surface of an object, and then calculates the color based on the properties of the light and the object’s material.

Implementation logic

The following code is used to implement a Whitted-style light trace with the following elements in the scene:

  • A lattice-shaped floor
  • A ball of diffuse material
  • A ball of specular reflection & refraction material
  • Two point light source

The scene is very simple, with some auxiliary utility classes to do the job

Key Code Description

There are detailed comments in the code, and key technical points are explained in this article.

Code in the use of many c++11 above the syntax features, encountered unfamiliar syntax, I suggest the reader to check

An overview of the

  • Main. CPP: implements logical scheduling, creates scene, and adds shpere and mesh to the scene
  • Object: sphere, Triangle (floor is two triangles) inherit from Object, Object defines abstract methods intersect(determine intersection), getSurfaceProperties(getSurfaceProperties)
  • Render: the core class that implements the logic of reflection, refraction, raycast, and path tracing
  • Light: There are only two properties that define position and intensity
  • Other classes: Vector(Vector manipulation), Global (utility methods, state display, etc.)

Rrender implementation

Space transformation

As shown in the figure above, raytrace needs to be calculated for each pixel of the screen, and the coordinates of pixel points are defined by the following formula:


I m a g e A s p e c t R a t i o = I m a g e W i d t h I m a g e H e i g h t {ImageAspectRatio = \dfrac{ImageWidth}{ImageHeight}}


P i x e l C a m e r a x = ( 2 P i x e l S c r e e n x 1 ) I m a g e A s p e c t R a t i o t a n ( Alpha. 2 ) {PixelCamera_x = (2 * {PixelScreen_x } – 1) * ImageAspectRatio * tan(\dfrac{\alpha}{2})}


P i x e l C a m e r a y = ( 1 2 P i x e l S c r e e n y ) t a n ( Alpha. 2 ) . {PixelCamera_y = (1 – 2 * {PixelScreen_y }) * tan(\dfrac{\alpha}{2}).}

ImageAspectRatio: Render window aspect ratio

Tan (alpha 2)tan(\dfrac{\alpha}{2})tan(2α) computs the size of the cone. If you open your eyes, you can see a larger portion of the scene, but the weight of a single object in the scene is reduced.

Detailed reference: www.scratchapixel.com/lessons/3d-…

castRay

CastRay is at the core of logic, the recursion explore the propagation path of the light, after the ejection of what object, find the source, if there is no fellowship with any object, finally take the default ambient light, which the ejection way can be a “reflection”, “reflection” and “diffuse”, the ejection way depends on the material of the object, The material is defined in global

enum MaterialType
{
    // Diffuse material
    DIFFUSE_AND_GLOSSY,
    // Reflect + refract material (glass)
    REFLECTION_AND_REFRACTION,
    // Reflect (mirror)
    REFLECTION
};
Copy the code

Pixel cache to generate image files

The pixel colors are stored in a framebuffer and implemented using a vector

Images stored in PPM format finally, PPM is a vector diagram, the reference: blog.csdn.net/kinghzkingk…

In Render, the implementation of refraction is also a bit complicated for the first time. It involves the theory of optics, which requires patience to derive. I wonder if you have forgotten all the physics in high school

Reflection refraction reference: www.scratchapixel.com/lessons/3d-…

Sphere, Triangle

Intersect intersect

Spheres and triangles have different ways of judging intersection

Ball intersection judgment:


R a y : r ( t ) = o + t d {Ray:r(t)=o + td}


s p h e r e : ( p c ) 2 R 2 = 0 {sphere:(p – c)^2 – R^2 =0}

Equation having solution t > = 0, intersection, strives for the equations is not the way we are familiar with, the purpose is to reduce error produced by the floating-point arithmetic, reference description: www.zhihu.com/people/cowi…

The code is as follows:

/ * * * avoids solving quadratic equation, implementation details: https://www.zhihu.com/people/cowill/posts * /
inline bool solvecQuadratic(const float& a, const float& b, const float& c, float& x0, float& x1)
{
    float discr = b * b - 4 * a * c;
    if (discr < 0)
        return false;
    else if (discr == 0)
        x0 = x1 = 0.5 * b / a;
    else
    {
        float q = (b > 0)?0.5 * (b + sqrt(discr)) : 0.5 * (b - sqrt(discr));
        x0 = q / a;
        x1 = c / q;
    }
    if (x0 > x1)
        std::swap(x0, x1);
    return true;
}
Copy the code

Triangle intersection judgment: the essence is to solve the equation, using Moller Trumbore Algorith to do optimization

Color sample

The color of the sphere is well defined, a diffuse reflection is defined as gray, a transparent colorless. Floor using the algorithm, in the shape of a grid is a kind of “procedural – texturing”, procedural textures, oneself achieve true don’t want to, refer to the article description: www.scratchapixel.com/lessons/3d-…

  /** ** Calculate the texture color of the floor grid, principle reference:  * https://www.scratchapixel.com/lessons/3d-basic-rendering/introduction-to-shading/procedural-texturing */
    Vector3f evalDiffuseColor(const Vector2f &st) const override
    {
        float scale = 5;
        float pattern = (fmodf(st.x * scale, 1) > 0.5) ^ (fmodf(st.y * scale, 1) > 0.5);
        return lerp(Vector3f(0.815.0.235.0.031), Vector3f(0.937.0.937.0.231), pattern);
    }
Copy the code

Master the algorithm principle, can also achieve other floor patterns

pattern = (cos(st.y * 2 * M_PI * scale) * sin(st.x * 2 * M_PI * scale) + 1) * 0.5; // compute sine wave pattern 
Copy the code

Welcome to follow the public account: Sumsmile/focus on image processing mobile development veterans ~~

The resources

[1] wikipedia – landneeded Whitted: en.wikipedia.org/wiki/J._Tur…

[2] Generating Camera Rays: www.scratchapixel.com/lessons/3d-…

[3] reflection refraction: www.scratchapixel.com/lessons/3d-…

[4] procedural – texturing: www.scratchapixel.com/lessons/3d-…

[5] GAMES – 101, hw code archive: alexandrite. Top / 2020/07/13 /…

[6] games101 finishing homework problems: zhuanlan.zhihu.com/p/375391720