路径追踪 SAH优化的Bvh

BVH 层次包围盒
SAH 优化BVH
BVH具体怎么做

我们加载模型用数组 一个个记录模型的三角形 和材质

光线追踪 判断光线和模型相交时返回命中的三角形 颜色材质
每次判断相交都是 把整个场景三角形 全部遍历 可想而知会很慢

就需要我们优化 把他们按照区域分类开来先判断 光线和区域相交
再判断区域中的三角形,一层层下去避免浪费 这就是Bvh结构

在这里插入图片描述
图片中的兔子就是按照250*250 直线判断相交 ,返回三角形表示命中, 这个点就显示出颜色

for (int i = 0; i < WIDTH; i +=2)
	{
		for (int j = 0; j < HEIGHT; j +=2)
		{
			// 像素坐标转投影平面坐标
			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 ray;
			ray.startPoint = coord;
			ray.direction = direction;

			vec3 color = vec3(0, 0, 0);

			HitResult res = hitBVH(ray, triangles, root);

			if (res.triangle != NULL) { //判断是否命中  得到三角形既命中模型返回颜色
				color = vec3(0, 0.5, 0);
			}
			buffer[i][j] = RGB(color.x * 255, color.y * 255, color.z * 255);
		}
	}

上面就是一个简单的光线追踪实现,不反射不计算材质也没有材质
完整代码可以使用第一章的框架 复制这份

#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>

#include <GL/glew.h>
#include <freeglut.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#define INF 114514.0


#include<ctime>
#include<mmintrin.h>



// 输出图像分辨率
const int WIDTH = 250;
const int HEIGHT = 250;
GLuint texture;
typedef unsigned int Color;
static  Color buffer[HEIGHT][WIDTH];
int frames; clock_t clocks;

using namespace glm;
vec3 光线命中坐标 = vec3(0, 0, 0);  // 光线命中点
// ----------------------------------------------------------------------------- //

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

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

typedef struct Triangle {
	vec3 p1, p2, p3;   // 三点
	vec3 center;       // 中心
	Triangle(vec3 a, vec3 b, vec3 c) {
		p1 = a, p2 = b, p3 = c;
		center = (p1 + p2 + p3) / vec3(3, 3, 3);
	}
} Triangle;
std::vector<Triangle> triangles;

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

// 求交结果
struct HitResult {
	Triangle* triangle = NULL;
	float distance = INF;
	vec3 光线命中点 = vec3(0, 0, 0);  // 光线命中点
	bool 是否命中 = 0;             // 是否命中
};

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

// ----------------------------------------------------------------------------- //

// 读取文件并且返回一个长字符串表示文件内容
std::string readShaderFile(std::string filepath) {
	std::string res, line;
	std::ifstream fin(filepath);
	if (!fin.is_open())
	{
		std::cout << "文件 " << filepath << " 打开失败" << std::endl;
		exit(-1);
	}
	while (std::getline(fin, line))
	{
		res += line + '\n';
	}
	fin.close();
	return res;
}

// 获取着色器对象
GLuint getShaderProgram(std::string fshader, std::string vshader) {
	// 读取shader源文件
	std::string vSource = readShaderFile(vshader);
	std::string fSource = readShaderFile(fshader);
	const char* vpointer = vSource.c_str();
	const char* fpointer = fSource.c_str();

	// 容错
	GLint success;
	GLchar infoLog[512];

	// 创建并编译顶点着色器
	GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, (const GLchar**)(&vpointer), NULL);
	glCompileShader(vertexShader);
	glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);   // 错误检测
	if (!success)
	{
		glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
		std::cout << "顶点着色器编译错误\n" << infoLog << std::endl;
		exit(-1);
	}

	// 创建并且编译片段着色器
	GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, (const GLchar**)(&fpointer), NULL);
	glCompileShader(fragmentShader);
	glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);   // 错误检测
	if (!success)
	{
		glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
		std::cout << "片段着色器编译错误\n" << infoLog << std::endl;
		exit(-1);
	}

	// 链接两个着色器到program对象
	GLuint shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glLinkProgram(shaderProgram);

	// 删除着色器对象
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);

	return shaderProgram;
}

// 读取 obj
void readObj(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);
		}
	}
}

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));
}

void addTriangle(Triangle* 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));
	}
}

// 光线和三角形求交 
float hitTriangle(Triangle* 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;

	光线命中坐标 = P;
	return INF;
}
//float intersect2(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 INF;
//}

// 构建 BVH
BVHNode* buildBVH(std::vector<Triangle>& triangles, 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(triangles[i].p1.x, min(triangles[i].p2.x, triangles[i].p3.x));
		float miny = min(triangles[i].p1.y, min(triangles[i].p2.y, triangles[i].p3.y));
		float minz = min(triangles[i].p1.z, min(triangles[i].p2.z, triangles[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(triangles[i].p1.x, max(triangles[i].p2.x, triangles[i].p3.x));
		float maxy = max(triangles[i].p1.y, max(triangles[i].p2.y, triangles[i].p3.y));
		float maxz = max(triangles[i].p1.z, max(triangles[i].p2.z, triangles[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(triangles.begin() + l, triangles.begin() + r + 1, cmpx);
	// 按 y 划分
	if (leny >= lenx && leny >= lenz)
		std::sort(triangles.begin() + l, triangles.begin() + r + 1, cmpy);
	// 按 z 划分
	if (lenz >= lenx && lenz >= leny)
		std::sort(triangles.begin() + l, triangles.begin() + r + 1, cmpz);

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

	return node;
}

// SAH 优化构建 BVH
BVHNode* buildBVHwithSAH(std::vector<Triangle>& triangles, 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(triangles[i].p1.x, min(triangles[i].p2.x, triangles[i].p3.x));
		float miny = min(triangles[i].p1.y, min(triangles[i].p2.y, triangles[i].p3.y));
		float minz = min(triangles[i].p1.z, min(triangles[i].p2.z, triangles[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(triangles[i].p1.x, max(triangles[i].p2.x, triangles[i].p3.x));
		float maxy = max(triangles[i].p1.y, max(triangles[i].p2.y, triangles[i].p3.y));
		float maxz = max(triangles[i].p1.z, max(triangles[i].p2.z, triangles[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(&triangles[0] + l, &triangles[0] + r + 1, cmpx);
		if (axis == 1) std::sort(&triangles[0] + l, &triangles[0] + r + 1, cmpy);
		if (axis == 2) std::sort(&triangles[0] + l, &triangles[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++) {
			Triangle& t = triangles[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--) {
			Triangle& t = triangles[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(&triangles[0] + l, &triangles[0] + r + 1, cmpx);
	if (Axis == 1) std::sort(&triangles[0] + l, &triangles[0] + r + 1, cmpy);
	if (Axis == 2) std::sort(&triangles[0] + l, &triangles[0] + r + 1, cmpz);

	// 递归
	node->left = buildBVHwithSAH(triangles, l, Split, n);
	node->right = buildBVHwithSAH(triangles, 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);
}

// 暴力查数组
HitResult hitTriangleArray(Ray ray, std::vector<Triangle>& triangles, int l, int r) {
	HitResult res;
	for (int i = l; i <= r; i++) {
		float d = hitTriangle(&triangles[i], ray);
		if (d < INF && d < res.distance) {
			res.distance = d;
			res.triangle = &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);
}

// 在 BVH 上遍历求交
HitResult hitBVH(Ray ray, std::vector<Triangle>& triangles, BVHNode* root) {
	if (root == NULL) return HitResult();

	// 是叶子 暴力查
	if (root->n > 0) {
		return hitTriangleArray(ray, triangles, 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);

	// 递归结果
	HitResult r1, r2, r3;
	if (d1>0) r1 = hitBVH(ray, triangles, root->left);
	if (d2>0) r2 = hitBVH(ray, triangles, root->right);



	r3= r1.distance < r2.distance ? r1 : r2;
	r3.光线命中点 = 光线命中坐标;
	r3.是否命中 = 1;
	return  r3;
}

// ----------------------------------------------------------------------------- //

// 显示回调函数
void display() {

	// 构造模型变换矩阵
	mat4 unit(    // 单位矩阵
		vec4(1, 0, 0, 0),
		vec4(0, 1, 0, 0),
		vec4(0, 0, 1, 0),
		vec4(0, 0, 0, 1)
	);
	mat4 scaleMat = scale(unit, scaleControl);   // xyz缩放0.6倍
	mat4 rotateMat = unit;    // 旋转
	rotateMat = rotate(rotateMat, radians(rotateControl.x), vec3(1, 0, 0)); // 绕x轴转
	rotateMat = rotate(rotateMat, radians(rotateControl.y), vec3(0, 1, 0)); // 绕y轴转
	rotateMat = rotate(rotateMat, radians(rotateControl.z), vec3(0, 0, 1)); // 绕z轴转
	mat4 modelMat = rotateMat * scaleMat;   // 变换级联 -- 生成模型变换矩阵

	GLuint mlocation = glGetUniformLocation(program, "model");  // 名为model的uniform变量的位置索引
	glUniformMatrix4fv(mlocation, 1, GL_FALSE, value_ptr(modelMat));

	GLuint clocation = glGetUniformLocation(program, "color");

	// 绘制
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);       // 清空窗口颜色缓存
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	glUniform3fv(clocation, 1, value_ptr(vec3(1, 0, 0)));
	glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);

	// 绘制 AABB 盒子  
	glUniform3fv(clocation, 1, value_ptr(vec3(1, 1, 1)));
	glDrawArrays(GL_LINES, vertices.size(), lines.size());
	glutSwapBuffers();  // 交换缓冲区
}

// 鼠标运动函数
double lastX = 0.0, lastY = 0.0;
void mouse(int x, int y)
{
	// 调整旋转
	rotateControl.y += -200 * (x - lastX) / 512;
	rotateControl.x += -200 * (y - lastY) / 512;
	lastX = x, lastY = y;
	glutPostRedisplay();    // 重绘
}

// 鼠标按下
void mouseDown(int button, int state, int x, int y) {
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
		lastX = x, lastY = y;
	}
}

// 鼠标滚轮函数
void mouseWheel(int wheel, int direction, int x, int y) {
	scaleControl.x += 1 * direction * 0.1;
	scaleControl.y += 1 * direction * 0.1;
	scaleControl.z += 1 * direction * 0.1;
	glutPostRedisplay();    // 重绘
}

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


// 相机参数
const double SCREEN_Z = 1.1;        // 视平面 z 坐标
const vec3 EYE = vec3(0, 0, 4.0);   // 相机位置
BVHNode* 	root;
//vec3 小图采样2[200 * 200]; 

void 渲染(){
#include<mmintrin.h>


	for (int i = 0; i < WIDTH; i +=2)
	{
		for (int j = 0; j < HEIGHT; j +=2)
		{

			// 像素坐标转投影平面坐标
			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 ray;
			ray.startPoint = coord;
			ray.direction = direction;

			vec3 color = vec3(0, 0, 0);
			/*	Ray ray;
			ray.startPoint = vec3(0, 0, 1);
			ray.direction = normalize(vec3(0.1, -0.1, -0.7));*/

			// HitResult res = hitTriangleArray(ray, triangles, 0, triangles.size()-1); // 暴力验证
			HitResult res = hitBVH(ray, triangles, root);
			//addTriangle(res.triangle);
			//addLine(ray.startPoint, ray.startPoint + ray.direction * vec3(5, 5, 5));

			if (res.triangle != NULL) { //判断是否命中  得到三角形既命中模型返回颜色
				color = vec3(0, 0.5, 0);

				//小图采样2[i + j] = color;
			}



			buffer[i][j] = RGB(color.x * 255, color.y * 255, color.z * 255);
			//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;
	}
}


int main() {

	// ------------------------------------------------------------------------------------------- //

	// 读 obj
	readObj("2.obj", vertices, indices);
	for (auto& v : vertices) {
		v.x *= 5.0, v.y *= 5.0, v.z *= 5.0;
		v.y -= 0.5;
	}
	//readObj("./models/quad.obj", vertices, indices);
	// 构建 Triangle 数组
	for (int i = 0; i < indices.size(); i += 3) {
		triangles.push_back(Triangle(vertices[indices[i]], vertices[indices[i + 1]], vertices[indices[i + 2]]));
	}

	// 建立 BVH 树
 //root = buildBVH(triangles, 0, triangles.size() - 1, 8);
 
		root = buildBVHwithSAH(triangles, 0, triangles.size() - 1, 80);

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

	dfsNlevel(root, 0, 1);   // 可视化第 n 层 bvh
							 /**/
	// ------------------------------------------------------------------------------------------- //

	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;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值