纯c++实现光线追踪渲染器

2024-04-29 02:38

本文主要是介绍纯c++实现光线追踪渲染器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这是一个几年前用c++实现的光线追踪渲染器,使用cpu多线程计算,没有使用任何gpu加速。最后画面的呈现也是使用的gdi绘制,没有使用d3d或ogl。不同于某些基于shader的光线追踪限制性太大,对于通用模型的支持不好(只支持一些标准集合体,且模型都是通过算法产生的)。本渲染器可以支持通用模型的渲染。

光线追踪渲染框架下可以很容易的实现反射、折射、阴影、环境光遮蔽等。不同于传统的3D渲染管线,光线追踪逐个像素计算关照没有光栅化这一步,之前实现过一个软3D渲染管线,光栅化是主要的性能瓶颈。相信随着电脑算力的提高若干年后光线追踪渲染框架将会取代传统的3D管线,不止是渲染效果上更好,当模型面数达到足够数量级时,效率上也会超过传统管线。

本光线追踪渲染器实现了几种基本图元 sphere、box、quad、triangle、billboard。公告板图元是特有的,计算射线追踪时使用的是球形碰撞,取纹理时使用的是面向射线的公告板,阴影还有些问题(树根没对齐)。

三角形图元是最通用的图元,可以配合各类3d建模软件的导出模型。效率上还没优化到实时的地步。有可能目前的cpu算力还做不到实时。使用gpu可能会快一些,下一步可以试试cuda等通用gpu计算。

优化方案:

方案一, 使用bsp加速射线追踪检测,虽然提出效率是log的,但是面多了后还是不够快。

方案二, 以摄像机位置为原点,使用经纬度划分空间分割来加速检测,然后将屏幕分成小块绘制,一个小块只需要做一次剔除(仅初次追踪,镜面体反射后就不行了)可以极快的加速,缺点是当原点附近有大量三角形时效率急速变低。

方案三, 体素分割加速检测,由近到远遍历射线穿过的体素也方便即时返回,测试下来体素分割速度更快一些。

核心源码:

#pragma once
#include <windows.h>#include "Mathlib.h"//Phong shading。  光照=环境光+漫反射+高光class TraceRes;
class Frustum;
class LaCone3Partion;
class UniformVoxelPartion;
class AnguleBoxPartion;
class RayTraceTexture;//根据形状划分 保存在个位
enum PrimitiveType
{//PT_Point,//PT_Line,//PT_Circle, //圆面PT_Sphere = 0,PT_Ellipsoid,PT_Trigon,PT_Quad,PT_Sylinder,PT_Billboard,
};//根据属性划分 保存在十位
enum PrimitiveType2
{PT_Mesh = 0,//面片PT_Light,   //光源PT_Stencil, //蒙版图元,射线击中后执行操作 比如skip ,或者未击中skip。
};enum CullFace
{CF_None,CF_All,CF_Front,CF_Back,
};enum FILTER
{Nearest=0,  Bilinear, ANISOTROPIC,
};//光线追踪没有光栅化,不好确定是放大滤波还是缩小滤波
//SAMP_MAGFILTER, 
//SAMP_MINFILTER, #define MaxPrimitive  4096
#define MaxThread 4
//不要虚函数 效率比较低
class Primitive
{
public:Primitive(PrimitiveType primitiveType);virtual ~Primitive(){};//仅拷贝void SetColorTexture(const vec3 &color, RayTraceTexture *texture);//计算了ODEtavoid SetRefleract(float reflection = 0.0f, float refraction = 0.0f, float Eta = 1.0f,RayTraceTexture* tex=NULL);//比switch(primitiveType)慢//virtual bool Intersect(vec3 &rayPos, const vec3 &rayDir, float maxDistance){return false;};public:PrimitiveType primitiveType;RayTraceTexture *pTexture;//折射率保存在贴图中? 保存在普通的alpha通道一个char内容不下? 折射 反射 折射率RayTraceTexture *refleraTexture;bool  visible;CullFace  cullface;float reflection; //反射系数float refraction; //折射系数float Eta, ODEta; //折射率 及其倒数   简单的半透明图元或叠加高亮图元通过折射率0来模拟vec3  color;////float lastDepth[18];  //缓存和上一个像素射线碰撞点的深度,很大的几率变化不大,用于快速排除 ?每个递归深度缓存一个  每线程单独缓存一份char  tag[MaxThread];//void* data;     //比如保存一个light光源指针?//包围球vec3  center;float radius;//包围盒AABB2 aabb;//todo 裁剪体 面 球 或box 限制交点在球或box的内或外才算碰撞,或在面的某一侧,?使用折射贴图跟快更灵活int laYIndexMax;int laYIndexMin;int laXIndexMax;int laXIndexMin;int laZIndexMax;int laZIndexMin;int loIndexMax1[6];int loIndexMin1[6];int loIndexMax2[6];int loIndexMin2[6];
};class TrigonPrim:public Primitive
{
public:TrigonPrim();void SetPos(const vec3 &ptA, const vec3 &ptB, const vec3 &ptC);void SetPos(const vec3 &ptA, const vec3 &ptB, const vec3 &ptC,const vec3& nA,const vec3& nB,const vec3& nC);bool Inside(float x, float y, float z);bool Inside(const vec3 &point);//相交测试中进行alpha测试 缺点:不是最近点的图元没必要浪费alpha测试时间,最近图元不镂空部分也没必要alpha测试//                        优点:减少多加的追踪深度bool Intersect(const vec3 &rayPos, const vec3 &rayDir, TraceRes& traceRes);bool Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance, float &distance, vec3 &point);bool Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance, float &distance);bool Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance);void CalBound();//todo 多返回一个折射率贴图void SampleTexColor(const vec3&pos,vec3&texColor,vec3&refleraColor,FILTER filter);void SampleNormal(const vec3&pos,vec3& normal);public:vec3  ptA, ptB, ptC;//顶点vec2  texA,texB,texC;//纹理坐标vec3  nA,nB,nC;      //法线 高洛德着色,不插值反射面会断开,插值的话正好平滑过渡vec3  dirAB, dirBC, dirCA; //边向量 注意后面两个有用到 dirAB指针++形式用到float lab, lbc, lca;vec3  N;          //面法线float D;vec3  N1, N2, N3; //边面法线float D1, D2, D3;/**/vec3  fa, fb, fc; //投射到摄像机空间远裁剪面上的四个顶点//纹理插值float kVal[2];vec3  B_C,A_C; bool  bLineXY;//xy 平面投影是否共线Polygon2D m_polygon;
};class QuadPrim:public Primitive
{
public:QuadPrim();void SetPos(const vec3 &ptA, const vec3 &ptB, const vec3 &ptC, const vec3 &ptD);bool Intersect(const vec3 &rayPos, const vec3 &rayDir, TraceRes& traceRes);bool Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance, float &distance, vec3 &point);bool Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance, float &distance);bool Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance);bool Inside(vec3 &point);void CalBound();void SampleTexColor(const vec3&pos,vec3&texColor,vec3&refleraColor,FILTER filter);public:vec3  ptA, ptB, ptC, ptD; //顶点vec2  texA,texB,texC,texD;//纹理坐标vec3  B_A, D_A;     //边向量vec3  m;          //重心vec3  dirAB, B, O;float odDisAB,odDisAC;vec3  N;          //面法线float D;vec3  N1, N2, N3, N4;//边面法线float D1, D2, D3, D4;/*D CA B*/vec3  fa, fb, fc, fd; //投射到摄像机空间远裁剪面上的四个顶点Polygon2D m_polygon;};//
class SpherePrim:public Primitive
{
public:SpherePrim();void SetPos(const vec3 &Position, float Radius);bool Intersect(const vec3 &rayPos, const vec3 &rayDir, TraceRes& traceRes);bool Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance, float &distance, vec3 &point);bool Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance, float &distance);bool Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance);void CalBound();public:float Radius2, ODRadius;};//class SylinderPrim:public Primitive
//{
//public:
//	SylinderPrim();
//	void SetPos(const vec3 &Position, float Radius);
//
//	bool Intersect(const vec3 &rayPos, const vec3 &rayDir, TraceRes& traceRes);
//	bool Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance, float &distance, vec3 &point);
//	bool Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance, float &distance);
//	bool Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance);
//	///** 检测是否与圆柱体碰撞 */
//	//int TestIntersionCylinder(const vec3& position,const vec3& direction, double& lamda, vec3& pNormal,vec3& newposition)
//	//{
//	//	vec3 RC;
//	//	double d;
//	//	double t,s;
//	//	vec3 n,D,O;
//	//	double ln;
//	//	double in,out;
//	//	vec3::subtract(position,cylinder._Position,RC);
//	//	vec3::cross(direction,cylinder._Axis,n);
//	//	ln = n.mag();
//	//	if ( (ln<ZERO)&&(ln>-ZERO) ) return 0;
//	//	n.unit();
//	//	d =  fabs( RC.dot(n) );
//	//	if (d <= cylinder._Radius)
//	//	{
//	//		vec3::cross(RC,cylinder._Axis,O);
//	//		t =  - O.dot(n)/ln;
//	//		vec3::cross(n,cylinder._Axis,O);
//	//		O.unit();
//	//		s =  fabs( sqrt(cylinder._Radius*cylinder._Radius - d*d) / direction.dot(O) );
//
//	//		in = t-s;
//	//		out = t+s;
//
//	//		if (in<-ZERO){
//	//			if (out<-ZERO) return 0;
//	//			else lamda = out;
//	//		}
//	//		else
//	//			if (out<-ZERO) {
//	//				lamda = in;
//	//			}
//	//			else
//	//				if (in<out) lamda = in;
//	//				else lamda = out;
//
//	//				newposition = position+direction*lamda;
//	//				vec3 HB = newposition-cylinder._Position;
//	//				pNormal = HB - cylinder._Axis*(HB.dot(cylinder._Axis));
//	//				pNormal.unit();
//
//	//				return 1;
//	//	}
//	//	return 0;
//	//}
//
//
//	void CalBound();
//
//public:
//	float Radius2, ODRadius;
//
//	vec3 _Axis;
//	//vec3 _Position;
//	//double _Radius;
//};//class BillboardPrim:public QuadPrim
//{
//public:
//	BillboardPrim();
//public:
//	//没检测一次射线都生成新的四个顶点 法线等
//	QuadPrim m_originQuad;
//};//
class BillboardPrim:public SpherePrim
{
public:BillboardPrim();//相交测试中进行alpha测试 缺点:不是最近点的图元没必要浪费alpha测试时间,最近图元不镂空部分也没必要alpha测试//                        优点:减少多加的追踪深度
public://使用对称的球形碰撞,仅仅是纹理坐标计算有些许差别
};//
class LightRT
{
public:LightRT();~LightRT();void Update();public:float Ambient, Diffuse;float ConstantAttenuation, LinearAttenuation, QuadraticAttenuation;SpherePrim *Sphere;QuadPrim   *Quad;//平行光 分割使用体素或光柱分割//LaCone3Partion *m_laConePartion;todo 异形发光体  ,光源颜色和图元颜色图元纹理混合作为最终的光源颜色,另外还具有灯光的方向衰减等普通属性//意义?:发光体表现可以通过叠加高亮模拟假象, 异形发光体的真正意义需要计算射线可追踪到的光源区域大小,来生成柔和的阴影边缘? 无影灯?////int m_quadsCount;//int m_spheresCount;//int m_lightsCount;//灯光图元 可以和普通的场景各种类型图元混合一起划分在一个空间树中,这样碰撞检测效率提高2~3倍,但是带来逻辑混乱?//灯光图元 必须另外单独划分一颗空间树,以便阴影检测时提高效率
};//
class TraceRes
{
public:TraceRes();
public:float distanceSofar;float testDistance;vec3  color, point, testPoint;int   traceDepth;Primitive *primitive;LightRT    *light;vec3  rayPos;vec3  rayDir;
};class PrimitiveBspTree;
class RayTracerThread;class Presenter
{
public:virtual void Present(int scrWidth,int scrHeight,BYTE* colorBuf)=0{};
protected:int  m_wndWidth;int  m_wndHeight;int  m_softBuffWidth;int  m_softBuffHeight;
};//
class RayTraceRendDriver
{
public:RayTraceRendDriver();virtual ~RayTraceRendDriver();virtual bool Init();virtual void Close();virtual void OnSize(int Width, int Height);void        SetPresenter(Presenter* presenter);//!参数设置bool SetSamples(int Samples);int  GetSamples();bool SetQuality(float quality);public://!添加删除图元void CheckPrimitiveVolume(int addCount=1);void AddPrimitives(Primitive* pprimitives,int count);void AddPrimitives(Primitive** pprimitives,int count);void RemovePrimitives(Primitive* pprimitives,int count);void RemovePrimitives(Primitive** pprimitives,int count);//!绘制void ClearColorBuffer();void Render();void RenderRect(int x,int y,int xend,int yend,int threadIndex);void AfterEffectHDR();void Present();////void		DrawPoint(int x, int y);//void		DrawLine(int x1, int y1, int x2, int y2);//void		DrawRect(const RectF& tar); bool	    DrawTextureRect(const RectF& tar);//!分割准备//void GenFrustumCell(int frustumSize,int x,int y,int cellX,int cellY,int cellXEnd,int cellYEnd,Frustum&res);//void PreparePartionWithFrustum();void CalRat();//!分割图元void PartionWithBsp(PrimitiveBspTree* bspPartion);//void PartionWithLaLo(laLoPartion *laLoPartion);void PartionWithLaCone(LaCone3Partion *laConePartion);void PartionWithVoxel(UniformVoxelPartion* voxelPartion);void PartionWithAnguleBox(AnguleBoxPartion *anguleBoxPartion);//!标记图元  没有添加,const Primitive* except//void TagWithFrustumLaCone(int cellX,int cellY,int cellXEnd,int cellYEnd);//void TagWithFrustum(Frustum& frustum);void TagWithBsp(const vec3&pos,const vec3&dir);void DumpPrimitives(Primitive** pprimitives,int count);//private://!总光照计算void IlluminatePoint(const Primitive *except, const vec3 &point, const vec3 &normal, vec3 &color,int threadindex);//!单光源密度vec3 LightIntensity(const Primitive *except, const vec3 &point, const vec3 &normal, const vec3 &lightPos, LightRT *light, float AO,int threadindex);//!测试阴影bool TraceShadow(const Primitive *except, const vec3 &lightPos, const vec3 &lightDir, float lightDis,int threadindex);//!环境遮蔽float AmbientOcclusionFactor(const Primitive *except, const vec3 &point, const vec3 &normal,int threadindex);//主投射vec3  TraceRay(const vec3 &rayPos, const vec3 &rayDir, int depth, Primitive *except,int threadindex);public:int MaxTraceDepth;//8 //2//private:Presenter *m_presenter;//BYTE *m_colorBuffer;vec3 *m_hdrColorBuffer;//0.01s并行时间不值得? 输入卡,双缓存需延后处理 一样卡//双缓加速 gdi paint 的同时,追踪不打断,要注意使用双缓冲时可能在追踪过程中接到onsize类消息或者camera改变消息,都需延后处理?//BYTE *m_colorBuffer01;//vec3 *m_hdrColorBuffer01;//BYTE *m_colorBuffer02;//vec3 *m_hdrColorBuffer02;int m_backbufWidth;int m_backbufHeight;int m_wndWidth;int m_wndHeight;float FarPlainDis;int SamplesPerPixel;//1*1 2*2 3*3//全局光照采样次数 辐射度 环境遮蔽int GISampleNum;float ODGISamples;int   WidthMSamples, HeightMSamples, WidthXHeightXSamplesSq;float ODSamples,ODSamplesSq;float AmbientOcclusionIntensity, ODGISamplesXAmbientOcclusionIntensity;//protected:
public://不能单独分开primitive buff obj,这样不利于优化? 区分静态和动态buff也不利?LightRT     *m_lights;int m_lightsCount;Primitive **m_primitives;int m_primitivesCount;int m_primitivesVolume;public:bool m_enableTexture2D;bool m_enableShadow;bool m_enableSoftShadow;bool m_enableAmbientOcclusion;bool m_enableHDR;bool m_enableReflection;bool m_enableRefraction;float  m_quality;bool m_sphereProject;public:PrimitiveBspTree    *m_bspPartion;LaCone3Partion      *m_eyeLaConePartion;AnguleBoxPartion    *m_eyeAnguleBoxPartion;UniformVoxelPartion *m_voxelPartion;Primitive *m_primitivesTagged[MaxPrimitive];int m_primitivesTaggedCount;RayTraceTexture* m_curTexture;FILTER m_texFilter;//预插值的跨度表 因为不是传统的投影矩阵平均插值float WRat[2048];float HRat[2048];////Primitive *m_primitivesInFrustum[MaxPrimitive];//int m_primitivesCountInFrustum;//int m_statisticPrimitivesCountInFrustumMax;//int m_statisticPrimitivesCountInFrustum[MaxPrimitive];char debugRegion;RayTracerThread*  m_traceThread;int               m_threadNum;};extern RayTraceRendDriver *G_RayTracer;

#include "Frustum.h"
#include "Camera.h"
#include "RayTraceRendDriver.h"
#include "RayTraceTexture.h"
#include "PrimitiveBspTree.h"
#include "LaCone3Partion.h"
#include "AnguleBoxPartion.h"
#include "UniformGridPartion.h"
#include <assert.h>#define  WIN32APP
#include "General/Thread.h"
#include <crtdbg.h>enum TraceThreadState
{TT_Waiting,TT_Tracing,TT_TracingCompleted,
};
class RayTracerThread: public Thread
{
public:RayTracerThread();//~RayTracerThread()//{}virtual bool Run(ThreadParm* pData);TraceThreadState m_state;int startLine;int endLine;int threadIndex;
};RayTracerThread::RayTracerThread()
:m_state(TT_Waiting)
{}bool RayTracerThread::Run(ThreadParm* pData)
{while (1){if(Thread::m_state== TS_RunningToEnd){Thread::m_state = Thread::TS_End;break;}switch(m_state){case TT_Waiting:{Sleep(1);break;}case TT_Tracing:{const int frustumSize = 16;const int halfFrustumSize = frustumSize/2;int cellY=startLine;while(cellY < endLine){int cellYEnd=cellY+frustumSize;if (cellYEnd>endLine/*-1*/){cellYEnd = endLine/*-1*/;}int cellX=0;while(cellX < G_RayTracer->m_backbufWidth){int cellXEnd=cellX+frustumSize;if (cellXEnd>G_RayTracer->m_backbufWidth-1){cellXEnd = G_RayTracer->m_backbufWidth-1;}//绘制格子G_RayTracer->RenderRect(cellX,cellY,cellXEnd,cellYEnd,threadIndex);cellX+=frustumSize;}cellY+=frustumSize;}m_state=TT_TracingCompleted;break;}default:Sleep(1);}}return true;
}Primitive::Primitive(PrimitiveType primitiveType_)
:pTexture(NULL)
,refleraTexture(NULL)
,primitiveType(primitiveType_)
,color(1,1,1)
,visible(true)
,cullface(CF_Back)
{for (int i=0;i<MaxThread;i++){tag[i]=-1;}reflection = 0;refraction = 0;Eta = 1;ODEta = 1.0f ;laYIndexMax=-1;laYIndexMin=512;laXIndexMax=-1;laXIndexMin=512;laZIndexMax=-1;laZIndexMin=512;
}void Primitive::SetColorTexture(const vec3 &color_, RayTraceTexture *texture)
{color = color_;pTexture = texture;
}void Primitive::SetRefleract(float Reflection_ /*= 0.0f*/, float Refraction_ /*= 0.0f*/, float Eta_ /*= 1.0f*/,RayTraceTexture* tex)
{reflection = Reflection_;refraction = Refraction_;Eta = Eta_;ODEta = 1.0f / Eta;refleraTexture = tex;
}TrigonPrim::TrigonPrim()
:Primitive(PT_Trigon)
,m_polygon(3)
{
}void TrigonPrim::SetPos(const vec3 &ptA_, const vec3 &ptB_, const vec3 &ptC_) 
{ ptA=ptA_;ptB=ptB_;ptC=ptC_;dirAB = ptB_ - ptA_; dirBC = ptC_ - ptB_; dirCA = ptA_ - ptC_;N = (Cross(dirAB, -dirCA));N.Normalize();D = -Dot(N, ptA_);N1 = (Cross(N, dirAB));N1.Normalize();D1 = -Dot(N1, ptA_);N2 = (Cross(N, dirBC));N2.Normalize();D2 = -Dot(N2, ptB_);N3 = (Cross(N, dirCA));N3.Normalize();D3 = -Dot(N3, ptC_);lab = (dirAB.Length()); dirAB /= lab;lbc = (dirBC.Length()); dirBC /= lbc;lca = (dirCA.Length());  dirCA /= lca;//解法二  P = wa*PA + wb*PB + (1-wa-wb)*PC 方程两边同时点乘(PB叉乘PC)//得  P.Dot(PB.Cross(PC)) = wa*PA.Dot(PB.Cross(PC)) + 0 + 0;//得  wa = PA.Dot(PB.Cross(PC)) / P.Dot(PB.Cross(PC));//可以推广到四维向量插值//已知三角形的三个顶点坐标PA, PB, PC, 三角形内的任意点P。未知数u和v(wa ≥ 0, wb ≥ 0, wa + wb ≤ 1),其中wa、wb体现了PA、PB对P的权重贡献,(1 - wa - wb)是PC权重//则 P = wa*PA + wb*PB + (1-wa-wb)*PC//解方程://(P -PC) = wa*(PA-PC) + wb*(PB-PC)//可得wa、wb、wc值,对PA, PB, PC的颜色值加权平均,即得P点颜色值或坐标值。//(P.x -PC.x) = wa*(PA_PC.x) + wb*(PB_PC.x)//(P.y -PC.y) = wa*(PA_PC.y) + wb*(PB_PC.y)//(P.z -PC.z) = wa*(PA_PC.z) + wb*(PB_PC.z)//wa = [(P.x -PC.x)*(PB_PC.y)-(P.y -PC.y)*(PB_PC.x)] / [(PA_PC.x)*(PB_PC.y)-(PA_PC.y)*(PB_PC.x)]//wb = [(P.x -PC.x)*(PA_PC.y)-(P.y -PC.y)*(PA_PC.x)] / [(PB_PC.x)*(PA_PC.y)-(PB_PC.y)*(PA_PC.x)]//x y z 随意组合																		 //wa = [(P.x -PC.x)*(PB_PC.z)-(P.z -PC.z)*(PB_PC.x)] / [(PA_PC.x)*(PB_PC.z)-(PA_PC.z)*(PB_PC.x)]//wb = [(P.x -PC.x)*(PA_PC.z)-(P.z -PC.z)*(PA_PC.x)] / [(PB_PC.x)*(PA_PC.z)-(PB_PC.z)*(PA_PC.x)]B_C = ptB - ptC;A_C = ptA - ptC; float lineTest = B_C.x*A_C.y-B_C.y*A_C.x;if (-_EPSILON<lineTest&&lineTest<_EPSILON){//xy 平面共线(斜率相等) 计算k必须有z参与bLineXY = true;//kVal[0] == 0则kVal[1]==0,空间共线kVal[0] = A_C.x*B_C.z - A_C.z*B_C.x;kVal[1] = B_C.x*A_C.z - B_C.z*A_C.x;if (kVal[0]<-_EPSILON || _EPSILON<kVal[0]){kVal[0] = 1/kVal[0];kVal[1] = 1/kVal[1];}}else{//已经不可能空间共线bLineXY = false;kVal[0] = A_C.x*B_C.y - A_C.y*B_C.x;kVal[1] = B_C.x*A_C.y - B_C.y*A_C.x;if (kVal[0]<-_EPSILON || _EPSILON<kVal[0]){kVal[0] = 1/kVal[0];kVal[1] = 1/kVal[1];}}CalBound();
}void TrigonPrim::SetPos(const vec3 &ptA_, const vec3 &ptB_, const vec3 &ptC_,const vec3& nA_,const vec3& nB_,const vec3& nC_)
{SetPos(ptA_,ptB_,ptC_);nA = nA_;nB = nB_;nC = nC_;if (N.Dot(nA)<0){N*=-1;}
}bool TrigonPrim::Inside(float x, float y, float z)
{if(N1.x * x + N1.y * y + N1.z * z + D1 < 0.0f) return false;if(N2.x * x + N2.y * y + N2.z * z + D2 < 0.0f) return false;if(N3.x * x + N3.y * y + N3.z * z + D3 < 0.0f) return false;return true;
}bool TrigonPrim::Inside(const vec3 &point)
{if(Dot(N1, point) + D1 < 0.0f) return false;if(Dot(N2, point) + D2 < 0.0f) return false;if(Dot(N3, point) + D3 < 0.0f) return false;return true;
}bool TrigonPrim::Intersect(const vec3 &rayPos, const vec3 &rayDir, TraceRes& traceRes)
{//tag时过滤,提高速度//if(visible==false) return false;float NdotR = -Dot(N, rayDir);背面也可能需要被追踪到 //if(cullface==CF_None //	|| (cullface==CF_Back&&NdotR>0.0f) //只追踪正面//	|| (cullface==CF_Front&&NdotR<0.0f)//只追踪反面//	|| (refraction>0.0f)               //可以折射出的背面//)//if(NdotR>0.0f)//和面的法线逆向 只追踪正面//if(NdotR > 0.0f)  || (refraction>0.0f && NdotR<0.0f))  //追踪正面 || 可以折射出的背面 普通背面也要被折射光线追踪到{//正反面都走这里float distance = (Dot(N, rayPos) + D) / NdotR;if(distance >= 0.0f && distance < traceRes.distanceSofar){vec3 point = rayPos + rayDir * distance;bool inside = Inside(point);if (inside){traceRes.testDistance = distance;traceRes.point = point;traceRes.distanceSofar = distance;traceRes.primitive = this;}return inside;}}return false;
}
bool TrigonPrim::Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance, float &distance, vec3 &point)
{float NdotR = -Dot(N, rayDir);if(NdotR > 0.0f){distance = (Dot(N, rayPos) + D) / NdotR;if(distance >= 0.0f && distance < maxDistance){point = rayDir * distance + rayPos;return Inside(point);}}return false;
}bool TrigonPrim::Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance, float &distance)
{float NdotR = -Dot(N, rayDir);if(NdotR > 0.0f){distance = (Dot(N, rayPos) + D) / NdotR;if(distance >= 0.0f && distance < maxDistance){return Inside(rayDir * distance + rayPos);}}return false;
}bool TrigonPrim::Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance)
{float NdotR = -Dot(N, rayDir);if(NdotR > 0.0f){float distance = (Dot(N, rayPos) + D) / NdotR;if(distance >= 0.0f && distance < maxDistance){return Inside(rayDir * distance + rayPos);}}return false;
}void TrigonPrim::CalBound()
{RitterSphere(&ptA, 3, center,radius);aabb.m_max = ptA;aabb.m_min = ptA;aabb.Merge(ptB);aabb.Merge(ptC);
}void TrigonPrim::SampleTexColor(const vec3&pos,vec3&texColor,vec3&refleraColor,FILTER filter)
{//wa = [(P.x -PC.x)*(PB_PC.y)-(P.y -PC.y)*(PB_PC.x)] / [(PA_PC.x)*(PB_PC.y)-(PA_PC.y)*(PB_PC.x)]//wb = [(P.x -PC.x)*(PA_PC.y)-(P.y -PC.y)*(PA_PC.x)] / [(PB_PC.x)*(PA_PC.y)-(PB_PC.y)*(PA_PC.x)]//x y z 随意组合																		 vec2 uv;if (-_EPSILON<kVal[0]&&kVal[0]<_EPSILON){uv = texA;}else{float wa,wb,wc;if (bLineXY){wa = ((pos.x-ptC.x)*B_C.z-(pos.z-ptC.z)*B_C.x)  * kVal[0];wb = ((pos.x-ptC.x)*A_C.z-(pos.z-ptC.z)*A_C.x)  * kVal[1];wc = 1-wa-wb;}else{wa = ((pos.x-ptC.x)*B_C.y-(pos.y-ptC.y)*B_C.x)  *kVal[0];wb = ((pos.x-ptC.x)*A_C.y-(pos.y-ptC.y)*A_C.x)  *kVal[1];wc = 1-wa-wb;}uv = texA*wa+texB*wb+texC*wc;}pTexture->GetColor11(uv.x, uv.y,texColor, filter);//texColor= pTexture->GetColorNearest(uv.x, uv.y);if (refleraTexture){refleraTexture->GetColor11(uv.x, uv.y,refleraColor, filter);//GetColorNearest}
}void TrigonPrim::SampleNormal(const vec3&pos,vec3& normal)
{//todo 法线贴图//normal = N;//return;if (-_EPSILON<kVal[0]&&kVal[0]<_EPSILON){normal = nA;}else{float wa,wb,wc;if (bLineXY){wa = ((pos.x-ptC.x)*B_C.z-(pos.z-ptC.z)*B_C.x)  * kVal[0];wb = ((pos.x-ptC.x)*A_C.z-(pos.z-ptC.z)*A_C.x)  * kVal[1];wc = 1-wa-wb;}else{wa = ((pos.x-ptC.x)*B_C.y-(pos.y-ptC.y)*B_C.x)  *kVal[0];wb = ((pos.x-ptC.x)*A_C.y-(pos.y-ptC.y)*A_C.x)  *kVal[1];wc = 1-wa-wb;}normal = nA*wa+nB*wb+nC*wc;}
}QuadPrim::QuadPrim()
:Primitive(PT_Quad)
,m_polygon(4)
{
}void QuadPrim::SetPos(const vec3 &ptA_, const vec3 &ptB_, const vec3 &ptC_, const vec3 &ptD_) 
{ptA=ptA_;ptB=ptB_;ptC=ptC_;ptD=ptD_;B_A = ptB - ptA;D_A = ptD - ptA;m = (ptA + ptB + ptC + ptD) / 4.0f;dirAB = B_A;odDisAB = B_A.Length();if (odDisAB>_EPSILON){odDisAB = 1/odDisAB;}else{odDisAB = 9999;}odDisAC = (ptA-ptC).Length();if (odDisAC>_EPSILON){odDisAC = 1/odDisAC;}else{odDisAC = 9999;}dirAB.Normalize();N = (Cross(B_A, ptC - ptA));N.Normalize();B = Cross(N, dirAB);O = vec3(Dot(dirAB, ptA), Dot(B, ptA), Dot(N, ptA));D = -Dot(N, ptA);N1 = (Cross(N, ptB - ptA));N1.Normalize();D1 = -Dot(N1, ptA);N2 = (Cross(N, ptC - ptB));N2.Normalize();D2 = -Dot(N2, ptB);N3 = (Cross(N, ptD - ptC));N3.Normalize();D3 = -Dot(N3, ptC);N4 = (Cross(N, ptA - ptD));N4.Normalize();D4 = -Dot(N4, ptD);CalBound();
}bool QuadPrim::Inside(vec3 &point)
{if(Dot(N1, point) + D1 < 0.0f) return false;if(Dot(N2, point) + D2 < 0.0f) return false;if(Dot(N3, point) + D3 < 0.0f) return false;if(Dot(N4, point) + D4 < 0.0f) return false;return true;
}
bool QuadPrim::Intersect(const vec3 &rayPos, const vec3 &rayDir, TraceRes& traceRes)
{float NdotR = -Dot(N, rayDir);//和面的法线逆向if(NdotR > 0.0f) // || (refraction > 0.0f && NdotR < 0.0f)){float distance = (Dot(N, rayPos) + D) / NdotR;if(distance >= 0.0f && distance < traceRes.distanceSofar){vec3 point = rayDir * distance + rayPos;bool inside = Inside(point);if (inside){traceRes.testDistance = distance;traceRes.point = point;traceRes.distanceSofar = distance;traceRes.primitive = this;}return inside;}}return false;
}
bool QuadPrim::Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance, float &distance, vec3 &point)
{float NdotR = -Dot(N, rayDir);//和面的法线逆向if(NdotR > 0.0f) // || (refraction > 0.0f && NdotR < 0.0f)){distance = (Dot(N, rayPos) + D) / NdotR;if(distance >= 0.0f && distance < maxDistance){point = rayDir * distance + rayPos;return Inside(point);}}return false;
}bool QuadPrim::Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance, float &distance)
{float NdotR = -Dot(N, rayDir);if(NdotR > 0.0f) // || (refraction > 0.0f && NdotR < 0.0f)){distance = (Dot(N, rayPos) + D) / NdotR;if(distance >= 0.0f && distance < maxDistance){return Inside(rayDir * distance + rayPos);}}return false;
}bool QuadPrim::Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance)
{float NdotR = -Dot(N, rayDir);if(NdotR > 0.0f) // || (refraction > 0.0f && NdotR < 0.0f)){float distance = (Dot(N, rayPos) + D) / NdotR;if(distance >= 0.0f && distance < maxDistance){return Inside(rayDir * distance + rayPos);}}return false;
}void QuadPrim::CalBound()
{RitterSphere(&ptA, 4, center,radius);aabb.m_max = ptA;aabb.m_min = ptA;aabb.Merge(ptB);aabb.Merge(ptC);aabb.Merge(ptD);
}void QuadPrim::SampleTexColor(const vec3&pos,vec3&texColor,vec3&refleraColor,FILTER filter)
{?只适用aabb ,双线性插值float tx,ty,txty;float realHeight;float height[4];tx = col0f - col0i;ty = row0f - row0i;txty = tx * ty;realHeight	= height[0] * (1.0f - ty - tx + txty)+ height[1] * (tx - txty)+ height[2] * txty+ height[3] * (ty - txty);///*//D C//A B//*///float realHeight;//float height[4];//tx = (pos.x - ptD.x)/(ptC.x - ptD.x);//ty = (pos.y - ptD.y)/(ptA.y - ptD.y);//txty = tx * ty;//vec2 uv	= texA * (1.0f - ty - tx + txty)//+ texB * (tx - txty)//+ texC * txty//+ texD * (ty - txty);//return pTexture->GetColorBilinear(uv.x, uv.y);float s = (Dot(dirAB, pos) - O.x) *odDisAB;float t = (Dot(B, pos) - O.y) *odDisAC;pTexture->GetColor11(s, t,texColor, filter);if (refleraTexture){refleraTexture->GetColor11(s, t,refleraColor, filter);}
}//SpherePrim::SpherePrim()
:Primitive(PT_Sphere)
{
}void SpherePrim::SetPos(const vec3 &Position, float Radius) 
{center = Position;radius = Radius;Radius2 = Radius * Radius;ODRadius = 1.0f / Radius;CalBound();
}bool SpherePrim::Intersect(const vec3 &rayPos, const vec3 &rayDir, TraceRes& traceRes)
{vec3 L = center - rayPos;float LdotR = Dot(L, rayDir);if(LdotR > 0.0f){float D2 = L.LengthSq() - LdotR * LdotR;if(D2 < Radius2){float distance = LdotR - sqrt(Radius2 - D2);if(distance >= 0.0f && distance < traceRes.distanceSofar){traceRes.testDistance = distance;traceRes.distanceSofar = distance;traceRes.point = rayDir * distance + rayPos;traceRes.primitive = this;return true;}}}return false;
}bool SpherePrim::Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance, float &distance, vec3 &point)
{vec3 L = center - rayPos;float LdotR = Dot(L, rayDir);if(LdotR > 0.0f){float D2 = L.LengthSq() - LdotR * LdotR;if(D2 < Radius2){distance = LdotR - sqrt(Radius2 - D2);if(distance >= 0.0f && distance < maxDistance){point = rayDir * distance + rayPos;return true;}}}return false;
}bool SpherePrim::Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance, float &distance)
{vec3 L = center - rayPos;float LdotR = Dot(L, rayDir);if(LdotR > 0.0f){float D2 = L.LengthSq() - LdotR * LdotR;if(D2 < Radius2){distance = LdotR - sqrt(Radius2 - D2);if(distance >= 0.0f && distance < maxDistance){return true;}}}return false;
}bool SpherePrim::Intersect(const vec3 &rayPos, const vec3 &rayDir, float maxDistance)
{//?没判断起点在圆内vec3 L = center - rayPos;float LdotR = Dot(L, rayDir);if(LdotR > 0.0f){float D2 = L.LengthSq() - LdotR * LdotR;if(D2 < Radius2){float distance = LdotR - sqrt(Radius2 - D2);if(distance >= 0.0f && distance < maxDistance){return true;}}}return false;
}void SpherePrim::CalBound()
{aabb.m_max = center;aabb.m_min = center;aabb.Merge(center-vec3(radius,radius,radius));aabb.Merge(center+vec3(radius,radius,radius));
}BillboardPrim::BillboardPrim()
//:Primitive(PT_Billboard)
{primitiveType = PT_Billboard;
}//LightRT::LightRT()
{Ambient = 1.0f;Diffuse = 1.0f;ConstantAttenuation = 1.0f;LinearAttenuation = 0.0f;QuadraticAttenuation = 0.0f;Sphere = NULL;Quad = NULL;m_laConePartion = new LaCone3Partion(32);//16
}LightRT::~LightRT()
{if(Sphere){delete Sphere;Sphere = NULL;}if(Quad){delete Quad;Quad = NULL;}if(m_laConePartion){delete m_laConePartion;m_laConePartion = NULL;}
}void LightRT::Update()
{m_laConePartion->Reset(Sphere ? Sphere->center : Quad->m);G_RayTracer->PartionWithLaCone(m_laConePartion);
}//TraceRes::TraceRes()
{distanceSofar = 1048576.0f;traceDepth = 0;light = NULL;primitive = NULL;
}//
RayTraceRendDriver *G_RayTracer;
RayTraceRendDriver G_RayTracer_;
CCamera G_Camera;RayTraceRendDriver::RayTraceRendDriver()
:m_presenter(NULL)
{G_RayTracer = this;m_colorBuffer = NULL;m_hdrColorBuffer = NULL;//m_colorBuffer01 = NULL;//m_hdrColorBuffer01 = NULL;//m_colorBuffer02 = NULL;//m_hdrColorBuffer02 = NULL;//反射两次已经足够,反射一次都可以MaxTraceDepth = 2;FarPlainDis = 1000;SamplesPerPixel = 1;GISampleNum = 4;//16ODGISamples = 1.0f / (float)GISampleNum;AmbientOcclusionIntensity = 0.5f;ODGISamplesXAmbientOcclusionIntensity = ODGISamples * AmbientOcclusionIntensity;m_lights = NULL;m_lightsCount = 0;m_primitivesVolume = MaxPrimitive;m_primitivesCount = 0;m_primitives = new Primitive *[m_primitivesVolume];m_enableTexture2D = true;m_enableShadow = true;m_enableSoftShadow = false;m_enableAmbientOcclusion = false;m_enableHDR = false;m_enableReflection = true;m_enableRefraction = true;m_quality = 1;m_sphereProject = false;m_bspPartion = new PrimitiveBspTree;m_voxelPartion = new UniformVoxelPartion;m_eyeLaConePartion = new LaCone3Partion(32);//16m_eyeAnguleBoxPartion = new AnguleBoxPartion(16);m_lights = new LightRT[8];m_curTexture = NULL;m_texFilter = Bilinear;
}RayTraceRendDriver::~RayTraceRendDriver()
{Close();
}bool RayTraceRendDriver::Init()
{_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ );assert(_CrtCheckMemory());//_CrtSetBreakAlloc(18835); m_threadNum = 4;m_traceThread = new RayTracerThread[m_threadNum];for (int i=0;i<m_threadNum;i++){m_traceThread[i].threadIndex = i;m_traceThread[i].startLine = i*m_backbufHeight/m_threadNum;  //400/2m_traceThread[i].endLine = (i+1)*m_backbufHeight/m_threadNum;m_traceThread[i].Start();}return true;
}void RayTraceRendDriver::Close()
{if (m_traceThread){for (int i=0;i<m_threadNum;i++){m_traceThread[i].Stop();}delete[] m_traceThread;m_traceThread = NULL;}//for//if (m_primitives){//for (int i=0;i<m_primitivesCount;i++)//{//	Primitive* primi = m_primitives[i];//创建的是数组 此处会crash//	delete primi;//}delete[] m_primitives;m_primitives = NULL;}if(m_lights != NULL){delete [] m_lights;m_lights = NULL;}if (m_bspPartion){delete m_bspPartion;m_bspPartion = NULL;}if (m_voxelPartion){delete m_voxelPartion;m_voxelPartion = NULL;}if(m_eyeLaConePartion){delete m_eyeLaConePartion;m_eyeLaConePartion = NULL;}if(m_eyeAnguleBoxPartion){delete m_eyeAnguleBoxPartion;m_eyeAnguleBoxPartion = NULL;}if(m_colorBuffer != NULL){delete [] m_colorBuffer;m_colorBuffer = NULL;}if(m_hdrColorBuffer != NULL){delete [] m_hdrColorBuffer;m_hdrColorBuffer = NULL;}//if(m_colorBuffer01 != NULL)//{//	delete [] m_colorBuffer01;//	m_colorBuffer01 = NULL;//}//if(m_hdrColorBuffer01 != NULL)//{//	delete [] m_hdrColorBuffer01;//	m_hdrColorBuffer01 = NULL;//}//if(m_colorBuffer02 != NULL)//{//	delete [] m_colorBuffer02;//	m_colorBuffer02 = NULL;//}//if(m_hdrColorBuffer02 != NULL)//{//	delete [] m_hdrColorBuffer02;//	m_hdrColorBuffer02 = NULL;//}
}void RayTraceRendDriver::OnSize(int width, int height)
{m_wndWidth = width;m_wndHeight = height;m_backbufWidth = width/m_quality;m_backbufHeight = height/m_quality;if(m_colorBuffer != NULL){delete [] m_colorBuffer;m_colorBuffer = NULL;}if(m_hdrColorBuffer != NULL){delete [] m_hdrColorBuffer;m_hdrColorBuffer = NULL;}if(m_backbufWidth > 0 && m_backbufHeight > 0){int WidthMod4 = m_backbufWidth%4;if(WidthMod4 > 0){m_backbufWidth += 4 - WidthMod4;}m_colorBuffer = new BYTE[m_backbufWidth * m_backbufHeight * 3];m_hdrColorBuffer = new vec3[m_backbufWidth * m_backbufHeight];WidthMSamples = m_backbufWidth * SamplesPerPixel;HeightMSamples = m_backbufHeight * SamplesPerPixel;WidthXHeightXSamplesSq = WidthMSamples * HeightMSamples;ODSamplesSq = 1.0f / (float)(SamplesPerPixel * SamplesPerPixel);ODSamples = 1.0f / (float)(SamplesPerPixel);//采样实数像素平均出整数像素反锯齿   第一个矩阵将像素归一G_Camera.matPixelNormal[0] = 1.0f / (float)(WidthMSamples - 1);G_Camera.matPixelNormal[5] = 1.0f / (float)(HeightMSamples - 1);float aspect = ((float)m_backbufWidth) /m_backbufHeight;G_Camera.SetAspect(aspect);CalRat();//?? waitfor (int i=0;i<m_threadNum;i++){m_traceThread[i].startLine = i*m_backbufHeight/m_threadNum;  //400/2m_traceThread[i].endLine = (i+1)*m_backbufHeight/m_threadNum;}}
}void RayTraceRendDriver::SetPresenter(Presenter* presenter)
{m_presenter = presenter;
}void RayTraceRendDriver::ClearColorBuffer()
{if(m_colorBuffer != NULL){memset(m_colorBuffer, 0, m_backbufWidth * m_backbufHeight * 3);}
}void RayTraceRendDriver::Render()
{if(m_colorBuffer == NULL) return;vec3 eyePos = G_Camera.m_eyePos;m_eyeLaConePartion->Reset(G_Camera.m_eyePos);PartionWithLaCone(m_eyeLaConePartion);//m_eyeAnguleBoxPartion->Reset(G_Camera.m_eyePos);//PartionWithAnguleBox(m_eyeAnguleBoxPartion);for (int i=0;i<m_threadNum;i++){m_traceThread[i].m_state = TT_Tracing;}while (1){bool completed = true;for (int i=0;i<m_threadNum;i++){if(m_traceThread[i].m_state != TT_TracingCompleted){completed = false;break;}}if (completed==true){break;}Sleep(1);}//const int frustumSize = 16;//const int halfFrustumSize = frustumSize/2;//int cellY=0;//while(cellY < m_backbufHeight)//{//	int cellYEnd=cellY+frustumSize;//	if (cellYEnd>m_backbufHeight)//	{//		cellYEnd = m_backbufHeight;//	}//	int cellX=0;//	while(cellX < m_backbufWidth)//	{//		int cellXEnd=cellX+frustumSize;//		if (cellXEnd>m_backbufWidth)//		{//			cellXEnd = m_backbufWidth;//		}//		//绘制格子//		RenderRect(cellX,cellY,cellXEnd,cellYEnd,0);//		cellX+=frustumSize;//	}//	cellY+=frustumSize;//}//if(m_enableHDR)AfterEffectHDR();
}void RayTraceRendDriver::RenderRect(int cellX,int cellY,int cellXEnd,int cellYEnd,int threadIndex)
{vec3 eyePos = G_Camera.m_eyePos;//第一次投射 使用二叉视椎标记图元的flag //第二次投射 视锥点为第一次视锥点(eye)相对于平面的对称点  椎体角度不变长度被拉长 剔除效率变低//第三次投射 视锥点为前一次视锥点相对于平面对称点 同上。。。//???第二次投射因为第一次交面不只有一个,所以反射椎会有多个,已经不适用该算法了,另外球形图元反射视锥不好计算或太大int line=cellY;vec3 rayDir;vec3 color;while(line < cellYEnd){BYTE *colorbuffer = m_colorBuffer + (m_backbufWidth * line+cellX) * 3 ;vec3 *hdrcolorbuffer = m_hdrColorBuffer + (m_backbufWidth * line+cellX);/*D CA B*/float rat = 1-HRat[line];//((float)line)*odHeight_1;vec3 dirLineStart = G_Camera.ptDw*(1-rat)+ G_Camera.ptAw*(rat);vec3 dirLineEnd = G_Camera.ptCw*(1-rat)+ G_Camera.ptBw*(rat);for(int x = cellX; x < cellXEnd; x++){//if (x<cellX+halfFrustumSize)//{//	if (line<cellY+halfFrustumSize)//	{//		debugRegion = 1;//	}//	else//	{//		debugRegion = 2;//	}//}//else{debugRegion = -1;}//ui不带alpha覆盖的地方不要追踪if(colorbuffer[0]==0 && colorbuffer[1]==0 && colorbuffer[2]==0) {if (SamplesPerPixel==1){//rayDir = (G_Camera.RayMatrix * vec3(x,line, 0.0f));//用插值代替上面的矩阵乘法 带旋转的世界坐标系 不能简单插值xyrat = WRat[x];//((float)x)*odWidth_1;rayDir  = dirLineStart*(1-rat)+ dirLineEnd*(rat);rayDir.Normalize();//这里不能返回alpha和backbuff混合,因为backbuff未被追踪,透明贴图需要继续追踪color = TraceRay(eyePos, rayDir,0,0,threadIndex);*hdrcolorbuffer = color;colorbuffer[2] = color.r <= 0.0f ? 0 : color.r >= 1.0 ? 255 : (BYTE)(color.r * 255);colorbuffer[1] = color.g <= 0.0f ? 0 : color.g >= 1.0 ? 255 : (BYTE)(color.g * 255);colorbuffer[0] = color.b <= 0.0f ? 0 : color.b >= 1.0 ? 255 : (BYTE)(color.b * 255);}else{//浮点像素追踪后取均值vec3 SamplesSum;//todo lerp y//for(int sy = 0; sy < SamplesPerPixel; sy++){for(int sx = 0; sx < SamplesPerPixel; sx++){//rayDir = G_Camera.RayMatrix * vec3((float)(X + sx), (float)Yyy, 0.0f);//todo lerp yrat = Lerp(WRat[x],WRat[x+1],sx*ODSamples);//((float)x)*odWidth_1;rayDir  = dirLineStart*(1-rat)+ dirLineEnd*(rat);rayDir.Normalize();color = TraceRay(G_Camera.m_eyePos, rayDir, 0, NULL, threadIndex);SamplesSum.r += color.r <= 0.0f ? 0.0f : color.r >= 1.0 ? 1.0f : color.r;SamplesSum.g += color.g <= 0.0f ? 0.0f : color.g >= 1.0 ? 1.0f : color.g;SamplesSum.b += color.b <= 0.0f ? 0.0f : color.b >= 1.0 ? 1.0f : color.b;}}SamplesSum.r *= ODSamples;SamplesSum.g *= ODSamples;SamplesSum.b *= ODSamples;//SamplesSum.r *= ODSamplesSq;//SamplesSum.g *= ODSamplesSq;//SamplesSum.b *= ODSamplesSq;*hdrcolorbuffer = SamplesSum;colorbuffer[2] = (BYTE)(SamplesSum.r * 255);colorbuffer[1] = (BYTE)(SamplesSum.g * 255);colorbuffer[0] = (BYTE)(SamplesSum.b * 255);}}hdrcolorbuffer++;colorbuffer += 3;}line++;}
}void RayTraceRendDriver::CalRat()
{float aspect = ((float)m_backbufWidth) /m_backbufHeight;//像素对应的射线方向权重预插值的跨度表//球形视口  方法一二 都是默认线性像素 视口边缘可能拉伸(?鱼眼收缩),使用环形视口改进   ?传统管线也存在此问题//每个像素使用一次tan直接计算出射线方向 替代方法一二中的前三个矩阵float odHeight_1 = 1.0f/(m_backbufHeight-1);float odWidth_1 = 1.0f/(m_backbufWidth-1);//传统的投影矩阵平均插值if (m_sphereProject==false){for (int w=0;w<m_backbufWidth;w++){WRat[w] = w*odWidth_1;}for (int h=0;h<m_backbufHeight;h++){HRat[h] = h*odHeight_1;}}else{//自变量圆割上的x,tan(x), ang的导数float tanfov2 = tan(G_Camera.m_fov/2);//0 width 对应-+fov/2float startAng = -G_Camera.m_fov/2;for (int w=0;w<m_backbufWidth;w++){float x = w*odWidth_1;//0~1x = x*2 -1; //-1~1x*=tanfov2;//x*=aspect;float ang = atan(x);WRat[w] = (ang-startAng)/G_Camera.m_fov;//当前像素对应角度的占比}for (int h=0;h<m_backbufHeight;h++){float y = h*odHeight_1;//0~1y = y*2 -1; //-1~1y*=tanfov2;float ang = atan(y);HRat[h] = (ang-startAng)/G_Camera.m_fov;//当前像素对应角度的占比}}
}int  RayTraceRendDriver::GetSamples()
{return SamplesPerPixel;
}void RayTraceRendDriver::AfterEffectHDR()
{if(m_colorBuffer == NULL || m_hdrColorBuffer == NULL) return;float SumLum = 0.0f;//最亮的float LumWhite = 0.0f;int LumNotNull = 0;vec3 *hdrColor = m_hdrColorBuffer;float Luminance;for(int i = 0; i < WidthXHeightXSamplesSq; i++){//Luminance = (hdrColor->r * 0.2125f + hdrColor->g * 0.7154f + hdrColor->b * 0.0721f);Luminance = (hdrColor->r * 0.30f + hdrColor->g * 0.59f + hdrColor->b * 0.11f);if(Luminance > 0.0f){SumLum += Luminance;LumNotNull++;LumWhite = LumWhite > Luminance ? LumWhite : Luminance;}hdrColor++;}float AvgLum = SumLum / (float)LumNotNull;float odAvgLum;if (AvgLum>0.00001){odAvgLum = 1/AvgLum;}else{odAvgLum = 0;}LumWhite /= AvgLum;float LumWhiteSq = LumWhite * LumWhite;hdrColor = m_hdrColorBuffer;vec3 newColor;float LumRel;float MappingFactor;for(int i = 0; i < WidthXHeightXSamplesSq; i++){//Luminance = (hdrColor->r * 0.2125f + hdrColor->g * 0.7154f + hdrColor->b * 0.0721f);Luminance = (hdrColor->r * 0.30f + hdrColor->g * 0.59f + hdrColor->b * 0.11f);LumRel = Luminance * odAvgLum;//MappingFactor = LumRel * (1.0f + LumRel / LumWhiteSq) / (1.0f + LumRel);//MappingFactor = sqrt(sqrt(LumRel));MappingFactor = sqrt(LumRel);//MappingFactor = (LumRel);newColor.r = hdrColor->r * MappingFactor;newColor.g = hdrColor->g * MappingFactor;newColor.b = hdrColor->b * MappingFactor;hdrColor->r = newColor.r <= 0.0f ? 0.0f : newColor.r >= 1.0f ? 1.0f : newColor.r;hdrColor->g = newColor.g <= 0.0f ? 0.0f : newColor.g >= 1.0f ? 1.0f : newColor.g;hdrColor->b = newColor.b <= 0.0f ? 0.0f : newColor.b >= 1.0f ? 1.0f : newColor.b;hdrColor++;}//int LineWidth_WidthX3 = (m_backbufWidth - m_backbufWidth) * 3;BYTE *colorbuffer = m_colorBuffer;hdrColor = m_hdrColorBuffer;for(int y = 0; y < m_backbufHeight; y++){for(int x = 0; x < m_backbufWidth; x++){colorbuffer[2] = (BYTE)(hdrColor->r * 255);colorbuffer[1] = (BYTE)(hdrColor->g * 255);colorbuffer[0] = (BYTE)(hdrColor->b * 255);hdrColor++;colorbuffer += 3;}colorbuffer += LineWidth_WidthX3;}
}bool RayTraceRendDriver::SetSamples(int Samples)
{if(SamplesPerPixel == Samples)return false;SamplesPerPixel = Samples;OnSize(m_backbufWidth, m_backbufHeight);return true;
}void RayTraceRendDriver::Present()
{if(m_presenter)m_presenter->Present(m_backbufWidth,m_backbufHeight,m_colorBuffer);//调试 保存为图片//IFileManager m;//bool yes=m.ExportFile_PPM("savedebug.ppm", mBufferWidth, mBufferHeight, *m_pOutColorBuffer,true);
}bool RayTraceRendDriver::TraceShadow(const Primitive *except, const vec3 &lightPos, const vec3 &lightDir, float lightDis,int threadindex)
{LaConeCross* laCross = m_lights[0].m_laConePartion->GetLaConeCross(lightDir);Primitive **EndPrimitive = laCross->m_primitives + laCross->m_primitivesCount;Primitive *primitive;for(Primitive **pprimitive = laCross->m_primitives; pprimitive < EndPrimitive; pprimitive++){primitive = *pprimitive;if(primitive == except) continue;实测虚函数稍慢0.94s//if (primitive->Intersect(point, lightDir, lightDis))//{//	return true;//}实测: switch0.88s , if else0.91sswitch(primitive->primitiveType){case PT_Sphere: {SpherePrim *Sphere = (SpherePrim *)primitive;if (Sphere->Intersect(lightPos, lightDir, lightDis)){//todo 更精确的不可以直接返回,还要看遮挡点的alpha值或折射度//速度?  alpha值0.5是半遮挡; 0是不遮挡直接在相交测试中alpha测试剔除?return true;}}break;case PT_Billboard:{float distance;vec3 respos;SpherePrim *sphere = (SpherePrim *)primitive;//vec3 lightPos = lightPos+lightDir*lightDis;//todoif (sphere->Intersect(lightPos, lightDir, lightDis,distance,respos)){//todo 更精确的不可以直接返回,还要看遮挡点的alpha值或折射度//考虑到速度,暂时只对公告板物体判断透明度//纹理if(m_enableTexture2D && sphere->refleraTexture){//和sphere唯一区别是纹理坐标的计算//将碰撞点转换到以射线为-z,以球心为原点的正交坐标系,只要根据xy插值坐标即可mat4 mat;mat.LookAt(lightPos,sphere->center,G_Camera.m_localY/*vec3(0,1,0)*/);vec3 newpos = mat*(respos);float s = newpos.x/sphere->radius*0.5f+0.5f;float t = newpos.y/sphere->radius*0.5f+0.5f;//if (sphere->refleraTexture){vec3 tempcolor;sphere->refleraTexture->GetColor11(s, t,tempcolor,m_texFilter);float refract = tempcolor.g;if (refract<0.5f){return true;}}}else{return true;}}}break;case PT_Quad:{		QuadPrim *Quad = (QuadPrim *)primitive;if (Quad->Intersect(lightPos, lightDir, lightDis)){return true;}}break;case PT_Trigon:{		TrigonPrim *trigon = (TrigonPrim *)primitive;if (trigon->Intersect(lightPos, lightDir, lightDis)){return true;}}break;}}return false;稍慢//float TestDistance;体素遍历即时返回//if(m_voxelPartion->Intersect(lightPos, lightDir,lightDis, TestDistance,except))//	return true;return false;}vec3 RayTraceRendDriver::LightIntensity(const Primitive *except, const vec3 &point, const vec3 &normal, const vec3 &lightPos, LightRT *light, float AO,int threadindex)
{vec3 lightDir = point - lightPos;float LightDis2 = lightDir.LengthSq();float lightDis = sqrt(LightDis2);lightDir *= 1.0f / lightDis;float Attenuation = light->QuadraticAttenuation * LightDis2 + light->LinearAttenuation * lightDis + light->ConstantAttenuation;float NdotLD = -Dot(normal, lightDir);//if(NdotLD > 0.0f){if(light->Sphere){if(m_enableShadow==false||TraceShadow(except, lightPos, lightDir, lightDis, threadindex) == false){//环境光+漫反射return light->Sphere->color * ((light->Ambient * AO + light->Diffuse * NdotLD) / Attenuation);}}else{float LNdotLD = Dot(light->Quad->N, lightDir);if(LNdotLD > 0.0f){if(m_enableShadow==false||TraceShadow(except, lightPos, lightDir, lightDis, threadindex) == false){//环境光+漫反射return light->Quad->color * ((light->Ambient * AO + light->Diffuse * NdotLD * LNdotLD) / Attenuation);}}}}//物体内的背面?//阴影 只有环境光return (light->Sphere ? light->Sphere->color : light->Quad->color) * (light->Ambient * AO / Attenuation);
}float ODRM = 1.0f / (float)RAND_MAX;
float TDRM = 2.0f / (float)RAND_MAX;float RayTraceRendDriver::AmbientOcclusionFactor(const Primitive *except, const vec3 &point, const vec3 &normal,int threadindex)
{//环境光遮蔽 16次随机方向采样float AO = 0.0f;for(int i = 0; i < GISampleNum; i++){//不能随机会闪烁? 固定若干方向,每帧计算一部分(静态可以 动态不行)?vec3 RandomRay = (vec3(TDRM * (float)rand() - 1.0f, TDRM * (float)rand() - 1.0f, TDRM * (float)rand() - 1.0f));RandomRay.Normalize();float NdotRR = Dot(normal, RandomRay);if(NdotRR < 0.0f){RandomRay = -RandomRay;NdotRR = -NdotRR;}float distance = 1048576.0f;float TestDistance;//TagWithVoxel(point, RandomRay);//Primitive **EndPrimitive = m_primitivesTagged + m_primitivesTaggedCount;//Primitive *primitive;//for(Primitive **pprimitive = m_primitivesTagged; pprimitive < EndPrimitive; pprimitive++)//{//	primitive = *pprimitive;//	if(primitive == except) continue;//	switch(primitive->primitiveType)//	{//	case PT_Sphere: case PT_Billboard://		{//			SpherePrim *Sphere = (SpherePrim *)primitive;//			if (Sphere->Intersect(point, RandomRay, distance, TestDistance))//			{//				distance = TestDistance;//			}//		}//		break;//	case PT_Quad://		{		//			QuadPrim *Quad = (QuadPrim *)primitive;//			if (Quad->Intersect(point, RandomRay, distance, TestDistance))//			{//				distance = TestDistance;//			}//		}//		break;//	case PT_Trigon://		{		//			TrigonPrim *trigon = (TrigonPrim *)primitive;//			if (trigon->Intersect(point, RandomRay, distance, TestDistance))//			{//				distance = TestDistance;//			}//		}//		break;//	}//}//体素遍历即时返回if(m_voxelPartion->Intersect(point, RandomRay,distance, TestDistance,except,threadindex))distance = TestDistance;AO += NdotRR / (1.0f + distance * distance);}return 1.0f - AO * ODGISamplesXAmbientOcclusionIntensity;
}void RayTraceRendDriver::IlluminatePoint(const Primitive *except, const vec3 &point, const vec3 &normal, vec3 &color,int threadindex)
{float AO = 1.0f;if(m_enableAmbientOcclusion){AO = AmbientOcclusionFactor(except, point, normal,threadindex);}if(m_lightsCount == 0){vec3 cam =G_Camera.m_eyePos - point;cam.Normalize();float NdotCD = Dot(normal, cam);if(NdotCD > 0.0f){color *= 0.5f * (AO + NdotCD);}else{color *= 0.5f * AO;}}else if(m_enableSoftShadow == false||m_enableShadow == false){vec3 LightsIntensitiesSum;LightRT *EndLight = m_lights + m_lightsCount;for(LightRT *light = m_lights; light < EndLight; light++){LightsIntensitiesSum += LightIntensity(except, point, normal, light->Sphere ? light->Sphere->center : light->Quad->m, light, AO, threadindex);}color *= LightsIntensitiesSum;}else{vec3 LightsIntensitiesSum;LightRT *EndLight = m_lights + m_lightsCount;for(LightRT *light = m_lights; light < EndLight; light++){if(light->Sphere){//todo 模拟辐射度 16次随机方向采样//体积光源产生边缘模糊的阴影 =》阴影闪烁for(int i = 0; i < GISampleNum; i++){vec3 RandomRay = vec3(TDRM * (float)rand() - 1.0f, TDRM * (float)rand() - 1.0f, TDRM * (float)rand() - 1.0f);RandomRay.Normalize();vec3 RandomLightPos = RandomRay * light->Sphere->radius + light->Sphere->center;LightsIntensitiesSum += LightIntensity(except, point, normal, RandomLightPos, light, AO, threadindex);}}else{for(int i = 0; i < GISampleNum; i++){float s = ODRM * (float)rand();float t = ODRM * (float)rand();vec3 RandomLightPos = light->Quad->B_A * s + light->Quad->D_A * t + light->Quad->ptA;LightsIntensitiesSum += LightIntensity(except, point, normal, RandomLightPos, light, AO, threadindex);}}}color *= LightsIntensitiesSum * ODGISamples;}
}float M_1_PI_2 = (float)M_1_PI * 0.5f;vec3 RayTraceRendDriver::TraceRay(const vec3 &rayPos, const vec3 &rayDir, int depth, Primitive *except,int threadindex)
{TraceRes traceRes;traceRes.traceDepth = depth;traceRes.rayPos = rayPos;traceRes.rayDir = rayDir;//第一次if (depth==0){//深度0有缓存,一射线剔除碰撞LaConeCross* anxel = m_eyeLaConePartion->GetLaConeCross(rayDir);Primitive **EndPrimitive = anxel->m_primitives + anxel->m_primitivesCount;Primitive *primitive;for(Primitive **pprimitive = anxel->m_primitives; pprimitive < EndPrimitive; pprimitive++){primitive = *pprimitive;if(primitive == except) continue;switch(primitive->primitiveType){case PT_Sphere: case PT_Billboard:{SpherePrim *Sphere = (SpherePrim *)primitive;Sphere->Intersect(rayPos, rayDir, traceRes);}break;case PT_Quad:{		QuadPrim *Quad = (QuadPrim *)primitive;Quad->Intersect(rayPos, rayDir, traceRes);}break;case PT_Trigon:{		TrigonPrim *trigon = (TrigonPrim *)primitive;trigon->Intersect(rayPos, rayDir, traceRes);}break;}}/*Boxel* boxel = m_eyeAnguleBoxPartion->GetBoxel(rayDir);Primitive **EndPrimitive = boxel->m_primitives + boxel->m_primitivesCount;Primitive *primitive;for(Primitive **pprimitive = boxel->m_primitives; pprimitive < EndPrimitive; pprimitive++){primitive = *pprimitive;if(primitive == except) continue;switch(primitive->primitiveType){case PT_Sphere: case PT_Billboard:{SpherePrim *Sphere = (SpherePrim *)primitive;Sphere->Intersect(rayPos, rayDir, traceRes);}break;case PT_Quad:{		QuadPrim *Quad = (QuadPrim *)primitive;Quad->Intersect(rayPos, rayDir, traceRes);}break;case PT_Trigon:{		TrigonPrim *trigon = (TrigonPrim *)primitive;trigon->Intersect(rayPos, rayDir, traceRes);}break;}}*/体素遍历即时返回//m_voxelPartion->Intersect(rayPos, rayDir,traceRes,NULL);//测试if (debugRegion==1){traceRes.primitive = NULL;int primCount = anxel->m_primitivesCount;traceRes.color.r = primCount/255.0f;traceRes.color.g = (primCount-255)/255.0f;traceRes.color.b = (primCount-510)/255.0f;}}else{第二级深度开始不方便缓存 即时剔除//体素遍历即时返回m_voxelPartion->Intersect(rayPos, rayDir,traceRes,except,threadindex);测试//if (debugShader==2)//{//	traceRes.primitive = NULL;//	int primCount = laCross->m_primitivesCount;//	traceRes.color.r = primCount/255.0f;//	traceRes.color.g = (primCount-255)/255.0f;//	traceRes.color.b = (primCount-510)/255.0f;//}第二级深度开始不方便缓存 即时剔除稍慢//TagWithBsp(rayPos,rayDir);//Primitive **EndPrimitive = m_primitivesTagged + m_primitivesTaggedCount;//Primitive *primitive;//for(Primitive **pprimitive = m_primitivesTagged; pprimitive < EndPrimitive; pprimitive++)//{//	primitive = *pprimitive;//	if(primitive == except) continue;//	//primitive->Intersect(rayPos, rayDir, traceRes);//	switch(primitive->primitiveType)//	{//	case PT_Sphere: case PT_Billboard://		{//			SpherePrim *Sphere = (SpherePrim *)primitive;//			Sphere->Intersect(rayPos, rayDir, traceRes);//		}//		break;//	case PT_Quad://		{		//			QuadPrim *Quad = (QuadPrim *)primitive;//			Quad->Intersect(rayPos, rayDir, traceRes);//		}//		break;//	case PT_Trigon://		{		//			TrigonPrim *trigon = (TrigonPrim *)primitive;//			trigon->Intersect(rayPos, rayDir, traceRes);//		}//		break;//	}//}}LightRT *EndLight = m_lights + m_lightsCount;for(LightRT *light = m_lights; light < EndLight; light++){if(light->Sphere){if(light->Sphere->Intersect(rayPos, rayDir, traceRes.distanceSofar, traceRes.testDistance, traceRes.testPoint)){traceRes.point = traceRes.testPoint;traceRes.distanceSofar = traceRes.testDistance;traceRes.light = light;traceRes.primitive = NULL;}}else{if(light->Quad->Intersect(rayPos, rayDir, traceRes.distanceSofar, traceRes.testDistance, traceRes.testPoint)){traceRes.point = traceRes.testPoint;traceRes.distanceSofar = traceRes.testDistance;traceRes.light = light;traceRes.primitive = NULL;}}}if(traceRes.light){traceRes.color = traceRes.light->Sphere ? traceRes.light->Sphere->color : traceRes.light->Quad->color;}else if(traceRes.primitive){vec3 texColor;vec3 refleraColor;vec3 ptNormal;switch(traceRes.primitive->primitiveType){case PT_Sphere: {SpherePrim* sphere = (SpherePrim*)(traceRes.primitive);traceRes.color = sphere->color;//*sphere->ODRadius =>normlized vec3 normal = (traceRes.point - sphere->center) * sphere->ODRadius;//纹理if(m_enableTexture2D && sphere->pTexture){float s = atan2(normal.x, normal.z) * M_1_PI_2 + 0.5f;float t = asin(normal.y < -1.0f ? -1.0f : normal.y > 1.0f ? 1.0f : normal.y) * (float)M_1_PI + 0.5f;vec3 tempcolor;sphere->pTexture->GetColor11(s, t,tempcolor,m_texFilter);traceRes.color *= tempcolor;//traceRes.color *= sphere->SampleTexColor( traceRes.point,m_texFilter);if (sphere->refleraTexture){sphere->refleraTexture->GetColor11(s, t,refleraColor,m_texFilter);}}//光照IlluminatePoint(sphere, traceRes.point, normal, traceRes.color, threadindex);//todo lerp(color,fle,fra,rat1,rat2,rat3)if (depth<MaxTraceDepth){float reflection = sphere->reflection;float refraction = sphere->refraction;//float Eta = trigon->Eta;//float ODEta = trigon->ODEta;//从折射贴图取得折射系数if (sphere->refleraTexture){reflection = refleraColor.r;refraction = refleraColor.g;//Eta = refleraColor.b;//if(Eta>_EPSILON)ODEta = 1/Eta; else ODEta = 99999;}//反射if(m_enableReflection && reflection > 0.0f){vec3 ReflectedRay = Reflect(rayDir, normal);traceRes.color = Lerp(traceRes.color, TraceRay(traceRes.point, ReflectedRay, depth+1, sphere,threadindex), reflection);}//纹理alpha穿透,这里不能返回alpha和backbuff混合,因为backbuff未被追踪,//透明贴图需要继续追踪  根据纹理alpha调整折射系数和折射率//追踪深度不能受到半透限制,否则草丛只追有限的几层,效率?//折射 	if(m_enableRefraction && refraction > 0.0f){vec3 RefractedRay = Refract(rayDir, normal, sphere->ODEta);vec3 L = sphere->center - traceRes.point;float LdotRR = Dot(L, RefractedRay);float D2 = L.LengthSq() - LdotRR * LdotRR;//assert(dis>=0);float dis_ = sphere->Radius2 - D2;if (dis_<0){dis_ = 0;}float distance = LdotRR + sqrt(dis_);//distance = LdotRR *2;  //?vec3 NewPoint = traceRes.point + RefractedRay*distance;vec3 NewNormal = (sphere->center - NewPoint) * sphere->ODRadius;//todo 球内穿越的距离 会积累球的颜色 类似体积雾RefractedRay = Refract(RefractedRay, NewNormal, sphere->Eta);//todo 重新采样射出点折射系数traceRes.color = Lerp(traceRes.color, TraceRay(NewPoint, RefractedRay, depth+1, sphere,threadindex), refraction);}}}break;case PT_Billboard:{BillboardPrim* sphere = (BillboardPrim*)(traceRes.primitive);traceRes.color = sphere->color;//*sphere->ODRadius =>normlized vec3 normal = (traceRes.point - sphere->center) * sphere->ODRadius;//纹理if(m_enableTexture2D && sphere->pTexture){//和sphere唯一区别是纹理坐标的计算//将碰撞点转换到以射线为-z,以球心为原点的正交坐标系,只要根据xy插值坐标即可mat4 mat;mat.LookAt(rayPos,sphere->center,G_Camera.m_localY/*vec3(0,1,0)*/);vec3 newpos = mat*(traceRes.point);//-sphere->center);//vec3 newDir(sphere->center-rayPos);//newDir.Normalize();//mat.FromToDir(newDir/*rayDir*/,vec3(0,0,-1));//vec3 newDir(0,rayDir.y,-1);//newDir.Normalize();//mat.FromToDir(rayDir,newDir);//mat.FromRotateY(atan2(rayDir.x,rayDir.z));//vec3 newpos = mat*(traceRes.point-sphere->center);float s = newpos.x/sphere->radius*0.5f+0.5f;float t = newpos.y/sphere->radius*0.5f+0.5f;vec3 tempcolor;sphere->pTexture->GetColor11(s, t,tempcolor,m_texFilter);traceRes.color *= tempcolor;//traceRes.color *= sphere->SampleTexColor( traceRes.point,m_texFilter);if (sphere->refleraTexture){sphere->refleraTexture->GetColor11(s, t,refleraColor,m_texFilter);//GetColorBilinear}}//插值法线 todo 法线贴图//sphere->SampleNormal(traceRes.point,ptNormal);//光照  todo透明不参与光照IlluminatePoint(sphere, traceRes.point, normal, traceRes.color, threadindex);//todo lerp(color,fle,fra,rat1,rat2,rat3)if (depth<MaxTraceDepth){float reflection = sphere->reflection;float refraction = sphere->refraction;//float Eta = trigon->Eta;//float ODEta = trigon->ODEta;//从折射贴图取得折射系数if (sphere->refleraTexture){reflection = refleraColor.r;refraction = refleraColor.g;//Eta = refleraColor.b;//if(Eta>_EPSILON)ODEta = 1/Eta; else ODEta = 99999;}//反射if(m_enableReflection && reflection > 0.0f){vec3 ReflectedRay = Reflect(rayDir, normal);traceRes.color = Lerp(traceRes.color, TraceRay(traceRes.point, ReflectedRay, depth+1, sphere,threadindex), reflection);}//纹理alpha穿透,这里不能返回alpha和backbuff混合,因为backbuff未被追踪,//透明贴图需要继续追踪  根据纹理alpha调整折射系数和折射率//追踪深度不能受到半透限制,否则草丛只追有限的几层,效率?//折射 	alphaif(m_enableRefraction && refraction > 0.0f){//仅仅是透明效果traceRes.color = Lerp(traceRes.color, TraceRay(traceRes.point, rayDir, depth+1, sphere,threadindex), refraction);//traceRes.color = TraceRay(traceRes.point, rayDir, depth+1, sphere);}}}break;case PT_Quad:{QuadPrim* quad = (QuadPrim*)(traceRes.primitive);traceRes.color = quad->color;//纹理if(m_enableTexture2D && quad->pTexture){quad->SampleTexColor( traceRes.point,texColor,refleraColor,m_texFilter);traceRes.color *= texColor;}插值法线//quad->SampleNormal(traceRes.point,ptNormal);ptNormal = quad->N;//光照IlluminatePoint(quad, traceRes.point, ptNormal, traceRes.color, threadindex);if (depth<MaxTraceDepth){float reflection = quad->reflection;float refraction = quad->refraction;//float Eta = trigon->Eta;//float ODEta = trigon->ODEta;//从折射贴图取得折射系数if (quad->refleraTexture){reflection = refleraColor.r;refraction = refleraColor.g;//Eta = refleraColor.b;//if(Eta>_EPSILON)ODEta = 1/Eta; else ODEta = 99999;}//反射if(m_enableReflection && reflection > 0.0f){vec3 ReflectedRay = Reflect(rayDir, ptNormal);traceRes.color = Lerp(traceRes.color, TraceRay(traceRes.point, ReflectedRay, depth+1, quad,threadindex), reflection);}//todo 球内穿越的距离 会积累球的颜色 类似体积雾//todo 反面要能碰撞检测到//折射 alphaif(m_enableRefraction && refraction > 0.0f){float Angle = -Dot(ptNormal, rayDir);vec3 normal;float Eta;if(Angle > 0.0f){normal = ptNormal;Eta = quad->ODEta;}else{normal = -ptNormal;Eta = quad->Eta;}vec3 RefractedRay = Refract(rayDir, normal, Eta);if(RefractedRay.x == 0.0f && RefractedRay.y == 0.0f && RefractedRay.z == 0.0f){RefractedRay = Reflect(rayDir, normal);}traceRes.color = Lerp(traceRes.color, TraceRay(traceRes.point, RefractedRay, depth+1, quad,threadindex), refraction);}}}break;case PT_Trigon:{TrigonPrim* trigon = (TrigonPrim*)(traceRes.primitive);traceRes.color = trigon->color;//纹理if(m_enableTexture2D && trigon->pTexture){trigon->SampleTexColor(traceRes.point,texColor,refleraColor,m_texFilter);traceRes.color *= texColor;}//插值法线trigon->SampleNormal(traceRes.point,ptNormal);//光照IlluminatePoint(trigon, traceRes.point, trigon->N, traceRes.color, threadindex);if (depth<MaxTraceDepth){float reflection = trigon->reflection;float refraction = trigon->refraction;//float Eta = trigon->Eta;//float ODEta = trigon->ODEta;//从折射贴图取得折射系数if (trigon->refleraTexture){reflection = refleraColor.r;refraction = refleraColor.g;//Eta = refleraColor.b;//if(Eta>_EPSILON)ODEta = 1/Eta; else ODEta = 99999;}//反射if(m_enableReflection && reflection > 0.0f){vec3 ReflectedRay = Reflect(rayDir, ptNormal);//trigon->N);traceRes.color = Lerp(traceRes.color, TraceRay(traceRes.point, ReflectedRay, depth+1, trigon,threadindex), reflection);}//todo 球内穿越的距离 会积累球的颜色 类似体积雾//todo 反面要能碰撞检测到//折射 alphaif(m_enableRefraction && refraction > 0.0f){float Angle = -Dot(trigon->N, rayDir);vec3 normal;float Eta;if(Angle > 0.0f){normal = ptNormal;//trigon->N;Eta = trigon->ODEta;}else{normal = -ptNormal;//trigon->N;Eta = trigon->Eta;}vec3 RefractedRay = Refract(rayDir, normal, Eta);if(RefractedRay.x == 0.0f && RefractedRay.y == 0.0f && RefractedRay.z == 0.0f){RefractedRay = Reflect(rayDir, normal);}traceRes.color = Lerp(traceRes.color, TraceRay(traceRes.point, RefractedRay, depth+1, trigon,threadindex), refraction);}}}break;}}return traceRes.color;
}void RayTraceRendDriver::PartionWithBsp(PrimitiveBspTree* bsptree)
{PrimitiveTreeBuilder builder(1,70,true);//16);70PrimitiveBuffRef primitiveBuff(m_primitives,sizeof(QuadPrim*),m_primitivesCount);builder.BuildTree(bsptree,primitiveBuff);//FILE* file = fopen("primitiveTree.txt","wt");//if (file)//{//	m_bsptree->Dump(file);//	fclose(file);//}
}void RayTraceRendDriver::PartionWithVoxel(UniformVoxelPartion* voxelPartion)
{voxelPartion->Generate(m_primitives,m_primitivesCount,16);//8);//32
}void RayTraceRendDriver::PartionWithLaCone(LaCone3Partion *laConePartion)
{Primitive **EndPrimitive = m_primitives + m_primitivesCount;for(Primitive **pprimitive = m_primitives; pprimitive < EndPrimitive; pprimitive++){laConePartion->GatherPrimtive(*pprimitive);}if (laConePartion->m_primitivesUsedCount>=laConePartion->m_primitivesVolume){MessageBox(0,"laConePartion->m_primitivesUsedCount>=laConePartion->m_primitivesVolume","",MB_OK);Primitive **oldPrimitives = laConePartion->m_primitives;laConePartion->m_primitivesVolume *= 2;laConePartion->m_primitives = new Primitive*[laConePartion->m_primitivesVolume];memcpy(laConePartion->m_primitives,oldPrimitives,laConePartion->m_primitivesUsedCount*sizeof(Primitive*));if(oldPrimitives != NULL){delete [] oldPrimitives;}}laConePartion->m_primitivesUsedCount = 0;laConePartion->AssignLaConeVolume();for(Primitive **pprimitive = m_primitives; pprimitive < EndPrimitive; pprimitive++){laConePartion->PushPrimtive(*pprimitive);}//内部近似深度排序,因为有误差还是要全部遍历 除了traceshadow时可以及时返回
}void RayTraceRendDriver::PartionWithAnguleBox(AnguleBoxPartion *anguleBoxPartion)
{Primitive **EndPrimitive = m_primitives + m_primitivesCount;for(Primitive **pprimitive = m_primitives; pprimitive < EndPrimitive; pprimitive++){anguleBoxPartion->GatherPrimtive(*pprimitive);}if (anguleBoxPartion->m_primitivesUsedCount>=anguleBoxPartion->m_primitivesVolume){MessageBox(0,"laConePartion->m_primitivesUsedCount>=laConePartion->m_primitivesVolume","",MB_OK);Primitive **oldPrimitives = anguleBoxPartion->m_primitives;anguleBoxPartion->m_primitivesVolume *= 2;anguleBoxPartion->m_primitives = new Primitive*[anguleBoxPartion->m_primitivesVolume];memcpy(anguleBoxPartion->m_primitives,oldPrimitives,anguleBoxPartion->m_primitivesUsedCount*sizeof(Primitive*));if(oldPrimitives != NULL){delete [] oldPrimitives;}}anguleBoxPartion->m_primitivesUsedCount = 0;anguleBoxPartion->AssignLaConeVolume();for(Primitive **pprimitive = m_primitives; pprimitive < EndPrimitive; pprimitive++){anguleBoxPartion->PushPrimtive(*pprimitive);}//内部近似深度排序,因为有误差还是要全部遍历 除了traceshadow时可以及时返回
}void RayTraceRendDriver::TagWithBsp(const vec3&pos,const vec3&dir)
{//内部防重复添加m_primitivesTaggedCount=0;m_bspPartion->WalkThroughTray(pos,dir,m_primitivesTagged,m_primitivesTaggedCount);//Primitive **EndPrimitive = m_primitives + m_primitivesCount;//Primitive *primitive;//for(Primitive **pprimitive = m_primitives; pprimitive < EndPrimitive; pprimitive++)//{//	primitive = *pprimitive;//	m_primitivesTagged[m_primitivesTaggedCount++] = primitive;//}
}void RayTraceRendDriver::CheckPrimitiveVolume(int addCount)
{if (m_primitivesCount+addCount>=m_primitivesVolume){MessageBox(0,"m_primitivesCount+addCount>=m_primitivesVolume","",MB_OK);Primitive **oldPrimitives = m_primitives;m_primitivesVolume *= 2;m_primitives = new Primitive*[m_primitivesVolume];memcpy(m_primitives,oldPrimitives,m_primitivesCount*sizeof(Primitive*));if(oldPrimitives != NULL){delete [] oldPrimitives;}}
}void RayTraceRendDriver::AddPrimitives(Primitive* pprimitives,int count)
{if (count<=0){return;}CheckPrimitiveVolume(count);PrimitiveType type = pprimitives->primitiveType;int stride = 0;switch(type){case PT_Sphere: stride = sizeof(SpherePrim);break;case PT_Billboard:stride = sizeof(BillboardPrim);break;case PT_Quad:stride = sizeof(QuadPrim);break;case PT_Trigon:stride = sizeof(TrigonPrim);break;}char* head = (char*)pprimitives;Primitive* prim;for (int i=0;i<count;i++){prim = (Primitive*)head;if (prim->primitiveType!=type){MessageBox(0,"primitiveType!=type","",MB_OK);}m_primitives[m_primitivesCount++] = prim;head+=stride;}
}void RayTraceRendDriver::AddPrimitives(Primitive** pprimitives,int count)
{if (count<=0){return;}CheckPrimitiveVolume(count);for (int i=0;i<count;i++){m_primitives[m_primitivesCount++] = *pprimitives;pprimitives++;}
}void RayTraceRendDriver::RemovePrimitives(Primitive* pprimitives,int count)
{if (count<=0){return;}PrimitiveType type = pprimitives->primitiveType;int stride = 0;switch(type){case PT_Sphere: case PT_Billboard:stride = sizeof(SpherePrim);break;case PT_Quad:stride = sizeof(QuadPrim);break;case PT_Trigon:stride = sizeof(TrigonPrim);break;}char* head = (char*)pprimitives;Primitive* prim;for (int i=0;i<count;i++){prim = (Primitive*)head;if (prim->primitiveType!=type){MessageBox(0,"primitiveType!=type","",MB_OK);}//	de *pprimitives;//	pprimitives++;head+=stride;}
}void RayTraceRendDriver::RemovePrimitives(Primitive** pprimitives,int count)
{if (count<=0){return;}for (int i=0;i<count;i++){//	de *pprimitives;//	pprimitives++;}
}void RayTraceRendDriver::DumpPrimitives(Primitive** pprimitives,int count)
{if (count<=0){return;}char buf[512];Primitive* primitive;for (int i=0;i<count;i++){primitive = *pprimitives;switch(primitive->primitiveType){case PT_Sphere: {SpherePrim *sphereprim = (SpherePrim*)primitive;sprintf(buf,"type SpherePrim,center%f,%f,%f  radius%f\n",sphereprim->center.x,sphereprim->center.y,sphereprim->center.z,sphereprim->radius);}break;case PT_Billboard:{BillboardPrim *sphereprim = (BillboardPrim*)primitive;sprintf(buf,"type BillboardPrim,center%f,%f,%f  radius%f\n",sphereprim->center.x,sphereprim->center.y,sphereprim->center.z,sphereprim->radius);}break;case PT_Trigon:{TrigonPrim *trigonprim = (TrigonPrim*)primitive;sprintf(buf,"type TrigonPrim,center%f,%f,%f  radius%f\n",trigonprim->center.x,trigonprim->center.y,trigonprim->center.z,trigonprim->radius);}break;case PT_Quad:{QuadPrim *quadprim = (QuadPrim*)primitive;sprintf(buf,"type PT_Quad,center%f,%f,%f  radius%f\n",quadprim->center.x,quadprim->center.y,quadprim->center.z,quadprim->radius);}break;}OutputDebugString(buf);pprimitives++;}
}bool RayTraceRendDriver::SetQuality(float quality)
{if (m_quality==quality){return false;}m_quality = quality;OnSize(m_wndWidth,m_wndHeight);return true;
}bool RayTraceRendDriver::DrawTextureRect(const RectF& tar)
{int x1 = tar.x;int x2 = tar.x+tar.width;int y1 = tar.y;int y2 = tar.y+tar.height;RayTraceTexture*texture=m_curTexture;x1 = Clamp(x1, 0, m_backbufWidth-1);x2 = Clamp(x2, 0, m_backbufWidth-1);y1 = Clamp(y1, 0, m_backbufHeight-1);y2 = Clamp(y2, 0, m_backbufHeight-1);if (x1 >= x2 || y1 >= y2){return false;}vec3 colorScr(1, 0,0);float invDstWidth = 1.0f/(x2 - x1+1);float invDstHeight = 1.0f/(y2 - y1+1);for (int y = y1;y <= y2;++y){float coordy = float(y - y1) * invDstHeight;BYTE* color_ = m_colorBuffer+(y*m_backbufWidth)*3;vec3* colorHdr = m_hdrColorBuffer+(y*m_backbufWidth);for (int x = x1;x <= x2;++x){float coordx = float(x - x1) *invDstWidth;texture->GetColor11(coordx, coordy,colorScr,m_texFilter);color_[2] = (BYTE)(colorScr.x*255);color_[1] = (BYTE)(colorScr.y*255);color_[0] = (BYTE)(colorScr.z*255);color_+=3;colorHdr->r = colorScr.x;colorHdr->g = colorScr.y;colorHdr->b = colorScr.z;colorHdr++;}}return true;
}

 

这篇关于纯c++实现光线追踪渲染器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/944913

相关文章

关于C++中的虚拟继承的一些总结(虚拟继承,覆盖,派生,隐藏)

1.为什么要引入虚拟继承 虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。实现的代码如下: class A class B1:public virtual A; class B2:pu

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

C++的模板(八):子系统

平常所见的大部分模板代码,模板所传的参数类型,到了模板里面,或实例化为对象,或嵌入模板内部结构中,或在模板内又派生了子类。不管怎样,最终他们在模板内,直接或间接,都实例化成对象了。 但这不是唯一的用法。试想一下。如果在模板内限制调用参数类型的构造函数会发生什么?参数类的对象在模板内无法构造。他们只能从模板的成员函数传入。模板不保存这些对象或者只保存他们的指针。因为构造函数被分离,这些指针在模板外

C++工程编译链接错误汇总VisualStudio

目录 一些小的知识点 make工具 可以使用windows下的事件查看器崩溃的地方 dumpbin工具查看dll是32位还是64位的 _MSC_VER .cc 和.cpp 【VC++目录中的包含目录】 vs 【C/C++常规中的附加包含目录】——头文件所在目录如何怎么添加,添加了以后搜索头文件就会到这些个路径下搜索了 include<> 和 include"" WinMain 和

C/C++的编译和链接过程

目录 从源文件生成可执行文件(书中第2章) 1.Preprocessing预处理——预处理器cpp 2.Compilation编译——编译器cll ps:vs中优化选项设置 3.Assembly汇编——汇编器as ps:vs中汇编输出文件设置 4.Linking链接——链接器ld 符号 模块,库 链接过程——链接器 链接过程 1.简单链接的例子 2.链接过程 3.地址和

C++必修:模版的入门到实践

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C++学习 贝蒂的主页:Betty’s blog 1. 泛型编程 首先让我们来思考一个问题,如何实现一个交换函数? void swap(int& x, int& y){int tmp = x;x = y;y = tmp;} 相信大家很快就能写出上面这段代码,但是如果要求这个交换函数支持字符型

通过SSH隧道实现通过远程服务器上外网

搭建隧道 autossh -M 0 -f -D 1080 -C -N user1@remotehost##验证隧道是否生效,查看1080端口是否启动netstat -tuln | grep 1080## 测试ssh 隧道是否生效curl -x socks5h://127.0.0.1:1080 -I http://www.github.com 将autossh 设置为服务,隧道开机启动

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测 目录 时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测基本介绍程序设计参考资料 基本介绍 MATLAB实现LSTM时间序列未来多步预测-递归预测。LSTM是一种含有LSTM区块(blocks)或其他的一种类神经网络,文献或其他资料中LSTM区块可能被描述成智能网络单元,因为

C++入门01

1、.h和.cpp 源文件 (.cpp)源文件是C++程序的实际实现代码文件,其中包含了具体的函数和类的定义、实现以及其他相关的代码。主要特点如下:实现代码: 源文件中包含了函数、类的具体实现代码,用于实现程序的功能。编译单元: 源文件通常是一个编译单元,即单独编译的基本单位。每个源文件都会经过编译器的处理,生成对应的目标文件。包含头文件: 源文件可以通过#include指令引入头文件,以使

vue项目集成CanvasEditor实现Word在线编辑器

CanvasEditor实现Word在线编辑器 官网文档:https://hufe.club/canvas-editor-docs/guide/schema.html 源码地址:https://github.com/Hufe921/canvas-editor 前提声明: 由于CanvasEditor目前不支持vue、react 等框架开箱即用版,所以需要我们去Git下载源码,拿到其中两个主