Author Topic: LODs as collision meshes  (Read 1873 times)

0 Members and 1 Guest are viewing this topic.

Offline zookeeper

  • *knock knock* Who's there? Poe. Poe who?
  • 210
LODs as collision meshes
I've committed this to zookeper branch, here's a patch against trunk:

Code: [Select]
Index: debris/debris.cpp
===================================================================
--- debris/debris.cpp (revision 11268)
+++ debris/debris.cpp (working copy)
@@ -926,6 +926,10 @@
  // reset flags to check MC_CHECK_MODEL | MC_CHECK_SPHERELINE and maybe MC_CHECK_INVISIBLE_FACES and MC_SUBMODEL_INSTANCE
  mc.flags = copy_flags | MC_SUBMODEL_INSTANCE;
 
+ if (Ship_info[Ships[ship_obj->instance].ship_info_index].collision_lod > -1) {
+ mc.lod = Ship_info[Ships[ship_obj->instance].ship_info_index].collision_lod;
+ }
+
  // check each submodel in turn
  for (smv = submodel_vector.begin(); smv != submodel_vector.end(); ++smv) {
  // turn on submodel for collision test
Index: model/model.h
===================================================================
--- model/model.h (revision 11268)
+++ model/model.h (working copy)
@@ -1022,7 +1022,8 @@
  vec3d *p0; // The starting point of the ray (sphere) to check
  vec3d *p1; // The ending point of the ray (sphere) to check
  int flags; // Flags that the model_collide code looks at.  See MC_??? defines
- float radius; // If MC_CHECK_THICK is set, checks a sphere moving with the radius.
+ float radius; // If MC_CHECK_THICK is set, checks a sphere moving with the radius.
+ int lod; // Which detail level of the submodel to check instead
 
  // Return values
  int num_hits; // How many collisions were found
Index: model/modelcollide.cpp
===================================================================
--- model/modelcollide.cpp (revision 11268)
+++ model/modelcollide.cpp (working copy)
@@ -1130,7 +1130,22 @@
  if ( Cmdline_old_collision_sys ) {
  model_collide_sub(sm->bsp_data);
  } else {
- model_collide_bsp(model_get_bsp_collision_tree(sm->collision_tree_index), 0);
+ if (Mc->lod > 0 && sm->num_details > 0) {
+ bsp_info *lod_sm = sm;
+
+ for (int i = Mc->lod - 1; i >= 0; i--) {
+ if (sm->details[i] != -1) {
+ lod_sm = &Mc_pm->submodel[sm->details[i]];
+
+ //mprintf(("Checking %s collision for %s using %s instead\n", Mc_pm->filename, sm->name, lod_sm->name));
+ break;
+ }
+ }
+
+ model_collide_bsp(model_get_bsp_collision_tree(lod_sm->collision_tree_index), 0);
+ } else {
+ model_collide_bsp(model_get_bsp_collision_tree(sm->collision_tree_index), 0);
+ }
  }
  }
  }
Index: model/modelread.cpp
===================================================================
--- model/modelread.cpp (revision 11268)
+++ model/modelread.cpp (working copy)
@@ -2639,6 +2639,12 @@
  }
  dl2 = tolower(sm2->name[first_diff]) - 'a';
 
+ // Handle LODs named "detail0/1/2/etc" too (as opposed to "detaila/b/c/etc")
+ if (sm1->parent == -1 && sm2->parent == -1 && !sm1->is_damaged && !sm2->is_damaged && !sm1->is_live_debris && !sm2->is_live_debris) {
+ dl2 = dl2 - dl1;
+ dl1 = 0;
+ }
+
  if ( (dl1<0) || (dl2<0) || (dl1>=MAX_MODEL_DETAIL_LEVELS) || (dl2>=MAX_MODEL_DETAIL_LEVELS) ) continue; // invalid detail levels
 
  if ( dl1 == 0 ) {
Index: object/collideshipship.cpp
===================================================================
--- object/collideshipship.cpp (revision 11268)
+++ object/collideshipship.cpp (working copy)
@@ -269,6 +269,10 @@
  // reset flags to check MC_CHECK_MODEL | MC_CHECK_SPHERELINE and maybe MC_CHECK_INVISIBLE_FACES and MC_SUBMODEL_INSTANCE
  mc.flags = copy_flags | MC_SUBMODEL_INSTANCE;
 
+ if (heavy_sip->collision_lod > -1) {
+ mc.lod = heavy_sip->collision_lod;
+ }
+
  // check each submodel in turn
  for (smv = submodel_vector.begin(); smv != submodel_vector.end(); ++smv) {
  // turn on submodel for collision test
Index: object/collideshipweapon.cpp
===================================================================
--- object/collideshipweapon.cpp (revision 11268)
+++ object/collideshipweapon.cpp (working copy)
@@ -168,6 +168,7 @@
  mc.pos = &ship_objp->pos;
  mc.p0 = &weapon_objp->last_pos;
  mc.p1 = &weapon_end_pos;
+ mc.lod = sip->collision_lod;
  memcpy(&mc_shield, &mc, sizeof(mc_info));
  memcpy(&mc_hull, &mc, sizeof(mc_info));
 
Index: ship/ship.cpp
===================================================================
--- ship/ship.cpp (revision 11268)
+++ ship/ship.cpp (working copy)
@@ -690,6 +690,7 @@
  sip->pof_file_hud[0] = '\0';
  sip->num_detail_levels = 1;
  sip->detail_distance[0] = 0;
+ sip->collision_lod = -1;
  sip->cockpit_model_num = -1;
  sip->model_num = -1;
  sip->model_num_hud = -1;
@@ -1611,6 +1612,13 @@
  sip->num_detail_levels = stuff_int_list(sip->detail_distance, MAX_SHIP_DETAIL_LEVELS, RAW_INTEGER_TYPE);
  }
 
+ if(optional_string("$Collision LOD:")) {
+ stuff_int(&sip->collision_lod);
+
+ // Cap to sane values, just in case
+ sip->collision_lod = MAX(0, MIN(sip->collision_lod, sip->num_detail_levels));
+ }
+
  // check for optional pixel colors
  while(optional_string("$ND:")){
  ubyte nr, ng, nb;
Index: ship/ship.h
===================================================================
--- ship/ship.h (revision 11268)
+++ ship/ship.h (working copy)
@@ -1175,6 +1175,7 @@
  char pof_file_hud[MAX_FILENAME_LEN]; // POF file to load for the HUD target box
  int num_detail_levels; // number of detail levels for this ship
  int detail_distance[MAX_SHIP_DETAIL_LEVELS]; // distance to change detail levels at
+ int collision_lod; // check for collisions using a LOD
  int cockpit_model_num; // cockpit model
  int model_num; // ship model
  int model_num_hud; // model to use when rendering to the HUD (eg, mini supercap)


In ships.tbl, this goes right below $Detail Distance, like so:

Code: [Select]
$Detail Distance: (0, 2000, 5000)
$Collision LOD: 2 ;use LOD2 for collisions


As it says on the tin, what this does is allowing LODs to be used as collision meshes. More specifically, collision detection for a submodel (including detail0) proceeds as normal through all the radius and bounding box checks, but once the actual submodel bsp tree needs to be traversed, the bsp tree of a lower LOD of that submodel (if one exists) will be used instead.

Of particular note is that LODs used for collision don't need to have all the same submodels as LOD0. If, for example, you set $Collision LOD: 2, then mesh collisions for engine01a will be done using the mesh of engine01c instead. What if there is no engine01c? No problem, in that case engine01b will be used, and if that doesn't exist either, then it just falls back to engine01a as usual.

 

Offline The E

  • He's Ebeneezer Goode
  • Moderator
  • 213
  • Nothing personal, just tech support.
    • Steam
    • Twitter
Re: LODs as collision meshes
Very cool, good job! Have you done any benchmarking to see what the performance impact is?
If I'm just aching this can't go on
I came from chasing dreams to feel alone
There must be changes, miss to feel strong
I really need lifе to touch me
--Evergrey, Where August Mourns

 

Offline zookeeper

  • *knock knock* Who's there? Poe. Poe who?
  • 210
Re: LODs as collision meshes
Nope, I haven't made any benchmarks yet.

 

Offline Cyborg17

  • 29
  • Life? Don't talk to me about life....
Re: LODs as collision meshes
I thought LOD1 was already used for collision detection as part of Swifty's optimizations.

 

Offline Swifty

  • 210
  • I reject your fantasy & substitute my own
Re: LODs as collision meshes
No, I didn't switch out which LODs were used. I did, however, change how the collision mesh BSP was structured in memory in order to make it more cache friendly. I did also try to allow POFs to have separate meshes for collisions but that ended up not making it in.

 

Offline Cyborg17

  • 29
  • Life? Don't talk to me about life....
Re: LODs as collision meshes
Alternate meshes must have been what I was thinking of.