目 录CONTENT

文章目录

【一周学会光线追踪】完成摄像机与视口

千年的霜雪
2025-04-08 / 0 评论 / 0 点赞 / 4 阅读 / 0 字 / 正在检测是否收录...

main.cpp:

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

#include <iostream>

color ray_color(const ray& r)
{
	// 线性插值
	vec3 unit_direction = unit_vector(r.direction());
	auto a = 0.5 * (unit_direction.y() + 1.0);
	return (1.0 - a) * color(1.0, 1.0, 1.0) + a * color(0.5, 0.7, 1.0);
}

/*
* 世界坐标为右手坐标系:x轴向右,y轴向上,z轴指向屏幕外
* 
* 这种世界坐标系与视口坐标系的y轴冲突:视口中原点在左上角,x轴向右,y轴向下
* 
* 视口像素的处理顺序是从左到右,从上到下
*/

/*
* 视口中的像素网格,其中的像素中点被从视口边缘向内缩进半个像素到像素的距离(显然,否则无法在中心)
*/

int main()
{
	// Image (输出图像)

	auto aspect_ratio = 16.0 / 9.0; // 宽高比
	int image_width = 400; // 图像宽度

	// Calculate the image height, and ensure that it's at least 1
	int image_height = int(image_width / aspect_ratio);
	image_height = (image_height < 1) ? 1 : image_height; // 保证图像高度至少为1

	/*
	* 视口是世界内的一个虚拟矩形
	* 视口具有像素组成的尺寸
	* 两个相邻像素之间的距离称为像素间距,
	  这里计算距离时是使用的两个像素的中心点进行计算
	* 如果像素在水平与垂直方向上的间距都相同,
	  那么显然视口将与输出图像的宽高比相同
	* 像素标准情况下为正方形
	*/

	/*
	* 相机,也就是相机中心,是一个三维空间中的点(常称为eye point)
	* 所有场景光线从此点出发
	* 相机中心在视口中心的正前方(相机中心到视口中心的向量与视口正交)
	* 相机中心与视口的距离称为焦距
	*/

	// Camera

	auto focal_length = 1.0; // 焦距
	auto viewport_height = 2.0; // 视口高度
	/*
	* 这里计算视口宽度不能直接使用设定的宽高比
	* 因为一方面设定的宽高比可能因为计算的精度丢失等原因,与实际的宽高比不同(图像高度被下取整为int)
	* 另一方面因为图像高度可能在小于1时被强制设为1
	*/
	auto viewport_width = viewport_height * (double(image_width) / image_height); // 视口宽度
	auto camera_center = point3(0, 0, 0); // 摄像机中心

	/*
	* 为了方便计算并解决坐标系冲突,同时方便定位像素网格,使用两个向量:
	* Vu 方向从左向右
	* Vv 方向从上到下
	*/

	// Calculate the vectors across the horizontal and down the vertical viewport edges
	auto viewport_u = vec3(viewport_width, 0, 0); // Vu
	auto viewport_v = vec3(0, -viewport_height, 0); // Vv

	/*
	* 两个像素之间的水平距离: delta u
	* 两个像素之间的垂直距离: delta v
	*/

	// Calculate the horizontal and vertical delta vectors form pixel to pixel
	auto pixel_delta_u = viewport_u / image_width; // 像素间水平距离
	auto pixel_delta_v = viewport_v / image_height; // 像素间垂直距离

	// Calculate the location of the upper left pixel
	auto viewport_upper_left = camera_center - vec3(0, 0, focal_length) - viewport_u / 2 - viewport_v / 2; // 视口左上角
	auto pixel00_loc = viewport_upper_left + 0.5 * (pixel_delta_u + pixel_delta_v); // 视口中左上角像素位置(第(0,0)个像素)

	// Render

	std::cout << "P3\n" << image_width << " " << image_height << "\n255\n";

	for (int j = 0; j < image_height; j++)
	{
		std::clog << "\rScanlines remaining: " << (image_height - j) << ' ' << std::flush; // 运行时进度条
		for (int i = 0; i < image_width; i++)
		{
			auto pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v);
			auto ray_direction = pixel_center - camera_center;
			ray r(camera_center, ray_direction);

			color pixel_color = ray_color(r);
			write_color(std::cout, pixel_color);
		}
	}

	std::clog << "\rDone.                \n"; // 进度条提示完成

	return 0;
}

0

评论区