Antialiasing:抗锯齿,反走样。 先看上一节的这张图,可以看出有一些锯齿存在,我们需要模糊化处理这些锯齿: [

](http://www.wjgbaby.com/wp-content/uploads/2018/05/18051601-300x276.png)
](http://www.wjgbaby.com/wp-content/uploads/2018/05/18051601-300x276.png)
边缘像素是一些前景和某些背景的混合物。我使用的是800乘400的大小,也就是有320000个像素点。之前的图是每个像素点设置一个颜色值,相当于将像素中心位置的颜色设置给了整个像素。所以,如果两个像素点中心位置的颜色值相差比较大时,这两个像素点就会产生清晰的边界。 而我们要做的就是针对每一个像素点,颜色取样一百次,求平均值,这个平均值就是这个像素点的颜色,这样就达到了一种模糊的效果,从而有效降低锯齿。

蒙特卡罗方法:

蒙特卡罗方法又称统计模拟法、随机抽样技术,是一种随机模拟方法,以概率和统计理论方法为基础的一种计算方法,是使用随机数(或更常见的伪随机数)来解决很多计算问题的方法。将所求解的问题同一定的概率模型相联系,用电子计算机实现统计模拟或抽样,以获得问题的近似解。为象征性地表明这一方法的概率统计特征,故借用赌城蒙特卡罗命名。 [

](http://www.wjgbaby.com/wp-content/uploads/2018/05/18051603.png)
](http://www.wjgbaby.com/wp-content/uploads/2018/05/18051603.png)
将之前的camera封装起来: camera.h:

#ifndef cameraH
#define cameraH

#include “ray.h”

class camera
{
public:
camera()
{
lower_left_corner = vec3(-2.0f, -1.0f, -1.0f);
horizontal = vec3(4.0f, 0.0f, 0.0f);
vertical = vec3(0.0f, 2.0f, 0.0f);
origin = vec3(0.0f, 0.0f, 0.0f);
}

ray getray(float u, float v)
{
    return ray(origin, lower\_left\_corner + u \* horizontal + v \* vertical - origin);
}

vec3 origin;
vec3 lower\_left\_corner;
vec3 horizontal;
vec3 vertical;

};
#endif

cpp:

#include
#include
#include
#include “sphere.h”
#include “hitable_list.h”
#include “camera.h”

using namespace std;

vec3 Color(const ray& r, hitable* world)
{
hit_record rec;
if (world->hit(r, 0.0, FLT_MAX, rec))
{
return 0.5f * vec3(rec.normal.x() + 1.0f, rec.normal.y() + 1.0f, rec.normal.z() + 1.0f);
}
else
{
vec3 unit_direction = unit_vector(r.direction());
float t = 0.5f * (unit_direction.y() + 1.0f);
//线性混合,t=1时蓝色,t=0时白色,t介于中间时是混合颜色
//blended_value = (1-t)*start_value + t*end_value
return (1.0f - t) * vec3(1.0f, 1.0f, 1.0f) + t * vec3(0.5f, 0.7f, 1.0f);
}
}

int main()
{
ofstream outfile;
outfile.open(“IMG.ppm”);

int nx = 800;
int ny = 400;
//采样次数100次
int ns = 100;
outfile << "P3\\n" << nx << " " << ny << "\\n255\\n";

hitable\* list\[2\];
list\[0\] = new sphere(vec3(0.0f, 0.0f, -1.0f), 0.5f);
list\[1\] = new sphere(vec3(0.0f, -100.5f, -1.0f), 100.0f);
hitable\* world = new hitable\_list(list, 2);

camera cam;

//随机数,每个像素点的区域是以像素中心点为中心向外距离为1的范围
default\_random\_engine reng;
uniform\_real\_distribution<float> uni\_dist(0.0f, 1.0f);

for (int j = ny - 1; j >= 0; j--)
{
    for (int i = 0; i < nx; i++)
    {
        vec3 col(0.0f, 0.0f, 0.0f);
        //每个区域采样ns次
        for (int s = 0; s < ns; s++)
        {
            float u = float(i + uni\_dist(reng)) / float(nx);
            float v = float(j + uni\_dist(reng)) / float(ny);
            ray r = cam.getray(u, v);
            //vec3 p = r.point\_at\_parameter(2.0);
            //将本区域((u,v)到(u+1,v+1))的颜色值累加
            col += Color(r, world);
        }
        //获得区域的颜色均值
        col /= float(ns);

        int ir = int(255.99 \* col\[0\]);
        int ig = int(255.99 \* col\[1\]);
        int ib = int(255.99 \* col\[2\]);
        outfile << ir << " " << ig << " " << ib << "\\n";
    }
}
outfile.close();
return 0;

}

每个像素点都采样100次,明显感觉渲染速度变慢了。 抗锯齿之后的效果图: 参考书籍:《Ray Tracing in One Weekend》 RTIOW系列项目地址:GitHub RTIOW系列笔记: RTIOW-ch1:Output an image RTIOW-ch2:The vec3 class RTIOW-ch3:Rays, a simple camera, and background RTIOW-ch4:Adding a sphere RTIOW-ch5:Surface normals and multiple objects RTIOW-ch6:Antialiasing RTIOW-ch7:Diffuse Materials RTIOW-ch8:Metal RTIOW-ch9:Dielectrics RTIOW-ch10:Positionable camera RTIOW-ch11:Defocus Blur RTIOW-ch12:Where next