Пример #1
0
/**
*  @brief
*    Recursive part of PerformQuery()
*/
bool SQPlaneSet::PerformQueryRec(SceneHierarchyNode &cHierarchyNode)
{
	// Is this scene hierarchy node intersecting the plane set?
	if (!cHierarchyNode.CheckPlaneSet(m_cPlaneSet))
		return true; // Continue the query

	// Touch this node
	cHierarchyNode.Touch();

	// Get the scene context
	SceneContext *pSceneContext = GetSceneContext();
	if (pSceneContext) {
		// Inform all listeners
		const SceneHierarchyNodeItem *pItem = cHierarchyNode.GetFirstItem();
		while (pItem) {
			// Get the linked scene node
			SceneNode *pSceneNode = pItem->GetSceneNode();

			// Was this scene node already processed?
			if (pSceneNode && !pSceneContext->IsNodeTouched(*pSceneNode)) {
				// Check scene node
				const AABoundingBox &cAABB = pSceneNode->GetContainerAABoundingBox();
				if (Intersect::PlaneSetAABox(m_cPlaneSet, cAABB.vMin, cAABB.vMax)) {
					// Touch this node
					pSceneContext->TouchNode(*pSceneNode);

					// Emit signal
					SignalSceneNode(*this, *pSceneNode);
					if (m_nFlags & StopQuery)
						return false; // Stop the query right now

					// Continue recursive?
					if (m_nFlags & Recursive) {
						// Is this a container and is recursion allowed?
						if (pSceneNode->IsContainer() && !(pSceneNode->GetFlags() & SceneContainer::NoRecursion)) {
							// Backup current plane set
							const PlaneSet cPlaneSet = m_cPlaneSet;

							// Transform the plane set into container space
							m_cPlaneSet *= pSceneNode->GetTransform().GetInverseMatrix();

							// Container recursion
							const bool bContinue = PerformQueryRec(static_cast<SceneContainer*>(pSceneNode)->GetHierarchyInstance()->GetRootNode());

							// Restore plane set
							m_cPlaneSet = cPlaneSet;

							// Stop the query right now?
							if (!bContinue)
								return false;

						// Is this a cell-portal?
						} else if (pSceneNode->IsPortal() && pSceneNode->IsInstanceOf("PLScene::SNCellPortal") && !(pSceneNode->GetFlags() & SNCellPortal::NoPassThrough)) {
							// Get the target cell
							SNCellPortal   &cCellPortal	= static_cast<SNCellPortal&>(*pSceneNode);
							SceneContainer *pCell		= reinterpret_cast<SceneContainer*>(cCellPortal.GetTargetCellInstance());
							if (pCell && pCell != pSceneNode->GetContainer()) {
								// Backup current plane set
								const PlaneSet cPlaneSet = m_cPlaneSet;

								// Transform the plane set into container space
								m_cPlaneSet *= cCellPortal.GetWarpMatrix();

								// Container recursion
								const bool bContinue = PerformQueryRec(pCell->GetHierarchyInstance()->GetRootNode());

								// Restore plane set
								m_cPlaneSet = cPlaneSet;

								// Stop the query right now?
								if (!bContinue)
									return false;
							}
						}
					}
				}
			}

			// Next item, please
			pItem = pItem->GetNextItem();
		}
	}

	// Check all sub-hierarchies
	for (uint32 i=0; i<cHierarchyNode.GetNumOfNodes(); i++) {
		if (!PerformQueryRec(*cHierarchyNode.GetNode(i)))
			return false; // Stop the query right now
	}

	// Done, continue the query
	return true;
}
Пример #2
0
/**
*  @brief
*    Perform mesh intersection
*/
void Picking::MeshIntersection(SceneNode &cSceneNode, const Vector3 &vLineStartPos, const Vector3 &vLineEndPos,
							   Array<uint32> *plstGeometries, Cull::Enum nCull)
{
	// First of all, check the intersection distance against the axis aligned bounding box of the scene node
	float fIntersection;
	const AABoundingBox &cAABoundngBox = cSceneNode.GetAABoundingBox();
	if (Intersect::AABoxLine(cAABoundngBox.vMin, cAABoundngBox.vMax, vLineStartPos, vLineEndPos, &fIntersection)) {
		// Get the mesh handler of the scene node
		MeshHandler *pMeshHandler = cSceneNode.GetMeshHandler();
		if (pMeshHandler) {
			// Transform matrix to bring something into the same container space the original line start position is in
			Matrix3x4 matTransform;
			if (cSceneNode.GetContainer() && m_pPickingResult->m_pSceneContainer)
				cSceneNode.GetContainer()->GetTransformMatrixTo(*m_pPickingResult->m_pSceneContainer, matTransform);

			// Before we perform the expensive triangle intersection test we check the found axis aligned bounding box
			// intersection distance against the current nearest intersection distance... maybe we're in luck and can
			// skip further tests if we detect that no triangle inside the box can be nearer than the current nearest
			// distance...
			if (fIntersection >= 0.0f && m_pPickingResult->m_fNearestSquaredDistance >= 0.0f) {
				// Our start point is outside the axis aligned bounding box of the scene node and there's already a previous picking result available

				// Get intersection point in node space
				Vector3 vIntersectionPos = vLineStartPos + (vLineEndPos-vLineStartPos).Normalize()*fIntersection;

				// Transform intersection point into container space
				vIntersectionPos *= cSceneNode.GetTransform().GetMatrix();

				// Bring the intersection point into the same container space the original line start position is in
				vIntersectionPos *= matTransform;

				// Do the early escape test
				if ((m_pPickingResult->m_vLineStartPos-vIntersectionPos).GetSquaredLength() > m_pPickingResult->m_fNearestSquaredDistance)
					return; // Get us out of this method right now, there's no change that any triangle intersection point is closer as the previous picking result
			} else {
				// Our start point is inside the axis aligned bounding box of the scene node or we have nothing to early escape test against
			}

			// We ran out of possible early escape tests... now find intersection triangle - this may be quite slow...
			Vector3 vCollisionPoint;
			uint32 nTriangle, nGeometry;
			if (pMeshHandler->FindTriangle(vLineStartPos, vLineEndPos, nTriangle, &nGeometry, &vCollisionPoint, plstGeometries, nCull)) {
				// Lookout! If our start point is inside the axis aligned bounding box of the scene node, we need to take care of "backfiring"
				if (fIntersection < 0) {
					// Our start point is inside the axis aligned bounding box of the scene node

					// Get the normalized line direction in scene node space
					Vector3 vLineDirection = vLineEndPos;
					vLineDirection -= vLineStartPos;
					vLineDirection.Normalize();

					// Get the normalized collision point to line start point direction in scene node space
					Vector3 vCollisionPointDirection = vCollisionPoint;
					vCollisionPointDirection -= vLineStartPos;
					vCollisionPointDirection.Normalize();

					// Is the collision point within the correct direction?
					if (vLineDirection.DotProduct(vCollisionPointDirection) < 0)
						return;	// Get us out of this method right now, the found collision point is behind us and so we are not interested in it
				}

				// Backup the node space collision point
				const Vector3 vNodeSpaceCollisionPoint = vCollisionPoint;

				// Transform collision point into container space
				vCollisionPoint *= cSceneNode.GetTransform().GetMatrix();

				// Bring the collision point into the same container space the original line start position is in
				vCollisionPoint *= matTransform;

				// Calculate the squared distance between the two positions (that are now within the same vector space)
				const float fSquaredDistance = (m_pPickingResult->m_vLineStartPos-vCollisionPoint).GetSquaredLength();

				// Is this collision point nearer?
				if (m_pPickingResult->m_fNearestSquaredDistance < 0.0f || m_pPickingResult->m_fNearestSquaredDistance > fSquaredDistance) {
					m_pPickingResult->m_pSceneNode				= &cSceneNode;
					m_pPickingResult->m_nGeometry				= nGeometry;
					m_pPickingResult->m_nTriangle				= nTriangle;
					m_pPickingResult->m_vPoint					= vNodeSpaceCollisionPoint;
					m_pPickingResult->m_fNearestSquaredDistance = fSquaredDistance;
				}
			}
		}
	}
}