#include "StdAfx.h" #include "CollisionData.h" NiImplementRTTI(CCollisionData, NiCollisionObject); CCollisionData::CCollisionData(NiAVObject* pkSceneObject) :NiCollisionObject(pkSceneObject) ,m_bWorldVerticesNeedUpdate(false) ,m_pkWorldVertex(NULL) ,m_usNumVertices(0) ,m_usNumTriangles(0) { m_BoundBox.Reset(); } //--------------------------------------------------------------------------- // This constructor is protected. CCollisionData::CCollisionData() :NiCollisionObject(0) ,m_bWorldVerticesNeedUpdate(false) ,m_pkWorldVertex(NULL) ,m_usNumVertices(0) ,m_usNumTriangles(0) { m_BoundBox.Reset(); } CCollisionData::~CCollisionData() { NiDelete[] m_pkWorldVertex; } void CCollisionData::SetSceneGraphObject(NiAVObject* pkSceneObject) { NiCollisionObject::SetSceneGraphObject(pkSceneObject); if (NiIsKindOf(NiGeometry, pkSceneObject)) { NiGeometryData* pkGeomData = ((NiGeometry*) pkSceneObject)->GetModelData(); if (pkGeomData) { unsigned int uiKeepFlags = pkGeomData->GetKeepFlags(); uiKeepFlags |= NiGeometryData::KEEP_XYZ; uiKeepFlags |= NiGeometryData::KEEP_INDICES; uiKeepFlags |= NiGeometryData::KEEP_BONEDATA; pkGeomData->SetKeepFlags(uiKeepFlags); } } } void CCollisionData::CreateWorldVertices() { NiTriBasedGeom* pkGeom = NiDynamicCast(NiTriBasedGeom, m_pkSceneObject); if (!pkGeom) return; if (!m_pkWorldVertex && pkGeom->GetVertexCount()) { m_usNumVertices = pkGeom->GetVertexCount(); m_pkWorldVertex = NiNew NiPoint3[m_usNumVertices]; m_bWorldVerticesNeedUpdate = true; m_usNumTriangles = pkGeom->GetTriangleCount(); } } void CCollisionData::UpdateWorldVertices() { NiGeometry* pkGeom = NiDynamicCast(NiGeometry, m_pkSceneObject); if (!pkGeom) return; if (m_pkWorldVertex && m_bWorldVerticesNeedUpdate) { NiProcessorSpecificCode::TransformPoints( pkGeom->GetActiveVertexCount(), (const float*)pkGeom->GetVertices(), (float*)m_pkWorldVertex, &(pkGeom->GetWorldTransform())); UpdateBoundBox(); m_bWorldVerticesNeedUpdate = false; } } void CCollisionData::UpdateBoundBox() { m_BoundBox.Reset(); for( unsigned short us = 0; us < m_usNumVertices; ++us ) { m_BoundBox.Intersect(m_pkWorldVertex[us]); } } bool CCollisionData::Collide(const NiPoint3& start, const NiPoint3& end, float& fTime) { if(!m_BoundBox.CollideLine(start, end)) return false; NiTriBasedGeom* pkGeom = (NiTriBasedGeom*)m_pkSceneObject; NIASSERT(NiIsKindOf(NiTriBasedGeom, pkGeom)); NiPoint3 kDir = end - start; unsigned short i0, i1, i2; float t; NiPoint3 n; for( unsigned short us = 0; us < m_usNumTriangles; ++us ) { pkGeom->GetTriangleIndices(us, i0, i1, i2); //退化的3角型 if( i0 == i1 || i1 == i2 || i0 == i2 ) continue; const NiPoint3& v0 = m_pkWorldVertex[i0]; const NiPoint3& v1 = m_pkWorldVertex[i1]; const NiPoint3& v2 = m_pkWorldVertex[i2]; n = (v1 - v0).Cross(v2 - v1); if( n.Dot(kDir) >= 0.f ) continue; t = LineCheckWithTriangle(start, end, v0, v1, v2); if(t < 1.f) { fTime = t; return true; } } return false; } void CCollisionData::MultiCollide(const NiPoint3& start, const NiPoint3& end, const NiPoint3& extent, ResultList& resultList) { if( !m_BoundBox.CollideBox(start, end, extent) ) return; NiTriBasedGeom* pkGeom = (NiTriBasedGeom*)m_pkSceneObject; NIASSERT(NiIsKindOf(NiTriBasedGeom, pkGeom)); NiPoint3 kDir = end - start; unsigned short i0, i1, i2; float t; NiPoint3 n; for( unsigned short us = 0; us < m_usNumTriangles; ++us ) { pkGeom->GetTriangleIndices(us, i0, i1, i2); //退化的3角型 if( i0 == i1 || i1 == i2 || i0 == i2 ) continue; const NiPoint3& v0 = m_pkWorldVertex[i0]; const NiPoint3& v1 = m_pkWorldVertex[i1]; const NiPoint3& v2 = m_pkWorldVertex[i2]; n = (v1 - v0).Cross(v2 - v1); if( n.Dot(kDir) >= 0.f ) continue; t = FindSeparatingAxis(v0, v1, v2, start, end, extent, NiPoint3(1.f, 0.f, 0.f), NiPoint3(0.f, 1.f, 0.f), NiPoint3(0.f, 0.f, 1.f)); if( t > 1.f ) continue; resultList.push_back(Result(t, n, m_pkSceneObject)); } } //--------------------------------------------------------------------------- // Cloning //--------------------------------------------------------------------------- NiImplementCreateClone(CCollisionData); //--------------------------------------------------------------------------- void CCollisionData::CopyMembers(CCollisionData* pkDest, NiCloningProcess& kCloning) { NiCollisionObject::CopyMembers(pkDest, kCloning); // m_pkScreneObject must be filled in by caller. if (pkDest->m_pkWorldVertex == NULL) { pkDest->CreateWorldVertices(); pkDest->UpdateWorldVertices(); } }