路径追踪低差异序列和重要性采样

本文介绍了一种基于OpenMP多线程和重要性采样的光线追踪算法,用于实时渲染3D场景,通过构建高效BVH树和使用Sobol序列进行低差异序列采样,提升渲染性能。关键算法包括路径追踪、漫反射重要性采样和SAH优化的BVH构建。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <iostream>
#include <vector>
#include <random>
#include <stdlib.h>
#include <glm/glm.hpp>  // 数学库支持


#include <omp.h>    // openmp多线程加速
#include<freeglut.h>
#include<ctime>
#include<mmintrin.h>

#include <algorithm>
#include <fstream>

int frames; clock_t clocks;
using namespace glm;
//using namespace std;
#define INF 114514.0
// --------------------- end of include --------------------- //

// 采样次数
const int SAMPLE = 10;

// 每次采样的亮度

//const double BRIGHTNESS = (2.0f * 3.1415926f) * (1.0f / double(300));
// 输出图像分辨率
const int WIDTH = 256;
const int HEIGHT = 256;

// 相机参数
const double SCREEN_Z = 1.1;        // 视平面 z 坐标
const vec3 EYE = vec3(0, 0, 4.0);   // 相机位置

									// 颜色
const vec3 RED(1, 0.5, 0.5);
const vec3 GREEN(0.5, 1, 0.5);
const vec3 BLUE(0.5, 0.5, 1);
const vec3 YELLOW(1.0, 1.0, 0.1);
const vec3 CYAN(0.1, 1.0, 1.0);
const vec3 MAGENTA(1.0, 0.1, 1.0);
const vec3 GRAY(0.5, 0.5, 0.5);
const vec3 WHITE(1, 1, 1);

// --------------- end of global variable definition --------------- //

// 光线
typedef struct Ray
{
	vec3 startPoint = vec3(0, 0, 0);    // 起点
	vec3 direction = vec3(0, 0, 0);     // 方向
}Ray;

// 物体表面材质定义
typedef struct Material
{
	bool isEmissive = false;        // 是否发光
	vec3 normal = vec3(0, 0, 0);    // 法向量
	vec3 color = vec3(0, 0, 0);     // 颜色
	double specularRate = 0.0f;     // 反射光占比
	double roughness = 1.0f;        // 粗糙程度
	double refractRate = 0.0f;      // 折射光占比
	double refractAngle = 1.0f;     // 折射率
	double refractRoughness = 0.0f; // 折射粗糙度
}Material;

struct BVHNode {
	BVHNode* left = NULL;       // 左右子树索引
	BVHNode* right = NULL;
	int n, index;               // 叶子节点信息               
	vec3 AA, BB;                // 碰撞盒
};
BVHNode* BVH树;


typedef struct 三角形类2 {
	Material material;  // 材质
	vec3 p1, p2, p3;   // 三点
	vec3 center;       // 中心


	三角形类2(vec3 a, vec3 b, vec3 c) {
		p1 = a, p2 = b, p3 = c;
		center = (p1 + p2 + p3) / vec3(3, 3, 3);
	}
} 三角形类2;
std::vector<三角形类2> 三角形集合;
// 光线求交结果
typedef struct 光线求交结果
{

	bool 是否命中 = false;             // 是否命中
	double 与交点的距离 = 0.0f;         // 与交点的距离
	vec3 光线命中点 = vec3(0, 0, 0);  // 光线命中点
	Material material;              // 命中点的表面材质
	int 是否离线 = 0;
	三角形类2* 三角形 = NULL;
}光线求交结果;





class Shape
{
public:
	Shape() {}
	virtual 光线求交结果 intersect(Ray ray) { return 光线求交结果(); }
};

// 三角形
class 三角形类 : public Shape
{
public:
	三角形类() {}
	三角形类(vec3 P1, vec3 P2, vec3 P3, vec3 C)
	{
		p1 = P1, p2 = P2, p3 = P3;
		material.normal = normalize(cross(p2 - p1, p3 - p1)); material.color = C;
	}
	vec3 p1, p2, p3;    // 三顶点
	Material material;  // 材质

						// 与光线求交
	光线求交结果 intersect(Ray ray)
	{
		光线求交结果 res;

		vec3 S = ray.startPoint;        // 射线起点
		vec3 d = ray.direction;         // 射线方向
		vec3 N = material.normal;       // 法向量
										//if (dot(N, d) > 0.0f) N = -N;   // 获取正确的法向量

										// 如果视线和三角形平行
										//if (fabs(dot(N, d)) < 0.00001f) return res;

										// 距离
		float t = (dot(N, p1) - dot(S, N)) / dot(d, N);
		if (t < 0.0005f) return res;    // 如果三角形在相机背面

										// 交点计算
		vec3 P = S + d * t;

		// 判断交点是否在三角形中
		vec3 c1 = cross(p2 - p1, P - p1);
		vec3 c2 = cross(p3 - p2, P - p2);
		vec3 c3 = cross(p1 - p3, P - p3);
		//vec3 n = material.normal;   // 需要 "原生法向量" 来判断
		if (dot(c1, N) < 0 || dot(c2, N) < 0 || dot(c3, N) < 0) return res;

		// 装填返回结果
		res.是否命中 = true;
		res.与交点的距离 = t;
		res.光线命中点 = P;
		res.material = material;
		res.material.normal = N;    // 要返回正确的法向
		return res;
	};
};

// 球
class Sphere : public Shape
{
public:
	Sphere() {}
	Sphere(vec3 o, double r, vec3 c) { O = o; R = r; material.color = c; }
	vec3 O;             // 圆心
	double R;           // 半径
	Material material;  // 材质

						// 与光线求交
	光线求交结果 intersect(Ray ray)
	{
		光线求交结果 res;

		vec3 S = ray.startPoint;        // 射线起点
		vec3 d = ray.direction;         // 射线方向

		float OS = length(O - S);
		float SH = dot(O - S, d);
		float OH = sqrt(pow(OS, 2) - pow(SH, 2));

		if (OH > R) return res; // OH大于半径则不相交

		float PH = sqrt(pow(R, 2) - pow(OH, 2));

		float t1 = length(SH) - PH;
		float t2 = length(SH) + PH;
		float t = (t1 < 0) ? (t2) : (t1);   // 最近距离
		vec3 P = S + t * d;     // 交点

								// 防止自己交自己
		if (fabs(t1) < 0.0005f || fabs(t2) < 0.0005f) return res;

		// 装填返回结果
		res.是否命中 = true;
		res.与交点的距离 = t;
		res.光线命中点 = P;
		res.material = material;
		res.material.normal = normalize(P - O); // 要返回正确的法向
		return res;
	}
};




// ---------------------------- end of class definition ---------------------------- //
GLuint program;                 // 着色器程序对象
std::vector<vec3> 模型顶点;     // 顶点坐标
std::vector<GLuint> 顶点索引;    // 顶点索引
std::vector<vec3> lines;        // 线段端点坐标
vec3 rotateControl(0, 0, 0);    // 旋转参数
vec3 scaleControl(1, 1, 1);     // 缩放参数


								// 按照三角形中心排序 -- 比较函数
bool cmpx(const 三角形类2& t1, const 三角形类2& t2) {
	return t1.center.x < t2.center.x;
}
bool cmpy(const 三角形类2& t1, const 三角形类2& t2) {
	return t1.center.y < t2.center.y;
}
bool cmpz(const 三角形类2& t1, const 三角形类2& t2) {
	return t1.center.z < t2.center.z;
}



void add三角形类(三角形类2* tri) {
	if (tri) {
		lines.push_back(tri->p1 - vec3(0.0005, 0.0005, 0.0005));
		lines.push_back(tri->p2 - vec3(0.0005, 0.0005, 0.0005));
		lines.push_back(tri->p2 - vec3(0.0005, 0.0005, 0.0005));
		lines.push_back(tri->p3 - vec3(0.0005, 0.0005, 0.0005));
		lines.push_back(tri->p3 - vec3(0.0005, 0.0005, 0.0005));
		lines.push_back(tri->p1 - vec3(0.0005, 0.0005, 0.0005));
		lines.push_back(tri->p1 + vec3(0.0005, 0.0005, 0.0005));
		lines.push_back(tri->p2 + vec3(0.0005, 0.0005, 0.0005));
		lines.push_back(tri->p2 + vec3(0.0005, 0.0005, 0.0005));
		lines.push_back(tri->p3 + vec3(0.0005, 0.0005, 0.0005));
		lines.push_back(tri->p3 + vec3(0.0005, 0.0005, 0.0005));
		lines.push_back(tri->p1 + vec3(0.0005, 0.0005, 0.0005));
	}
}
void addLine(vec3 p1, vec3 p2) {
	lines.push_back(p1);
	lines.push_back(p2);
}

void addBox(BVHNode* root) {
	float x1 = root->AA.x, y1 = root->AA.y, z1 = root->AA.z;
	float x2 = root->BB.x, y2 = root->BB.y, z2 = root->BB.z;
	lines.push_back(vec3(x1, y1, z1)), lines.push_back(vec3(x2, y1, z1));
	lines.push_back(vec3(x1, y1, z1)), lines.push_back(vec3(x1, y1, z2));
	lines.push_back(vec3(x1, y1, z1)), lines.push_back(vec3(x1, y2, z1));
	lines.push_back(vec3(x2, y1, z1)), lines.push_back(vec3(x2, y1, z2));
	lines.push_back(vec3(x2, y1, z1)), lines.push_back(vec3(x2, y2, z1));
	lines.push_back(vec3(x1, y2, z1)), lines.push_back(vec3(x2, y2, z1));
	lines.push_back(vec3(x1, y1, z2)), lines.push_back(vec3(x1, y2, z2));
	lines.push_back(vec3(x1, y2, z1)), lines.push_back(vec3(x1, y2, z2));
	lines.push_back(vec3(x1, y2, z2)), lines.push_back(vec3(x2, y2, z2));
	lines.push_back(vec3(x1, y1, z2)), lines.push_back(vec3(x2, y1, z2));
	lines.push_back(vec3(x2, y2, z1)), lines.push_back(vec3(x2, y2, z2));
	lines.push_back(vec3(x2, y1, z2)), lines.push_back(vec3(x2, y2, z2));
}

// 构建 BVH
BVHNode* buildBVH(std::vector<三角形类2>& 三角集合, int l, int r, int n) {
	if (l > r) return 0;

	BVHNode* node = new BVHNode();
	node->AA = vec3(1145141919, 1145141919, 1145141919);
	node->BB = vec3(-1145141919, -1145141919, -1145141919);

	// 计算 AABB
	for (int i = l; i <= r; i++) {
		// 最小点 AA
		float minx = min(三角集合[i].p1.x, min(三角集合[i].p2.x, 三角集合[i].p3.x));
		float miny = min(三角集合[i].p1.y, min(三角集合[i].p2.y, 三角集合[i].p3.y));
		float minz = min(三角集合[i].p1.z, min(三角集合[i].p2.z, 三角集合[i].p3.z));
		node->AA.x = min(node->AA.x, minx);
		node->AA.y = min(node->AA.y, miny);
		node->AA.z = min(node->AA.z, minz);
		// 最大点 BB
		float maxx = max(三角集合[i].p1.x, max(三角集合[i].p2.x, 三角集合[i].p3.x));
		float maxy = max(三角集合[i].p1.y, max(三角集合[i].p2.y, 三角集合[i].p3.y));
		float maxz = max(三角集合[i].p1.z, max(三角集合[i].p2.z, 三角集合[i].p3.z));
		node->BB.x = max(node->BB.x, maxx);
		node->BB.y = max(node->BB.y, maxy);
		node->BB.z = max(node->BB.z, maxz);
	}

	// 不多于 n 个三角形 返回叶子节点
	if ((r - l + 1) <= n) {
		node->n = r - l + 1;
		node->index = l;
		return node;
	}

	// 否则递归建树
	float lenx = node->BB.x - node->AA.x;
	float leny = node->BB.y - node->AA.y;
	float lenz = node->BB.z - node->AA.z;
	// 按 x 划分
	if (lenx >= leny && lenx >= lenz)
		std::sort(三角集合.begin() + l, 三角集合.begin() + r + 1, cmpx);
	// 按 y 划分
	if (leny >= lenx && leny >= lenz)
		std::sort(三角集合.begin() + l, 三角集合.begin() + r + 1, cmpy);
	// 按 z 划分
	if (lenz >= lenx && lenz >= leny)
		std::sort(三角集合.begin() + l, 三角集合.begin() + r + 1, cmpz);

	// 递归
	int mid = (l + r) / 2;
	node->left = buildBVH(三角集合, l, mid, n);
	node->right = buildBVH(三角集合, mid + 1, r, n);

	return node;
}

// SAH 优化构建 BVH
BVHNode* SAH优化(std::vector<三角形类2>& 三角集合, int l, int r, int n) {
	if (l > r) return 0;

	BVHNode* node = new BVHNode();
	node->AA = vec3(1145141919, 1145141919, 1145141919);
	node->BB = vec3(-1145141919, -1145141919, -1145141919);

	// 计算 AABB
	for (int i = l; i <= r; i++) {
		// 最小点 AA
		float minx = min(三角集合[i].p1.x, min(三角集合[i].p2.x, 三角集合[i].p3.x));
		float miny = min(三角集合[i].p1.y, min(三角集合[i].p2.y, 三角集合[i].p3.y));
		float minz = min(三角集合[i].p1.z, min(三角集合[i].p2.z, 三角集合[i].p3.z));
		node->AA.x = min(node->AA.x, minx);
		node->AA.y = min(node->AA.y, miny);
		node->AA.z = min(node->AA.z, minz);
		// 最大点 BB
		float maxx = max(三角集合[i].p1.x, max(三角集合[i].p2.x, 三角集合[i].p3.x));
		float maxy = max(三角集合[i].p1.y, max(三角集合[i].p2.y, 三角集合[i].p3.y));
		float maxz = max(三角集合[i].p1.z, max(三角集合[i].p2.z, 三角集合[i].p3.z));
		node->BB.x = max(node->BB.x, maxx);
		node->BB.y = max(node->BB.y, maxy);
		node->BB.z = max(node->BB.z, maxz);
	}

	// 不多于 n 个三角形 返回叶子节点
	if ((r - l + 1) <= n) {
		node->n = r - l + 1;
		node->index = l;
		return node;
	}

	// 否则递归建树
	float Cost = INF;
	int Axis = 0;
	int Split = (l + r) / 2;
	for (int axis = 0; axis < 3; axis++) {
		// 分别按 x,y,z 轴排序
		if (axis == 0) std::sort(&三角集合[0] + l, &三角集合[0] + r + 1, cmpx);
		if (axis == 1) std::sort(&三角集合[0] + l, &三角集合[0] + r + 1, cmpy);
		if (axis == 2) std::sort(&三角集合[0] + l, &三角集合[0] + r + 1, cmpz);

		// leftMax[i]: [l, i] 中最大的 xyz 值
		// leftMin[i]: [l, i] 中最小的 xyz 值
		std::vector<vec3> leftMax(r - l + 1, vec3(-INF, -INF, -INF));
		std::vector<vec3> leftMin(r - l + 1, vec3(INF, INF, INF));
		// 计算前缀 注意 i-l 以对齐到下标 0
		for (int i = l; i <= r; i++) {
			三角形类2& t = 三角集合[i];
			int bias = (i == l) ? 0 : 1;  // 第一个元素特殊处理

			leftMax[i - l].x = max(leftMax[i - l - bias].x, max(t.p1.x, max(t.p2.x, t.p3.x)));
			leftMax[i - l].y = max(leftMax[i - l - bias].y, max(t.p1.y, max(t.p2.y, t.p3.y)));
			leftMax[i - l].z = max(leftMax[i - l - bias].z, max(t.p1.z, max(t.p2.z, t.p3.z)));

			leftMin[i - l].x = min(leftMin[i - l - bias].x, min(t.p1.x, min(t.p2.x, t.p3.x)));
			leftMin[i - l].y = min(leftMin[i - l - bias].y, min(t.p1.y, min(t.p2.y, t.p3.y)));
			leftMin[i - l].z = min(leftMin[i - l - bias].z, min(t.p1.z, min(t.p2.z, t.p3.z)));
		}

		// rightMax[i]: [i, r] 中最大的 xyz 值
		// rightMin[i]: [i, r] 中最小的 xyz 值
		std::vector<vec3> rightMax(r - l + 1, vec3(-INF, -INF, -INF));
		std::vector<vec3> rightMin(r - l + 1, vec3(INF, INF, INF));
		// 计算后缀 注意 i-l 以对齐到下标 0
		for (int i = r; i >= l; i--) {
			三角形类2& t = 三角集合[i];
			int bias = (i == r) ? 0 : 1;  // 第一个元素特殊处理

			rightMax[i - l].x = max(rightMax[i - l + bias].x, max(t.p1.x, max(t.p2.x, t.p3.x)));
			rightMax[i - l].y = max(rightMax[i - l + bias].y, max(t.p1.y, max(t.p2.y, t.p3.y)));
			rightMax[i - l].z = max(rightMax[i - l + bias].z, max(t.p1.z, max(t.p2.z, t.p3.z)));

			rightMin[i - l].x = min(rightMin[i - l + bias].x, min(t.p1.x, min(t.p2.x, t.p3.x)));
			rightMin[i - l].y = min(rightMin[i - l + bias].y, min(t.p1.y, min(t.p2.y, t.p3.y)));
			rightMin[i - l].z = min(rightMin[i - l + bias].z, min(t.p1.z, min(t.p2.z, t.p3.z)));
		}

		// 遍历寻找分割
		float cost = INF;
		int split = l;
		for (int i = l; i <= r - 1; i++) {
			float lenx, leny, lenz;
			// 左侧 [l, i]
			vec3 leftAA = leftMin[i - l];
			vec3 leftBB = leftMax[i - l];
			lenx = leftBB.x - leftAA.x;
			leny = leftBB.y - leftAA.y;
			lenz = leftBB.z - leftAA.z;
			float leftS = 2.0 * ((lenx * leny) + (lenx * lenz) + (leny * lenz));
			float leftCost = leftS * (i - l + 1);

			// 右侧 [i+1, r]
			vec3 rightAA = rightMin[i + 1 - l];
			vec3 rightBB = rightMax[i + 1 - l];
			lenx = rightBB.x - rightAA.x;
			leny = rightBB.y - rightAA.y;
			lenz = rightBB.z - rightAA.z;
			float rightS = 2.0 * ((lenx * leny) + (lenx * lenz) + (leny * lenz));
			float rightCost = rightS * (r - i);

			// 记录每个分割的最小答案
			float totalCost = leftCost + rightCost;
			if (totalCost < cost) {
				cost = totalCost;
				split = i;
			}
		}
		// 记录每个轴的最佳答案
		if (cost < Cost) {
			Cost = cost;
			Axis = axis;
			Split = split;
		}
	}

	// 按最佳轴分割
	if (Axis == 0) std::sort(&三角集合[0] + l, &三角集合[0] + r + 1, cmpx);
	if (Axis == 1) std::sort(&三角集合[0] + l, &三角集合[0] + r + 1, cmpy);
	if (Axis == 2) std::sort(&三角集合[0] + l, &三角集合[0] + r + 1, cmpz);

	// 递归
	node->left = SAH优化(三角集合, l, Split, n);
	node->right = SAH优化(三角集合, Split + 1, r, n);

	return node;
}


void dfsNlevel(BVHNode* root, int depth, int targetDepth) {
	if (root == NULL) return;
	if (targetDepth == depth) {
		addBox(root);
		return;
	}
	dfsNlevel(root->left, depth + 1, targetDepth);
	dfsNlevel(root->right, depth + 1, targetDepth);
}

float hitTriangle(三角形类2* triangle, Ray ray) {

	vec3 p1 = triangle->p1, p2 = triangle->p2, p3 = triangle->p3;
	vec3 S = ray.startPoint;        // 射线起点
	vec3 d = ray.direction;         // 射线方向
	vec3 N = normalize(cross(p2 - p1, p3 - p1));    // 法向量
	if (dot(N, d) > 0.0f) N = -N;   // 获取正确的法向量

									// 如果视线和三角形平行
	if (fabs(dot(N, d)) < 0.00001f) return INF;

	// 距离
	float t = (dot(N, p1) - dot(S, N)) / dot(d, N);
	if (t < 0.0005f) return INF;    // 如果三角形在光线背面

									// 交点计算
	vec3 P = S + d * t;

	// 判断交点是否在三角形中
	vec3 c1 = cross(p2 - p1, P - p1);
	vec3 c2 = cross(p3 - p2, P - p2);
	vec3 c3 = cross(p1 - p3, P - p3);
	if (dot(c1, N) > 0 && dot(c2, N) > 0 && dot(c3, N) > 0) return t;
	if (dot(c1, N) < 0 && dot(c2, N) < 0 && dot(c3, N) < 0) return t;

	return INF;
}

光线求交结果 光线和三角形求交(三角形类2* 三角形类, Ray ray)
{
	光线求交结果 res;

	vec3 p1 = 三角形类->p1, p2 = 三角形类->p2, p3 = 三角形类->p3;
	vec3 S = ray.startPoint;        // 射线起点
	vec3 d = ray.direction;         // 射线方向
	vec3 N = 三角形类->material.normal;       // 法向量
	if (dot(N, d) > 0.0f) N = -N;   // 获取正确的法向量

									// 如果视线和三角形平行
									//if (fabs(dot(N, d)) < 0.00001f) return res;
									//std::cout << "光线命中点\n" << 3 << "  " << 2 << "  " << 4 << std::endl;

									// 距离
	float t = (dot(N, p1) - dot(S, N)) / dot(d, N);
	if (t < 0.0005f) return res;    // 如果三角形在相机背面

									// 交点计算
	vec3 P = S + d * t;



	// 判断交点是否在三角形中
	vec3 c1 = cross(p2 - p1, P - p1);
	vec3 c2 = cross(p3 - p2, P - p2);
	vec3 c3 = cross(p1 - p3, P - p3);
	vec3 n = 三角形类->material.normal;   // 需要 "原生法向量" 来判断
	if (dot(c1, n) < 0 || dot(c2, n) < 0 || dot(c3, n) < 0) return res;


	// 装填返回结果
	//res.三角形 = 三角形类;
	res.是否命中 = true;
	res.与交点的距离 = t;
	res.光线命中点 = P;
	res.material = 三角形类->material;
	res.material.normal = N;    // 要返回正确的法向

	return res;
};

// 暴力查数组
光线求交结果 hit三角形类Array(Ray ray, std::vector<三角形类2>& triangles, int l, int r) {
	光线求交结果 res;
	for (int i = l; i <= r; i++) {
		float d = hitTriangle(&triangles[i], ray);
		if (d < INF && d < res.与交点的距离) {
			res.与交点的距离 = d;
			res.三角形 = &triangles[i];
		}
	}
	return res;
}


// 和 aabb 盒子求交,没有交点则返回 -1
float hitAABB(Ray r, vec3 AA, vec3 BB) {
	// 1.0 / direction
	vec3 invdir = vec3(1.0 / r.direction.x, 1.0 / r.direction.y, 1.0 / r.direction.z);

	vec3 in = (BB - r.startPoint) * invdir;
	vec3 out = (AA - r.startPoint) * invdir;

	vec3 tmax = max(in, out);
	vec3 tmin = min(in, out);

	float t1 = min(tmax.x, min(tmax.y, tmax.z));
	float t0 = max(tmin.x, max(tmin.y, tmin.z));

	return (t1 >= t0) ? ((t0 > 0.0) ? (t0) : (t1)) : (-1);
}

光线求交结果 hitBVH(Ray ray, std::vector<三角形类2>& 三角集合, BVHNode* root, int a) {
	if (root == NULL) return 光线求交结果();

	// 是叶子 暴力查
	if (root->n > 0) {
		//return hit三角形类Array(ray, 三角集合, root->n, root->n + root->index - 1);

	}

	// 和左右子树 AABB 求交
	float d1 = INF, d2 = INF;
	if (root->left) d1 = hitAABB(ray, root->left->AA, root->left->BB);
	if (root->right) d2 = hitAABB(ray, root->right->AA, root->right->BB);

	//std::cout << "光线命中点\n" << ray.direction.x << "  " << d2 << std::endl;
	// 递归结果
	光线求交结果 r1, r2;
	if (d1>0) r1 = hitBVH(ray, 三角集合, root->left, a++);
	if (d2>0) r2 = hitBVH(ray, 三角集合, root->right, a++);
	//r1.是否命中 = true; r2.是否命中 = true;

	//std::cout << "光线命中点\n" <<r1.与交点的距离 << "  " << a << std::endl;

	return r1.与交点的距离 < r2.与交点的距离 ? r1 : r2;
}


//Shape* 平面求交数据[WIDTH * HEIGHT] = new Shape ;

std::vector<Shape*> 屏幕优先物体;

Shape* shape2 = new Shape; int 深度A = 0;
// 返回距离最近 hit 的结果
光线求交结果 shoot(std::vector<Shape*>& shapes, Ray ray, int 进度)
{
	光线求交结果 res, r;
	res.与交点的距离 = 1145141919.810f; // inf

	if (进度 > 0) {
		r = 屏幕优先物体[进度]->intersect(ray);
		if (r.是否命中 && r.与交点的距离 < res.与交点的距离) {
			res = r;  // 记录距离最近的求交结果
			return res;
		}
	}
	if (深度A == 0) {
		深度A++;
		r = shape2->intersect(ray);
		if (r.是否命中 && r.与交点的距离 < res.与交点的距离) {
			res = r;  // 记录距离最近的求交结果
			return res;
		}
	}


	for (int k = 0; k < shapes.size(); ++k)
	{
		r = shapes[k]->intersect(ray);
		if (r.是否命中 && r.与交点的距离 < res.与交点的距离) {

			res = r;  // 记录距离最近的求交结果
			if (深度A == 0) {
				shape2 = shapes[k];
			}
			return res;
		}
	}
	return res;
}

// 0-1 随机数生成
std::uniform_real_distribution<> dis(0.0, 1.0);
std::random_device rd;
std::mt19937 gen(rd());
double randf()
{
	return dis(gen);
}

// 单位球内的随机向量
vec3 randomVec3()
{

	vec3 d;
	do
	{
		d = 2.0f * vec3(randf(), randf(), randf()) - vec3(1, 1, 1);
	} while (dot(d, d) > 1.0);
	return normalize(d);
	/*
	double r1 = randf(), r2 = randf();
	double z = sqrt(1.0f - r2);
	double phi = 2 * 3.1415926 * r1;
	float x = cos(phi) * sqrt(r2);
	float y = sin(phi) * sqrt(r2);
	return normalize(vec3(x, y, z));
	*/
}

// 1 ~ 8 维的 sobol 生成矩阵
const uint V[8 * 32] = {
	2147483648, 1073741824, 536870912, 268435456, 134217728, 67108864, 33554432, 16777216, 8388608, 4194304, 2097152, 1048576, 524288, 262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1,
	2147483648, 3221225472, 2684354560, 4026531840, 2281701376, 3422552064, 2852126720, 4278190080, 2155872256, 3233808384, 2694840320, 4042260480, 2290614272, 3435921408, 2863267840, 4294901760, 2147516416, 3221274624, 2684395520, 4026593280, 2281736192, 3422604288, 2852170240, 4278255360, 2155905152, 3233857728, 2694881440, 4042322160, 2290649224, 3435973836, 2863311530, 4294967295,
	2147483648, 3221225472, 1610612736, 2415919104, 3892314112, 1543503872, 2382364672, 3305111552, 1753219072, 2629828608, 3999268864, 1435500544, 2154299392, 3231449088, 1626210304, 2421489664, 3900735488, 1556135936, 2388680704, 3314585600, 1751705600, 2627492864, 4008611328, 1431684352, 2147543168, 3221249216, 1610649184, 2415969680, 3892340840, 1543543964, 2382425838, 3305133397,
	2147483648, 3221225472, 536870912, 1342177280, 4160749568, 1946157056, 2717908992, 2466250752, 3632267264, 624951296, 1507852288, 3872391168, 2013790208, 3020685312, 2181169152, 3271884800, 546275328, 1363623936, 4226424832, 1977167872, 2693105664, 2437829632, 3689389568, 635137280, 1484783744, 3846176960, 2044723232, 3067084880, 2148008184, 3222012020, 537002146, 1342505107,
	2147483648, 1073741824, 536870912, 2952790016, 4160749568, 3690987520, 2046820352, 2634022912, 1518338048, 801112064, 2707423232, 4038066176, 3666345984, 1875116032, 2170683392, 1085997056, 579305472, 3016343552, 4217741312, 3719483392, 2013407232, 2617981952, 1510979072, 755882752, 2726789248, 4090085440, 3680870432, 1840435376, 2147625208, 1074478300, 537900666, 2953698205,
	2147483648, 1073741824, 1610612736, 805306368, 2818572288, 335544320, 2113929216, 3472883712, 2290089984, 3829399552, 3059744768, 1127219200, 3089629184, 4199809024, 3567124480, 1891565568, 394297344, 3988799488, 920674304, 4193267712, 2950604800, 3977188352, 3250028032, 129093376, 2231568512, 2963678272, 4281226848, 432124720, 803643432, 1633613396, 2672665246, 3170194367,
	2147483648, 3221225472, 2684354560, 3489660928, 1476395008, 2483027968, 1040187392, 3808428032, 3196059648, 599785472, 505413632, 4077912064, 1182269440, 1736704000, 2017853440, 2221342720, 3329785856, 2810494976, 3628507136, 1416089600, 2658719744, 864310272, 3863387648, 3076993792, 553150080, 272922560, 4167467040, 1148698640, 1719673080, 2009075780, 2149644390, 3222291575,
	2147483648, 1073741824, 2684354560, 1342177280, 2281701376, 1946157056, 436207616, 2566914048, 2625634304, 3208642560, 2720006144, 2098200576, 111673344, 2354315264, 3464626176, 4027383808, 2886631424, 3770826752, 1691164672, 3357462528, 1993345024, 3752330240, 873073152, 2870150400, 1700563072, 87021376, 1097028000, 1222351248, 1560027592, 2977959924, 23268898, 437609937
};

// 格林码 
uint grayCode(uint i) {
	return i ^ (i >> 1);
}

// 生成第 d 维度的第 i 个 sobol 数
float sobol(uint d, uint i) {
	uint result = 0;
	uint offset = d * 32;
	for (uint j = 0; i; i >>= 1, j++)
		if (i & 1)
			result ^= V[j + offset];

	return float(result) * (1.0f / float(0xFFFFFFFFU));
}


// 生成第 i 帧的第 b 次反弹需要的二维随机向量
vec2 sobol低差异序列(uint i, uint b) {
	float u = sobol(b * 2, grayCode(i));
	float v = sobol(b * 2 + 1, grayCode(i));
	return vec2(u, v);
}



#define PI 3.1415926f
vec3 SampleHemisphere(float xi_1, float xi_2) {
	float z = xi_1;
	float r =max(0.0f, (float)sqrt(1.0 - z*z));
	float phi = 2.0 * PI * xi_2;
	return vec3(r * cos(phi), r * sin(phi), z);
}







//#include <bits/stdc++.h>

//using namespace std;

//typedef unsigned int uint;

// V[d] 表示第 d 维度的生成矩阵 

//
 格林码 
//uint grayCode(uint i) {
//	return i ^ (i >> 1);
//}

// 生成第 dimension 维度的第 i 个 sobol 数
//float sobol(unsigned int vectors[][32], unsigned int dimension, unsigned int i) {
//	unsigned int result = 0;
//
//	for (unsigned int j = 0; i; i >>= 1, j++)
//		if (i & 1)
//			result ^= vectors[dimension][j];
//
//	return result * (1.0f / (float)0xFFFFFFFF);
//}



// 将向量 v 投影到 N 的法向半球
vec3 toNormalHemisphere(vec3 v, vec3 N) {
	vec3 helper = vec3(1, 0, 0);
	if (abs(N.x)>0.999) helper = vec3(0, 0, 1);
	vec3 tangent = normalize(cross(N, helper));
	vec3 bitangent = normalize(cross(N, tangent));
	return v.x * tangent + v.y * bitangent + v.z * N;
}
 

// 余弦加权的法向半球采样
vec3 漫反射重要性采样(float xi_1, float xi_2, vec3 N) {
	// 均匀采样 xy 圆盘然后投影到 z 半球
	float r = sqrt(xi_1);
	float theta = xi_2 * 2.0 * PI;
	float x = r * cos(theta);
	float y = r * sin(theta);
	float z = sqrt(1.0 - x*x - y*y);

	// 从 z 半球投影到法向半球
	vec3 L = toNormalHemisphere(vec3(x, y, z), N);
	return L;
}



// 法向半球随机向量
vec3 randomDirection(vec3 n)
{
	/*
	// 法向半球
	vec3 d;
	do
	{
	d = randomVec3();
	} while (dot(d, n) < 0.0f);
	return d;
	*/
	// 法向球
	return normalize(randomVec3() + n);
}


int ll = 0; vec3 微积分 = vec3(0, 0, 0); vec3 前面原色 = vec3(0, 0, 0);



typedef struct 三角形类3 {
	std::vector<Shape*> shapes1;  // 几何物体的集合


};
std::vector<三角形类3*> 大场景几何;


std::vector<Shape*> shapes;  // 几何物体的集合
vec3 光线追踪(std::vector<Shape*>& 场景, Ray ray, int 光追深度)
{
	float 反光;

	光线求交结果 res;
	res = shoot(shapes, ray, 0);
	//res = hitBVH(ray, 三角形集合, BVH树, 0);
	//return vec3(1, 0.5, 0);
	if (!res.是否命中) return vec3(0); // 未命中
								   // 如果发光则返回颜色
	if (res.material.isEmissive) return res.material.color;
	// 否则继续
	Ray randomRay;
	randomRay.startPoint = res.光线命中点;
	//randomRay.direction = SampleCosineHemisphere(frames + 1, 光追深度, res.material.normal);
	vec3 L;
	for (int bounce = 0; bounce<光追深度; bounce++) {

		//randomRay.direction = SampleCosineHemisphere(frames + 1, depth, res.material.normal);
		vec2 uv = sobol低差异序列(frames + 1, bounce);
		L = SampleHemisphere(uv.x, uv.y);
		L = toNormalHemisphere(L, res.material.normal);


	}
	randomRay.direction = L;
	vec3 color = vec3(0);
	float cosine = fabs(dot(-ray.direction, res.material.normal));

	反光 = res.material.specularRate;
	if (反光 > 0 && 光追深度 > 0)
	{
		vec3 ref = normalize(reflect(ray.direction, res.material.normal));
		randomRay.direction = mix(ref, randomRay.direction, res.material.roughness);
		color = 光线追踪(shapes, randomRay, 光追深度 - 1) * cosine;
	}

	return color;

}

// 路径追踪 -- 重要性采样版本
//vec3 pathTracingImportanceSampling(光线求交结果 hit, int maxBounce) {
//
//	vec3 Lo = vec3(0);      // 最终的颜色
//	vec3 history = vec3(1); // 递归积累的颜色
//
//	for (int bounce = 0; bounce<maxBounce; bounce++) {
//		vec3 V = -vec3(0.001, 0.001, 0.001);
//		vec3 N = hit.material.normal;
//
//		// 获取 3 个随机数        
//		float xi_1, xi_2, xi_3 = ...
//
//
//			// 采样 BRDF 得到一个方向 L
//			vec3 L = SampleBRDF(xi_1, xi_2, xi_3, V, N, hit.material);
//		float NdotL = dot(N, L);
//		if (NdotL <= 0.0) break;
//
//		// 发射光线
//		Ray randomRay;
//		randomRay.startPoint = hit.hitPoint;
//		randomRay.direction = L;
//
//		光线求交结果 newHit = shoot(shapes, randomRay, 0);
//		// 获取 L 方向上的 BRDF 值和概率密度
//		//vec3 f_r = BRDF_Evaluate(V, N, L, hit.material);
//		vec3 f_r = vec3(0.001,0.001,0.001);
//		float pdf_brdf = BRDF_Pdf(V, N, L, hit.material);
//		if (pdf_brdf <= 0.0) break;
//
//		// 未命中        
//		if (!newHit.是否命中) {
//			vec3 color = vec3(1,1, 1);
//			Lo += history * color * f_r * NdotL / pdf_brdf;
//			break;
//		}
//
//		// 命中光源积累颜色
//		vec3 Le = newHit.material.color;
//		Lo += history * Le * f_r * NdotL / pdf_brdf;
//
//		// 递归(步进)
//		hit = newHit;
//		history *= f_r * NdotL / pdf_brdf;   // 累积颜色
//	}
//
//	return Lo;
//}


// 路径追踪
vec3 路径追踪(std::vector<Shape*>& shapes, Ray ray, int depth)
{
	if (depth >8) return vec3(0);
	光线求交结果 res;
	res = shoot(shapes, ray, 0);
	//res = hitBVH(ray, 三角形集合, BVH树);
	//add三角形类(res.三角形);
	//addLine(ray.startPoint, ray.startPoint + ray.direction * vec3(5, 5, 5));

	if (!res.是否命中) return vec3(0); // 未命中

								   // 如果发光则返回颜色
	if (res.material.isEmissive) return res.material.color;

	// 有 P 的概率终止
	double r = randf();
	float P = 0.8;
	if (r > P) return vec3(0);

	vec3 color = vec3(0);

	// 否则继续
	Ray randomRay;
	randomRay.startPoint = res.光线命中点;
	 
	//std::cout << "光线命中点\n" << res.material.normal.x << res.material.normal.y << res.material.normal.z << std::endl;
	//randomRay.direction = randomDirection(res.material.normal);
	//randomRay.direction = (randomRay.direction + randomRay.direction + randomRay.direction) / vec3(3, 3, 3);
	vec3 L;
	for (int bounce = 0; bounce<depth; bounce++) {
		
		//randomRay.direction = SampleCosineHemisphere(frames + 1, depth, res.material.normal);
		vec2 uv = sobol低差异序列(frames + 1, depth);
		L = 漫反射重要性采样(uv.x, uv.y, res.material.normal);
		//L = 漫反射重要性采样(rand() % 8, rand() % 8, res.material.normal);
	}
	randomRay.direction = L ;

	float cosine = fabs(dot(-ray.direction, res.material.normal));

	// 根据反射率决定光线最终的方向
	r = randf();
	if (r < res.material.specularRate)  // 镜面反射
	{
		vec3 ref = normalize(reflect(ray.direction, res.material.normal));
		randomRay.direction = mix(ref, randomRay.direction, res.material.roughness);
		color = 路径追踪(shapes, randomRay, depth + 1) * cosine;
	}
	else if (res.material.specularRate <= r && r <= res.material.refractRate)    // 折射
	{
		vec3 ref = normalize(refract(ray.direction, res.material.normal, float(res.material.refractAngle)));
		randomRay.direction = mix(ref, -randomRay.direction, res.material.refractRoughness);
		color = 路径追踪(shapes, randomRay, depth + 1) * cosine;
	}
	else    // 漫反射
	{
		vec3 srcColor = res.material.color;
		vec3 ptColor = 路径追踪(shapes, randomRay, depth + 1) * cosine;
		color = ptColor * srcColor;    // 和原颜色混合
	}

	return color / P;

}


GLuint texture;
typedef unsigned int Color;
static  Color buffer[HEIGHT][WIDTH];

vec3 累计积分[WIDTH * HEIGHT];

vec3 上个原色;
vec3 离线交点颜色[WIDTH * HEIGHT];
vec3 离线交点积分[WIDTH * HEIGHT];
光线求交结果 离线交点;

int a = 400;
double* image = new double[WIDTH * HEIGHT * 3];
vec3 小图采样2[200 * 200]; vec3 小图采样3;

// ---------------------------- end of functions ---------------------------- //


int p7;
int 采样进度 = 200;
void 渲染() {

	int 幸运阈值 = 1; int 幸运阈值2 = 1;	vec3 AA = vec3(0.1, 0.2, 0.2);
	vec3 小图采样; int 渲染进度; int 小图指针; Ray 离线光; int 对焦值, 对焦A, 对焦B, 对焦C; int 对焦清晰度;
	对焦清晰度 = 10; int j变量值记录;
	vec3 color;			Ray ray; vec3 s;
	光线求交结果 res;

	//采样进度++;		if (采样进度 > 300) {
	//	采样进度 = 200;
	//}
	double BRIGHTNESS = (2.0f * 3.1415926f) * (1.0f / double(采样进度));

	for (int k = 0; k < 1; ++k)
	{
		double* p = image;
		for (int i = 0; i < WIDTH; i++)
		{
			++渲染进度;
			if (渲染进度 > 500) {
				渲染进度 = 1;
				if (j变量值记录 < (HEIGHT)*0.3 && j变量值记录 >(HEIGHT)*0.7)
				{
					对焦清晰度 = 200; 对焦A = 50; 对焦C = 150;
				}
				else if (j变量值记录 > (HEIGHT)*0.4 && j变量值记录 < (HEIGHT)*0.6)
				{
					对焦清晰度 = 20; 对焦A = 5; 对焦C = 15;
				}
				else if (j变量值记录 >(HEIGHT)*0.45 &&  j变量值记录 < (HEIGHT)*0.55)
				{
					/*	对焦清晰度 = 7; 对焦A = 3;  对焦C = 5;
					}
					else if (j变量值记录 >(HEIGHT) * 0.48 && j变量值记录 <(HEIGHT)*0.51)
					{*/

					//对焦清晰度 = 2; 对焦A = 1;  对焦C = 1;
				}
				//对焦清晰度 = 400; 对焦A = 400; 对焦C = 400;
			}
			for (int j = 0; j < HEIGHT; j++)
			{
				j变量值记录 = j;


				++幸运阈值;
				if (幸运阈值 >对焦清晰度) { 幸运阈值 = 1; }


				if (幸运阈值 == rand() % 对焦清晰度) {
					// 像素坐标转投影平面坐标
					double x = 2.0 * double(j) / double(WIDTH) - 1.0;
					double y = 2.0 * double(HEIGHT - i) / double(HEIGHT) - 1.0;
					// MSAA
					x += (randf() - 0.5f) / double(WIDTH);
					y += (randf() - 0.5f) / double(HEIGHT);

					vec3 coord = vec3(x, y, SCREEN_Z);          // 计算投影平面坐标
					vec3 direction = normalize(coord - EYE);    // 计算光线投射方向

																// 生成光线

					ray.startPoint = coord;
					ray.direction = direction;

					// 与场景的交点


					深度A = 0;
					res = shoot(shapes, ray, i + j);
					//res = hitBVH(ray, 三角形集合, BVH树, 0);


					color = vec3(0, 0, 0);

					if (res.是否命中) {

						// 命中光源直接返回光源颜色
						if (res.material.isEmissive) {
							color = res.material.color;
						}
						// 命中实体则选择一个随机方向重新发射光线并且进行路径追踪
						else {
							// 根据交点处法向量生成交点处反射的随机半球向量

							Ray randomRay;
							randomRay.startPoint = res.光线命中点;
							//randomRay.direction = SampleCosineHemisphere(frames+1,0, res.material.normal);
							randomRay.direction = randomDirection(res.material.normal);
							//randomRay.direction = (randomRay.direction + randomRay.direction + randomRay.direction) / vec3(3, 3, 3);
							
						 

							// 根据反射率决定光线最终的方向
							double r = randf();
							if (r < res.material.specularRate)  // 镜面反射
							{

								vec3 ref = normalize(reflect(ray.direction, res.material.normal));
								randomRay.direction = mix(ref, randomRay.direction, res.material.roughness);
								微积分 = 路径追踪(shapes, randomRay, 0);
								color = 微积分;

							}
							else if (res.material.specularRate <= r && r <= res.material.refractRate)    // 折射
							{
								vec3 ref = normalize(refract(ray.direction, res.material.normal, float(res.material.refractAngle)));
								randomRay.direction = mix(ref, -randomRay.direction, res.material.refractRoughness);
								微积分 = 路径追踪(shapes, randomRay, 0);
								color = 微积分;

							}
							else     // 漫反射
							{
						 
								vec3 L;
								//for (int bounce = 0; bounce<4; bounce++) {
								vec2 uv = sobol低差异序列(frames + 1,0);
								L = SampleHemisphere(uv.x, uv.y);
								L = toNormalHemisphere(L, randomRay.direction);

								//L = 漫反射重要性采样(uv.x, uv.y, randomRay.direction);
								//L = SampleCosineHemisphere(rand() % 8000, rand() % 8000, randomRay.direction);
								//}
								randomRay.direction = L;
								s = res.material.color;
								微积分 = 路径追踪(shapes, randomRay, 0);
								//if (幸运阈值 < 对焦A)
								//{
								//	微积分 = 光线追踪(shapes, randomRay, 0);

								//}
								//else	if (幸运阈值 <= 对焦C  && 幸运阈值 >= 对焦B)
								//{
								//	微积分 = 光线追踪(shapes, 离线光, 0);
								//}
								//else
								//{
								//	微积分 = 光线追踪(shapes, 离线光, 0);
								//	//微积分 = 路径追踪(shapes, 离线光, 2);
								//}
								color = 微积分*s;
								//}
							}
							//color *= BRIGHTNESS*0.1;

							离线交点颜色[i + j] = res.material.color;
							离线交点积分[i + j] *= 微积分;
							/*		for (int M = 0; M < 4; M++)
							{
							离线交点颜色[i + j + M - 4] = 离线交点颜色[i + j];
							离线交点积分[i + j + M - 4] *= 微积分;
							}*/
							离线交点 = res;
							离线光 = randomRay;
							小图采样 = color;
							上个原色 = res.material.color;
							小图采样 *= BRIGHTNESS;

						}
					}
			 
				}
				else
				{
					
					小图采样 = 上个原色 * 离线交点积分[i + j] * 微积分;


					小图采样 *= BRIGHTNESS;
				}
				*p += 小图采样.x; p++;  // R 通道
				小图采样2[i + j].x = *p;
				*p += 小图采样.y; p++;  // G 通道
				小图采样2[i + j].y = *p;
				*p += 小图采样.z; p++;  // B 通道
				小图采样2[i + j].z = *p;


				buffer[i][j] = RGB(小图采样2[i + j].x * 255, 小图采样2[i + j].y * 255, 小图采样2[i + j].z * 255);

			}
		}

	}



	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, WIDTH, HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
	glLoadIdentity();
	glBegin(GL_QUADS);
	glTexCoord2f(0, 0);
	glVertex2f(-1, 1);
	glTexCoord2f(0, 1);
	glVertex2f(-1, -1);
	glTexCoord2f(1, 1);
	glVertex2f(1, -1);
	glTexCoord2f(1, 0);
	glVertex2f(1, 1);
	glEnd();
	glutSwapBuffers();
	++frames;
	if (clock() - clocks > CLOCKS_PER_SEC)
	{
		char title[64];
		sprintf(title, "  FPS:%d", frames);
		glutSetWindowTitle(title);
		clocks = clock();
		frames = 0;
	}

	std::cout << "fps: 共 " << ++p7  << std::endl;
}







#include <fstream>
#include <sstream>

void 读取obj模型(std::string filepath, std::vector<vec3>& vertices, std::vector<GLuint>& indices) {
	// 打开文件流
	std::ifstream fin(filepath);
	std::string line;
	if (!fin.is_open()) {
		//std::cout << "文件 " << filepath << " 打开失败" << std::endl;
		exit(-1);
	}

	// 增量读取
	int offset = vertices.size();

	// 按行读取
	while (std::getline(fin, line)) {
		std::istringstream sin(line);   // 以一行的数据作为 string stream 解析并且读取
		std::string type;
		GLfloat x, y, z;
		int v0, v1, v2;

		// 读取obj文件
		sin >> type;
		if (type == "v") {
			sin >> x >> y >> z;
			vertices.push_back(vec3(x, y, z));
		}
		if (type == "f") {
			sin >> v0 >> v1 >> v2;
			indices.push_back(v0 - 1 + offset);
			indices.push_back(v1 - 1 + offset);
			indices.push_back(v2 - 1 + offset);
		}
	}
}


int main()
{
	Shape* 单个数据 = new Shape;
	for (int i = 0; i < WIDTH * HEIGHT; ++i) {
		屏幕优先物体.push_back(单个数据);
	}
	//这个放在main初始化



	三角形类3* a2;
	std::vector<三角形类3*> 大场景几何;

	//读取obj模型("2.obj", 模型顶点, 顶点索引);
	//for (auto& v : 模型顶点) {
	//	v.x *= 5.0, v.y *= 5.0, v.z *= 5.0;
	//	v.y -= 0.5;
	//}
	读取obj模型("2.obj", 模型顶点, 顶点索引);
	// 构建 三角形类 数组

	vec3 pa1;
	//for (int i = 0; i < 顶点索引.size(); i += 3) {
	//	a2->shapes1.push_back(new 三角形类(模型顶点[顶点索引[i]], 模型顶点[顶点索引[i + 1]], 模型顶点[顶点索引[i + 2]], vec3(0.1, 0.5, 0.1)));
	//	//三角形集合.push_back(三角形类2(模型顶点[顶点索引[i]], 模型顶点[顶点索引[i + 1]], 模型顶点[顶点索引[i + 2]]));
	//	if (pa1> 模型顶点[顶点索引[i]])
	//	{

	//	}
	//}
	//大场景几何.push_back(a2);



	std::cout << "模型读取完成: 共 " << 顶点索引.size() << " 个三角形" << std::endl;


	// 建立 BVH 树
	BVHNode* root = buildBVH(三角形集合, 0, 三角形集合.size() - 1, 8);
	BVH树 = SAH优化(三角形集合, 0, 三角形集合.size() - 1, 8);

	//addBox(root->left); 
	//addBox(root->right);

	dfsNlevel(BVH树, 0, 5);   // 可视化第 n 层 bvh




	Sphere s1 = Sphere(vec3(0.0, -0.3, 0.0), 0.5, GREEN);
	Sphere s2 = Sphere(vec3(0.0, -0.3, 0.0), 0.4, WHITE);
	Sphere s3 = Sphere(vec3(0.65, 0.1, 0.0), 0.3, BLUE);
	s1.material.specularRate = 0.3;
	s1.material.roughness = 0.1;
	//s1.material.refractRate = 0.95;

	s2.material.specularRate = 0.3;
	s2.material.refractRate = 0.95;
	s2.material.refractAngle = 0.1;
	//s2.material.refractRoughness = 0.05;

	s3.material.specularRate = 0.3;

	shapes.push_back(&s1);
	//shapes.push_back(&s2);
	shapes.push_back(&s3);

	//shapes.push_back(new 三角形类(vec3(-0.15, 0.4, -0.6), vec3(-0.15, -0.95, -0.6), vec3(0.15, 0.4, -0.6), YELLOW));
	//shapes.push_back(new 三角形类(vec3(0.15, 0.4, -0.6), vec3(-0.15, -0.95, -0.6), vec3(0.15, -0.95, -0.6), YELLOW));

	三角形类 tt = 三角形类(vec3(-0.2, -0.2, -0.95), vec3(0.2, -0.2, -0.95), vec3(-0.0, -0.9, 0.4), YELLOW);
	//tt.material.specularRate = 0.1;
	//tt.material.refractRate = 0.85;
	//tt.material.refractRoughness = 0.3;
	//shapes.push_back(&tt);

	// 发光物
	三角形类 l1 = 三角形类(vec3(0.4, 0.99, 0.4), vec3(-0.4, 0.99, -0.4), vec3(-0.4, 0.99, 0.4), WHITE);
	三角形类 l2 = 三角形类(vec3(0.4, 0.99, 0.4), vec3(0.4, 0.99, -0.4), vec3(-0.4, 0.99, -0.4), WHITE);
	l1.material.isEmissive = true;
	l2.material.isEmissive = true;
	shapes.push_back(&l1);
	shapes.push_back(&l2);

	// 背景盒子
	// bottom
	shapes.push_back(new 三角形类(vec3(1, -1, 1), vec3(-1, -1, -1), vec3(-1, -1, 1), WHITE));
	shapes.push_back(new 三角形类(vec3(1, -1, 1), vec3(1, -1, -1), vec3(-1, -1, -1), WHITE));
	// back
	shapes.push_back(new 三角形类(vec3(1, -1, -1), vec3(-1, 1, -1), vec3(-1, -1, -1), CYAN));
	shapes.push_back(new 三角形类(vec3(1, -1, -1), vec3(1, 1, -1), vec3(-1, 1, -1), CYAN));
	// top
	shapes.push_back(new 三角形类(vec3(1, 1, 1), vec3(-1, 1, 1), vec3(-1, 1, -1), WHITE));
	shapes.push_back(new 三角形类(vec3(1, 1, 1), vec3(-1, 1, -1), vec3(1, 1, -1), WHITE));


	//shapes.push_back(new 三角形类(vec3(-1, -1, -1), vec3(-1, 1, 1), vec3(-1, -1, 1), BLUE));
	//shapes.push_back(new 三角形类(vec3(-1, -1, -1), vec3(-1, 1, -1), vec3(-1, 1, 1), BLUE));

	//shapes.push_back(new 三角形类(vec3(1, 1, 1), vec3(1, -1, -1), vec3(1, -1, 1), RED));
	//shapes.push_back(new 三角形类(vec3(1, -1, -1), vec3(1, 1, 1), vec3(1, 1, -1), RED));



	int argc = 1;
	char* argv[] = { "MFC_GLUT" };
	clocks = clock();
	frames = 0;
	glutInitWindowSize(WIDTH, HEIGHT);
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
	glutCreateWindow("RayTracing");
	glutDisplayFunc(渲染);
	glutIdleFunc(渲染);
	glEnable(GL_TEXTURE_2D);
	glGenTextures(1, &texture);
	glBindTexture(GL_TEXTURE_2D, texture);
	glTexImage2D(GL_TEXTURE_2D, 0, 4, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);	// 线形滤波
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);	// 线形滤波

	glutMainLoop();

	return 0;
}

代码中有很多加速算法,这次加入了低差异序列和重要性采样 

完整代码 自建立 空项目 优化开 完全优化

2.obj 模型 https://share.weiyun.com/kIUa26X8
GL依赖库 https://share.weiyun.com/CjutWxwd
dll和模型 自己放在编译目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值