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

This is my graphics notes. The cases are from 8 assignments of yan Lingqi – Modern Computer Graphics [1]. Homework to address: http://games-cn.org/forums/topic/allhw/

The first part of the implementation of drawing a triangle, sparrow although small five viscera complete, do not use any graphics API, simulation opengL principle to complete the simple graphics razzle, the whole implementation of many details need to be carefully reviewed.

Directory:

  • 1. Achieve results
  • 2. Preparation
  • 3. Core concepts
    • 3.1 What is Rasterization
    • 3.1 Implementation Process
  • 4. Core code description
    • 4.1 implement the MVP
    • 4.2 Rasterizer implementation
    • 4.3 Organize the main program
    • 4.4 Compile and run
  • conclusion

1. Achieve results

In addition to displaying the triangle, it can also respond to the button left and right (A/D) rotation, Esc exit.

2. Preparation

Minimal development environment:

  • Develop IDE: Visual Studio Code, or VS for Windows or Xcode for Mac
  • Dependency libraries: Eigen(Linear algebra operations), OpencV (rendering, image processing)
  • Development language: C++
  • Cmake compilation tool

3. Core concepts

3.1 What is Rasterization

“Raster” is German for “screen,” and to rasterize means to draw graphics on a screen.

Rasterization takes many forms and does not necessarily mean display on the screen.

Rasterization of CNC equipment

3.1 Implementation Process

  1. Prepare triangle points
  2. MVP transform (Model, View/Camera, projection)
  3. Restore the normalized coordinates to the coordinates of the real scene and draw the three sides of the triangle
  4. Listen for buttons and process different key messages in the loop logic

Highlight the MVP transformation,

Model transform: Like when you’re taking a picture and you put an object into the scene and Pose it. A Pose is a model transform

View /camera transform: move the camera and the object at the same time so that the camera is at (0,0,0) in the global coordinate system, i.e. the origin. The view transformation is just for the convenience of calculation.

The view/camera transformation

Projection: The final image of the object is projected onto the camera’s sensitive equipment. This process is projection, and the scene is scaled to unit cubes, i.e. 1x1x1, for calculation purposes.

Perspective projection
Projection imaging

Note: Projection can be divided into orthogonal projection and perspective projection. Orthogonal projection means that objects are projected parallel to the screen. Perspective projection simulates the characteristics of human eyes and scales according to the near large, far small

https://stackoverflow.com/questions/36573283/from-perspective-picture-to-orthographic-picture
Perspective projection – near bigger, far smaller

4. Core code description

4.1 implement the MVP

The model transformation

The model transformation mainly involves rotation

// Model transform, which only rotates around the z axis

Eigen::Matrix4f get_model_matrix(float rotation_angle)

{

    Eigen::Matrix4f model = Eigen::Matrix4f::Identity();



    // TODO: Implement this function

    // Create the model matrix for rotating the triangle around the Z axis.

    // Then return it.



    float angle = rotation_angle * MY_PI / 180;

    model(0.0) = cos(angle);

    model(0.1) = -sin(angle);

    model(1.0) = sin(angle);

    model(1.1) = cos(angle);

    return model;

}

Copy the code

The view transformation

The view transformation involves translation and rotation, and the rotation is a little more complicated, so you need the inverse of the matrix. This example is simple and deals only with translation

Eigen::Matrix4f get_view_matrix(Eigen::Vector3f eye_pos)

{

    Eigen::Matrix4f view = Eigen::Matrix4f::Identity();



    Eigen::Matrix4f translate;

    translate << 1, 0, 0, -eye_pos[0], 0, 1, 0, -eye_pos[1], 0, 0, 1,

        -eye_pos[2], 0, 0, 0, 1;



    view = translate * view;



    return view;

}



Copy the code

Projection transform, where perspective projection is implemented

Slightly more complicated, in several steps:

  • Extrude the perspective projection cone into a cube of orthogonal projection
  • Move the window to the origin and scale to 1 * 1 * 1

Note: Windows can be interpreted as display Windows, where you select which part of the scene to display on the screen

The scene is extruded into a cube
Move & Scale

The code implementation can be calculated in 3 steps, or it can be combined into a matrix by three matrix multiplications:

  • Step 1: Perspective –> orthogonal

  • The second and third steps: orthogonal projection transformation

Matrix merging:

Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,

                                      float zNear, float zFar)


{

    // Generate the identity matrix

    Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();



    // Turn the Angle to radians

    float eye_angle = eye_fov * MY_PI / 180;

    float t,b,l,r;

    

    // Calculate the top right left bottom coordinates

    t = zNear * tan(eye_angle/2);

    r = t * aspect_ratio;

    l = -r;

    b = -t;

    

    Eigen::Matrix4f m1;

    Eigen::Matrix4f m2;

    Eigen::Matrix4f m3;

    

    // 1. The perspective projection is compressed into an orthogonal projection

    m1 << zNear,0.0.0.0,zNear,0.0.0.0,zNear + zFar, -zNear*zFar, 0.0.1.0;

    // 2. The center is moved to the origin to facilitate calculation. The projection is equivalent to an observation window. The center of the window moves to the origin as a whole, without changing the relative position of the Model and view.

    m2 <<1.0.0.0.0.1.0.0.0.0.1,-(zNear + zFar)/2.0.0.0.1;

    // 3. Scaling into a unit cube is also easy to calculate

    // Note that the scale operation is not linear and cannot be restored. The Z coordinate is lost, but it can still be used to indicate depth

    m3 << 2/(r-l),0.0.0.0.2/(t-b),0.0.0.0.2/(zNear-zFar),0.0.0.0.1;



    projection = m3 * m2 * m1 * projection; 



    return projection;

}

Copy the code

4.2 Rasterizer implementation

Rasterizer.cpp implements the core function of drawing. Take drawing a line segment as an example:

  1. Give the starting point and ending point of the line segment: P0 and P1
  2. In fact, there is no color difference in the code. Finally, the color is uniformly white (255,255,255). Opencv’s color channel is ABGR, that is, the rightmost channel is R channel
  3. Rasterized traversal starts at the lower left corner, while image array buffering starts at the upper left corner. Recall that in OpengL, when sampling an image texture, we have to flip it up and down. That is, the y coordinates of the image store and the render sample are oppositePerspective projection analysis note at the end of the paper[2]

Code is longer, not one by one analysis, may refer to: https://github.com/kingiluob/Games101/blob/master/Assignment1/rasterizer.cpp

Note:

  1. Bresenham line drawing algorithm
  2. Normalized coordinates are restored to screen coordinates

Code Breshnham linear interpolation algorithm is not very elegant, reference is an implementation of stack overflow: https://stackoverflow.com/a/16405254

Refer to the following blog Breshnham code, to achieve better: https://www.cnblogs.com/1Kasshole/p/14038274.html. Who is the Bresenham [3]

4.3 Organize the main program

nt main(int argc, const char** argv)

{

    float angle = 0;

    // Control whether the command line call, and output pictures, here I simplify the code to remove the relevant logic

    bool command_line = false;

    std: :string filename = "output.png";



    // Set rasterization size, width * height

    rst::rasterizer r(700.700);

    

    // The position of the glasses (or camera)

    Eigen::Vector3f eye_pos = {0.0.5};

    

    // Initialize the three points of the triangle

    std: :vector<Eigen::Vector3f> pos{{2.0.2 -}, {0.2.2 -}, {2 -.0.2 -}};

    

    // Select the above three points, corner index 0, 1, 2, same as opengL based on corner point selection

    std: :vector<Eigen::Vector3i> ind{{0.1.2}};

  

    // Load the index corner of the coordinate points and, as with opengL, the same point can be used multiple times

    auto pos_id = r.load_positions(pos);

    auto ind_id = r.load_indices(ind);

    

    // Keylogger

    int key = 0;

    int frame_count = 0;



    while(key ! =27) {

        

        // Clear buffer: color buffer and depth buffer

        r.clear(rst::Buffers::Color | rst::Buffers::Depth);

        

        / / set the MVP

        r.set_model(get_model_matrix(angle));

        r.set_view(get_view_matrix(eye_pos));

        r.set_projection(get_projection_matrix(45.1.0.1.50));

        

        / / to draw

        r.draw(pos_id, ind_id, rst::Primitive::Triangle);

        

        // CV_32FC3 is understood below

        // Calculate the image memory can be larger, generate the image memory can be smaller

        cv::Mat image(700.700, CV_32FC3, r.frame_buffer().data());

        

        // 1.0f is an alpha channel, that is, completely opaque

        image.convertTo(image, CV_8UC3, 1.0 f);

        cv::imshow("image", image);

        

        // Wait 10ms for keyboard input

        key = cv::waitKey(10);



        std: :cout << "frame count: " << frame_count++ << '\n';



        if (key == 'a') {

            angle += 10;

        }

        else if (key == 'd') {

            angle -= 10;

        }

    }



    return 0;

}



Copy the code

CV_8UC1 and CV_32FC3 indicate the meanings of these parameters

bit_depth

8 bits - on behalf of the bite, 16 bites, 32 bites, 64 bites - for example, say,

If you now create a Mat object that stores a grayscale image, the image size is 100 wide and 100 high, then the grayscale image now has 10,000 pixels, and the memory size of each pixel is 8bite,8 bits -- so it corresponds to CV_8;



S|U|F

S-- for --signed int-- signed integer

U-- for --unsigned int-- unsigned integer

F - -float--------- Single-precision floating point



C<number_of_channels>

Represents the number of channels in an image, such as:

1-- Grayscale image --grayImg-- yes -- single channel image

2--RGB color images --------- is --3 channel images

3-- RGB image with Alph channel -- is --4 channel image

Copy the code

4.4 Compile and run

Project based on cmake organization code, do not know cmake can simply refer to the basic operations of cmake and cmakelist.txt compilation.

The basic cmake command: go to the build folder and generate the cmake related file cmake..

Compile, j4 means make -j4 with 4 threads

Run. / Rasterizer

Cmakelist.txt: find_package(OpenCV REQUIRED) : run findOpencv in the root directory of Cmake. OpenCV is usually found here, but other libraries may not work, depending on how you install them. If find fails, include, such as

include_directories(/usr/local/ Cellar/eigen / 3.3.9 / include)

Copy the code

conclusion

You should be able to easily implement the results and run the demo by following the instructions in the article, which gives me a reference code at the end of the article. Thanks to Teacher Yan Lingqi for the graphics course, I have gained a lot.

Ms. Yan lingqi was born in the 1990s and won the best doctoral thesis in the same year. Now she is a doctoral supervisor and assistant professor at the University of California, Santa Barbara.

“Lingqi Yan, first of his name, the unrejected, author of seven papers, breaker of the record, and the chicken eater.” — Born to be Legendary, by Lifan Wu, UCSD

Some life and extraordinary!


Other reference

GAMES101 Implementation — 1[4] GAMES101 Implementation — 2[5] GAMES101 Experiment Notes [6]

The resources

[1]

GAMES101: Introduction to modern computer Graphics: http://games-cn.org/intro-graphics/


[2]

Perspective projection resolution’s note: https://www.cnblogs.com/1Kasshole/p/13993749.html


[3]

Bresenham introduced: en.wikipedia.org/wiki/Jack_Elton_Bresenham


[4]

Making implementation – 1: https://github.com/kingiluob/Games101/blob/master/Assignment1/rasterizer.cpp


[5]

Games101 implementation – 2: https://github.com/Quanwei1992/GAMES101/blob/master/01/rasterizer.cpp


[6]

GAMES101 lab notes: https://zhuanlan.zhihu.com/p/355170943

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