这是一个几年前用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
#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) ) 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
#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
#define WIN32APP
#include "General/Thread.h"
#include
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;i0.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 (-_EPSILONGetColor11(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_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 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;iReset(G_Camera.m_eyePos);
PartionWithLaCone(m_eyeLaConePartion);
//m_eyeAnguleBoxPartion->Reset(G_Camera.m_eyePos);
//PartionWithAnguleBox(m_eyeAnguleBoxPartion);
for (int i=0;im_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= 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;wr * 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 (depthreflection;
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 (depthreflection;
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 (depthreflection;
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 (depthreflection;
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;iprimitiveType!=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;iprimitiveType;
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;iprimitiveType!=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;iprimitiveType)
{
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;
}