路径追踪 光栅化结合

30 篇文章 0 订阅

路径追踪 光栅化 2种渲染结果结合

如何移植到光线追踪研究一下,以下代码完整编译无误

OpenGL 后台渲染 完整代码
https://share.weiyun.com/AIbpC4vn

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

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

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




 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值