#include "stdafx.h" #include "SceneTree.h" #include "Camera.h" tPool cSceneTreeNode::mPool( 2048, 256 ); /// Äøµ¿ë NiFrustumPlanes* cSceneTreeNode::mFrustum = 0; cSceneNode::eType cSceneTreeNode::mPickType = cSceneNode::eNULL; /// Ãæµ¹ °Ë»ç¿ë const cRay* cSceneTreeNode::mRay = 0; float cSceneTreeNode::mMaxDistance = 0; const cSphere* cSceneTreeNode::mSphere = 0; tArray* cSceneTreeNode::mCollidedArray = 0; bool cSceneTreeNode::mCameraRay = false; cSceneTreeNode::cSceneTreeNode( cSceneTree* tree, cSceneTreeNode* parent, const NiPoint3& center, float radius ) : cSphere( center, radius ) , mTree( tree ) , mParent( parent ) { mChild[0] = mChild[1] = mChild[2] = mChild[3] = 0; float r = (radius * 1.4142135623731f) * 0.5f;//radius * 0.5f; float d = r * 0.5f; // float d = r * 1.0f/1.4142135623731f; mTestSpheres[0].Set( center.x - d, center.y - d, 0.0f, r ); mTestSpheres[0].mResult = false; mTestSpheres[1].Set( center.x + d, center.y - d, 0.0f, r ); mTestSpheres[1].mResult = false; mTestSpheres[2].Set( center.x - d, center.y + d, 0.0f, r ); mTestSpheres[2].mResult = false; mTestSpheres[3].Set( center.x + d, center.y + d, 0.0f, r ); mTestSpheres[3].mResult = false; mObjectList.Clear(); } cSceneTreeNode::cSceneTreeNode( cSceneTree* tree, cSceneTreeNode* parent, const cSphere& sphere ) : cSphere( sphere ) , mTree( tree ) , mParent( parent ) { mChild[0] = mChild[1] = mChild[2] = mChild[3] = 0; /// ¿ÜÁ¢¿ø float r = mRadius * 0.5f; float d = r * 1.0f/1.4142135623731f; // float r = (mRadius * 1.4142135623731f) * 0.5f; // float d = r * 0.95f; mTestSpheres[0].Set( mCenter.x - d, mCenter.y - d, 0.0f, r ); mTestSpheres[0].mResult = false; mTestSpheres[1].Set( mCenter.x + d, mCenter.y - d, 0.0f, r ); mTestSpheres[1].mResult = false; mTestSpheres[2].Set( mCenter.x - d, mCenter.y + d, 0.0f, r ); mTestSpheres[2].mResult = false; mTestSpheres[3].Set( mCenter.x + d, mCenter.y + d, 0.0f, r ); mTestSpheres[3].mResult = false; mObjectList.Clear(); } cSceneTreeNode::~cSceneTreeNode() { delete mChild[0]; delete mChild[1]; delete mChild[2]; delete mChild[3]; mParent = 0; mObjectList.Clear(); } void* cSceneTreeNode::operator new( size_t /*n*/ ) { return mPool.Alloc(); } void cSceneTreeNode::operator delete( void* p ) { mPool.Free( (cSceneTreeNode*)p ); } void cSceneTreeNode::PushDirect( cSceneNode* node ) { assert(node); cSphere s = node->GetBoundSphere(); if( ContainSphere( s ) ) { node->mContainer = this; node->mIteratorValid = true; node->mIteratorByContainer = mObjectList.Insert( mObjectList.End(), node ); } else { if( mParent ) { mParent->PushDirect( node ); } else { assert(0); node->mContainer = this; node->mIteratorValid = true; node->mIteratorByContainer = mObjectList.Insert( mObjectList.End(), node ); } } } void cSceneTreeNode::Push( cSceneNode* node ) { assert( node ); if( node->GetRadius() <= 0.0f ) { node->mContainer = this; node->mIteratorValid = true; node->mIteratorByContainer = mObjectList.Insert( mObjectList.End(), node ); return; } /// Àå¸é ³ëµå°¡ Æ®¸® ³ëµåº¸´Ù ´õ Å©¸é »óÀ§ ³ëµå·Î Àå¸é ³ëµå¸¦ Àü´Þ if( node->GetRadius() > mRadius ) { if( mParent ) { mParent->PushDirect( node ); } else { // assert(0); node->mContainer = this; node->mIteratorValid = true; node->mIteratorByContainer = mObjectList.Insert( mObjectList.End(), node ); } return; } /// ´õ ÀÛÀº ÇÏÀ§³ëµå¸¦ ¸¸µéÁö ¾Ê´Â´Ù. if( mRadius <= 10000.0f ) { node->mContainer = this; node->mIteratorValid = true; node->mIteratorByContainer = mObjectList.Insert( mObjectList.End(), node ); return; } /// ÀÚ½Ä ³ëµåµé¿¡ ´ëÇØ Àå¸é ³ëµå Æ÷ÇÔ ¿©ºÎ¸¦ °Ë»ç int i = 0; int count = 0; NiPoint3 checkPos = node->GetCenter(); //float checkR = node->GetRadius(); cSphere s( node->GetCenter(), node->GetRadius() ); mTestSpheres[0].mResult = false; mTestSpheres[1].mResult = false; mTestSpheres[2].mResult = false; mTestSpheres[3].mResult = false; if( mTestSpheres[0].ContainSphere( s ) ) { i = 0; mTestSpheres[0].mResult = true; ++count; } if( mTestSpheres[1].ContainSphere( s ) ) { i = 1; mTestSpheres[1].mResult = true; ++count; } if( mTestSpheres[2].ContainSphere( s ) ) { i = 2; mTestSpheres[2].mResult = true; ++count; } if( mTestSpheres[3].ContainSphere( s ) ) { i = 3; mTestSpheres[3].mResult = true; ++count; } /// Àå¸é ³ëµå¸¦ ¿ÏÀüÈ÷ Æ÷ÇÔÇÏ´Â ÀÚ½Ä ³ëµåÀÇ ¼ö¸¦ °Ë»ç switch( count ) { case 0: { /// ÇöÀç ³ëµå¿¡ Ãß°¡ node->mContainer = this; node->mIteratorValid = true; node->mIteratorByContainer = mObjectList.Insert( mObjectList.End(), node ); } break; case 1: { /// ÇØ´ç ÀÚ½Ä ³ëµå¿¡ Àå¸é ³ëµå¸¦ Àü´Þ cSceneTreeNode* child = mChild[i]; if( child == 0 ) child = mChild[i] = new cSceneTreeNode( mTree, this, mTestSpheres[i] ); child->Push( node ); } break; case 2: case 3: case 4: default: { /// °¡Àå °¡±î¿î ÀÚ½Ä ³ëµå¿¡ Àå¸é ³ëµå¸¦ Àü´Þ float minDistance = NI_INFINITY; int i = 0; const NiPoint3& c = node->GetCenter(); float d; if( mTestSpheres[0].mResult ) { d = mTestSpheres[0].GetDistance2( c ); if( d < minDistance ) { i = 0; minDistance = d; } } if( mTestSpheres[1].mResult ) { d = mTestSpheres[1].GetDistance2( c ); if( d < minDistance ) { i = 1; minDistance = d; } } if( mTestSpheres[2].mResult ) { d = mTestSpheres[2].GetDistance2( c ); if( d < minDistance ) { i = 2; minDistance = d; } } if( mTestSpheres[3].mResult ) { d = mTestSpheres[3].GetDistance2( c ); if( d < minDistance ) { i = 3; minDistance = d; } } /// ÇØ´ç ÀÚ½Ä ³ëµå¿¡ Àå¸é ³ëµå¸¦ Àü´Þ cSceneTreeNode* child = mChild[i]; if( child == 0 ) child = mChild[i] = new cSceneTreeNode( mTree, this, mTestSpheres[i] ); child->Push( node ); } break; } } void cSceneTreeNode::Remove( cSceneNode* node ) { assert( node ); if( node->mIteratorValid ) { node->mIteratorValid = false; mObjectList.Erase( node->mIteratorByContainer ); } } void cSceneTreeNode::Update( cSceneNode* node ) { /// Àå¸é ³ëµå°¡ ¼ÓÇÑ Æ®¸® ³ëµå¿¡ ´ëÇØ Æ÷ÇÔ ¿©ºÎ¸¦ °Ë»ç const cSphere& s = node->GetBoundSphere(); if( ContainSphere( s ) == false ) { /// Àå¸é ³ëµå¸¦ Æ®¸® ³ëµå¿¡¼­ Á¦°ÅÇÏ°í »óÀ§ Æ®¸® ³ëµå¿¡ ´ëÇØ Æ÷ÇÔ À¯¹«¸¦ °Ë»ç Remove( node ); if( mParent ) { if( mParent->ContainSphere( s ) ) mParent->Push( node ); else mTree->Push( node ); } else { mTree->Push( node ); } } } void cSceneTreeNode::Cull() { unsigned int saveActive = mFrustum->GetActivePlaneState(); unsigned int side = 0; unsigned int c = 0; { unsigned int i; for( i = 0; iIsPlaneActive(i) == false ) continue; side = WhichSide( mFrustum->GetPlane(i) ); if( side == NiPlane::POSITIVE_SIDE ) { mFrustum->DisablePlane(i); c++; } } saveActive = mFrustum->GetActivePlaneState(); if( c == NiFrustumPlanes::MAX_PLANES ) { AddToVisibleArray(); } else { /// ºÎºÐ ±³Â÷ -> ÀÚ¼ÕµéÀ» °è¼Ó °Ë»ç /// Æ÷ÇÔµÈ °³Ã¼µé¿¡ ´ëÇØ °Ë»ç if( mObjectList.IsEmpty() == false ) { cObjectList::cIterator itr = mObjectList.Begin(); cObjectList::cIterator iend = mObjectList.End(); cSceneNode* n = 0; for( ; itr != iend; ++itr ) { n = (cSceneNode*)*itr; if( n->IsKindof( mPickType ) == false ) continue; if( n->IsEnableFrustumFlag() == false ) continue; if( mFrustum->IsPlaneActive(NiFrustumPlanes::FAR_PLANE) && n->WhichSide( mFrustum->GetPlane(NiFrustumPlanes::FAR_PLANE) ) == NiPlane::NEGATIVE_SIDE ) continue; if( mFrustum->IsPlaneActive(NiFrustumPlanes::LEFT_PLANE) && n->WhichSide( mFrustum->GetPlane(NiFrustumPlanes::LEFT_PLANE) ) == NiPlane::NEGATIVE_SIDE ) continue; if( mFrustum->IsPlaneActive(NiFrustumPlanes::RIGHT_PLANE) && n->WhichSide( mFrustum->GetPlane(NiFrustumPlanes::RIGHT_PLANE) ) == NiPlane::NEGATIVE_SIDE ) continue; if( mFrustum->IsPlaneActive(NiFrustumPlanes::TOP_PLANE) && n->WhichSide( mFrustum->GetPlane(NiFrustumPlanes::TOP_PLANE) ) == NiPlane::NEGATIVE_SIDE ) continue; if( mFrustum->IsPlaneActive(NiFrustumPlanes::BOTTOM_PLANE) && n->WhichSide( mFrustum->GetPlane(NiFrustumPlanes::BOTTOM_PLANE) ) == NiPlane::NEGATIVE_SIDE ) continue; if( n->OnVisible() ) n->AddToVisibleArray(); } } } /// Àڼյ鿡 ´ëÇØ Äøµ if( mChild[0] ) { mFrustum->SetActivePlaneState( saveActive ); mChild[0]->Cull(); } if( mChild[1] ) { mFrustum->SetActivePlaneState( saveActive ); mChild[1]->Cull(); } if( mChild[2] ) { mFrustum->SetActivePlaneState( saveActive ); mChild[2]->Cull(); } if( mChild[3] ) { mFrustum->SetActivePlaneState( saveActive ); mChild[3]->Cull(); } } /* unsigned int saveActive = mFrustum->GetActivePlaneState(); unsigned int side = 0; unsigned int c = 0; { if( mFrustum->IsPlaneActive(NiFrustumPlanes::FAR_PLANE) ) { side = WhichSide( mFrustum->GetPlane(NiFrustumPlanes::FAR_PLANE) ); if( side == NiPlane::NEGATIVE_SIDE ) { mFrustum->SetActivePlaneState( saveActive ); return; } if( side == NiPlane::POSITIVE_SIDE ) { mFrustum->DisablePlane( NiFrustumPlanes::FAR_PLANE ); ++c; } } if( mFrustum->IsPlaneActive(NiFrustumPlanes::LEFT_PLANE) ) { side = WhichSide( mFrustum->GetPlane(NiFrustumPlanes::LEFT_PLANE) ); if( side == NiPlane::NEGATIVE_SIDE ) { mFrustum->SetActivePlaneState( saveActive ); return; } if( side == NiPlane::POSITIVE_SIDE ) { mFrustum->DisablePlane( NiFrustumPlanes::LEFT_PLANE ); ++c; } } if( mFrustum->IsPlaneActive(NiFrustumPlanes::RIGHT_PLANE) ) { side = WhichSide( mFrustum->GetPlane(NiFrustumPlanes::RIGHT_PLANE) ); if( side == NiPlane::NEGATIVE_SIDE ) { mFrustum->SetActivePlaneState( saveActive ); return; } if( side == NiPlane::POSITIVE_SIDE ) { mFrustum->DisablePlane( NiFrustumPlanes::RIGHT_PLANE ); ++c; } } if( mFrustum->IsPlaneActive(NiFrustumPlanes::TOP_PLANE) ) { side = WhichSide( mFrustum->GetPlane(NiFrustumPlanes::TOP_PLANE) ); if( side == NiPlane::NEGATIVE_SIDE ) { mFrustum->SetActivePlaneState( saveActive ); return; } if( side == NiPlane::POSITIVE_SIDE ) { mFrustum->DisablePlane( NiFrustumPlanes::TOP_PLANE ); ++c; } } if( mFrustum->IsPlaneActive(NiFrustumPlanes::BOTTOM_PLANE) ) { side = WhichSide( mFrustum->GetPlane(NiFrustumPlanes::BOTTOM_PLANE) ); if( side == NiPlane::NEGATIVE_SIDE ) { mFrustum->SetActivePlaneState( saveActive ); return; } if( side == NiPlane::POSITIVE_SIDE ) { mFrustum->DisablePlane( NiFrustumPlanes::BOTTOM_PLANE ); ++c; } } } if( c == 5 ) { /// ¿ÏÀü Æ÷ÇÔ -> ÀÚ¼ÕµéÀ» ¸ðµÎ Ãß°¡ AddToVisibleArray(); } else { /// ºÎºÐ ±³Â÷ -> ÀÚ¼ÕµéÀ» °è¼Ó °Ë»ç /// Æ÷ÇÔµÈ °³Ã¼µé¿¡ ´ëÇØ °Ë»ç if( mObjectList.IsEmpty() == false ) { cObjectList::cIterator i = mObjectList.Begin(); cObjectList::cIterator iend = mObjectList.End(); cSceneNode* n = 0; for( ; i != iend; ++i ) { n = (cSceneNode*)*i; if( n->IsKindof( mPickType ) == false ) continue; if( mFrustum->IsPlaneActive(NiFrustumPlanes::FAR_PLANE) && n->WhichSide( mFrustum->GetPlane(NiFrustumPlanes::FAR_PLANE) ) == NiPlane::NEGATIVE_SIDE ) continue; if( mFrustum->IsPlaneActive(NiFrustumPlanes::LEFT_PLANE) && n->WhichSide( mFrustum->GetPlane(NiFrustumPlanes::LEFT_PLANE) ) == NiPlane::NEGATIVE_SIDE ) continue; if( mFrustum->IsPlaneActive(NiFrustumPlanes::RIGHT_PLANE) && n->WhichSide( mFrustum->GetPlane(NiFrustumPlanes::RIGHT_PLANE) ) == NiPlane::NEGATIVE_SIDE ) continue; if( mFrustum->IsPlaneActive(NiFrustumPlanes::TOP_PLANE) && n->WhichSide( mFrustum->GetPlane(NiFrustumPlanes::TOP_PLANE) ) == NiPlane::NEGATIVE_SIDE ) continue; if( mFrustum->IsPlaneActive(NiFrustumPlanes::BOTTOM_PLANE) && n->WhichSide( mFrustum->GetPlane(NiFrustumPlanes::BOTTOM_PLANE) ) == NiPlane::NEGATIVE_SIDE ) continue; if( n->OnVisible() ) n->AddToVisibleArray(); } } /// Àڼյ鿡 ´ëÇØ Äøµ if( mChild[0] ) mChild[0]->Cull(); if( mChild[1] ) mChild[1]->Cull(); if( mChild[2] ) mChild[2]->Cull(); if( mChild[3] ) mChild[3]->Cull(); } mFrustum->SetActivePlaneState( saveActive ); */ } void cSceneTreeNode::AddToVisibleArray() const { /// Æ÷ÇÔµÈ °³Ã¼µéÀ» Ãß°¡ cObjectList::cConstIterator i = mObjectList.Begin(); cObjectList::cConstIterator iend = mObjectList.End(); cSceneNode* n = 0; for( ; i != iend; ++i ) { n = (cSceneNode*)*i; if( n->IsKindof( mPickType ) == false ) continue; if( n->OnVisible() ) n->AddToVisibleArray(); } // ÀÚ½Ä ³ëµåµé¿¡ ´ëÇØ Àç±Í È£Ãâ if( mChild[0] ) mChild[0]->AddToVisibleArray(); if( mChild[1] ) mChild[1]->AddToVisibleArray(); if( mChild[2] ) mChild[2]->AddToVisibleArray(); if( mChild[3] ) mChild[3]->AddToVisibleArray(); } bool cSceneTreeNode::CollideRay_Kind() { bool ret = false; if( IntersectRay( *mRay, mMaxDistance ) ) { /// Æ÷ÇÔµÈ Àå¸é ³ëµåµé¿¡ ´ëÇØ ±³Â÷ °Ë»ç if( mObjectList.IsEmpty() == false ) { cObjectList::cIterator i = mObjectList.Begin(); cObjectList::cIterator iend = mObjectList.End(); cSceneNode* n = 0; for( ; i != iend; ++i ) { n = (cSceneNode*)*i; if( n->IsKindof( mPickType ) == false ) continue; if( n->IsViewNode() == false ) continue; if( n->Pick( *mRay ) && n->GetPickDistance() < mMaxDistance ) { if( cSceneTreeNode::mCameraRay == true ) { if( n->UpdateCameraPickInfo() == true ) { mCollidedArray->PushBack( n ); ret = true; } } else { mCollidedArray->PushBack( n ); ret = true; } } } } /// Àڽĵ鿡 ´ëÇØ ±³Â÷ °Ë»ç if( mChild[0] ) ret |= mChild[0]->CollideRay_Kind(); if( mChild[1] ) ret |= mChild[1]->CollideRay_Kind(); if( mChild[2] ) ret |= mChild[2]->CollideRay_Kind(); if( mChild[3] ) ret |= mChild[3]->CollideRay_Kind(); } return ret; } bool cSceneTreeNode::CollideSphere_Kind() { bool ret = false; if( IntersectSphere( *mSphere ) ) { /// Æ÷ÇÔµÈ Àå¸é ³ëµåµé¿¡ ´ëÇØ ±³Â÷ °Ë»ç if( mObjectList.IsEmpty() == false ) { cObjectList::cIterator i = mObjectList.Begin(); cObjectList::cIterator iend = mObjectList.End(); cSceneNode* n = 0; for( ; i != iend; ++i ) { n = (cSceneNode*)*i; if( n->IsKindof( mPickType ) == false ) continue; if( n->GetBoundSphere().IntersectSphere( *mSphere ) ) { n->UpdatePickInfo( (void*)mSphere ); mCollidedArray->PushBack( n ); ret = true; } } } /// Àڽĵ鿡 ´ëÇØ ±³Â÷ °Ë»ç if( mChild[0] ) ret |= mChild[0]->CollideSphere_Kind(); if( mChild[1] ) ret |= mChild[1]->CollideSphere_Kind(); if( mChild[2] ) ret |= mChild[2]->CollideSphere_Kind(); if( mChild[3] ) ret |= mChild[3]->CollideSphere_Kind(); } return ret; } bool cSceneTreeNode::CollideSphere_Type() { bool ret = false; if( IntersectSphere( *mSphere ) ) { /// Æ÷ÇÔµÈ Àå¸é ³ëµåµé¿¡ ´ëÇØ ±³Â÷ °Ë»ç if( mObjectList.IsEmpty() == false ) { cObjectList::cIterator i = mObjectList.Begin(); cObjectList::cIterator iend = mObjectList.End(); cSceneNode* n = 0; for( ; i != iend; ++i ) { n = (cSceneNode*)*i; if( n->GetType() != mPickType ) continue; if( n->GetBoundSphere().IntersectSphere( *mSphere ) ) { n->UpdatePickInfo( (void*)mSphere ); mCollidedArray->PushBack( n ); ret = true; } } } /// Àڽĵ鿡 ´ëÇØ ±³Â÷ °Ë»ç if( mChild[0] ) ret |= mChild[0]->CollideSphere_Type(); if( mChild[1] ) ret |= mChild[1]->CollideSphere_Type(); if( mChild[2] ) ret |= mChild[2]->CollideSphere_Type(); if( mChild[3] ) ret |= mChild[3]->CollideSphere_Type(); } return ret; } cSceneTree::cSceneTree() : mRootNode( 0 ) , mCenter( NiPoint3::ZERO ) , mMinRadius( 0.0f ) , mMaxRadius( 0.0f ) { } cSceneTree::~cSceneTree() { Clear(); } void cSceneTree::Clear() { delete mRootNode; mRootNode = 0; } void cSceneTree::Init( const NiPoint3& center, float minRadius, float maxRadius ) { mCenter = center; mMinRadius = minRadius; mMaxRadius = maxRadius; delete mRootNode; mRootNode = new cSceneTreeNode( this, 0, center, maxRadius ); } void cSceneTree::Push( cSceneNode* node ) { assert( node ); assert( mRootNode ); mRootNode->Push( node ); } void cSceneTree::Cull( NiVisibleArray* solidArray, NiVisibleArray* alphaArray, NiVisibleArray* alphaTestArray, cCamera* cam,cSceneNode::eType type ) { assert( solidArray ); assert( alphaArray ); assert( cam ); assert( mRootNode ); NiCamera* nicam = (NiCamera*)*cam; NiFrustumPlanes frustum( *nicam ); cSceneNode::mCamera = nicam; cSceneNode::mSolidArray = solidArray; cSceneNode::mAlphaArray = alphaArray; cSceneNode::mAlphaTestArray = alphaTestArray; cSceneTreeNode::mFrustum = &frustum; cSceneTreeNode::mPickType = type; mRootNode->Cull(); } bool cSceneTree::CollideRay_Kind( tArray* collidedArray, const cRay& ray, bool camRay, float maxDistance, bool sortByDistance, cSceneNode::eType type ) { assert( collidedArray ); if( IsEmpty() ) return false; cSceneTreeNode::mRay = &ray; cSceneTreeNode::mMaxDistance = maxDistance; cSceneTreeNode::mPickType = type; cSceneTreeNode::mCollidedArray = collidedArray; cSceneTreeNode::mCameraRay = camRay; bool ret = mRootNode->CollideRay_Kind(); if( ret && sortByDistance && collidedArray->GetSize() > 1 ) { ::Sort( collidedArray->Begin(), collidedArray->End(), cSceneNodeCompareForPicking() ); } return ret; } bool cSceneTree::CollideSphere_Kind( tArray* collidedArray, const cSphere& sphere, cSceneNode::eType type ) { assert( collidedArray ); if( IsEmpty() ) return false; cSceneTreeNode::mSphere = &sphere; cSceneTreeNode::mPickType = type; cSceneTreeNode::mCollidedArray = collidedArray; return mRootNode->CollideSphere_Kind(); } bool cSceneTree::CollideSphere_Type( tArray* collidedArray, const cSphere& sphere, cSceneNode::eType type ) { assert( collidedArray ); if( IsEmpty() ) return false; cSceneTreeNode::mSphere = &sphere; cSceneTreeNode::mPickType = type; cSceneTreeNode::mCollidedArray = collidedArray; return mRootNode->CollideSphere_Type(); }