feat(physics): implemented overlap queries
This commit is contained in:
parent
5043f1a53e
commit
a70658bab6
|
@ -9,9 +9,9 @@
|
|||
typedef struct Range {float min; Vector minpoint; float max; Vector maxpoint; } Range;
|
||||
|
||||
static
|
||||
Range _internal_collision_get_range_on_axis(PhysicsEntity self, Vector axis) {
|
||||
Transform* transform = self.transformable->get_transform(self.data);
|
||||
Shape* shape = self.tc->get_shape(self.data);
|
||||
Range _internal_collision_get_range_on_axis(PhysicsQuery self, Vector axis) {
|
||||
Transform* transform = self.transform;
|
||||
Shape* shape = self.shape;
|
||||
Vector point = shape_get_point_transformed(shape, 0, *transform);
|
||||
float dot = vdotf(axis, point);
|
||||
Range range = {dot, point, dot, point};
|
||||
|
@ -33,7 +33,7 @@ Range _internal_collision_get_range_on_axis(PhysicsEntity self, Vector axis) {
|
|||
}
|
||||
|
||||
static
|
||||
Vector _internal_collision_overlap_on_axis(PhysicsEntity self, PhysicsEntity other, Vector axis, Vector* out_point) {
|
||||
Vector _internal_collision_overlap_on_axis(PhysicsQuery self, PhysicsQuery other, Vector axis, Vector* out_point) {
|
||||
Range a_range = _internal_collision_get_range_on_axis(self, axis);
|
||||
Range b_range = _internal_collision_get_range_on_axis(other, axis);
|
||||
|
||||
|
@ -49,10 +49,20 @@ Vector _internal_collision_overlap_on_axis(PhysicsEntity self, PhysicsEntity oth
|
|||
}
|
||||
|
||||
static
|
||||
int _internal_collision_get_overlap(PhysicsEntity self, PhysicsEntity other, Collision* out) {
|
||||
int _internal_collision_get_collisions(PhysicsEntity self, PhysicsEntity other, Collision* out) {
|
||||
// get components used
|
||||
Shape* self_shape = self.tc->get_shape(self.data);
|
||||
Transform* self_transform = self.transformable->get_transform(self.data);
|
||||
PhysicsQuery self_query = {
|
||||
.shape = self_shape,
|
||||
.transform = self_transform,
|
||||
.mask = 0x0 // not used
|
||||
};
|
||||
PhysicsQuery other_query = {
|
||||
.shape = other.tc->get_shape(other.data),
|
||||
.transform = other.transformable->get_transform(other.data),
|
||||
.mask = 0x0 // not used
|
||||
};
|
||||
|
||||
// the shortest distance to solve collision found so far
|
||||
Vector shortest_escape = InfinityVector;
|
||||
|
@ -74,7 +84,7 @@ int _internal_collision_get_overlap(PhysicsEntity self, PhysicsEntity other, Col
|
|||
|
||||
Vector overlap_point;
|
||||
// the smallest escape vector on this axis
|
||||
Vector escape = _internal_collision_overlap_on_axis(self, other, normal, &overlap_point);
|
||||
Vector escape = _internal_collision_overlap_on_axis(self_query, other_query, normal, &overlap_point);
|
||||
float dot = vdotf(vinvf(normal), escape);
|
||||
if(dot <= 0.0) {
|
||||
return 0;
|
||||
|
@ -90,7 +100,7 @@ int _internal_collision_get_overlap(PhysicsEntity self, PhysicsEntity other, Col
|
|||
RigidBody* rbb = other.tc->get_rigidbody(other.data);
|
||||
const Vector velocity = vsubf(rigidbody_get_velocity(rba), rigidbody_get_velocity(rbb));
|
||||
const Vector normal = vnormalizedf(shortest_escape);
|
||||
Vector world_point = _internal_collision_get_range_on_axis(self, normal).minpoint;
|
||||
Vector world_point = _internal_collision_get_range_on_axis(self_query, normal).minpoint;
|
||||
|
||||
*out = (Collision) {
|
||||
.other = other,
|
||||
|
@ -109,8 +119,12 @@ int _internal_collision_get_overlap(PhysicsEntity self, PhysicsEntity other, Col
|
|||
}
|
||||
|
||||
Collision collision_invert(Collision collision_a, PhysicsEntity a) {
|
||||
Vector world_point = _internal_collision_get_range_on_axis(collision_a.other, collision_a.normal).maxpoint;
|
||||
RigidBody* body = collision_a.other.tc->get_rigidbody(collision_a.other.data);
|
||||
Shape* shape = collision_a.other.tc->get_shape(collision_a.other.data);
|
||||
Transform* transform = rigidbody_get_transform(body);
|
||||
|
||||
Vector world_point = _internal_collision_get_range_on_axis((PhysicsQuery){.shape = shape, .transform = transform }, collision_a.normal).maxpoint;
|
||||
|
||||
return (Collision){
|
||||
.other = a,
|
||||
.point = inverse_transform_point(rigidbody_get_transform(body), world_point),
|
||||
|
@ -124,8 +138,8 @@ Collision collision_invert(Collision collision_a, PhysicsEntity a) {
|
|||
|
||||
int collision_check(PhysicsEntity a, PhysicsEntity b, Collision* out_a, Collision* out_b) {
|
||||
Collision collision_a, collision_b;
|
||||
int collision_a_overlaps = _internal_collision_get_overlap(a, b, &collision_a);
|
||||
int collision_b_overlaps = _internal_collision_get_overlap(b, a, &collision_b);
|
||||
int collision_a_overlaps = _internal_collision_get_collisions(a, b, &collision_a);
|
||||
int collision_b_overlaps = _internal_collision_get_collisions(b, a, &collision_b);
|
||||
|
||||
if(!collision_a_overlaps || !collision_b_overlaps)
|
||||
return 0;
|
||||
|
@ -139,3 +153,38 @@ int collision_check(PhysicsEntity a, PhysicsEntity b, Collision* out_a, Collisio
|
|||
*out_b = collision_b;
|
||||
return (collision_b_overlaps << 1) | collision_a_overlaps;
|
||||
}
|
||||
|
||||
static
|
||||
int _internal_overlap_check(PhysicsQuery a, PhysicsQuery b) {
|
||||
Shape* shape = a.shape;
|
||||
Transform* transform = a.transform;
|
||||
const size_t shape_point_count = shape_get_points_count(shape);
|
||||
|
||||
for(size_t point_index = 0; point_index < shape_point_count; ++point_index) {
|
||||
// the next point on the line
|
||||
size_t next_index = (point_index + 1) % shape_point_count;
|
||||
// get the two points defining the collision edge
|
||||
Vector edge_lhs = shape_get_point_transformed(shape, point_index, *transform);
|
||||
Vector edge_rhs = shape_get_point_transformed(shape, next_index, *transform);
|
||||
// the direction of the line
|
||||
Vector normal = vnormalizedf(vperpendicularf(vsubf(edge_rhs, edge_lhs)));
|
||||
|
||||
Vector overlap_point;
|
||||
// the smallest escape vector on this axis
|
||||
Vector escape = _internal_collision_overlap_on_axis(a, b, normal, &overlap_point);
|
||||
float dot = vdotf(vinvf(normal), escape);
|
||||
if(dot <= 0.0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int overlap_check(PhysicsQuery query, PhysicsEntity entity) {
|
||||
PhysicsQuery entity_q = {
|
||||
.shape = entity.tc->get_shape(entity.data),
|
||||
.transform = entity.transformable->get_transform(entity.data),
|
||||
.mask = rigidbody_get_layers(entity.tc->get_rigidbody(entity.data)),
|
||||
};
|
||||
return (query.mask & entity_q.mask) != 0 && _internal_overlap_check(query, entity_q) || _internal_overlap_check(entity_q, query);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "physics_entity.h"
|
||||
#include <stddef.h>
|
||||
|
||||
typedef uint32_t PhysicsMask;
|
||||
|
||||
typedef struct Collision {
|
||||
PhysicsEntity other;
|
||||
|
||||
|
@ -18,7 +20,14 @@ typedef struct Collision {
|
|||
Vector edge_right;
|
||||
} Collision;
|
||||
|
||||
typedef struct PhysicsQuery {
|
||||
Shape* shape;
|
||||
Transform* transform;
|
||||
PhysicsMask mask;
|
||||
} PhysicsQuery;
|
||||
|
||||
extern Collision collision_invert(Collision src, PhysicsEntity new_other);
|
||||
extern int collision_check(PhysicsEntity a, PhysicsEntity b, Collision* out_a, Collision* out_b);
|
||||
extern int overlap_check(PhysicsQuery query, PhysicsEntity entity);
|
||||
|
||||
#endif // !_fencer_collision_h
|
||||
|
|
Loading…
Reference in a new issue