⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scene.cpp

📁 蒙特卡罗方法可以有效地解决复杂的工程问题
💻 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 + -