纯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);
	//计算了ODEta
	void 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 C
	A 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;//16
	
	ODGISamples = 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);//16
	m_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/2
		m_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();

		//?? wait
		for (int i=0;i<m_threadNum;i++)
		{
			m_traceThread[i].startLine = i*m_backbufHeight/m_threadNum;  //400/2
			m_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 C
		A 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));
					//用插值代替上面的矩阵乘法 带旋转的世界坐标系 不能简单插值xy
					rat = 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 y
							rat = 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/2
		float startAng = -G_Camera.m_fov/2;
		for (int w=0;w<m_backbufWidth;w++)
		{
			float x = w*odWidth_1;//0~1
			x = x*2 -1; //-1~1
			x*=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~1
			y = y*2 -1; //-1~1
			y*=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.91s
		switch(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;//todo
				if (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调整折射系数和折射率
					//追踪深度不能受到半透限制,否则草丛只追有限的几层,效率?

					//折射 	alpha
					if(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 反面要能碰撞检测到

					//折射 alpha
					if(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 反面要能碰撞检测到

					//折射 alpha
					if(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);70
	PrimitiveBuffRef 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;
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值