2022-07-05 20:19 EDT
 All Projects | FSSCP: wxFRED

View Issue Details
IDProjectCategoryView StatusLast Update
0002664FSSCPmath-relatedpublic2012-11-23 21:14
Reporterniffiwan
Assigned Toniffiwan
PrioritynormalSeveritymajorReproducibilityalways
StatusresolvedResolutionfixed
Product Version3.6.14 RC6
Target Version3.6.16Fixed in Version3.6.15
Summary0002664: shockwaves uses target objects radius to calculate damage
DescriptionWhen calculating the distance at which shockwaves will do damage to a given target, the target of the shockwave is treated as being a sphere. For any model with a shape that is not perfect sphere, this method will have inaccuracies. It's particularly noticeable with the Karuna from Blueplanet2 as the one of the Karunas primary weapons is the Apocalyse missile (which has a shockwave), and the Karuna model is long and thin. Any target of the Karuna that is close and not directly fore/aft of the ship will cause the Karuna to take damage from it's own weapons, even though "logically" the ship is outside the shockwave outer radius.
Steps To ReproduceSome discussion has occurred in this forum post.

http://www.hard-light.net/forums/index.php?topic=80146.msg1615180#msg1615180

I've attached a mission from qwadtep which showcases the issue. In theory none of the Karunas should take damage from their own missiles, however either 2 or 3 do, depending on which Karuna model is in use.
Additional InformationThe obvious solution is to be to be more accurate with the distance calculation. My concern is how this will affect performance, as I believe that collision detection is the current bottleneck in FSO.

One idea would be to calculate a cylinder for shockwave distance calculations - which is still an approximation but could be accurate enough for most cases. I think this would require two more pieces of information, radius & world position we have, we'd need length and orientation of the cylinder. I think I came across a existing function somewhere which will calculate the closest point on a cylinder to a given world position? (of course I can't find said function now...)

Another idea would be to use something similar to the weapon impact calculations, i.e. use the lod0 model with all its polygons. Obviously this gives the most accurate results, but is it too computationally expensive?
TagsNo tags attached.
Attached Files
• test-range.fs2 (14,882 bytes) 2012-06-09 23:53
• mantis_2664.patch (6,003 bytes) 2012-11-19 04:11
```Index: fs2_open/code/ai/aicode.cpp
===================================================================
--- fs2_open/code/ai/aicode.cpp    (revision 9359)
+++ fs2_open/code/ai/aicode.cpp    (working copy)
@@ -1834,28 +1834,7 @@ int is_ignore_object(ai_info *aip, int objnum, int just_the_original = 0)
return 0;
}

-/**
- * Given a ship with bounding box and a point, find the closest point on the bbox
- */
-int get_nearest_bbox_point(object *ship_obj, vec3d *start, vec3d *box_pt)
-{
-	vec3d temp, rf_start;
-	polymodel *pm;
-	pm = model_get(Ship_info[Ships[ship_obj->instance].ship_info_index].model_num);

-	// get start in ship rf
-	vm_vec_sub(&temp, start, &ship_obj->pos);
-	vm_vec_rotate(&rf_start, &temp, &ship_obj->orient);
-
-	// find box_pt
-	int inside = project_point_onto_bbox(&pm->mins, &pm->maxs, &rf_start, &temp);
-
-	// get box_pt in world rf
-	vm_vec_unrotate(box_pt, &temp, &ship_obj->orient);
-
-	return inside;
-}

typedef struct eval_nearest_objnum {
Index: fs2_open/code/ship/ship.cpp
===================================================================
--- fs2_open/code/ship/ship.cpp    (revision 9359)
+++ fs2_open/code/ship/ship.cpp    (working copy)
@@ -61,6 +61,7 @@
#include "ship/shipcontrails.h"
#include "weapon/beam.h"
#include "math/staticrand.h"
+#include "math/fvi.h"
#include "missionui/missionshipchoice.h"
#include "hud/hudartillery.h"
#include "species_defs/species_defs.h"
@@ -17417,3 +17418,32 @@ bool ship_has_sound(object *objp, GameSoundsIndex id)
return true;
}

+/**
+ * Given a ship with bounding box and a point, find the closest point on the bbox
+ *
+ * @param ship_obj Object that has the bounding box (should be a ship)
+ * @param start World position of the point being compared
+ * @param box_pt OUTPUT PARAMETER: closest point on the bbox to start
+ *
+ * @return point is inside bbox, TRUE/1
+ * @return point is outside bbox, FALSE/0
+ */
+int get_nearest_bbox_point(object *ship_obj, vec3d *start, vec3d *box_pt)
+{
+	vec3d temp, rf_start;
+	polymodel *pm;
+	pm = model_get(Ship_info[Ships[ship_obj->instance].ship_info_index].model_num);
+
+	// get start in ship rf
+	vm_vec_sub(&temp, start, &ship_obj->pos);
+	vm_vec_rotate(&rf_start, &temp, &ship_obj->orient);
+
+	// find box_pt
+	int inside = project_point_onto_bbox(&pm->mins, &pm->maxs, &rf_start, &temp);
+
+	// get box_pt in world rf
+	vm_vec_unrotate(box_pt, &temp, &ship_obj->orient);
+
+	return inside;
+}
Index: fs2_open/code/ship/ship.h
===================================================================
--- fs2_open/code/ship/ship.h    (revision 9359)
+++ fs2_open/code/ship/ship.h    (working copy)
@@ -1975,4 +1975,16 @@ bool ship_has_sound(object *objp, GameSoundsIndex id);
*/
int get_default_player_ship_index();

+/**
+ * Given a ship with bounding box and a point, find the closest point on the bbox
+ *
+ * @param ship_obj Object that has the bounding box (should be a ship)
+ * @param start World position of the point being compared
+ * @param box_pt OUTPUT PARAMETER: closest point on the bbox to start
+ *
+ * @return point is inside bbox, TRUE/1
+ * @return point is outside bbox, FALSE/0
+ */
+int get_nearest_bbox_point(object *ship_obj, vec3d *start, vec3d *box_pt);
+
#endif
Index: fs2_open/code/weapon/weapons.cpp
===================================================================
--- fs2_open/code/weapon/weapons.cpp    (revision 9359)
+++ fs2_open/code/weapon/weapons.cpp    (working copy)
@@ -5589,7 +5589,7 @@ void weapon_do_electronics_effect(object *ship_objp, vec3d *blast_pos, int wi_in
}

/**
- * Calculate teh damage for an object based on the location of an area-effect
+ * Calculate the damage for an object based on the location of an area-effect
* explosion.
*
* @param objp			Object pointer ship receiving blast effect
@@ -5607,23 +5607,33 @@ void weapon_do_electronics_effect(object *ship_objp, vec3d *blast_pos, int wi_in
*/
int weapon_area_calc_damage(object *objp, vec3d *pos, float inner_rad, float outer_rad, float max_blast, float max_damage, float *blast, float *damage, float limit)
{
-	float			dist, max_dist, min_dist;
+	float dist;
+	vec3d box_pt;
+
+	// if object receiving the blast is a ship, use the bbox for distances
+	// otherwise use the objects radius
+	// could possibly exclude SIF_SMALL_SHIP (& other small objects) from using the bbox
+	if (objp->type == OBJ_SHIP) {
+		int inside = get_nearest_bbox_point(objp, pos, &box_pt);
+		if (inside) {
+			dist = 0.0001f;
+		} else {
+			dist = vm_vec_dist_quick(pos, &box_pt);
+		}
+	} else {
+		dist = vm_vec_dist_quick(&objp->pos, pos) - objp->radius;
+	}

-	dist = vm_vec_dist_quick(&objp->pos, pos);
-	if ( (dist > max_dist) || (dist > (limit+objp->radius)) ) {
+	if ( (dist > outer_rad) || (dist > limit) ) {
return -1;	// spheres don't intersect at all
}

+	if ( dist < inner_rad ) {
// damage is maximum within inner radius
*damage = max_damage;
*blast = max_blast;
} else {
-		min_dist = dist - objp->radius;
-

// this means the inner and outer radii are basically equal... and since we aren't within the inner radius,
@@ -5635,8 +5645,7 @@ int weapon_area_calc_damage(object *objp, vec3d *pos, float inner_rad, float out
// AL 2-24-98: drop off damage relative to square of distance
-
}

return 0;
```
mantis_2664.patch (6,003 bytes) 2012-11-19 04:11
• mantis_2664_puresvn.patch (5,481 bytes) 2012-11-23 04:11
```Index: code/weapon/weapons.cpp
===================================================================
--- code/weapon/weapons.cpp	(revision 9370)
+++ code/weapon/weapons.cpp	(working copy)
@@ -5589,7 +5589,7 @@
}

/**
- * Calculate teh damage for an object based on the location of an area-effect
+ * Calculate the damage for an object based on the location of an area-effect
* explosion.
*
* @param objp			Object pointer ship receiving blast effect
@@ -5607,23 +5607,33 @@
*/
int weapon_area_calc_damage(object *objp, vec3d *pos, float inner_rad, float outer_rad, float max_blast, float max_damage, float *blast, float *damage, float limit)
{
-	float			dist, max_dist, min_dist;
+	float dist;
+	vec3d box_pt;

-	dist = vm_vec_dist_quick(&objp->pos, pos);
-	if ( (dist > max_dist) || (dist > (limit+objp->radius)) ) {
+	// if object receiving the blast is a ship, use the bbox for distances
+	// otherwise use the objects radius
+	// could possibly exclude SIF_SMALL_SHIP (& other small objects) from using the bbox
+	if (objp->type == OBJ_SHIP) {
+		int inside = get_nearest_bbox_point(objp, pos, &box_pt);
+		if (inside) {
+			dist = 0.0001f;
+		} else {
+			dist = vm_vec_dist_quick(pos, &box_pt);
+		}
+	} else {
+		dist = vm_vec_dist_quick(&objp->pos, pos) - objp->radius;
+	}
+
+	if ( (dist > outer_rad) || (dist > limit) ) {
return -1;	// spheres don't intersect at all
}

+	if ( dist < inner_rad ) {
// damage is maximum within inner radius
*damage = max_damage;
*blast = max_blast;
} else {
-		min_dist = dist - objp->radius;
-

// this means the inner and outer radii are basically equal... and since we aren't within the inner radius,
@@ -5635,8 +5645,7 @@
// AL 2-24-98: drop off damage relative to square of distance
-
}

return 0;
Index: code/ai/aicode.cpp
===================================================================
--- code/ai/aicode.cpp	(revision 9370)
+++ code/ai/aicode.cpp	(working copy)
@@ -1834,30 +1834,9 @@
return 0;
}

-/**
- * Given a ship with bounding box and a point, find the closest point on the bbox
- */
-int get_nearest_bbox_point(object *ship_obj, vec3d *start, vec3d *box_pt)
-{
-	vec3d temp, rf_start;
-	polymodel *pm;
-	pm = model_get(Ship_info[Ships[ship_obj->instance].ship_info_index].model_num);

-	// get start in ship rf
-	vm_vec_sub(&temp, start, &ship_obj->pos);
-	vm_vec_rotate(&rf_start, &temp, &ship_obj->orient);

-	// find box_pt
-	int inside = project_point_onto_bbox(&pm->mins, &pm->maxs, &rf_start, &temp);

-	// get box_pt in world rf
-	vm_vec_unrotate(box_pt, &temp, &ship_obj->orient);
-
-	return inside;
-}
-
-
typedef struct eval_nearest_objnum {
int	objnum;
object *trial_objp;
Index: code/ship/ship.cpp
===================================================================
--- code/ship/ship.cpp	(revision 9370)
+++ code/ship/ship.cpp	(working copy)
@@ -61,6 +61,7 @@
#include "ship/shipcontrails.h"
#include "weapon/beam.h"
#include "math/staticrand.h"
+#include "math/fvi.h"
#include "missionui/missionshipchoice.h"
#include "hud/hudartillery.h"
#include "species_defs/species_defs.h"
@@ -17435,3 +17436,32 @@
return true;
}

+/**
+ * Given a ship with bounding box and a point, find the closest point on the bbox
+ *
+ * @param ship_obj Object that has the bounding box (should be a ship)
+ * @param start World position of the point being compared
+ * @param box_pt OUTPUT PARAMETER: closest point on the bbox to start
+ *
+ * @return point is inside bbox, TRUE/1
+ * @return point is outside bbox, FALSE/0
+ */
+int get_nearest_bbox_point(object *ship_obj, vec3d *start, vec3d *box_pt)
+{
+	vec3d temp, rf_start;
+	polymodel *pm;
+	pm = model_get(Ship_info[Ships[ship_obj->instance].ship_info_index].model_num);
+
+	// get start in ship rf
+	vm_vec_sub(&temp, start, &ship_obj->pos);
+	vm_vec_rotate(&rf_start, &temp, &ship_obj->orient);
+
+	// find box_pt
+	int inside = project_point_onto_bbox(&pm->mins, &pm->maxs, &rf_start, &temp);
+
+	// get box_pt in world rf
+	vm_vec_unrotate(box_pt, &temp, &ship_obj->orient);
+
+	return inside;
+}
Index: code/ship/ship.h
===================================================================
--- code/ship/ship.h	(revision 9370)
+++ code/ship/ship.h	(working copy)
@@ -1975,4 +1975,16 @@
*/
int get_default_player_ship_index();

+/**
+ * Given a ship with bounding box and a point, find the closest point on the bbox
+ *
+ * @param ship_obj Object that has the bounding box (should be a ship)
+ * @param start World position of the point being compared
+ * @param box_pt OUTPUT PARAMETER: closest point on the bbox to start
+ *
+ * @return point is inside bbox, TRUE/1
+ * @return point is outside bbox, FALSE/0
+ */
+int get_nearest_bbox_point(object *ship_obj, vec3d *start, vec3d *box_pt);
+
#endif
```
mantis_2664_puresvn.patch (5,481 bytes) 2012-11-23 04:11

 Relationships
 Relationships

 Notes ~0013652 The_E (administrator) 2012-06-10 17:18 Why not use the rotated model bounding box?Seems to me that that would be a good first place to start, instead of going straight to full-on ray collisions with LOD0. ~0013653 niffiwan (developer) 2012-06-10 22:27 The bounding box sounds like a good idea, I'm ashamed to admit it but I didn't know they existed when I logged the ticket :-) Since then I've been doing some wiki reading about the .pof format. Just to further expose my knowledge deficiencies in this area - what's the "rotated" model bbox? I presume that the "normal" bbox is described in the OBJ chunks, by these three values? vector geometric_center vector bounding_box_min_point vector bounding_box_max_point http://www.hard-light.net/wiki/index.php/POF_data_structure ~0013660 The_E (administrator) 2012-06-11 05:08 Rotated just means that you have to rotate the bbox coords into world coordinates by using vec_rotate with the objects current orientation matrix. ~0013731 niffiwan (developer) 2012-06-27 23:10 I found a function in the aicode for getting the nearest point on a bounding box so I moved that around and reused it for the shockwaves check. My testing with the attached mission now has only the 400m Karuna taking some self damage, and only some of the time, probably from missile impacts on the nearest engine section of the Deimos. Could someone please review the patch and provide comments? Thanks ~0014020 Goober5000 (administrator) 2012-11-11 00:18 The patch looks okay, but I want to look at it in context with the code, and unfortunately the patch can no longer be cleanly applied. Can you make a new patch against latest trunk? ~0014069 niffiwan (developer) 2012-11-19 04:22 Oops - old patch was in git format, not svn format. Does this one apply cleanly? You might need the tortoise equivalent of "patch -p1" to ignore the leading fs2_open directory in the patch paths. ~0014152 Goober5000 (administrator) 2012-11-22 22:10 Unfortunately no. Is it diff'd against current trunk? ~0014153 niffiwan (developer) 2012-11-22 22:20 Gah! It was created vs the current trunk on the day it was attached. I've had a problem like this before, I'll redo the patch again not using git at all this time... ~0014160 niffiwan (developer) 2012-11-23 04:13 OK - try mantis_2664_puresvn.patch :) ~0014165 Goober5000 (administrator) 2012-11-23 13:04 Looks good. :yes: Both the math and the logic. I say go ahead and commit it. ~0014169 niffiwan (developer) 2012-11-23 21:14 Thanks - committed in r9371
 Notes

 Date Modified Username Field Change Issue History 2012-06-09 23:53 niffiwan New Issue 2012-06-09 23:53 niffiwan File Added: test-range.fs2 2012-06-10 17:18 The_E Note Added: 0013652 2012-06-10 22:27 niffiwan Note Added: 0013653 2012-06-11 05:08 The_E Note Added: 0013660 2012-06-27 23:07 niffiwan Assigned To => niffiwan 2012-06-27 23:07 niffiwan Status new => assigned 2012-06-27 23:07 niffiwan File Added: mantis_2664.patch 2012-06-27 23:08 niffiwan Product Version 3.6.14 RC5 => 3.6.14 RC6 2012-06-27 23:10 niffiwan Note Added: 0013731 2012-06-27 23:10 niffiwan Status assigned => code review 2012-11-11 00:18 Goober5000 Note Added: 0014020 2012-11-16 00:56 Goober5000 Target Version 3.7.2 => 3.6.16 2012-11-19 04:11 niffiwan File Deleted: mantis_2664.patch 2012-11-19 04:11 niffiwan File Added: mantis_2664.patch 2012-11-19 04:22 niffiwan Note Added: 0014069 2012-11-22 22:10 Goober5000 Note Added: 0014152 2012-11-22 22:20 niffiwan Note Added: 0014153 2012-11-23 04:11 niffiwan File Added: mantis_2664_puresvn.patch 2012-11-23 04:13 niffiwan Note Added: 0014160 2012-11-23 13:04 Goober5000 Note Added: 0014165 2012-11-23 21:14 niffiwan Note Added: 0014169 2012-11-23 21:14 niffiwan Status code review => resolved 2012-11-23 21:14 niffiwan Fixed in Version => 3.6.15 2012-11-23 21:14 niffiwan Resolution open => fixed
 Issue History