📄 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<a_Height; l++)
{
m_Buffer[l] = new RGBQUAD[a_Width];
}
}
void CSurface::Clear()
{
int s = m_Width * m_Height;
for(int i=m_Height-1; i>=0; i--)
{
for(int j=0; j<m_Width; j++)
{
m_Buffer[i][j].rgbBlue =0;
m_Buffer[i][j].rgbGreen=0;
m_Buffer[i][j].rgbRed =0;
m_Buffer[i][j].rgbReserved = 0;
}
}
}
CSurface::~CSurface()
{
delete [] m_Buffer;
}
CRayTraceEngine::CRayTraceEngine()
{
m_Scene = new CScene();
}
CRayTraceEngine::~CRayTraceEngine()
{
delete m_Scene;
}
void CRayTraceEngine::SetTarget(RGBQUAD** a_Dest,int a_Width,int a_Height)
{
m_Dest = a_Dest;
m_Width = a_Width;
m_Height = a_Height;
}
void CRayTraceEngine::InitRender()
{
// set firts line to draw to
m_CurrLine = 20;
// set pixel buffer address of first pixel
m_PPos = m_CurrLine * m_Width;
// screen plane in world space coordinates
m_WX1 = -4, m_WX2 = 4, m_WY1 = m_SY = 3, m_WY2 = -3;
// calculate deltas for interpolation
m_DX = (m_WX2 - m_WX1) / m_Width;
m_DY = (m_WY2 - m_WY1) / m_Height;
m_SY += m_CurrLine * m_DY;
// allocate space to store pointers to primitives for previous line
m_LastRow = new CPrimitive*[m_Width];
memset( m_LastRow, 0, m_Width * 4 );
}
CPrimitive* CRayTraceEngine::Raytrace( CRay& a_Ray, Color& a_Acc, int a_Depth, float a_RIndex, float& a_Dist )
{
if (a_Depth > 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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -