//显示选中物体的包围盒 void ObjectPositionEditor::HandlePostRenderUpdate(StringHash eventType, VariantMap& eventData) { EditorRoot* pEditorRoot = EditorRoot::Instance(); DebugRenderer* debug = pEditorRoot->scene_->GetComponent<DebugRenderer>(); if(debug == NULL) return; vector<Node*> nodes = pEditorRoot->GetUnionSelections(); for(int i = 0;i < nodes.size();i ++) { Node* node = nodes[i]; if(node->GetComponent<Skybox>() != NULL) continue; debug->AddNode(node,1.0f,false); const Vector<SharedPtr<Component> >& components = node->GetComponents(); for(int j = 0;j < node->GetNumComponents();j ++) { Drawable* drawable = dynamic_cast<Drawable*>(components[j].Get()); if(drawable != NULL) { debug->AddBoundingBox(drawable->GetWorldBoundingBox(),Color::WHITE,true); } } } //计算总的 if(nodes.size() > 1) { BoundingBox allBox; for(int i = 0;i < nodes.size();i ++) { Node* node = nodes[i]; if(node->GetComponent<Skybox>() != NULL) continue; const Vector<SharedPtr<Component> >& components = node->GetComponents(); for(int j = 0;j < node->GetNumComponents();j ++) { Drawable* drawable = dynamic_cast<Drawable*>(components[j].Get()); if(drawable != NULL) { allBox.Merge(drawable->GetWorldBoundingBox()); } } } debug->AddBoundingBox(allBox,Color::BLUE,true); } if(CurrentHoverObject != NULL) { CurrentHoverObject->DrawDebugGeometry(debug,false); } }
void Navigation::AddOrRemoveObject() { // Raycast and check if we hit a mushroom node. If yes, remove it, if no, create a new one Vector3 hitPos; Drawable* hitDrawable; if (Raycast(250.0f, hitPos, hitDrawable)) { // The part of the navigation mesh we must update, which is the world bounding box of the associated // drawable component BoundingBox updateBox; Node* hitNode = hitDrawable->GetNode(); if (hitNode->GetName() == "Mushroom") { updateBox = hitDrawable->GetWorldBoundingBox(); hitNode->Remove(); } else { Node* newNode = CreateMushroom(hitPos); updateBox = newNode->GetComponent<StaticModel>()->GetWorldBoundingBox(); } // Rebuild part of the navigation mesh, then recalculate path if applicable scene_->GetComponent<NavigationMesh>()->Build(updateBox); RecalculatePath(); } }
void BoxOctreeQuery::TestDrawables(Drawable** start, Drawable** end, bool inside) { while (start != end) { Drawable* drawable = *start++; if ((drawable->GetDrawableFlags() & drawableFlags_) && (drawable->GetViewMask() & viewMask_)) { if (inside || box_.IsInsideFast(drawable->GetWorldBoundingBox())) result_.Push(drawable); } } }
void Octree::RaycastSingle(RayOctreeQuery& query) const { PROFILE(Raycast); query.result_.Clear(); rayQueryDrawables_.Clear(); GetDrawablesOnlyInternal(query, rayQueryDrawables_); // Sort by increasing hit distance to AABB for (PODVector<Drawable*>::Iterator i = rayQueryDrawables_.Begin(); i != rayQueryDrawables_.End(); ++i) { Drawable* drawable = *i; drawable->SetSortValue(query.ray_.HitDistance(drawable->GetWorldBoundingBox())); } Sort(rayQueryDrawables_.Begin(), rayQueryDrawables_.End(), CompareDrawables); // Then do the actual test according to the query, and early-out as possible float closestHit = M_INFINITY; for (PODVector<Drawable*>::Iterator i = rayQueryDrawables_.Begin(); i != rayQueryDrawables_.End(); ++i) { Drawable* drawable = *i; if (drawable->GetSortValue() < Min(closestHit, query.maxDistance_)) { unsigned oldSize = query.result_.Size(); drawable->ProcessRayQuery(query, query.result_); if (query.result_.Size() > oldSize) closestHit = Min(closestHit, query.result_.Back().distance_); } else break; } if (query.result_.Size() > 1) { Sort(query.result_.Begin(), query.result_.End(), CompareRayQueryResults); query.result_.Resize(1); } }
void Octree::Update(const FrameInfo& frame) { // Let drawables update themselves before reinsertion. This can be used for animation if (!drawableUpdates_.Empty()) { PROFILE(UpdateDrawables); // Perform updates in worker threads. Notify the scene that a threaded update is going on and components // (for example physics objects) should not perform non-threadsafe work when marked dirty Scene* scene = GetScene(); WorkQueue* queue = GetSubsystem<WorkQueue>(); scene->BeginThreadedUpdate(); int numWorkItems = queue->GetNumThreads() + 1; // Worker threads + main thread int drawablesPerItem = Max((int)(drawableUpdates_.Size() / numWorkItems), 1); PODVector<Drawable*>::Iterator start = drawableUpdates_.Begin(); // Create a work item for each thread for (int i = 0; i < numWorkItems; ++i) { SharedPtr<WorkItem> item = queue->GetFreeItem(); item->priority_ = M_MAX_UNSIGNED; item->workFunction_ = UpdateDrawablesWork; item->aux_ = const_cast<FrameInfo*>(&frame); PODVector<Drawable*>::Iterator end = drawableUpdates_.End(); if (i < numWorkItems - 1 && end - start > drawablesPerItem) end = start + drawablesPerItem; item->start_ = &(*start); item->end_ = &(*end); queue->AddWorkItem(item); start = end; } queue->Complete(M_MAX_UNSIGNED); scene->EndThreadedUpdate(); } // Notify drawable update being finished. Custom animation (eg. IK) can be done at this point Scene* scene = GetScene(); if (scene) { using namespace SceneDrawableUpdateFinished; VariantMap& eventData = GetEventDataMap(); eventData[P_SCENE] = scene; eventData[P_TIMESTEP] = frame.timeStep_; scene->SendEvent(E_SCENEDRAWABLEUPDATEFINISHED, eventData); } // Reinsert drawables that have been moved or resized, or that have been newly added to the octree and do not sit inside // the proper octant yet if (!drawableUpdates_.Empty()) { PROFILE(ReinsertToOctree); for (PODVector<Drawable*>::Iterator i = drawableUpdates_.Begin(); i != drawableUpdates_.End(); ++i) { Drawable* drawable = *i; drawable->updateQueued_ = false; Octant* octant = drawable->GetOctant(); const BoundingBox& box = drawable->GetWorldBoundingBox(); // Skip if no octant or does not belong to this octree anymore if (!octant || octant->GetRoot() != this) continue; // Skip if still fits the current octant if (drawable->IsOccludee() && octant->GetCullingBox().IsInside(box) == INSIDE && octant->CheckDrawableFit(box)) continue; InsertDrawable(drawable); #ifdef _DEBUG // Verify that the drawable will be culled correctly octant = drawable->GetOctant(); if (octant != this && octant->GetCullingBox().IsInside(box) != INSIDE) { LOGERROR("Drawable is not fully inside its octant's culling bounds: drawable box " + box.ToString() + " octant box " + octant->GetCullingBox().ToString()); } #endif } } drawableUpdates_.Clear(); }
void NavigationMesh::CollectGeometries(Vector<NavigationGeometryInfo>& geometryList, Node* node, HashSet<Node*>& processedNodes, bool recursive) { // Make sure nodes are not included twice if (processedNodes.Contains(node)) return; // Exclude obstacles and crowd agents from consideration if (node->HasComponent<Obstacle>() || node->HasComponent<CrowdAgent>()) return; processedNodes.Insert(node); Matrix3x4 inverse = node_->GetWorldTransform().Inverse(); #ifdef ATOMIC_PHYSICS // Prefer compatible physics collision shapes (triangle mesh, convex hull, box) if found. // Then fallback to visible geometry PODVector<CollisionShape*> collisionShapes; node->GetComponents<CollisionShape>(collisionShapes); bool collisionShapeFound = false; for (unsigned i = 0; i < collisionShapes.Size(); ++i) { CollisionShape* shape = collisionShapes[i]; if (!shape->IsEnabledEffective()) continue; ShapeType type = shape->GetShapeType(); if ((type == SHAPE_BOX || type == SHAPE_TRIANGLEMESH || type == SHAPE_CONVEXHULL) && shape->GetCollisionShape()) { Matrix3x4 shapeTransform(shape->GetPosition(), shape->GetRotation(), shape->GetSize()); NavigationGeometryInfo info; info.component_ = shape; info.transform_ = inverse * node->GetWorldTransform() * shapeTransform; info.boundingBox_ = shape->GetWorldBoundingBox().Transformed(inverse); geometryList.Push(info); collisionShapeFound = true; } } if (!collisionShapeFound) #endif { PODVector<Drawable*> drawables; node->GetDerivedComponents<Drawable>(drawables); for (unsigned i = 0; i < drawables.Size(); ++i) { /// \todo Evaluate whether should handle other types. Now StaticModel & TerrainPatch are supported, others skipped Drawable* drawable = drawables[i]; if (!drawable->IsEnabledEffective()) continue; NavigationGeometryInfo info; if (drawable->GetType() == StaticModel::GetTypeStatic()) info.lodLevel_ = static_cast<StaticModel*>(drawable)->GetOcclusionLodLevel(); else if (drawable->GetType() == TerrainPatch::GetTypeStatic()) info.lodLevel_ = 0; else continue; info.component_ = drawable; info.transform_ = inverse * node->GetWorldTransform(); info.boundingBox_ = drawable->GetWorldBoundingBox().Transformed(inverse); geometryList.Push(info); } } if (recursive) { const Vector<SharedPtr<Node> >& children = node->GetChildren(); for (unsigned i = 0; i < children.Size(); ++i) CollectGeometries(geometryList, children[i], processedNodes, recursive); } }