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;// MSAAx += (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);// 计算 AABBfor (int i = l; i <= r; i++) {// 最小点 AAfloat 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);// 最大点 BBfloat 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);// 计算 AABBfor (int i = l; i <= r; i++) {// 最小点 AAfloat 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);// 最大点 BBfloat 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 以对齐到下标 0for (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 以对齐到下标 0for (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 / directionvec3 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;// MSAAx += (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() {// ------------------------------------------------------------------------------------------- //// 读 objreadObj("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;
}

路径追踪 SAH优化的Bvh相关推荐

  1. 闫令琪:Games101 现代计算机图形学-光线追踪(三):渲染方程和路径追踪path ray tracing 作业Assignment07解析

    文章目录 0 whitted光线追踪的局限 1 辐射度量学 1.1 光线的表示 Radiance 1.2 物体表面上一个点的亮度 Irradiance 1.3 BRDF(Bidirectional R ...

  2. 儿童手表运动轨迹和路径追踪_如何将智能手表或健身追踪器用作静音闹钟

    儿童手表运动轨迹和路径追踪 When you need to wake up without disturbing everyone around you a silent vibration-bas ...

  3. 光线追踪渲染实战:蒙特卡洛路径追踪及其c++实现

    项目代码仓库: GitHub:https://github.com/AKGWSB/EzRT gitee:https://gitee.com/AKGWSB/EzRT 目录 写在前面 光线追踪简介 渲染方 ...

  4. 路径追踪相关的一些内容

    序 引用自: GAMES101-现代计算机图形学入门-闫令琪_哔哩哔哩_bilibili 在了解了 这个: (62条消息) 辐射度量学与相关物理量_averagePerson的博客-CSDN博客 这个 ...

  5. 19、计算机图形学——蒙特卡洛路径追踪

    一.蒙特卡洛积分 蒙特卡洛积分主要解决的问题是当被积函数很难被以函数的形式表示时,需要对该被积函数指定概率密度函数并进行多次采样.然后用采样得到的局部面积除以局部采样点的概率来近似得到整体的面积(积分 ...

  6. 数据结构之并查集:路径压缩继续优化并查集——20

    路径压缩继续优化并查集 在实现的并查集中,在合并操作merge(item1, item2)时,会不管两个元素所在的分组大小,总是将item 1的分组合并到item2的分组,这样可能会导致树的深度无必要 ...

  7. Q136:PBRT-V3,双向路径追踪(Bidirectional Path Tracing)(16.3章节)

    之前了解了路径追踪,参考如下: Q124:PBRT-V3,"路径追踪"积分器(14.5章节) 接下来,先回忆一下Path Tracing,然后具体了解Bidirectional P ...

  8. GAMES101课程学习笔记—Lec 14(2)~16:Ray Tracing(2) BRDF、渲染方程、全局光照、路径追踪

    GAMES101课程学习笔记-Lec 14(2)~16:Ray Tracing(2) BRDF.渲染方程.全局光照.路径追踪 0 引入--辐射度量学概述 1 相关概念 1.1 Radiant Ener ...

  9. 重要性采样和多重重要性采样在路径追踪中的应用

    重要性采样和多重重要性采样在路径追踪中的应用 1 蒙特卡洛路径追踪简要回顾 1.1 算法主要流程 1.2 半球面均匀采样方法 2 重要性采样的运用 2.1 简单例子与基本概念 2.2 路径追踪中的重要 ...

最新文章

  1. Python之%s%d%f
  2. Error in variable_response could not find function “variable_response“
  3. 【直播回顾】云栖社区特邀专家徐雷Java Spring Boot开发实战系列课程(第19讲):Java Spring Cloud微服务架构模式与开发实战...
  4. Homebrew替换源
  5. open api的鉴权以及oauth2.0协议
  6. 在js在页面中添加百度统计代码
  7. 英特尔傲腾内存linux,英特尔傲腾内存怎么样?intel傲腾内存优点和缺点你知道吗?...
  8. QML工作笔记-仿前端滑出界面(JavaScript)
  9. 第一次参加项目个人工作总结 (转)
  10. Windows恶搞脚本,太实用了医院WiFi很快
  11. 后端CORS解决跨域问题
  12. oracle stream参数,oracle stream实验(双向复制)
  13. Java并发工具类之CountDownLatch
  14. Web组态—低代码物联网组态平台
  15. AntDesign Upload组件上传图片
  16. 【测试】26.用户需求规格跟踪矩阵
  17. JAVA数组内存分析 面向对象 类和对象 创建对象的内存分析 成员变量 局部变量
  18. python怎么加图片_python图片加水印
  19. ubuntu 16.04登陆界面循环(输密码闪屏回到登陆界面)排查过程
  20. elastix2.5vtigercrm5.2.1来电弹屏和点击呼叫的配置

热门文章

  1. PCI、PCI-X、PCI-E、PCI-E Card、Mini PCI-E、M.2、Add-in Card 它们有啥区别?这些概念你搞清楚了吗?
  2. 游戏盾一个深藏功与名的盾
  3. C语言 strstr()函数介绍
  4. python end用法_python中end的使用方法
  5. python中circle函数圆心位置_python opencvfinding circle(Sun),圆心坐标来自pictu
  6. 关于将pem证书转为jellyfin可以使用的pkcs12证书
  7. [ISA]QQ通过ISA2006代理登陆无法接收发送文件和图片表情的解决方法
  8. 中国哲学简史学习笔记
  9. 合天——SQL注入实验一
  10. WIN10下安装SQL SERVER 2017