文章

The Vec3 Class

几乎所有的图形程序都有一些类用于存储向量与颜色。在很多系统中,这些向量是4维的,对于位置向量来说,这包括三维空间中的位置以及一个齐次坐标,对于颜色向量来说,包括RGB颜色以及alpha透明值。对于我们的渲染器来说,三维向量就足够了。我们将会使用同一个Vec3类用于表示颜色、位置、方向、偏移量等。同时,我们还会声明两个别名:Point3Color

我们将这个类的定义放在math.hpp头文件中。同时我们也会定义一些有用的向量函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#pragma once

#include <pch.hpp>

namespace EngineCore
{
    // Vec3 class
    // ----------
    class Vec3
    {
    public:
        Vec3();
        Vec3(double e0, double e1, double e2);

        double x() const;
        double y() const;
        double z() const;

        Vec3    operator-() const;
        Vec3&   operator+=(const Vec3& v);
        Vec3&   operator*=(const double t);
        Vec3&   operator/=(const double t);
        double  operator[](int i) const;
        double& operator[](int i);

        double lengthSquared() const;
        double length() const;

    public:
        double e[3];
    };

    // vector utility functions
    // ------------------------
    inline std::ostream& operator<<(std::ostream& out, const Vec3& v)
    {
        return out << v.e[0] << ' ' << v.e[1] << ' ' << v.e[2];
    }

    inline Vec3 operator+(const Vec3& u, const Vec3& v)
    {
        return Vec3(u.e[0] + v.e[0], u.e[1] + v.e[1], u.e[2] + v.e[2]);
    }

    inline Vec3 operator-(const Vec3& u, const Vec3& v)
    {
        return Vec3(u.e[0] - v.e[0], u.e[1] - v.e[1], u.e[2] - v.e[2]);
    }

    inline Vec3 operator*(const Vec3& u, const Vec3& v)
    {
        return Vec3(u.e[0] * v.e[0], u.e[1] * v.e[1], u.e[2] * v.e[2]);
    }

    inline Vec3 operator*(double t, const Vec3& v)
    {
        return Vec3(t * v.e[0], t * v.e[1], t * v.e[2]);
    }

    inline Vec3 operator*(const Vec3& v, double t)
    {
        return t * v;
    }

    inline Vec3 operator/(Vec3 v, double t)
    {
        return (1 / t) * v;
    }

    inline double dot(const Vec3& u, const Vec3& v)
    {
        return u.e[0] * v.e[0] + u.e[1] * v.e[1] + u.e[2] * v.e[2];
    }

    inline Vec3 cross(const Vec3& u, const Vec3& v)
    {
        return Vec3(u.e[1] * v.e[2] - u.e[2] * v.e[1],
                    u.e[2] * v.e[0] - u.e[0] * v.e[2],
                    u.e[0] * v.e[1] - u.e[1] * v.e[0]);
    }

    inline Vec3 normalize(Vec3 v)
    {
        return v / v.length();
    }

}



3.1 Color Utility Functions

此外,我们创建一个color.h头文件,并定义一个utility函数,用于将单个像素的颜色写入standard output stream:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#pragma once

#include <engine/math.hpp>

namespace EngineCore
{
    using Color = Vec3;

    inline void writeColor(std::ostream& out, const Color& pixelColor)
    {
        auto r = pixelColor.x();
        auto g = pixelColor.y();
        auto b = pixelColor.z();

        // write the translated [0,255] value of each color component
        // ----------------------------------------------------------
        int byteR = int(255.999 * r);
        int byteG = int(255.999 * g);
        int byteB = int(255.999 * b);

        // write out to the ppm file
        // -------------------------
        out << byteR << ' ' << byteG << ' ' << byteB << '\n';
    }

}

现在,我们可以使用新的vec3类来修改我们main函数了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>

#include "vec3.h"
#include "color.h"

int main()
{
    // Image
    int imageWidth = 256;
    int imageHeight = 256;

    // Render
    std::cout << "P3\n" << imageWidth << ' ' << imageHeight << "\n255\n";
    for (int j = 0; j < imageHeight; j++)
    {
        std::clog << "rScanlines remaining: " << (imageHeight - j) << ' ' << std::flush;

        for (int i = 0; i < imageWidth; i++)
        {
            double r = double(i) / (imageWidth - 1);
            double g = double(j) / (imageHeight - 1);

            int pixelR = int(255.999 * r);
            int pixelG = int (255.999 * g);
            std::cout << pixelR << ' ' << pixelG << ' ' << "0\n";

            vec3 currentPixelColor = vec3(r, g, 0);
            writeColor(std::cout, currentPixelColor);
        }
    }

    std::clog << "rDone.              \n";

    return 0;
}
本文由作者按照 CC BY 4.0 进行授权