void Stem::Update(float msec) { mesh->Update(msec); SceneNode::Update(msec); if (mesh->GetDrawIndices() > branchAdd && numBranches < maxBranches) { int tempsize = (((rand() % (stemSize/2)) + stemSize/4)); SceneNode* branch = new Branch(tempsize); float branchpos = (float)((branchAdd / 24) / 5); branchpos -= (branchpos / 9); branch->SetTransform(Matrix4::Translation(Vector3(0, branchpos * maxScale.y, 0))); float branchAngle = (float)((rand() % 180) - 90); while (branchAngle < 20 && branchAngle > -20) { branchAngle = (float)((rand() % 180) - 90); } branch->SetTransform(branch->GetTransform() * Matrix4::Rotation(branchAngle, Vector3(0, 0, 1))); branchAngle = (float)((rand() % 180) - 90); while (branchAngle < 20 && branchAngle > -20) { branchAngle = (float)((rand() % 180) - 90); } branch->SetTransform(branch->GetTransform() * Matrix4::Rotation(branchAngle, Vector3(1, 0, 0))); AddChild(branch); numBranches++; branchAdd += (((stemSize - stemSize / maxBranches) * 24) / maxBranches); } Vector3 endPos = myNode->GetPosition(); float v = mesh->GetDrawIndices(); float z = v / (stemSize * 24); endPos.y += 200 * z; myNode->SetCollisionVolume(new CollisionCylinder(2, myNode->GetPosition(), endPos)); if (modelScale.x < maxScale.x) { modelScale.x += 0.0001; modelScale.z += 0.0001; } }
/** * @brief * Constructor */ SNMScaleRandomAnimation::SNMScaleRandomAnimation(SceneNode &cSceneNode) : SNMTransform(cSceneNode), Speed(this), Radius(this), FixScale(this), EventHandlerUpdate(&SNMScaleRandomAnimation::OnUpdate, this), m_fTimer(0.0f) { // Set initial fixed scale FixScale.Set(cSceneNode.GetTransform().GetScale()); }
/** * @brief * Called when a scene node was found */ void Picking::OnSceneNode(SceneQuery &cQuery, SceneNode &cSceneNode) { // First at all, call the picking filter function if (m_pPickingResult->m_pSceneContainer && OnPickingCandidate(cSceneNode)) { // Is there a mesh handler with a mesh? if (cSceneNode.GetMeshHandler() && cSceneNode.GetMeshHandler()->GetMesh()) { // We KNOW that it's a SQLine! SQLine &cLineQuery = static_cast<SQLine&>(cQuery); // Get line start/end position in node space const Vector3 vLineStartPos = cSceneNode.GetTransform().GetInverseMatrix()*cLineQuery.GetLine().vStart; const Vector3 vLineEndPos = cSceneNode.GetTransform().GetInverseMatrix()*cLineQuery.GetLine().vEnd; // Perform mesh intersection MeshIntersection(cSceneNode, vLineStartPos, vLineEndPos, nullptr, cLineQuery.GetCull()); } else { // There's no mesh we can use for an intersection test // [TODO] Currently it's impossible to pick something which does not have a polygonal mesh, think // of a way to handle this case properly, especially when dealing with overlapping scene nodes } } }
/** * @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; }
/** * @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; } } } } }