路径追踪 光栅化 2种渲染结果结合
如何移植到光线追踪研究一下,以下代码完整编译无误
OpenGL 后台渲染 完整代码
https://share.weiyun.com/AIbpC4vn
#include
#include
#include
#include
#include // 数学库支持
#include // openmp多线程加速
#include
#include
#include
#include
using namespace glm;
using namespace std;
int frames; clock_t clocks;
// --------------------- end of include --------------------- //
#define PI 3.1415926f
// 采样次数
const int SAMPLE = 1;
GLuint fbo = 0; // FBO对象的句柄
GLuint depthbuffer = 0;
GLuint 渲染到窗体target = 0; // 纹理对象的句柄
const double NEAR_PLANE = 1.0f;
const double FAR_PLANE = 1000.0f;
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 800;
// 输出图像分辨率
const int WIDTH = 400;
const int HEIGHT = 400;
// 相机参数
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; // 折射粗糙度
double 清漆 = 0.5f;
vec3 baseColor = vec3(0.3, 0.3, 0.3);
float metallic = 0.8f;
float clearcoat = 0.8f;
float clearcoatGloss = 0.8f;
}Material;
// 光线求交结果
typedef struct 光线求交结果
{
bool 是否命中 = false; // 是否命中
double 与交点的距离 = 0.0f; // 与交点的距离
vec3 光线命中点 = vec3(0, 0, 0); // 光线命中点
Material material; // 命中点的表面材质
}光线求交结果;
class Shape
{
public:
Shape() {}
virtual 光线求交结果 intersect(Ray ray) { return 光线求交结果(); }
};
std::vector<Shape*> shapes; // 几何物体的集合
// 三角形
class Triangle : public Shape
{
public:
Triangle() {}
Triangle(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;
}
};
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);
random_device rd;
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));
*/
}
// 法向半球随机向量
vec3 randomDirection(vec3 n)
{
/*
// 法向半球
vec3 d;
do
{
d = randomVec3();
} while (dot(d, n) < 0.0f);
return d;
*/
// 法向球
return normalize(randomVec3() + n);
}
// 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));
}
vec3 SampleHemisphere(float xi_1, float xi_2) {
float z = xi_1;
float r = max(0.0, sqrt(1.0 - z*z));
float phi = 2.0 * PI * xi_2;
return vec3(r * cos(phi), r * sin(phi), z);
}
// 生成第 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);
}
// 将向量 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;
}
// GTR1 重要性采样
vec3 SampleGTR1(float xi_1, float xi_2, vec3 V, vec3 N, float alpha) {
float phi_h = 2.0 * PI * xi_1;
float sin_phi_h = sin(phi_h);
float cos_phi_h = cos(phi_h);
float cos_theta_h = sqrt((1.0 - pow(alpha*alpha, 1.0 - xi_2)) / (1.0 - alpha*alpha));
float sin_theta_h = sqrt(max(0.0, 1.0 - cos_theta_h * cos_theta_h));
// 采样 "微平面" 的法向量 作为镜面反射的半角向量 h
vec3 H = vec3(sin_theta_h*cos_phi_h, sin_theta_h*sin_phi_h, cos_theta_h);
H = toNormalHemisphere(H, N); // 投影到真正的法向半球
// 根据 "微法线" 计算反射光方向
vec3 L = reflect(-V, H);
return L;
}
// GTR2 重要性采样
vec3 SampleGTR2(float xi_1, float xi_2, vec3 V, vec3 N, float alpha) {
float phi_h = 2.0 * PI * xi_1;
float sin_phi_h = sin(phi_h);
float cos_phi_h = cos(phi_h);
float cos_theta_h = sqrt((1.0 - xi_2) / (1.0 + (alpha*alpha - 1.0)*xi_2));
float sin_theta_h = sqrt(max(0.0, 1.0 - cos_theta_h * cos_theta_h));
// 采样 "微平面" 的法向量 作为镜面反射的半角向量 h
vec3 H = vec3(sin_theta_h*cos_phi_h, sin_theta_h*sin_phi_h, cos_theta_h);
H = toNormalHemisphere(H, N); // 投影到真正的法向半球
// 根据 "微法线" 计算反射光方向
vec3 L = reflect(-V, H);
return L;
}
float sqr(float x) {
return x*x;
}
float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay) {
return 1 / (PI * ax*ay * sqr(sqr(HdotX / ax) + sqr(HdotY / ay) + NdotH*NdotH));
}
// 按照辐射度分布分别采样三种 BRDF
vec3 SampleBRDF(float xi_1, float xi_2, float xi_3, vec3 V, vec3 N, Material material) {
float alpha_GTR1 = mix(0.1, 0.001, material.clearcoatGloss);
float alpha_GTR2 = max(0.001f, sqr(material.roughness));
// 辐射度统计
float r_diffuse = (1.0 - material.metallic);
float r_specular = 1.0;
float r_clearcoat = 0.25 * material.clearcoat;
float r_sum = r_diffuse + r_specular + r_clearcoat;
// 根据辐射度计算概率
float p_diffuse = r_diffuse / r_sum;
float p_specular = r_specular / r_sum;
float p_clearcoat = r_clearcoat / r_sum;
// 按照概率采样
float rd = xi_3;
// 漫反射
if (rd <= p_diffuse) {
return 漫反射重要性采样(xi_1, xi_2, N);
}
// 镜面反射
else if (p_diffuse < rd && rd <= p_diffuse + p_specular) {
return SampleGTR2(xi_1, xi_2, V, N, alpha_GTR2);
}
// 清漆
else if (p_diffuse + p_specular < rd) {
return SampleGTR1(xi_1, xi_2, V, N, alpha_GTR1);
}
return vec3(0, 1, 0);
}
float GTR1(float NdotH, float a) {
if (a >= 1) return 1 / PI;
float a2 = a*a;
float t = 1 + (a2 - 1)*NdotH*NdotH;
return (a2 - 1) / (PI*log(a2)*t);
}
float GTR2(float NdotH, float a) {
float a2 = a*a;
float t = 1 + (a2 - 1)*NdotH*NdotH;
return a2 / (PI * t*t);
}
// 获取 BRDF 在 L 方向上的概率密度
float BRDF_Pdf(vec3 V, vec3 N, vec3 L, Material material) {
float NdotL = dot(N, L);
float NdotV = dot(N, V);
if (NdotL < 0 || NdotV < 0) return 0;
vec3 H = normalize(L + V);
float NdotH = dot(N, H);
float LdotH = dot(L, H);
// 镜面反射 -- 各向同性
float alpha = max(0.001f, sqr(material.roughness));
float Ds = GTR2(NdotH, alpha);
float Dr = GTR1(NdotH, mix(0.1, 0.001, material.清漆)); // 清漆
// 分别计算三种 BRDF 的概率密度
float pdf_diffuse = NdotL / PI;
float pdf_specular = Ds * NdotH / (4.0 * dot(L, H));
float pdf_clearcoat = Dr * NdotH / (4.0 * dot(L, H));
// 辐射度统计
float r_diffuse = (1.0 - material.metallic);
float r_specular = 1.0;
float r_clearcoat = 0.25 * material.clearcoat;
float r_sum = r_diffuse + r_specular + r_clearcoat;
// 根据辐射度计算选择某种采样方式的概率
float p_diffuse = r_diffuse / r_sum;
float p_specular = r_specular / r_sum;
float p_clearcoat = r_clearcoat / r_sum;
// 根据概率混合 pdf
float pdf = p_diffuse * pdf_diffuse
+ p_specular * pdf_specular
+ p_clearcoat * pdf_clearcoat;
pdf = max(1e-10f, pdf);
return pdf;
}
template<class T>
T clamp2(T x, T min, T max)
{
if (x > max)
return max;
if (x < min)
return min;
return x;
}
float SchlickFresnel(float u) {
float m = clamp2((float)1 - u, 0.0f, 1.0f);
float m2 = m*m;
return m2*m2*m; // pow(m,5)
}
vec3 BRDF_Evaluate(vec3 V, vec3 N, vec3 L, Material material) {
vec3 Cdlin = material.baseColor;
float NdotL = dot(N, L);
float NdotV = dot(N, V);
//if (NdotL < 0 || NdotV < 0) return 0;
vec3 H = normalize(L + V);
float NdotH = dot(N, H);
float LdotH = dot(L, H);
// 漫反射
float Fd90 = 0.5 + 2.0 * LdotH * LdotH * material.roughness;
float FL = SchlickFresnel(NdotL);
float FV = SchlickFresnel(NdotV);
float Fd = mix(1.0f, Fd90, FL) * mix(1.0f, Fd90, FV);
vec3 diffuse = Fd * Cdlin / PI;
diffuse.x *= (1.0 - material.metallic);
diffuse.y *= (1.0 - material.metallic);
diffuse.z *= (1.0 - material.metallic);
return diffuse;
}
//路径追踪 -- 重要性采样版本
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 = rand() % 500;
float xi_2 = rand() % 1500;
float xi_3 = rand() % 3000;
// 采样 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.光线命中点;
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;
}
// 初始化摄像机
void 初始化摄像机(void)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, (double)SCREEN_WIDTH / (double)SCREEN_HEIGHT, NEAR_PLANE, FAR_PLANE);
//gluLookAt(0, 0, 4.0, 0, 0, 0, 0, 1, 0);
gluLookAt(0.0, 0.0, 40, 0.0, 0.0, 0.0, 0.0, 1.0, 1000.0);
// 各种变换应该在GL_MODELVIEW模式下进行
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Z-buffer
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// 启用2D贴图
glEnable(GL_TEXTURE_2D);
}
// 初始化几何形体
void 初始化几何形体(void)
{
// 创建纹理
glGenTextures(1, &渲染到窗体target);
glBindTexture(GL_TEXTURE_2D, 渲染到窗体target);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
/*
// 创建深度缓冲区
glGen渲染到窗体buffersEXT(1, &depthbuffer);
glBind渲染到窗体bufferEXT(GL_渲染到窗体BUFFER_EXT, depthbuffer);
gl渲染到窗体bufferStorageEXT(GL_渲染到窗体BUFFER_EXT, GL_DEPTH_COMPONENT, WIDTH, HEIGHT);
glBind渲染到窗体bufferEXT(GL_渲染到窗体BUFFER_EXT, 0);
*/
// 创建FBO对象
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 渲染到窗体target, 0);
//glFramebuffer渲染到窗体bufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_渲染到窗体BUFFER_EXT, depthbuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
}
}
void 光照(void)
// 定义太阳光源,它是一种白色的光源
{
GLfloat sun_light_position[] = { 0.0f, 0.0f, 100.0f, 1.0f }; // 光源的位置
GLfloat sun_light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
GLfloat sun_light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat sun_light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glLightfv(GL_LIGHT0, GL_POSITION, sun_light_position); //指定第0号光源的位置
glLightfv(GL_LIGHT0, GL_AMBIENT, sun_light_ambient); //GL_AMBIENT表示各种光线照射到该材质上,
//经过很多次反射后最终遗留在环境中的光线强度(颜色)
glLightfv(GL_LIGHT0, GL_DIFFUSE, sun_light_diffuse); //漫反射后~~
glLightfv(GL_LIGHT0, GL_SPECULAR, sun_light_specular);//镜面反射后~~~
glEnable(GL_LIGHT0); //使用第0号光照
glEnable(GL_LIGHTING); //在后面的渲染中使用光照
glEnable(GL_DEPTH_TEST); //这句是启用深度测试,这样,在后面的物体会被挡着,例如房子后面有棵树,如果不启用深度测试,
//你先画了房子再画树,树会覆盖房子的;但启用深度测试后无论你怎么画,树一定在房子后面(被房子挡着)
}
vec4 环境色 = vec4(1, 2, 3, 4);
vec4 漫反射度 = vec4(1, 2, 3, 4);
vec4 镜面反射 = vec4(1, 2, 3, 4);
vec4 材质发射 = vec4(1, 2, 3, 4);
GLfloat 光滑 = 15.0f; // 球体比较的光滑
vec3 大小 = vec3(0.5, 40, 32);
void 球体(int x, int y, int z) {
GLfloat 环境的[] = { 环境色.x,环境色.y,环境色.z, 环境色.w };
GLfloat 漫反射B[] = { 漫反射度.x,漫反射度.y,漫反射度.z, 漫反射度.w }; // 漫反射的颜色(也就是该对象的颜色) 定义了黄色的
GLfloat 镜面反射B[] = { 镜面反射.x,镜面反射.y,镜面反射.z, 镜面反射.w }; // 材质的镜面反射颜色 定义了白色
GLfloat 材质发射B[] = { 材质发射.x,材质发射.y,材质发射.z, 材质发射.w }; // 材质发射出的光的颜色,定义发出微微的黄色的光
glPushMatrix();
glMaterialfv(GL_FRONT, GL_AMBIENT, 环境的);
glMaterialfv(GL_FRONT, GL_DIFFUSE, 漫反射B);
glMaterialfv(GL_FRONT, GL_SPECULAR, 镜面反射B);
glMaterialfv(GL_FRONT, GL_EMISSION, 材质发射B);
glMaterialf(GL_FRONT, GL_SHININESS, 光滑);
glTranslatef(x, y, z);
//如果使用glutSolidSphere函数来绘制球体,则该函数会自动的指定这些法线向量,
//不必再手工指出。如果是自己指定若干的顶点来绘制一个球体,则需要自己指定法线向量。
glutSolidSphere(大小.x, 大小.y, 大小.z);
glPopMatrix();
}
void 渲染模型() {
// 渲染
glClearColor(1, 1, 1, 1);//背景清除
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
光照();
大小 = vec3(3, 40, 32);//三个都一样
环境色 = vec4(1.0f, 1.0f, 1.0f, 1.0f);
漫反射度 = vec4(1.0f, 1.0f, 1.0f, 1.0f);
镜面反射 = vec4(1.0f, 1.0f, 0.0f, 1.0f);
材质发射 = vec4(0.2f, 0.2f, 0.0f, 1.0f);
光滑 = 15.0f; // 球体比较的光滑
球体(-6.5f, -7.0f, 0.0f);
大小 = vec3(4, 40, 32);//三个都一样
环境色 = vec4(1.0f, 1.0f, 1.0f, 1.0f);
漫反射度 = vec4(1.0f, 1.0f, 1.0f, 1.0f);
镜面反射 = vec4(1.0f, 1.0f, 0.0f, 1.0f);
材质发射 = vec4(0.2f, 0.2f, 0.0f, 1.0f);
光滑 = 15.0f; // 球体比较的光滑
球体(0.0f, -3.0f, 0.0f);
大小 = vec3(3, 40, 32);//三个都一样
环境色 = vec4(1.0f, 1.0f, 1.0f, 1.0f);
漫反射度 = vec4(1.0f, 1.0f, 1.0f, 1.0f);
镜面反射 = vec4(1.0f, 1.0f, 0.0f, 1.0f);
材质发射 = vec4(0.2f, 0.2f, 0.0f, 1.0f);
光滑 = 15.0f; // 球体比较的光滑
球体(6.5f, 1.0f, 0.0f);
}
// 路径追踪
vec3 路径追踪(vector<Shape*>& shapes, Ray ray, int depth)
{
if (depth > 8) return vec3(0);
光线求交结果 res = shoot(shapes, ray, 0);
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);
// 否则继续
Ray randomRay;
randomRay.startPoint = res.光线命中点;
randomRay.direction = randomDirection(res.material.normal);
vec3 L;
vec2 uv = sobol低差异序列(frames + 1, 0);
L = 漫反射重要性采样(uv.x, uv.y, randomRay.direction);
//L = SampleHemisphere(uv.x, uv.y);
//L = toNormalHemisphere(L, randomRay.direction);
randomRay.direction = L;
vec3 color = vec3(0);
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;
}
vec3 光线追踪(std::vector<Shape*>& 场景, Ray ray, int 光追深度)
{
float 反光;
光线求交结果 res;
res = shoot(shapes, ray, 0);
if (!res.是否命中) return vec3(0); // 未命中
// 如果发光则返回颜色
if (res.material.isEmissive) return res.material.color;
// 否则继续
Ray randomRay;
randomRay.startPoint = res.光线命中点;
randomRay.direction = randomDirection(res.material.normal);
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;
}
// 渲染到纹理
void 渲染到纹理(void)
{
//glBindTexture(GL_TEXTURE_2D, 0); // 取消绑定,因为如果不取消,渲染到纹理的时候会使用纹理本身
渲染模型();//必须在这一行
// 绑定渲染目标
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glViewport(0, 0, WIDTH, HEIGHT);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
int ll = 0; vec3 微积分 = vec3(0, 0, 0); vec3 微积分2 = vec3(0, 0, 0); vec3 前面原色 = vec3(0, 0, 0);
GLuint texture;
typedef unsigned int Color;
static Color buffer[HEIGHT][WIDTH];
vec3 累计积分[WIDTH * HEIGHT];
vec3 上个原色;
vec3 离线交点颜色[WIDTH][HEIGHT]; vec3 离线交点颜色2[WIDTH][HEIGHT];
vec3 离线交点积分[WIDTH][HEIGHT]; int 离线交点积分2[WIDTH][HEIGHT];
vec3 光栅化颜色[WIDTH][HEIGHT];
光线求交结果 离线交点;
int a = 400; int 矩形 = 80;
double* image = new double[WIDTH * HEIGHT * 3];
double* imageA = new double[WIDTH * HEIGHT * 3];
vec3 小图采样2; vec3 小图采样3; vec3 小图采样A[HEIGHT][WIDTH]; vec3 小图积分A[HEIGHT][WIDTH];
vec3 小图积分[HEIGHT][WIDTH];
// ---------------------------- end of functions ---------------------------- //
void 提取fbo图片() {
//从颜色缓冲区中读取数据
int tmpPixelSize = WIDTH*HEIGHT * 4;
char* tmpBuffer = (char*)malloc(tmpPixelSize);
glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, tmpBuffer);
int i = 0;
for (int k = HEIGHT - 1; k >= 0; k--)
{
for (int j = 0; j < WIDTH; j++)
{
//buffer[k][j] = RGB(tmpBuffer[i], tmpBuffer[i + 1], tmpBuffer[i + 2]);
光栅化颜色[k][j].x = tmpBuffer[i];
光栅化颜色[k][j].y = tmpBuffer[i + 1];
光栅化颜色[k][j].z = tmpBuffer[i + 2];
i += 4;
}
}
}
int p7;
int 采样进度 = 1;// 每次采样的亮度
int 采样亮度 = 20;// 每次采样的亮度
int AC = 0;
void 渲染() {
渲染到纹理();
提取fbo图片();
glClearColor(1, 1, 0, 1);//背景清除 110 1 黄色
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int 幸运阈值3 = 0;
int 幸运阈值 = 1; int 幸运阈值2 = 1; vec3 AA = vec3(0.1, 0.2, 0.2); vec3 BB = vec3(2, 2, 2);
vec3 小图采样; int 渲染进度; int 小图指针; Ray 离线光; int 对焦值, 对焦A, 对焦B, 对焦C; int 对焦清晰度;
对焦清晰度 = 10; int j变量值记录;
vec3 color; Ray ray; vec3 s;
光线求交结果 res;
采样进度++; if (采样进度 >3) {
采样亮度 = 20; 对焦清晰度 = 200; AC = 1;
}
double BRIGHTNESS = (2.0f * 3.1415926f) * (1.0f / double(采样亮度));
double* p2;
for (int i5 = 0; i5 < 1; i5++) {
p2 = imageA;
for (int i = 0; i < 矩形 + 40; i++)
{
for (int j = 0; j < 矩形; j++)
{
j变量值记录 = j;
// 像素坐标转投影平面坐标
double x = 2.0 * double(j) / double(矩形) - 1.0;
double y = 2.0 * double(矩形 - i) / double(矩形) - 1.0;
// MSAA
x += (randf() - 0.5f) / double(矩形);
y += (randf() - 0.5f) / double(矩形);
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);
color = vec3(0, 0, 0);
if (res.是否命中)
{
// 命中光源直接返回光源颜色
if (res.material.isEmissive)
{
color = res.material.color;
}
// 命中实体则选择一个随机方向重新发射光线并且进行路径追踪
else
{
// 根据交点处法向量生成交点处反射的随机半球向量
Ray randomRay;
randomRay.startPoint = res.光线命中点;
randomRay.direction = randomDirection(res.material.normal);
vec3 L;
vec2 uv = sobol低差异序列(frames + 1, 0);
L = 漫反射重要性采样(uv.x, uv.y, randomRay.direction);
//L = SampleHemisphere(uv.x, uv.y);
//L = toNormalHemisphere(L, randomRay.direction);
randomRay.direction = L;
// 根据反射率决定光线最终的方向
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);
//微积分 = 光线追踪(shapes, randomRay, 4);
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);
//微积分 = 光线追踪(shapes, randomRay, 4);
color = 微积分;
}
else // 漫反射
{
s = res.material.color;
//微积分 = 路径追踪(shapes, randomRay, 0);
微积分 = 光线追踪(shapes, randomRay, 8);
//color = 微积分;
color = 微积分*s;
}
小图积分A[i][j] = color;
小图采样A[i][j] = res.material.color;
}
}
}
}
}
p2 = imageA; double* p = image; int t2; double FC = 1.0f; double FB = 0.0f; int L = 5;
for (int i = 0; i < WIDTH; i++)
{
for (int j = 0; j < HEIGHT; j++)
{
int t = 0;
if (i / 10<20)
{
t = 1;
}
else
{
t = 0;
}
{
int t2 = 0;
if (j / 10 < 20)
{
t2 = 1;
}
else
{
t2 = 0;
}
离线交点颜色[i][j] = 小图采样A[i / L + t][j / L + t2];
小图积分[i][j] = 小图积分A[i / L + t][j / L + t2];
小图采样 = 光栅化颜色[i][j];
小图采样 *= 小图积分[i][j];
double BRIGHTNESS2 = (2.0f * 3.1415926f) * (1.0f / double(采样进度 + 100));
小图采样 *= BRIGHTNESS2;
*p += 小图采样.x; p++; // R 通道
小图采样2.x = *p;
*p += 小图采样.y; p++; // G 通道
小图采样2.y = *p;
*p += 小图采样.z; p++; // B 通道
小图采样2.z = *p;
buffer[i][j] = RGB(小图采样2.x * 255, 小图采样2.y * 255, 小图采样2.z * 255);
}
}
}
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, WIDTH, HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
glLoadIdentity();
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
int buf大小 = 25;
glVertex2f(-buf大小, buf大小);
glTexCoord2f(0, 1);
glVertex2f(-buf大小, -buf大小);
glTexCoord2f(1, 1);
glVertex2f(buf大小, -buf大小);
glTexCoord2f(1, 0);
glVertex2f(buf大小, buf大小);
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;
}
int main()
{
Sphere s1 = Sphere(vec3(-0.65, -0.7, 0.0), 0.3, 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;
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 Triangle(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 Triangle(vec3(0.15, 0.4, -0.6), vec3(-0.15, -0.95, -0.6), vec3(0.15, -0.95, -0.6), YELLOW));
Triangle tt = Triangle(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);
// 发光物
Triangle l1 = Triangle(vec3(0.4, 0.99, 0.4), vec3(-0.4, 0.99, -0.4), vec3(-0.4, 0.99, 0.4), WHITE);
Triangle l2 = Triangle(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 Triangle(vec3(1, -1, 1), vec3(-1, -1, -1), vec3(-1, -1, 1), WHITE));
shapes.push_back(new Triangle(vec3(1, -1, 1), vec3(1, -1, -1), vec3(-1, -1, -1), WHITE));
// top
shapes.push_back(new Triangle(vec3(1, 1, 1), vec3(-1, 1, 1), vec3(-1, 1, -1), WHITE));
shapes.push_back(new Triangle(vec3(1, 1, 1), vec3(-1, 1, -1), vec3(1, 1, -1), WHITE));
// back
shapes.push_back(new Triangle(vec3(1, -1, -1), vec3(-1, 1, -1), vec3(-1, -1, -1), CYAN));
shapes.push_back(new Triangle(vec3(1, -1, -1), vec3(1, 1, -1), vec3(-1, 1, -1), CYAN));
// left
shapes.push_back(new Triangle(vec3(-1, -1, -1), vec3(-1, 1, 1), vec3(-1, -1, 1), BLUE));
shapes.push_back(new Triangle(vec3(-1, -1, -1), vec3(-1, 1, -1), vec3(-1, 1, 1), BLUE));
// right
shapes.push_back(new Triangle(vec3(1, 1, 1), vec3(1, -1, -1), vec3(1, -1, 1), RED));
shapes.push_back(new Triangle(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");
GLenum err = glewInit(); // GLEW的初始化必须在OpenGL上下文被创建之后调用
初始化摄像机();
初始化几何形体();
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;
}