路径追踪 随机追踪法提速一倍

本文介绍了一个使用光线追踪技术进行3D渲染的方法,结合多线程加速。算法采用随机采样策略,一半的像素使用前一个像素的颜色,另一半进行光线追踪。通过调整采样次数和随机性,实现了速度和质量的平衡。同时,代码中包含了随机向量生成、物体表面材质定义、光线求交计算等功能,展示了光线追踪的基本流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

随机2分之一进行 光线追踪,另一半取前一个像素颜色,效果还行,速度提升一倍

#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>

using namespace glm;
using namespace std;
int frames; clock_t clocks;
// --------------------- end of include --------------------- //


#define PI 3.1415926f
// 采样次数
const int SAMPLE = 1;


int p7;

// 输出图像分辨率
const int WIDTH = 300;
const int HEIGHT = WIDTH;

// 相机参数
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;
	}
};
Shape* 屏幕优先物体[WIDTH*HEIGHT][4];
//Shape* 屏幕优先物体[WIDTH *HEIGHT];
//std::vector<Shape*> 屏幕优先物体;

Shape* shape2 = new Shape; int 深度A = 0;
// 返回距离最近 hit 的结果
光线求交结果 shoot(std::vector<Shape*>& shapes, Ray ray, int 像素, int 深度)
{
	光线求交结果 res, r;
	res.与交点的距离 = 1145141919.810f; // inf
	int 第一层记忆 = 0;


	if (p7 > 50) {
		if (像素 > 0 && 深度 == 0) {

			r = 屏幕优先物体[像素][深度]->intersect(ray);
			if (r.是否命中 && r.与交点的距离 < res.与交点的距离) {
				////std::cout << "像素  " << 像素 << std::endl;
				res = r;  // 记录距离最近的求交结果
				return res;
			}
			

		}
	}

	if (深度A == 0) {
		深度A++; 第一层记忆 = 1;
		r = shape2->intersect(ray);
		if (r.是否命中 && r.与交点的距离 < res.与交点的距离) {
			res = r;  // 记录距离最近的求交结果
			return res;
		}
	}

	/*if (p7 > 4 && 深度 == 0) {
	std::cout << "像素  " << 像素 << std::endl;
	}*/

	for (int k = 0; k < shapes.size(); ++k)
	{
		r = shapes[k]->intersect(ray);
		if (r.是否命中 && r.与交点的距离 < res.与交点的距离) {

			res = r;  // 记录距离最近的求交结果
					  //if (深度 == 0 ) {

			屏幕优先物体[像素][深度] = shapes[k];
			//}
			if (第一层记忆 == 1) {
				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;

		//vec3 L;
		vec2 uv = sobol低差异序列(p7, 1);
		//L = 漫反射重要性采样(uv.x, uv.y, res.material.normal);

		//L = SampleHemisphere(uv.x, uv.y);
		//L = toNormalHemisphere(L, randomRay.direction);
		//randomRay.direction = L;
		// 采样 BRDF 得到一个方向 L
		vec3 L = SampleBRDF(uv.x, uv.y, 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, maxBounce);
		// 获取 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;
}

uint wang_hash(uint seed) {
	seed = uint(seed ^ uint(61)) ^ uint(seed >> uint(16));
	seed *= uint(9);
	seed = seed ^ (seed >> 4);
	seed *= uint(0x27d4eb2d);
	seed = seed ^ (seed >> 15);
	return seed;
}

vec3 pix;
vec2 CranleyPattersonRotation(vec2 p) {
	uint pseed = uint(
		uint((pix.x * 0.5 + 0.5) * WIDTH)  * uint(1973) +
		uint((pix.y * 0.5 + 0.5) * HEIGHT) * uint(9277) +
		uint(114514 / 1919) * uint(26699)) | uint(1);

	float u = float(wang_hash(pseed)) / 4294967296.0;
	float v = float(wang_hash(pseed)) / 4294967296.0;

	p.x += u;
	if (p.x>1) p.x -= 1;
	if (p.x<0) p.x += 1;

	p.y += v;
	if (p.y>1) p.y -= 1;
	if (p.y<0) p.y += 1;

	return p;
}

// 路径追踪
vec3 路径追踪(vector<Shape*>& shapes, Ray ray, int depth)
{

	if (depth > 4) return vec3(1);
	光线求交结果 res = shoot(shapes, ray, 0, depth);

	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低差异序列(p7 + 1, 1);
	uv = CranleyPattersonRotation(uv);
	L = 漫反射重要性采样(uv.x, uv.y, res.material.normal);

	//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;    // 和原颜色混合

	}
	//color=pathTracingImportanceSampling(res, depth);
	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;

}

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]; vec3 期待渲染近似效果[WIDTH][HEIGHT];
 
光线求交结果 离线交点;

int a = 400; int 矩形 = 50;
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 ---------------------------- //



int 采样进度 = 1;// 每次采样的亮度
int 采样亮度 = 20;// 每次采样的亮度
int AC = 0;
int 小图渲染次数 =1; //这里决定开局的亮度和清晰度,否则开始很暗
int 对焦清晰度 = 200;
int  第一帧亮度 = 300;
int  多少次结束 = 100+1;
#include <thread>
#include <iostream>

DWORD WINAPI myfun1(LPVOID lpParameter); //声明线程函数
DWORD WINAPI myfun2(LPVOID lpParameter);

//分别实现线程函数,并返回值
DWORD WINAPI myfun1(LPVOID lpParameter)
{
	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 j变量值记录;
	vec3 color;			Ray ray; vec3 s;
	光线求交结果 res;

	采样进度++;		if (采样进度 >1) {
		采样亮度 = 5; 对焦清晰度 = 2; AC = 1;
	}
	double BRIGHTNESS = (2.0f * 3.1415926f) * (1.0f / double(采样亮度));
	double* p;
	double A4 = 0.05;
	if (p7 < 多少次结束)
	{

		p = image;
		for (int i = 0; i < HEIGHT; i += 2)
		{
			for (int j = 0; j < WIDTH; 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, 0);
				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低差异序列(p7 + 1, 1);
						//uv = CranleyPattersonRotation(uv);
						L = 漫反射重要性采样(uv.x, uv.y, res.material.normal);

						//L = SampleHemisphere(uv.x, uv.y);
						//L = toNormalHemisphere(L, randomRay.direction);
						randomRay.direction = L;
						// 根据反射率决定光线最终的方向
						double r = randf();
						int b = 0;
						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 = 微积分;
							b = 1;
						}
						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 = 微积分;
							b = 1;
						}
						else    // 漫反射
						{
							s = res.material.color;
							微积分 = 路径追踪(shapes, randomRay, 0);
							//微积分 = 光线追踪(shapes, randomRay, 4);

							//微积分 = 微积分+ 微积分;
							color = 微积分 *s;
						}
						/*			小图积分A[i][j] = color;
						小图采样A[i][j] = res.material.color;
						*/
						上个原色 = res.material.color;
						离线交点颜色[i][j] = res.material.color;
						离线交点积分[i][j] += 微积分;
						小图采样 = color;
					/*	小图采样 = color * 离线交点积分[i][j - 1];
						小图采样 /= 2;*/
						/*		 				小图采样A[i][j - 1] *= 0.1;
						小图采样 = 小图采样 + 小图采样A[i][j - 1];
						小图采样 /=4;*/




					}

					int a5 = 1000;
					if (p7 > 10)
					{
						a5 = 1000 + p7;
					}

					double BRIGHTNESS2 = (2.0f * 3.1415926f) * (1.0f / double(a5));
					小图采样 *= BRIGHTNESS2;
				}
					}
				else
				{

				小图采样 = 上个原色 * 微积分;
				//小图采样 *= 0.01;

				int a5 = 1000;
				if (p7 > 200)
				{
				a5 = p7 + 1000;
				}
				double BRIGHTNESS2 = (2.0f * 3.1415926f) * (1.0f / double(a5));
				小图采样 *= BRIGHTNESS2;
				}
			/*	if (p7<2) {
					double BRIGHTNESS2 = (2.0f * 3.1415926f) * (1.0f / double(第一帧亮度));

					小图采样 = 离线交点颜色[i][j] * 小图积分[i][j];
					小图采样 *= BRIGHTNESS2;
				}*/
					if (p7<2) {
						屏幕颜色记忆[i][j] = res.material.color;
				}
				*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);



			}
		}

	}


	return 0;
}

DWORD WINAPI myfun2(LPVOID lpParameter)
{

	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 j变量值记录;
	vec3 color;			Ray ray; vec3 s;
	光线求交结果 res;


	double BRIGHTNESS = (2.0f * 3.1415926f) * (1.0f / double(采样亮度));
	double* p;
	double A4 = 0.05;
	if (p7 < 多少次结束)
	{

		p = image;
		for (int i = 1; i < HEIGHT; i += 2)
		{
			for (int j = 0; j < WIDTH; 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, 0);
				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低差异序列(p7 + 1, 1);
						//uv = CranleyPattersonRotation(uv);
						L = 漫反射重要性采样(uv.x, uv.y, res.material.normal);

						//L = SampleHemisphere(uv.x, uv.y);
						//L = toNormalHemisphere(L, randomRay.direction);
						randomRay.direction = L;
						// 根据反射率决定光线最终的方向
						double r = randf();
						int b = 0;
						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 = 微积分;
							b = 1;
						}
						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 = 微积分;
							b = 1;
						}
						else    // 漫反射
						{
							s = res.material.color;
							微积分 = 路径追踪(shapes, randomRay, 0);
							//微积分 = 光线追踪(shapes, randomRay, 4);

							//微积分 = 微积分+ 微积分;
							color = 微积分 *s;
						}
						/*			小图积分A[i][j] = color;
						小图采样A[i][j] = res.material.color;
						*/
						上个原色 = res.material.color;
						离线交点颜色[i][j] = res.material.color;
						离线交点积分[i][j] += 微积分;
						小图采样 = color;
			/*			小图采样 = color*离线交点积分[i][j-1];
						小图采样 /= 2;*/
						/*		 				小图采样A[i][j - 1] *= 0.1;
						小图采样 = 小图采样 + 小图采样A[i][j - 1];
						小图采样 /=4;*/




					}

					int a5 = 1000;
					if (p7 > 10)
					{
						a5 = 1000 + p7;
					}

					double BRIGHTNESS2 = (2.0f * 3.1415926f) * (1.0f / double(a5));
					小图采样 *= BRIGHTNESS2;
				}
					}
				else
				{

				小图采样 = 上个原色  * 微积分;
				//小图采样 *= 0.01;

				int a5 = 1000;
				if (p7 > 200)
				{
				a5 = p7 + 1000;
				}
				double BRIGHTNESS2 = (2.0f * 3.1415926f) * (1.0f / double(a5));
				小图采样 *= BRIGHTNESS2;
				}
		/*		if (p7<2) {
					double BRIGHTNESS2 = (2.0f * 3.1415926f) * (1.0f / double(第一帧亮度));

					小图采样 = 离线交点颜色[i][j] * 小图积分[i][j];
					小图采样 *= 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);



			}
		}

	}

	return 0;
}
void 渲染() {

	//if (p7 < 1) {
	//	vec3 color;			Ray ray;	光线求交结果 res;
	//	double*   p2 = imageA;
	//	for (int i5 = 0; i5 <小图渲染次数; i5++)
	//	{

	//		for (int i = 0; i < 矩形; i++)
	//		{

	//			for (int j = 0; 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, 0);
	//				color = vec3(0, 0, 0);
	//				if (res.是否命中)
	//				{
	//					// 命中光源直接返回光源颜色
	//					if (res.material.isEmissive)
	//					{
	//						color = res.material.color;
	//					}
	//					// 命中实体则选择一个随机方向重新发射光线并且进行路径追踪
	//					else
	//					{
	//						// 根据交点处法向量生成交点处反射的随机半球向量
	//						Ray randomRay;
	//						randomRay.startPoint = res.光线命中点;


	//						vec3 L;
	//						vec2 uv = sobol低差异序列(p7, 0);
	//						//uv = CranleyPattersonRotation(uv);
	//						L = 漫反射重要性采样(uv.x, uv.y, res.material.normal);
	//						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    // 漫反射
	//						{
	//							//vec3 s = res.material.color;
	//							//微积分 = 路径追踪(shapes, randomRay, 0);
	//							微积分 = 光线追踪(shapes, randomRay, 4);

	//							//color = 微积分;
	//							color = 微积分;
	//						}
	//						小图积分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 = WIDTH / 矩形;
	//	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];


	//			}
	//		}
	//	}

	//}
	HANDLE h1, h2;//声明句柄变量
	h1 = CreateThread(NULL, 0, myfun1, NULL, 0, NULL);//创建线程1

	h2 = CreateThread(NULL, 0, myfun2, NULL, 0, NULL);//创建线程2





	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;
	}
	//++p7;
	std::cout << "fps: 共 " << ++p7 << std::endl;
}






int main()
{

	Shape* 单个数据 = new Shape;
	for (int i = 0; i < WIDTH * HEIGHT; ++i) {
		for (int i2 = 0; i2 < WIDTH * HEIGHT; ++i2) {
			屏幕优先物体[i][i2] = 单个数据;
		}
	}

	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.0, 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));

	Triangle l3 = Triangle(vec3(1, 1, 1), vec3(1, -1, -1), vec3(1, -1, 1), WHITE);
	shapes.push_back(&l3);
	l3.material.isEmissive = true;
	Triangle l4 = Triangle(vec3(1, -1, -1), vec3(1, 1, 1), vec3(1, 1, -1), WHITE);
	shapes.push_back(&l4);
	l4.material.isEmissive = true;


	Triangle l5 = Triangle(vec3(-1, -1, -1), vec3(-1, 1, 1), vec3(-1, -1, 1), WHITE);
	shapes.push_back(&l5);
	l5.material.isEmissive = true;
	Triangle l6 = Triangle(vec3(-1, -1, -1), vec3(-1, 1, -1), vec3(-1, 1, 1), WHITE);
	shapes.push_back(&l6);
	l6.material.isEmissive = true;


	int argc = 1;
	char* argv[] = { "MFC_GLUT" };
	clocks = clock();
	frames = 0;
	glutInitWindowSize(400-100, 400 - 100);
	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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值