文章

The Vec3 Class

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

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

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#ifndef VEC3_H
#define VEC3_H

#include <cmath>
#include <iostream>

using std::sqrt;

class vec3;
using point3 = vec3;

class vec3
{
    public:
    double e[3];

    vec3(): e {0, 0, 0} {}
    vec3(double e0, double e1, double e2): e{e0, e1, e2} {}

    double x() const {return e[0];}
    double y() const {return e[1];}
    double z() const {return e[2];}

    vec3 operator- () const {return vec3(-e[0], -e[1], -e[2]);}
    double operator[] (int i) const {return e[i];}
    double& operator[] (int i) {return e[i];}

    vec3& operator+= (const vec3& v)
    {
        e[0] += v.e[0];
        e[1] += v.e[1];
        e[2] += v.e[2];
        return *this;
    }

    vec3& operator*= (double t)
    {
        e[0] *= t;
        e[1] *= t;
        e[2] *= t;
        return *this;
    }

    vec3 operator/= (double t)
    {
        return *this *= 1 / t;
    }

    double lengthSquared() const
    {
        return e[0] * e[0] + e[1] * e[1] + e[2] * e[2];
    }

    double length() const
    {
        return sqrt(lengthSquared());
    }
};

// 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(v.e[0] * t, v.e[1] * t, v.e[2] * t);
}

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

inline vec3 operator/ (const 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 unitVectorLength(const vec3& v)
{
    return v / v.length();
}

#endif

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
27
// color.h

#ifndef COLOR_H
#define COLOR_H

#include "vec3.h"

#include <iostream>

using color = vec3;

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

    // translate [0, 1] component values to byte range[0, 255]
    int rByte = int(255.999 * r);
    int gByte = int(255.999 * g);
    int bByte = int(255.999 * b);

    // write out pixel color components
    out << rByte << ' ' << gByte << ' ' << bByte << '\n';
}

#endif

现在,我们可以使用新的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 进行授权