#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和模型 自己放在编译目录