📄 scene.cpp
字号:
// Scene.cpp: implementation of the CScene class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "RayTrace.h"
#include "Scene.h"
#include "RayTraceView.h"
#include "MainFrm.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//构造函数,初始化场景
CScene::CScene()
:
dFocalLength ( 4.0 ),
dRotateAngle ( 0 ),
dTiltAngle ( 0 ),
nXRes ( 600 ),
nYRes ( 450 ),
nDepth ( 0 ),
nMaxDepth ( 5 ),
ObservePosition ( 0.0,-400.0,400.0 ),
LookAt (0,0,0),
LocalWeight ( 0.9,0.9,0.9 ),
ReflectWeight ( 0.95,0.95,0.95 ),
TransmitWeight ( 0.75,0.75,0.75 ),
MinWeight ( 0.0,0.0,0.0 ),
MaxWeight ( 1.0,1.0,1.0 )
{
//计算观察方向向量
CVector temp = ObservePosition - LookAt;
//计算观察方向向量绕z轴的旋转角和俯仰角
dRotateAngle = atan( temp.GetX() / temp.GetY() );
dTiltAngle = asin( temp.GetZ() / temp.GetLength() );
double Phi = dRotateAngle;
double Theta = dTiltAngle;
double x,y,z;
x = cos( Theta ) * sin( Phi );
y = cos( Theta ) * cos( Phi );
z = -sin( Theta );
ViewDir.SetOffset(x,y,z);
x = cos( Phi );
y = -sin( Phi );
z = 0.0;
U.SetOffset(x,y,z);
x = sin( Theta ) * sin( Phi );
y = sin( Theta ) * cos( Phi );
z = cos( Theta );
V.SetOffset(x,y,z);
}
/*************************************************************************
*
* 函数名称:
* CScene::InitDirection()
*
* 参数:
* int ScreenX, int ScreenY - 屏幕上的点的坐标
*
* 返回值:
* CVector - 返回点(ScreenX, ScreenY)到视点的方向向量
*
* 说明:
* 获得屏幕上点到视点的方向向量。
* 计算视点旋转角和俯仰角
*
************************************************************************/
CVector CScene::InitDirection(int ScreenX, int ScreenY)
{
CVector viewdir = ViewDir;
CVector u = U;
CVector v = V;
double XDivFocLen = 1 / dFocalLength;
double YDivFocLen = 1 / dFocalLength;
double CenterX = nXRes / 2;
double CenterY = nYRes / 2;
viewdir *= CenterX;
u *= ( ScreenX - CenterX ) * XDivFocLen;
v *= ( CenterY - ScreenY ) * YDivFocLen;
u += v;
u += viewdir;
u.Normalize();
return u;
}
/*************************************************************************
*
* 函数名称:
* CScene::Raytracing()
*
* 参数:
* CRay *InitRay - 入射光线指针
*
* 返回值:
* CVector - 返回对应点的光亮度
*
* 说明:
* 获取对应点的光强值。
*
************************************************************************/
CVector CScene::Raytracing(CRay *InitRay)
{
nDepth++; //进入光线跟踪函数,递归深度加1
CVector Color; //存放交点光亮度值
CRTObject* pObj; //场景景物链表
CLight* pLight; //场景光源链表
int ObjectIndex = 0; //当前景物在物体链中的序号
int LightIndex = 0; //当前光源在光源链中的序号
int ObjectNumber = ObjectList.GetNodeNum(); //物体链的总结点数目
int LightNumber = LightList.GetNodeNum(); //光源链的总结点数目
//场景中没有物体,直接返回背景光亮度
if( 0 == ObjectNumber ) return GetBackground( InitRay );
//清空景物参数(反射、折射光线及交点)
int i;
for( i = 1; i <= ObjectNumber; i++ )
{
pObj = (CRTObject*)ObjectList.GetNode(i);
pObj->Empty();
}
//清空光源参数(反射光线及交点)
for( i = 1; i <= LightNumber; i++ )
{
pLight = (CLight*)LightList.GetNode(i);
pLight->Empty();
}
double MinDist=100000.; //定义交点的最小参数
double Distant=0.; //定义最小距离
//求得与光线最先相交的物体序号
for( i = 1; i <= ObjectNumber; i++ )
{
pObj = (CRTObject*)ObjectList.GetNode(i);
pObj->InitHitRay( InitRay );
Distant = pObj->Intersect();
if( Distant < MinDist && Distant != 0 )
{
MinDist = Distant;
ObjectIndex = i;
}
}
MinDist=100000.;
//求得与光线最先相交的光源序号
for( i = 1; i <= LightNumber; i++ )
{
pLight = (CLight*)LightList.GetNode(i);
pLight->InitHitRay( InitRay );
Distant = pLight->Intersect();
if( Distant < MinDist && Distant !=0.0 )
{
MinDist = Distant;
LightIndex = i;
}
}
//光线与景物和光源都没交,交点光亮度值为背景
if( 0 == ObjectIndex && 0 == LightIndex )
{
Color = GetBackground( InitRay );
}
//光线只与光源相交,交点光亮度值为光源亮度
else if( 0 == ObjectIndex && 0 != LightIndex )
{
Color = pLight->GetIntensity();
}
//光线与景物和光源都有交
else if( 0 != ObjectIndex && 0 != LightIndex )
{
pObj = (CRTObject*)ObjectList.GetNode( ObjectIndex );
pLight = (CLight*)LightList.GetNode( ObjectIndex );
if( pObj->Intersect() < pLight->Intersect() ) //先与物体相交
{
if( pObj->GetMaterial()->bTransparency ) //可折射
{
Color = pLight->GetIntensity();
Color.ElemMult( pObj->GetMaterial()->vecTransmission );
}
else
Color = pObj->GetLocalColor( LightList,ObjectList );
}
else //先与光源相交
{
Color = pLight->GetIntensity();
}
}
//光线只与景物相交
else
{
pObj = (CRTObject*)ObjectList.GetNode( ObjectIndex );
Color = pObj->GetLocalColor( LightList, ObjectList );
Color.ElemMult( LocalWeight );
if( nDepth < nMaxDepth ) //低于最大递归深度
{
CVector TempColor;
if( pObj->GetMaterial()->bReflectable )//跟踪反射光线
{
//当前光线、交点压栈
CRay* CurrentRay = new CRay( InitRay->StartPoint, InitRay->Direction );
RayStack.Push( CurrentRay );
CVector* CurrentPoint = new CVector( pObj->GetIntersectPoint() );
PointStack.Push( CurrentPoint );
//生成反射光线,继续跟踪
CRay* ReflRay = new CRay( pObj->GetIntersectPoint(), pObj->GetReflectDir() );
TempColor = Raytracing( ReflRay );
delete ReflRay;
TempColor.ElemMult( pObj->GetMaterial()->vecSpecular );
TempColor.ElemMult( ReflectWeight );
Color += TempColor;
//光线出栈
if( !RayStack.IsEmpty() )
{
InitRay = (CRay*)RayStack.Pop();
pObj->InitHitRay( InitRay );
delete CurrentRay;
}
else
{
}
//交点出栈
if( !PointStack.IsEmpty() )
{
pObj->SetIntersectPt( *(CVector*)PointStack.Pop() );
delete CurrentPoint;
}
else
{
}
}
if( pObj->GetMaterial()->bTransparency ) //跟踪折射光线
{
//生成折射光线,继续跟踪
CRay* TranRay=new CRay( pObj->GetIntersectPoint(),pObj->GetRefractDir() );
TempColor = Raytracing( TranRay );
delete TranRay;
TempColor.ElemMult( pObj->GetMaterial()->vecTransmission );
TempColor.ElemMult( TransmitWeight );
Color += TempColor;
}
}
}
nDepth--;
return Color;
}
/*************************************************************************
*
* 函数名称:
* BeginTrace()
*
* 参数:
* 无
*
* 返回值:
* 无
*
* 说明:
* 绘制场景,对屏幕每一点进行光线跟踪,计算光强值,设置进度条。
*
************************************************************************/
void CScene::BeginTrace()
{
//获得框架类指针
CMainFrame* pFrame = (CMainFrame*)(AfxGetApp()->m_pMainWnd);
//设置进度条量程
pFrame->m_wndStatusBar.m_wndProgBar.SetRange(0,nYRes);
//视点到屏幕的光线
CRay *InitRay = new CRay;
//对(x,y)象素光线跟踪
for( int y = 0; y <= nYRes; y++ )
{
for( int x = 0 ; x < nXRes; x++ )
{
InitRay->StartPoint = ObservePosition;
InitRay->Direction = InitDirection(x,y);
//光线跟踪
CVector result = Raytracing( InitRay );
//rgb数组记录(x,y)光亮度值
if( result.GetX() > 1 )
rgb[x][y][0] = 1;
else
rgb[x][y][0] = result.GetX();
if( result.GetY() > 1 )
rgb[x][y][1] = 1;
else
rgb[x][y][1] = result.GetY();
if( result.GetZ() > 1 )
rgb[x][y][2] = 1;
else
rgb[x][y][2] = result.GetZ();
}
//设置进度条
pFrame->SendMessage(WM_SET_PROGRESS, y);
}
delete InitRay;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -