- Timestamp:
- 09/28/06 17:49:37 (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
GTP/trunk/Lib/Geom/shared/GTGeometry/src/GeoLodManager.cpp
r1309 r1526 12 12 #include "GeoLodManager.h" 13 13 #include "GeoLodObject.h" 14 #include <algorithm> 15 /* 14 #include "VertexData.h" 15 #include <ntls.h> 16 #include <map> 17 18 using namespace Geometry; 19 20 //#define MINIMUM_VALID_LOD_SIMILARITY 0.1f 21 22 16 23 namespace Geometry 17 24 { 18 19 20 class lodobj_idpos_node_t 25 class lodobj_node_t : public Moveable<lodobj_node_t> 21 26 { 22 27 public: 23 lodobj_idpos_node_t(LodObject *o):lodobj(o),must_recalculate_distance(true),dist2cam(0.0f){} 28 lodobj_node_t(const std::string &nam, float dist, LodObject *o):dist2cam(dist),lodobj(o),name(nam){ must_recalculate_distance=false; to_update=0; master=NULL; lodfactor=o->GetCurrentLodFactor(); precalpos=-1; } 29 lodobj_node_t(const lodobj_node_t &n){ operator=(n); } 30 float dist2cam; 24 31 LodObject *lodobj; 25 float dist2cam; // used to index the lodobj in the other map 26 bool operator < (const lodobj_idpos_node_t &o) const { return (lodobj->GetUniqueID()<o.lodobj->GetUniqueID()); } 32 bool must_recalculate_distance; 33 uint32 to_update; 34 bool operator < (const lodobj_node_t &o) const { return (dist2cam < o.dist2cam); } 35 void operator = (const lodobj_node_t &n){ dist2cam=n.dist2cam; lodobj=n.lodobj; must_recalculate_distance=n.must_recalculate_distance; master=n.master; lodfactor=n.lodfactor; precalpos=-1; name=n.name; } 36 37 lodobj_node_t * master; 38 VectorMap<uint32,lodobj_node_t*> disciples; 39 float lodfactor; // virtual lod factor (the lodfactor it seems, not its real internal lodfactor) 40 int precalpos; 41 std::string name; 27 42 }; 28 }*/ 29 30 using namespace Geometry; 31 32 LodManager::LodManager(float near, float far, const Geometry::Vector3 &campos) 33 :targetFPS(30),camera_changed(true),camera_pos(campos), 34 near_range(near),far_range(far) 35 { 36 // make the lodobj_dists vector into a heap 37 make_heap(lodobj_dists.begin(),lodobj_dists.end()); 38 } 39 40 void Geometry::LodManager::AddLodObj(LodObject * o, const Geometry::Vector3 &p) 41 { 42 float dist = CalculateDistToCamera(p); 43 lodobj_dists.push_back(lodobj_dist_node_t(dist,o)); 44 push_heap(lodobj_dists.begin(),lodobj_dists.end()); 45 // lodobj_dists[dist] = lodobj_dist_node_t(o); 43 44 class NodeContainer 45 { 46 public: 47 Vector<lodobj_node_t> lodobj_dists; 48 std::map<uint32,Geometry::Vector3> lodobj_pos; // map key: LodObject UniqueID for efficient ID-based finding 49 Vector3 camera_pos; 50 51 int num_lod_sim; 52 53 NodeContainer(const Geometry::Vector3 &campos) 54 :camera_pos(campos){ 55 } 56 57 ~NodeContainer(void){ 58 for (VectorMap<std::string,lodobj_node_t**>::Iterator it = precalculated_lods.Begin(); 59 it != precalculated_lods.End(); it ++) 60 { 61 lodobj_node_t **nodes = *it; 62 delete[] nodes; 63 } 64 } 65 66 void RecalculateDist(lodobj_node_t & node){ 67 std::map<uint32,Vector3>::iterator posit = lodobj_pos.find(node.lodobj->GetUniqueID()); 68 assert(posit!=lodobj_pos.end()); 69 const Vector3 & pos = posit->second; 70 71 node.dist2cam = CalculateDistToCamera(pos); 72 } 73 74 float CalculateDistToCamera(const Geometry::Vector3 &p) const 75 { 76 Geometry::Vector3 v = camera_pos - p; 77 float distquad = v.length(); 78 return distquad; 79 } 80 81 lodobj_node_t * & GetPrecalculatedLOD(const std::string &name, int ipos){ 82 int foundpos = precalculated_lods.Find(name); 83 if (foundpos==-1) 84 { 85 lodobj_node_t **new_precalculated_lods=new lodobj_node_t*[num_lod_sim+1]; // +1 is done to include the highest lod (1.0) 86 for (int i=0; i<num_lod_sim+1; i++) 87 new_precalculated_lods[i]=NULL; 88 precalculated_lods.Add(name) = new_precalculated_lods; 89 return new_precalculated_lods[ipos]; 90 } 91 else 92 { 93 return precalculated_lods[foundpos][ipos]; 94 } 95 } 96 97 uint32 lod2precalpos(Real lodfactor){ 98 return (uint32)(num_lod_sim*lodfactor); 99 } 100 101 private: 102 // the following is an array of precalculated lods 103 // for 10 precalculated lods each element is in order [0.1, 0.2, 0.3, 0.4, 0.5, ...] 104 // for 100 precalculated lods each element is in order [0.01, 0.02, 0.03, 0.04, 0.05, ...] 105 // the funcion lod2precalpos translates a LOD factor to a position in the array 106 VectorMap<std::string,lodobj_node_t**> precalculated_lods; 107 108 }; 109 } 110 111 LodManager::LodManager(Real near, Real far, const Geometry::Vector3 &campos, int numslots) 112 :lasttime(0),camera_changed(true),node_added(false), 113 near_range(near),far_range(far), 114 always_calculate_lod(false),force_highest_lod(false) 115 { 116 lodobj_container=new NodeContainer(campos); 117 lodobj_container->num_lod_sim = numslots; 118 } 119 120 LodManager::~LodManager(void) 121 { 122 delete lodobj_container; 123 // delete[] precalculated_lods; 124 } 125 126 void Geometry::LodManager::AddLodObj(const std::string &name, LodObject * o, const Geometry::Vector3 &p) 127 { 128 float dist = lodobj_container->CalculateDistToCamera(p); 129 lodobj_node_t auxnode(name,dist,o); 130 131 lodobj_container->lodobj_dists.Add(auxnode); 132 Sort(lodobj_container->lodobj_dists); 133 46 134 UpdateLODObjectPos(o,p); 47 } 48 49 50 void Geometry::LodManager::UpdateLOD(void) 51 { 52 if (!lodobj_dists.empty()) 135 node_added=true; 136 } 137 138 139 void Geometry::LodManager::UpdateLOD(uint32 currFPS, uint32 targetFPS) 140 { 141 if (!lodobj_container->lodobj_dists.IsEmpty()) 53 142 { 54 143 // update distances to the camera 55 bool must_resort = false; 56 for (std::vector<lodobj_dist_node_t>::iterator it=lodobj_dists.begin(); it!=lodobj_dists.end(); it++) 57 { 58 lodobj_dist_node_t & node = *it; 59 if (camera_changed || node.must_recalculate_distance) 60 { 61 RecalculateDist(node); 62 must_resort=true; 63 } 64 } 65 if (must_resort) 66 sort_heap(lodobj_dists.begin(),lodobj_dists.end()); 67 68 // select a tree to change its LOD 69 // float random_dist = SelectRandomDistance(); 70 // std::map<float,Geometry::lodobj_dist_node_t>::iterator nearest = lodobj_dists.upper_bound(random_dist); 71 72 // the begining of the list is the greater element (greater dist) 73 lodobj_dist_node_t & node = lodobj_dists.front(); 144 if (camera_changed || node_added) 145 { 146 bool must_resort = false; 147 for (Vector<lodobj_node_t>::Iterator it=lodobj_container->lodobj_dists.Begin(); 148 it!=lodobj_container->lodobj_dists.End(); 149 it++) 150 { 151 lodobj_node_t & node = *it; 152 if (node.must_recalculate_distance || camera_changed || node_added) 153 { 154 lodobj_container->RecalculateDist(node); 155 must_resort=true; 156 } 157 } 158 /* if (must_resort) 159 Sort(lodobj_container->lodobj_dists);*/ 160 } 161 162 // the end of the list is the greater element (greater dist) 163 /* if (currFPS < targetFPS - 5) 164 { 165 Vector<lodobj_node_t>::Iterator selnode; 166 for (selnode=lodobj_container->lodobj_dists.End()-1; selnode!=lodobj_container->lodobj_dists.Begin()-1; selnode--) 167 { 168 // NO HAY QUE USAR CURRENT LOD FACTOR SINO lodobj_container->lodobj_lodfactor 169 if (selnode->lodobj->GetCurrentLodFactor()>0.00001f) 170 { 171 if (selnode->to_update==0) 172 break; 173 else 174 selnode->to_update--; 175 } 176 } 177 178 if (selnode!=lodobj_container->lodobj_dists.Begin()-1) 179 { 180 // EL DECREMENTO O EL NUMERO DE DECREMENTOS TIENE QUE VENIR EN FUNCION DE LA DIFERENCIA DE FPS 181 // NO HAY QUE USAR CURRENT LOD FACTOR SINO lodobj_container->lodobj_lodfactor 182 selnode->lodobj->GoToLod(selnode->lodobj->GetCurrentLodFactor()-0.02f); 183 selnode->to_update=10; // ESTO DEBE ASIGNARSE BASADO EN LA DISTANCIA A LA CAMARA! 184 } 185 } 186 if (currFPS > targetFPS + 5) 187 { 188 Vector<lodobj_node_t>::Iterator selnode; 189 for (selnode=lodobj_container->lodobj_dists.Begin(); selnode!=lodobj_container->lodobj_dists.End(); selnode++) 190 { 191 // NO HAY QUE USAR CURRENT LOD FACTOR SINO lodobj_container->lodobj_lodfactor 192 if (selnode->lodobj->GetCurrentLodFactor()<0.99999f) 193 { 194 if (selnode->to_update==0) 195 break; 196 else 197 selnode->to_update--; 198 } 199 } 200 201 if (selnode!=lodobj_container->lodobj_dists.End()) 202 { 203 // NO HAY QUE USAR CURRENT LOD FACTOR SINO lodobj_container->lodobj_lodfactor 204 selnode->lodobj->GoToLod(selnode->lodobj->GetCurrentLodFactor()+0.02f); 205 selnode->to_update=10; // ESTO DEBE ASIGNARSE BASADO EN LA DISTANCIA A LA CAMARA! 206 } 207 }*/ 208 209 if (camera_changed) 210 { 211 // por ahora solo sacar el lod basado en la camara 212 for (Vector<lodobj_node_t>::Iterator it = lodobj_container->lodobj_dists.Begin(); 213 it != lodobj_container->lodobj_dists.End(); it ++) 214 { 215 float lodfactor = - ((it->dist2cam - near_range) / (far_range - near_range)); 216 if (lodfactor < 0.0f) 217 lodfactor = 0.0f; 218 if (lodfactor > 1.0f) 219 lodfactor = 1.0f; 220 221 if (force_highest_lod) 222 lodfactor = 1.0f; 223 224 ChangeLOD(it,lodfactor); 225 } 226 } 74 227 } 75 228 camera_changed=false; 76 } 77 78 void Geometry::LodManager::RecalculateDist(lodobj_dist_node_t & node) 79 { 80 std::map<uint32,Vector3>::iterator posit = lodobj_pos.find(node.lodobj->GetUniqueID()); 81 assert(posit!=lodobj_pos.end()); 82 const Vector3 & pos = posit->second; 83 84 node.dist2cam = CalculateDistToCamera(pos); 85 } 86 229 node_added=false; 230 } 231 232 void Geometry::LodManager::ChangeLOD(lodobj_node_t *lodobjnode, Real lodfactor) 233 { 234 LodObject *lodobj = lodobjnode->lodobj; 235 236 if (always_calculate_lod) 237 { 238 lodobj->GoToLod(lodfactor); 239 return; 240 } 241 242 // if the lodfactor is exactly 1.0 its level of detail must be always regenerated (for closeups) 243 if (lodfactor<1.0f) 244 { 245 // if the desired lod is very similar to the previous one, 246 // then there is no need to change the level of detail at all 247 // float sim = fabsf(lodfactor - lodobjnode->lodfactor); 248 // if (sim <= MINIMUM_VALID_LOD_SIMILARITY) 249 // return; // do not change anything if the lod is very similar! 250 int desiredpos = lodobj_container->lod2precalpos(lodfactor); 251 int mypos = lodobj_container->lod2precalpos(lodobjnode->lodfactor); 252 if (mypos==desiredpos) 253 return; 254 } 255 256 lodobj_node_t *found_node = FindMostSimilarRealLOD(lodobjnode->name,lodfactor); 257 258 if (found_node && found_node->lodobj->GetUniqueID()!=lodobj->GetUniqueID()) 259 { 260 // DEBUG 261 assert(found_node->master==NULL); 262 263 // float sim = fabsf(lodfactor - found_node->lodfactor); 264 // if (sim <= MINIMUM_VALID_LOD_SIMILARITY) 265 int desiredpos = lodobj_container->lod2precalpos(lodfactor); 266 int foundpos = lodobj_container->lod2precalpos(found_node->lodfactor); 267 if (foundpos==desiredpos) 268 { 269 lodobj->GetIndexDataInterface()->BorrowIndexData(found_node->lodobj->GetIndexDataInterface()); 270 MakeDiscipleOf(found_node,lodobjnode); 271 } 272 else 273 ReallyGoToLOD(lodobjnode,lodfactor); 274 } 275 else 276 ReallyGoToLOD(lodobjnode,lodfactor); 277 278 lodobjnode->lodfactor = lodfactor; 279 } 280 281 void Geometry::LodManager::DeleteMeFromMyMastersDiscipleList(lodobj_node_t *lodobjnode) 282 { 283 // if I have a master... 284 if (lodobjnode->master) 285 lodobjnode->master->disciples.RemoveKey(lodobjnode->lodobj->GetUniqueID()); 286 } 287 288 289 void Geometry::LodManager::MakeIndependent(lodobj_node_t *lodobjnode) 290 { 291 DeleteMeFromMyMastersDiscipleList(lodobjnode); 292 293 // next, delete my master 294 lodobjnode->master=NULL; 295 } 296 297 void Geometry::LodManager::MakeDiscipleOf(lodobj_node_t *master_node, lodobj_node_t *disciple_node) 298 { 299 ChangeMaster(disciple_node, master_node); 300 301 // delete my disciples 302 disciple_node->disciples.Clear(); 303 304 // first remove me from my master's disciple list 305 DeleteMeFromMyMastersDiscipleList(disciple_node); 306 307 master_node->disciples.GetAdd(disciple_node->lodobj->GetUniqueID()) = disciple_node; 308 309 // set master 310 disciple_node->master = master_node; 311 312 // no one must take me as a master! 313 if (disciple_node->precalpos!=-1) 314 { 315 // lodobj_container->precalculated_lods[disciple_node->precalpos] = NULL; 316 lodobj_container->GetPrecalculatedLOD(master_node->name,disciple_node->precalpos) = NULL; 317 disciple_node->precalpos = -1; 318 } 319 } 320 321 void Geometry::LodManager::ChangeMaster(lodobj_node_t *lodobj, lodobj_node_t *newmaster) 322 { 323 // delete me from my disciples' master list 324 for (VectorMap<uint32,lodobj_node_t*>::Iterator it = lodobj->disciples.Begin(); it != lodobj->disciples.End(); it++) 325 { 326 lodobj_node_t * auxnode = *it; 327 assert(auxnode->master->lodobj->GetUniqueID() == lodobj->lodobj->GetUniqueID()); 328 // auxnode->master = NULL; 329 // chanbge the master to the new one 330 auxnode->master = newmaster; 331 332 // add the new disciple to the new master 333 if (newmaster) 334 newmaster->disciples.GetAdd(auxnode->lodobj->GetUniqueID()) = auxnode; 335 } 336 } 337 338 339 void Geometry::LodManager::UpdateDisciples(lodobj_node_t *master_node) 340 { 341 for (VectorMap<uint32,lodobj_node_t*>::Iterator it= master_node->disciples.Begin(); it!= master_node->disciples.End(); it++) 342 { 343 lodobj_node_t *disciple_node = *it; 344 disciple_node->lodobj->GetIndexDataInterface()->BorrowIndexData(master_node->lodobj->GetIndexDataInterface()); 345 disciple_node->lodfactor = master_node->lodobj->GetCurrentLodFactor(); // we can use currentlodfactor here because the master is supposed to be at its REAL level of detail 346 } 347 } 348 349 void Geometry::LodManager::ReallyGoToLOD(lodobj_node_t *lodobjnode, Real lodfactor) 350 { 351 lodobjnode->lodobj->GoToLod(lodfactor); 352 353 MakeIndependent(lodobjnode); 354 UpdateDisciples(lodobjnode); 355 356 // store the precalculated lod in the table 357 int i = lodobj_container->lod2precalpos(lodfactor); 358 359 assert(i>=0 && i<=lodobj_container->num_lod_sim); // <= por lo del +1 360 361 if (lodobjnode->precalpos != -1) 362 //lodobj_container->precalculated_lods[lodobjnode->precalpos] = NULL; 363 lodobj_container->GetPrecalculatedLOD(lodobjnode->name,lodobjnode->precalpos) = NULL; 364 365 // lodobj_container->precalculated_lods[i] = lodobjnode; 366 lodobj_container->GetPrecalculatedLOD(lodobjnode->name,i) = lodobjnode; 367 368 lodobjnode->precalpos = i; 369 } 370 371 372 lodobj_node_t * Geometry::LodManager::FindMostSimilarRealLOD(const std::string &name, Real desired_lod) 373 { 374 uint32 i = lodobj_container->lod2precalpos(desired_lod); 375 assert(i>=0 && i<=lodobj_container->num_lod_sim); // <= por lo del +1 376 // lodobj_node_t *obj = lodobj_container->precalculated_lods[i]; 377 lodobj_node_t *obj = lodobj_container->GetPrecalculatedLOD(name,i); 378 379 return obj; 380 } 87 381 88 382 void Geometry::LodManager::UpdateCamera(const Geometry::Vector3 &p) 89 383 { 90 camera_pos = p;384 lodobj_container->camera_pos = p; 91 385 camera_changed = true; 92 386 } … … 94 388 void Geometry::LodManager::UpdateLODObjectPos(LodObject *o, const Geometry::Vector3 &p) 95 389 { 96 lodobj_pos[o->GetUniqueID()] = p; 97 } 98 99 100 float Geometry::LodManager::CalculateDistToCamera(const Geometry::Vector3 &p) const 101 { 102 return camera_pos.dotProduct(p); 103 } 390 lodobj_container->lodobj_pos[o->GetUniqueID()] = p; 391 } 392 104 393 105 394 float Geometry::LodManager::SelectRandomDistance(void) const
Note: See TracChangeset
for help on using the changeset viewer.