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

📄 scene.cpp

📁 蒙特卡罗方法可以有效地解决复杂的工程问题
💻 CPP
📖 第 1 页 / 共 3 页
字号:
			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 + -