www.pudn.com > RayTrace1.1.rar > Vector3.cpp


// Vector3.cpp : implementation file 
// 
 
#include "stdafx.h" 
#include "noname.h" 
#include "Vector3.h" 
#include "AddSphere.h" 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
#include "Vector3.h" 
void CPrimitive::SetName(char *a_Name) 
{ 
	delete m_Name;  
	m_Name = new char[strlen( a_Name ) + 1];  
	strcpy( m_Name, a_Name );  
} 
int CSphere::Intersect(CRay &a_Ray,float &a_Dist) 
{ 
	CVector3 v = a_Ray.GetOrigin() - m_Centre; 
	float b = -DOT( v, a_Ray.GetDirection() ); 
	float det = (b * b) - DOT( v, v ) + m_SqRadius; 
	int retval = MISS; 
	if (det > 0) 
	{ 
		det = sqrtf( det ); 
		float i1 = b - det; 
		float i2 = b + det; 
		if (i2 > 0) 
		{ 
			if (i1 < 0)  
			{ 
				if (i2 < a_Dist)  
				{ 
					a_Dist = i2; 
					retval = INPRIM; 
				} 
			} 
			else 
			{ 
				if (i1 < a_Dist) 
				{ 
					a_Dist = i1; 
					retval = HIT; 
				} 
			} 
		} 
	} 
	return retval; 
 
} 
CVector3 CPlanePrim::GetNormal( CVector3& a_Pos ) 
{ 
	return m_Plane.N; 
} 
int CPlanePrim::Intersect(CRay &a_Ray,float &a_Dist) 
{ 
	float d = DOT( m_Plane.N, a_Ray.GetDirection() ); 
	if (d != 0) 
	{ 
		float dist = -(DOT( m_Plane.N, a_Ray.GetOrigin() ) + m_Plane.D) / d; 
		if (dist > 0) 
		{ 
			if (dist < a_Dist)  
			{ 
				a_Dist = dist; 
				return HIT; 
			} 
		} 
	} 
	return MISS; 
} 
 
void CScene::InitScene() 
{ 
	m_Primitive = new CPrimitive*[500]; 
	// ground plane 
	m_Primitive[0] = new CPlanePrim( CVector3( 0, 1, 0 ), 4.4f ); 
	m_Primitive[0]->SetName( "plane" ); 
	m_Primitive[0]->GetMaterial()->SetReflection( 0.0f ); 
	m_Primitive[0]->GetMaterial()->SetRefraction( 0.0f ); 
	m_Primitive[0]->GetMaterial()->SetDiffuse( 1.0f ); 
	m_Primitive[0]->GetMaterial()->SetColor( Color( 0.4f, 0.3f, 0.3f ) ); 
	// big sphere 
	m_Primitive[1] = new CSphere( CVector3( 2, 0.8f, 3 ), 2.5f ); 
	m_Primitive[1]->SetName( "big sphere" ); 
	m_Primitive[1]->GetMaterial()->SetReflection( 0.2f ); 
	m_Primitive[1]->GetMaterial()->SetRefraction( 0.8f ); 
	m_Primitive[1]->GetMaterial()->SetRefrIndex( 1.3f ); 
	m_Primitive[1]->GetMaterial()->SetColor( Color( 0.7f, 0.7f, 1.0f ) ); 
	// small sphere 
	m_Primitive[2] = new CSphere( CVector3( -5.5f, -0.5, 7 ), 2 ); 
	m_Primitive[2]->SetName( "small sphere" ); 
	m_Primitive[2]->GetMaterial()->SetReflection( 0.5f ); 
	m_Primitive[2]->GetMaterial()->SetRefraction( 0.0f ); 
	m_Primitive[2]->GetMaterial()->SetRefrIndex( 1.3f ); 
	m_Primitive[2]->GetMaterial()->SetDiffuse( 0.1f ); 
	m_Primitive[2]->GetMaterial()->SetColor( Color( 0.7f, 0.7f, 1.0f ) ); 
	// light source 1 
	m_Primitive[3] = new CSphere( CVector3( 0, 5, 5 ), 0.1f ); 
	m_Primitive[3]->Light( true ); 
	m_Primitive[3]->GetMaterial()->SetColor( Color( 0.4f, 0.4f, 0.4f ) ); 
	// light source 2 
	m_Primitive[4] = new CSphere( CVector3( -3, 5, 1 ), 0.1f ); 
	m_Primitive[4]->Light( true ); 
	m_Primitive[4]->GetMaterial()->SetColor( Color( 0.6f, 0.6f, 0.8f ) ); 
	// extra sphere 
	m_Primitive[5] = new CSphere( CVector3( -1.5f, -3.8f, 1 ), 1.5f ); 
	m_Primitive[5]->SetName( "extra sphere" ); 
	m_Primitive[5]->GetMaterial()->SetReflection( 0.0f ); 
	m_Primitive[5]->GetMaterial()->SetRefraction( 0.8f ); 
	m_Primitive[5]->GetMaterial()->SetColor( Color( 1.0f, 0.4f, 0.4f ) ); 
	// back plane 
	m_Primitive[6] = new CPlanePrim( CVector3( 0.0f, 0, -1 ), 12 ); 
	m_Primitive[6]->SetName( "back plane" ); 
	m_Primitive[6]->GetMaterial()->SetReflection( 0.0f ); 
	m_Primitive[6]->GetMaterial()->SetRefraction( 0.0f ); 
	m_Primitive[6]->GetMaterial()->SetSpecular( 0 ); 
	m_Primitive[6]->GetMaterial()->SetDiffuse( 0.6f ); 
	m_Primitive[6]->GetMaterial()->SetColor( Color( 0.5f, 0.3f, 0.5f ) ); 
	// ceiling plane 
	m_Primitive[7] = new CPlanePrim( CVector3( 0, -1, 0 ), 7.4f ); 
	m_Primitive[7]->SetName( "back plane" ); 
	m_Primitive[7]->GetMaterial()->SetReflection( 0.0f ); 
	m_Primitive[7]->GetMaterial()->SetRefraction( 0.0f ); 
	m_Primitive[7]->GetMaterial()->SetSpecular( 0 ); 
	m_Primitive[7]->GetMaterial()->SetDiffuse( 0.5f ); 
	m_Primitive[7]->GetMaterial()->SetColor( Color( 0.4f, 0.7f, 0.7f ) ); 
	// grid 
	int prim = 8; 
 
	for ( int x = 0; x < 8; x++ )  
	for ( int y = 0; y < 7; y++ ) 
	{ 
		m_Primitive[prim] = new CSphere( CVector3( -4.5f + x * 1.5f, -4.3f + y * 1.5f, 10 ), 0.3f ); 
		m_Primitive[prim]->SetName( "grid sphere" ); 
		m_Primitive[prim]->GetMaterial()->SetReflection( 0 ); 
		m_Primitive[prim]->GetMaterial()->SetRefraction( 0 ); 
		m_Primitive[prim]->GetMaterial()->SetSpecular( 0.6f ); 
		m_Primitive[prim]->GetMaterial()->SetDiffuse( 0.6f ); 
		m_Primitive[prim]->GetMaterial()->SetColor( Color( 0.3f, 1.0f, 0.4f ) ); 
		prim++; 
	} 
 
	// set number of primitives 
	m_Primitives = prim; 
} 
CScene::~CScene() 
{ 
	delete m_Primitive;	 
} 
CSurface::CSurface( int a_Width, int a_Height ) : 
	m_Width( a_Width ), 
	m_Height( a_Height ) 
{ 
	m_Buffer  = new RGBQUAD*[a_Height]; 
	for(int l=0 ; l=0; i--) 
	{ 
		for(int j=0; j TRACEDEPTH) return 0; 
	// trace primary ray 
	a_Dist = 1000000.0f; 
	CVector3 pi; 
	CPrimitive* prim = 0; 
	int result; 
	// find the nearest intersection 
	for ( int s = 0; s < m_Scene->GetNrPrimitives(); s++ ) 
	{ 
		CPrimitive* pr = m_Scene->GetPrimitive( s ); 
		int res; 
		if (res = pr->Intersect( a_Ray, a_Dist ))  
		{ 
			prim = pr; 
			result = res; // 0 = miss, 1 = hit, -1 = hit from inside primitive 
		} 
	} 
	// no hit, terminate ray 
	if (!prim) return 0; 
	// handle intersection 
	if (prim->IsLight()) 
	{ 
		// we hit a light, stop tracing 
		a_Acc = Color( 1, 1, 1 ); 
	} 
	else 
	{ 
		// determine color at point of intersection 
		pi = a_Ray.GetOrigin() + a_Ray.GetDirection() * a_Dist; 
		// trace lights 
		for ( int l = 0; l < m_Scene->GetNrPrimitives(); l++ ) 
		{ 
			CPrimitive* p = m_Scene->GetPrimitive( l ); 
			if (p->IsLight())  
			{ 
				CPrimitive* light = p; 
				// handle point light source 
				float shade = 1.0f; 
				if (light->GetType() == CPrimitive::SPHERE) 
				{ 
					CVector3 L = ((CSphere*)light)->GetCentre() - pi; 
					float tdist = LENGTH( L ); 
					L *= (1.0f / tdist); 
					CRay r = CRay( pi + L * EPSILON, L ); 
					for ( int s = 0; s < m_Scene->GetNrPrimitives(); s++ ) 
					{ 
						CPrimitive* pr = m_Scene->GetPrimitive( s ); 
						if ((pr != light) && (pr->Intersect( r, tdist ))) 
						{ 
							shade = 0; 
							break; 
						} 
					} 
				} 
				if (shade > 0) 
				{ 
					// calculate diffuse shading 
					CVector3 L = ((CSphere*)light)->GetCentre() - pi; 
					NORMALIZE( L ); 
					CVector3 N = prim->GetNormal( pi ); 
					if (prim->GetMaterial()->GetDiffuse() > 0) 
					{ 
						float dot = DOT( L, N ); 
						if (dot > 0) 
						{ 
							float diff = dot * prim->GetMaterial()->GetDiffuse() * shade; 
							// add diffuse component to ray color 
							a_Acc += diff * prim->GetMaterial()->GetColor() * light->GetMaterial()->GetColor(); 
						} 
					} 
					// determine specular component 
					if (prim->GetMaterial()->GetSpecular() > 0) 
					{ 
						// point light source: sample once for specular highlight 
						CVector3 V = a_Ray.GetDirection(); 
						CVector3 R = L - 2.0f * DOT( L, N ) * N; 
						float dot = DOT( V, R ); 
						if (dot > 0) 
						{ 
							float spec = powf( dot, 20 ) * prim->GetMaterial()->GetSpecular() * shade; 
							// add specular component to ray color 
							a_Acc += spec * light->GetMaterial()->GetColor(); 
						} 
					} 
				} 
			} 
		} 
		// calculate reflection 
		float refl = prim->GetMaterial()->GetReflection(); 
		if ((refl > 0.0f) && (a_Depth < TRACEDEPTH)) 
		{ 
			CVector3 N = prim->GetNormal( pi ); 
			CVector3 R = a_Ray.GetDirection() - 2.0f * DOT( a_Ray.GetDirection(), N ) * N; 
			Color rcol( 0, 0, 0 ); 
			float dist; 
			Raytrace( CRay( pi + R * EPSILON, R ), rcol, a_Depth + 1, a_RIndex, dist ); 
			a_Acc += refl * rcol * prim->GetMaterial()->GetColor(); 
		} 
		// calculate refraction 
		float refr = prim->GetMaterial()->GetRefraction(); 
		if ((refr > 0) && (a_Depth < TRACEDEPTH)) 
		{ 
			float rindex = prim->GetMaterial()->GetRefrIndex(); 
			float n = a_RIndex / rindex; 
			CVector3 N = prim->GetNormal( pi ) * (float)result; 
			float cosI = -DOT( N, a_Ray.GetDirection() ); 
			float cosT2 = 1.0f - n * n * (1.0f - cosI * cosI); 
			if (cosT2 > 0.0f) 
			{ 
				CVector3 T = (n * a_Ray.GetDirection()) + (n * cosI - sqrtf( cosT2 )) * N; 
				Color rcol( 0, 0, 0 ); 
				float dist; 
				Raytrace( CRay( pi + T * EPSILON, T ), rcol, a_Depth + 1, rindex, dist ); 
				// apply Beer's law 
				Color absorbance = prim->GetMaterial()->GetColor() * 0.15f * -dist; 
				Color transparency = Color( expf( absorbance.r ), expf( absorbance.g ), expf( absorbance.b ) ); 
				a_Acc += rcol * transparency; 
			} 
		} 
	} 
	// return pointer to primitive hit by primary ray 
	return prim; 
} 
bool CRayTraceEngine::Render() 
{ 
	 
	// initialize timer 
	int msecs = GetTickCount(); 
	// reset last found primitive pointer 
	CPrimitive* lastprim = 0; 
	//m_Width=40;//ÊÔÒ»Ï嵀 
	// render remaining lines 
	for ( int y = m_CurrLine; y < (m_Height - 20); y++ ) 
	{ 
		m_SX = m_WX1; 
		// render pixels for current line 
		for ( int x = 0; x < m_Width; x++ ) 
		{ 
			// fire primary rays 
			Color acc( 0, 0, 0 ); 
			CVector3 dir = CVector3( m_SX, m_SY, 0 ) - o; 
			NORMALIZE( dir ); 
			CRay r( o, dir ); 
			float dist; 
			CPrimitive* prim = Raytrace( r, acc, 1, 1.0f, dist ); 
			int red, green, blue; 
			if (prim != lastprim) 
			{ 
				lastprim = prim; 
				Color acc( 0, 0, 0 ); 
				for ( int tx = -1; tx < 2; tx++ )  
				for ( int ty = -1; ty < 2; ty++ ) 
				{ 
					CVector3 dir = CVector3( m_SX + m_DX * tx / 2.0f, m_SY + m_DY * ty / 2.0f, 0 ) - o; 
					NORMALIZE( dir ); 
					CRay r( o, dir ); 
					float dist; 
					CPrimitive* prim = Raytrace( r, acc, 1, 1.0f, dist ); 
				} 
				red = (int)(acc.r * (256 / 9)); 
				green = (int)(acc.g * (256 / 9)); 
				blue = (int)(acc.b * (256 / 9)); 
			} 
			else 
			{ 
				red = (int)(acc.r * 256); 
				green = (int)(acc.g * 256); 
				blue = (int)(acc.b * 256); 
			} 
			if (red > 255) red = 255; 
			if (green > 255) green = 255; 
			if (blue > 255) blue = 255; 
			m_Dest[y][x].rgbRed=red; 
			m_Dest[y][x].rgbGreen=green; 
			m_Dest[y][x].rgbBlue=blue; 
			 
			m_SX += m_DX; 
		} 
		m_SY += m_DY; 
		// see if we've been working to long already 
		/* 
		if ((GetTickCount() - msecs) > 100)  
		{ 
			// return control to windows so the screen gets updated 
			m_CurrLine = y + 1; 
			return false; 
		} 
		*/ 
	} 
	// all done 
	return true; 
} 
 
 
void CScene::AddScene(int type) 
{ 
	float r,colorr,colorg,colorb,centerx,centery,centerz; 
	float reflect,refract,refrindex,dif; 
	CAddSphere newsphere; 
	switch(type) 
	{ 
		case 1: 
			 
			if(IDOK==newsphere.DoModal()) 
			{ 
				r=newsphere.m_R; 
				colorr=newsphere.m_ColorRed; 
				colorg=newsphere.m_ColorGreen; 
				colorb=newsphere.m_ColorBlue; 
				centerx=newsphere.m_Centerx; 
				centery=newsphere.m_Centery; 
				centerz=newsphere.m_Centerz; 
				reflect=newsphere.m_Refre; 
				refract=newsphere.m_Refra; 
 
				m_Primitive[m_Primitives] = new CSphere( CVector3( centerx,centery,centerz ),r ); 
				m_Primitive[m_Primitives]->SetName( "sphere" ); 
				m_Primitive[m_Primitives]->GetMaterial()->SetReflection( reflect );//0.5f 
				m_Primitive[m_Primitives]->GetMaterial()->SetRefraction( refract );//0.0f 
				m_Primitive[m_Primitives]->GetMaterial()->SetRefrIndex( 1.3f ); 
				m_Primitive[m_Primitives]->GetMaterial()->SetDiffuse( 0.1f ); 
				m_Primitive[m_Primitives]->GetMaterial()->SetColor( Color(colorr, colorg, colorb ) ); 
				m_Primitives++; 
 
 
			} 
 
			break; 
		case 2: 
			break; 
	} 
} 
 
void CScene::DeleteLastObject() 
{ 
	m_Primitives--; 
} 
 
void CRayTraceEngine::GetViewPoint(CVector3 ViewPoint) 
{ 
	o=ViewPoint; 
}