📄 scene.cpp
字号:
vmax.cell[q] = a_MaxBox.cell[q] - v;
}
else
{
vmin.cell[q] = a_MaxBox.cell[q] - v;
vmax.cell[q] = -a_MaxBox.cell[q] - v;
}
}
if (DOT( a_Normal, vmin) > 0.0f) return false;
if (DOT( a_Normal, vmax) >= 0.0f) return true;
return false;
}
bool Primitive::IntersectTriBox( vector3& a_BoxCentre, vector3& a_BoxHalfsize, vector3& a_V0, vector3& a_V1, vector3& a_V2 )
{
vector3 v0, v1, v2, normal, e0, e1, e2;
float min, max, p0, p1, p2, rad, fex, fey, fez;
v0 = a_V0 - a_BoxCentre;
v1 = a_V1 - a_BoxCentre;
v2 = a_V2 - a_BoxCentre;
e0 = v1 - v0, e1 = v2 - v1, e2 = v0 - v2;
fex = fabsf( e0.cell[0] );
fey = fabsf( e0.cell[1] );
fez = fabsf( e0.cell[2] );
AXISTEST_X01( e0.cell[2], e0.cell[1], fez, fey );
AXISTEST_Y02( e0.cell[2], e0.cell[0], fez, fex );
AXISTEST_Z12( e0.cell[1], e0.cell[0], fey, fex );
fex = fabsf( e1.cell[0] );
fey = fabsf( e1.cell[1] );
fez = fabsf( e1.cell[2] );
AXISTEST_X01( e1.cell[2], e1.cell[1], fez, fey );
AXISTEST_Y02( e1.cell[2], e1.cell[0], fez, fex );
AXISTEST_Z0 ( e1.cell[1], e1.cell[0], fey, fex );
fex = fabsf( e2.cell[0] );
fey = fabsf( e2.cell[1] );
fez = fabsf( e2.cell[2] );
AXISTEST_X2 ( e2.cell[2], e2.cell[1], fez, fey );
AXISTEST_Y1 ( e2.cell[2], e2.cell[0], fez, fex );
AXISTEST_Z12( e2.cell[1], e2.cell[0], fey, fex );
FINDMINMAX( v0.cell[0], v1.cell[0], v2.cell[0], min, max );
if (min > a_BoxHalfsize.cell[0] || max < -a_BoxHalfsize.cell[0]) return false;
FINDMINMAX( v0.cell[1], v1.cell[1], v2.cell[1], min, max );
if (min > a_BoxHalfsize.cell[1] || max < -a_BoxHalfsize.cell[1]) return false;
FINDMINMAX( v0.cell[2], v1.cell[2], v2.cell[2], min, max );
if (min > a_BoxHalfsize.cell[2] || max < -a_BoxHalfsize.cell[2]) return false;
normal = e0.Cross( e1 );
if (!PlaneBoxOverlap( normal, v0, a_BoxHalfsize )) return false;
return true;
}
bool Primitive::IntersectSphereBox( vector3& a_Centre, aabb& a_Box )
{
float dmin = 0;
vector3 spos = a_Centre;
vector3 bpos = a_Box.GetPos();
vector3 bsize = a_Box.GetSize();
for ( int i = 0; i < 3; i++ )
{
if (spos.cell[i] < bpos.cell[i])
{
dmin = dmin + (spos.cell[i] - bpos.cell[i]) * (spos.cell[i] - bpos.cell[i]);
}
else if (spos.cell[i] > (bpos.cell[i] + bsize.cell[i]))
{
dmin = dmin + (spos.cell[i] - (bpos.cell[i] + bsize.cell[i])) * (spos.cell[i] - (bpos.cell[i] + bsize.cell[i]));
}
}
return (dmin <= m_SqRadius);
}
bool Primitive::IntersectBox( aabb& a_Box )
{
if (m_Type == SPHERE)
{
return IntersectSphereBox( m_Centre, a_Box );
}
else
{
return IntersectTriBox( a_Box.GetPos() + a_Box.GetSize() * 0.5f, a_Box.GetSize() * 0.5f,
m_Vertex[0]->GetPos(), m_Vertex[1]->GetPos(), m_Vertex[2]->GetPos() );
}
}
void Primitive::CalculateRange( real& a_Pos1, real& a_Pos2, int a_Axis )
{
if (m_Type == SPHERE)
{
a_Pos1 = m_Centre.cell[a_Axis] - m_Radius;
a_Pos2 = m_Centre.cell[a_Axis] + m_Radius;
}
else
{
vector3 pos1 = m_Vertex[0]->GetPos();
a_Pos1 = pos1.cell[a_Axis], a_Pos2 = pos1.cell[a_Axis];
for ( int i = 1; i < 3; i++ )
{
vector3 pos = m_Vertex[i]->GetPos();
if (pos.cell[a_Axis] < a_Pos1) a_Pos1 = pos.cell[a_Axis];
if (pos.cell[a_Axis] > a_Pos2) a_Pos2 = pos.cell[a_Axis];
}
}
}
// -----------------------------------------------------------
// Light class implementation
// -----------------------------------------------------------
Light::Light( int a_Type, vector3& a_P1, vector3& a_P2, vector3& a_P3, Color& a_Color )
{
m_Type = a_Type;
m_Color = a_Color;
m_Grid = new vector3[16];
m_Grid[ 0] = vector3( 1, 2, 0 );
m_Grid[ 1] = vector3( 3, 3, 0 );
m_Grid[ 2] = vector3( 2, 0, 0 );
m_Grid[ 3] = vector3( 0, 1, 0 );
m_Grid[ 4] = vector3( 2, 3, 0 );
m_Grid[ 5] = vector3( 0, 3, 0 );
m_Grid[ 6] = vector3( 0, 0, 0 );
m_Grid[ 7] = vector3( 2, 2, 0 );
m_Grid[ 8] = vector3( 3, 1, 0 );
m_Grid[ 9] = vector3( 1, 3, 0 );
m_Grid[10] = vector3( 1, 0, 0 );
m_Grid[11] = vector3( 3, 2, 0 );
m_Grid[12] = vector3( 2, 1, 0 );
m_Grid[13] = vector3( 3, 0, 0 );
m_Grid[14] = vector3( 1, 1, 0 );
m_Grid[15] = vector3( 0, 2, 0 );
m_CellX = (a_P2 - a_P1) * 0.25f;
m_CellY = (a_P3 - a_P1) * 0.25f;
for ( int i = 0; i < 16; i++ )
m_Grid[i] = m_Grid[i].cell[0] * m_CellX + m_Grid[i].cell[1] * m_CellY + a_P1;
m_Pos = a_P1 + 2 * m_CellX + 2 * m_CellY;
}
// -----------------------------------------------------------
// Scene class implementation
// -----------------------------------------------------------
Scene::Scene() :
m_Primitives( 0 ),
m_Primitive( 0 ),
m_Extends( vector3( 0, 0, 0 ), vector3( 0, 0, 0 ) ),
m_State( 0 )
{
}
Scene::~Scene()
{
delete m_Primitive;
}
void Scene::Load3DS( char* filename, Material* a_Material, vector3& a_Pos, real a_Size )
{
// load 3ds file to memory
FILE* f = fopen( filename, "rb" );
char* memfile = new char[800 * 1024];
unsigned long filelength = fread( memfile, 800 * 1024, 1, f );
fclose( f );
// initialize chunk parser
m_Verts = m_TCoords = 0;
m_Faces = 0;
// process chunks
EatChunk( memfile );
delete memfile;
// determine extends
vector3 min( vector3( m_Verts[0], m_Verts[1], m_Verts[2] ) );
vector3 max = min;
for ( int i = 1; i < m_NrVerts; i++ )
{
if (m_Verts[i * 3] < min.x) min.x = m_Verts[i * 3];
if (m_Verts[i * 3] > max.x) max.x = m_Verts[i * 3];
if (m_Verts[i * 3 + 1] < min.y) min.y = m_Verts[i * 3 + 1];
if (m_Verts[i * 3 + 1] > max.y) max.y = m_Verts[i * 3 + 1];
if (m_Verts[i * 3 + 2] < min.z) min.z = m_Verts[i * 3 + 2];
if (m_Verts[i * 3 + 2] > max.z) max.z = m_Verts[i * 3 + 2];
}
vector3 size = max - min;
// determine scale based on largest extend
real scale;
if ((size.x > size.y) && (size.x > size.z)) scale = a_Size / size.x;
else if (size.y > size.z) scale = a_Size / size.y;
else scale = a_Size / size.z;
// determine offset
vector3 centre = (min + max) * 0.5f;
vector3 offset = (centre * scale) - a_Pos;
// create vertices
Vertex** vert = new Vertex*[m_NrVerts];
Primitive*** vertface = new Primitive**[m_NrVerts];
int* vertfaces = new int[m_NrVerts];
for ( i = 0; i < m_NrVerts; i++ )
{
real x = m_Verts[i * 3], z = m_Verts[i * 3 + 1], y = m_Verts[i * 3 + 2];
vert[i] = new Vertex( vector3( (x * scale) - offset.x, (y * scale ) - offset.y, (z * scale) - offset.z ), 0, 0 );
vert[i]->SetUV( vert[i]->GetPos().cell[0] / a_Size, vert[i]->GetPos().cell[1] / a_Size );
vertface[i] = new Primitive*[10];
vertfaces[i] = 0;
}
// convert to ray tracer primitives
for ( i = 0; i < m_NrFaces; i++ )
{
int idx[3];
for ( int v = 0; v < 3; v++ ) idx[v] = m_Faces[i * 3 + v];
m_Primitive[m_Primitives] = new Primitive( Primitive::TRIANGLE, vert[idx[0]], vert[idx[1]], vert[idx[2]] );
m_Primitive[m_Primitives++]->SetMaterial( a_Material );
for ( v = 0; v < 1; v++ ) if (vertfaces[idx[v]] < 10) vertface[idx[v]][vertfaces[idx[v]]++] = m_Primitive[m_Primitives - 1];
}
// calculate vertex normals
for ( i = 0; i < m_NrVerts; i++ )
{
vector3 N( 0, 0, 0 );
for ( int v = 0; v < vertfaces[i]; v++ ) N += vertface[i][v]->GetNormal();
N *= 1.0f / vertfaces[i];
vert[i]->SetNormal( N );
delete vertface[i];
}
delete vertface;
delete vertfaces;
delete vert;
}
unsigned char* temp = new unsigned char[8];
unsigned char* aligned = (unsigned char*)(((unsigned long)temp + 4) & 0xFFFFFFFC);
inline float getf( char* addr )
{
memcpy( aligned, addr, 4 );
return *(float*)aligned;
}
inline unsigned short getw( char* addr )
{
memcpy( aligned, addr, 2 );
return *(unsigned short*)aligned;
}
inline unsigned long getd( char* addr )
{
memcpy( aligned, addr, 4 );
return *(unsigned long*)aligned;
}
long Scene::EatChunk( char* buffer )
{
short chunkid = getw( buffer );
long chunklength = getd( buffer + 2 );
int j, i = 6, cp = 0, tcoords = 0;
switch (chunkid)
{
case 0x4D4D:
while ((getw( buffer + i) != 0x3D3D) && (getw( buffer + i) != 0xB000)) i += 2;
break;
case 0x4000:
while (*(buffer + (i++)) != 0);
break;
case 0x4110:
m_NrVerts = getw( buffer + i );
delete m_Verts;
m_Verts = new float[m_NrVerts * 3];
i += 2;
for ( j = 0; j < m_NrVerts; j++ )
{
m_Verts[j * 3] = getf( buffer + i );
m_Verts[j * 3 + 1] = getf( buffer + i + 4 );
m_Verts[j * 3 + 2] = getf( buffer + i + 8 );
i += 12;
}
break;
case 0x4120:
m_NrFaces = getw( buffer + i );
delete m_Faces;
m_Faces = new unsigned short[m_NrFaces * 3];
i += 2;
for ( j = 0; j < m_NrFaces; j++ )
{
m_Faces[j * 3] = getw( buffer + i );
m_Faces[j * 3 + 1] = getw( buffer + i + 2 );
m_Faces[j * 3 + 2] = getw( buffer + i + 4 );
i += 8;
}
case 0x4140:
tcoords = getw( buffer + i );
delete m_TCoords;
m_TCoords = new float[tcoords * 2];
i += 2;
for ( j = 0; j < tcoords; j++ )
{
m_TCoords[j * 2] = getf( buffer + i );
m_TCoords[j * 2 + 1] = getf( buffer + i + 4 );
i += 8;
}
case 0x3D3D:
case 0x4100:
break;
default:
i = chunklength;
break;
}
while (i < chunklength) i += EatChunk( buffer + i );
return chunklength;
}
void Scene::AddBox( vector3 a_Pos, vector3 a_Size )
{
Vertex* v[8];
v[0] = new Vertex( vector3( a_Pos.x, a_Pos.y, a_Pos.z ), 0, 0 );
v[1] = new Vertex( vector3( a_Pos.x + a_Size.x, a_Pos.y, a_Pos.z ), 0, 0 );
v[2] = new Vertex( vector3( a_Pos.x + a_Size.x, a_Pos.y + a_Size.y, a_Pos.z ), 0, 0 );
v[3] = new Vertex( vector3( a_Pos.x, a_Pos.y + a_Size.y, a_Pos.z ), 0, 0 );
v[4] = new Vertex( vector3( a_Pos.x, a_Pos.y, a_Pos.z + a_Size.z ), 0, 0 );
v[5] = new Vertex( vector3( a_Pos.x + a_Size.x, a_Pos.y, a_Pos.z + a_Size.z ), 0, 0 );
v[6] = new Vertex( vector3( a_Pos.x + a_Size.x, a_Pos.y + a_Size.y, a_Pos.z + a_Size.z ), 0, 0 );
v[7] = new Vertex( vector3( a_Pos.x, a_Pos.y + a_Size.y, a_Pos.z + a_Size.z ), 0, 0 );
// front plane
m_Primitive[m_Primitives++] = new Primitive( Primitive::TRIANGLE, v[0], v[1], v[3] );
m_Primitive[m_Primitives++] = new Primitive( Primitive::TRIANGLE, v[1], v[2], v[3] );
// back plane
m_Primitive[m_Primitives++] = new Primitive( Primitive::TRIANGLE, v[5], v[4], v[7] );
m_Primitive[m_Primitives++] = new Primitive( Primitive::TRIANGLE, v[5], v[7], v[6] );
// left plane
m_Primitive[m_Primitives++] = new Primitive( Primitive::TRIANGLE, v[4], v[0], v[3] );
m_Primitive[m_Primitives++] = new Primitive( Primitive::TRIANGLE, v[4], v[3], v[7] );
// right plane
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -