mirror of
https://github.com/scratchfoundation/bgfx.git
synced 2024-11-28 10:35:43 -05:00
Added ray intersection tests.
This commit is contained in:
parent
e5b9a6a6b5
commit
4a1861f367
2 changed files with 393 additions and 22 deletions
|
@ -21,16 +21,9 @@ void aabbToObb(Obb& _obb, const Aabb& _aabb)
|
|||
|
||||
void sphereToAabb(Aabb& _aabb, const Sphere& _sphere)
|
||||
{
|
||||
float xx = _sphere.m_center[0];
|
||||
float yy = _sphere.m_center[1];
|
||||
float zz = _sphere.m_center[2];
|
||||
float radius = _sphere.m_radius;
|
||||
_aabb.m_min[0] = xx - radius;
|
||||
_aabb.m_min[1] = yy - radius;
|
||||
_aabb.m_min[2] = zz - radius;
|
||||
_aabb.m_max[0] = xx + radius;
|
||||
_aabb.m_max[1] = yy + radius;
|
||||
_aabb.m_max[2] = zz + radius;
|
||||
bx::vec3Sub(_aabb.m_min, _sphere.m_center, radius);
|
||||
bx::vec3Add(_aabb.m_max, _sphere.m_center, radius);
|
||||
}
|
||||
|
||||
void aabbTransformToObb(Obb& _obb, const Aabb& _aabb, const float* _mtx)
|
||||
|
@ -129,7 +122,7 @@ void aabbExpand(Aabb& _aabb, float _factor)
|
|||
_aabb.m_max[2] += _factor;
|
||||
}
|
||||
|
||||
uint32_t aabbOverlapTest(Aabb& _aabb0, Aabb& _aabb1)
|
||||
uint32_t aabbOverlapTest(const Aabb& _aabb0, const Aabb& _aabb1)
|
||||
{
|
||||
const uint32_t ltMinX = _aabb0.m_max[0] < _aabb1.m_min[0];
|
||||
const uint32_t gtMaxX = _aabb0.m_min[0] > _aabb1.m_max[0];
|
||||
|
@ -222,9 +215,7 @@ void calcMaxBoundingSphere(Sphere& _sphere, const void* _vertices, uint32_t _num
|
|||
maxDistSq = bx::fmax(distSq, maxDistSq);
|
||||
}
|
||||
|
||||
_sphere.m_center[0] = center[0];
|
||||
_sphere.m_center[1] = center[1];
|
||||
_sphere.m_center[2] = center[2];
|
||||
bx::vec3Move(_sphere.m_center, center);
|
||||
_sphere.m_radius = sqrtf(maxDistSq);
|
||||
}
|
||||
|
||||
|
@ -236,9 +227,7 @@ void calcMinBoundingSphere(Sphere& _sphere, const void* _vertices, uint32_t _num
|
|||
|
||||
float center[3];
|
||||
float* position = (float*)&vertex[0];
|
||||
center[0] = position[0];
|
||||
center[1] = position[1];
|
||||
center[2] = position[2];
|
||||
bx::vec3Move(center, position);
|
||||
|
||||
position = (float*)&vertex[1*_stride];
|
||||
center[0] += position[0];
|
||||
|
@ -284,8 +273,329 @@ void calcMinBoundingSphere(Sphere& _sphere, const void* _vertices, uint32_t _num
|
|||
|
||||
} while (!done);
|
||||
|
||||
_sphere.m_center[0] = center[0];
|
||||
_sphere.m_center[1] = center[1];
|
||||
_sphere.m_center[2] = center[2];
|
||||
_sphere.m_radius = sqrtf(maxDistSq);
|
||||
bx::vec3Move(_sphere.m_center, center);
|
||||
_sphere.m_radius = bx::fsqrt(maxDistSq);
|
||||
}
|
||||
|
||||
Ray makeRay(float _x, float _y, const float* _invVp)
|
||||
{
|
||||
Ray ray;
|
||||
|
||||
const float near[3] = { _x, _y, 0.0f };
|
||||
bx::vec3MulMtxH(ray.m_pos, near, _invVp);
|
||||
|
||||
float tmp[3];
|
||||
const float far[3] = { _x, _y, 1.0f };
|
||||
bx::vec3MulMtxH(tmp, far, _invVp);
|
||||
|
||||
float dir[3];
|
||||
bx::vec3Sub(dir, tmp, ray.m_pos);
|
||||
bx::vec3Norm(ray.m_dir, dir);
|
||||
|
||||
return ray;
|
||||
}
|
||||
|
||||
inline void getPointAt(float* _result, const Ray& _ray, float _t)
|
||||
{
|
||||
float tmp[3];
|
||||
bx::vec3Mul(tmp, _ray.m_dir, _t);
|
||||
bx::vec3Add(_result, _ray.m_pos, tmp);
|
||||
}
|
||||
|
||||
bool intersect(const Ray& _ray, const Aabb& _aabb, Intersection* _intersection)
|
||||
{
|
||||
float invDir[3];
|
||||
bx::vec3Rcp(invDir, _ray.m_dir);
|
||||
|
||||
float tmp[3];
|
||||
|
||||
float t0[3];
|
||||
bx::vec3Sub(tmp, _aabb.m_min, _ray.m_pos);
|
||||
bx::vec3Mul(t0, tmp, invDir);
|
||||
|
||||
float t1[3];
|
||||
bx::vec3Sub(tmp, _aabb.m_max, _ray.m_pos);
|
||||
bx::vec3Mul(t1, tmp, invDir);
|
||||
|
||||
float min[3];
|
||||
bx::vec3Min(min, t0, t1);
|
||||
|
||||
float max[3];
|
||||
bx::vec3Max(max, t0, t1);
|
||||
|
||||
const float tmin = bx::fmax3(min[0], min[1], min[2]);
|
||||
const float tmax = bx::fmin3(max[0], max[1], max[2]);
|
||||
|
||||
if (tmax < 0.0f
|
||||
|| tmin > tmax)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NULL != _intersection)
|
||||
{
|
||||
_intersection->m_normal[0] = (min[0] == tmin) - (max[0] == tmin);
|
||||
_intersection->m_normal[1] = (min[1] == tmin) - (max[1] == tmin);
|
||||
_intersection->m_normal[2] = (min[2] == tmin) - (max[2] == tmin);
|
||||
|
||||
_intersection->m_dist = tmin;
|
||||
getPointAt(_intersection->m_pos, _ray, tmin);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool intersect(const Ray& _ray, const Disk& _disk, Intersection* _intersection)
|
||||
{
|
||||
Plane plane;
|
||||
bx::vec3Move(plane.m_normal, _disk.m_normal);
|
||||
plane.m_dist = -bx::vec3Dot(_disk.m_center, _disk.m_normal);
|
||||
|
||||
Intersection tmpIntersection;
|
||||
_intersection = NULL != _intersection ? _intersection : &tmpIntersection;
|
||||
|
||||
if (intersect(_ray, plane, _intersection) )
|
||||
{
|
||||
float tmp[3];
|
||||
bx::vec3Sub(tmp, _disk.m_center, _intersection->m_pos);
|
||||
return bx::vec3Dot(tmp, tmp) <= bx::fsq(_disk.m_radius);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool intersect(const Ray& _ray, const Cylinder& _cylinder, bool _capsule, Intersection* _intersection)
|
||||
{
|
||||
float axis[3];
|
||||
bx::vec3Sub(axis, _cylinder.m_end, _cylinder.m_pos);
|
||||
|
||||
float rc[3];
|
||||
bx::vec3Sub(rc, _ray.m_pos, _cylinder.m_pos);
|
||||
|
||||
float normal[3];
|
||||
bx::vec3Cross(normal, _ray.m_dir, axis);
|
||||
|
||||
const float len = bx::vec3Norm(normal, normal);
|
||||
const float dist = bx::fabsolute(bx::vec3Dot(rc, normal) );
|
||||
|
||||
if (dist > _cylinder.m_radius)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float vo[3];
|
||||
bx::vec3Cross(vo, rc, axis);
|
||||
const float t0 = -bx::vec3Dot(vo, normal) / len;
|
||||
|
||||
bx::vec3Cross(vo, normal, axis);
|
||||
bx::vec3Norm(vo, vo);
|
||||
|
||||
const float rsq = bx::fsq(_cylinder.m_radius);
|
||||
const float ddoto = bx::vec3Dot(_ray.m_dir, vo);
|
||||
const float ss = t0 - bx::fabsolute(bx::fsqrt(rsq - bx::fsq(dist) ) / ddoto);
|
||||
|
||||
float point[3];
|
||||
getPointAt(point, _ray, ss);
|
||||
|
||||
const float axisLen = bx::vec3Norm(axis, axis);
|
||||
const float pdota = bx::vec3Dot(_cylinder.m_pos, axis);
|
||||
const float height = bx::vec3Dot(point, axis) - pdota;
|
||||
|
||||
if (height > 0.0f
|
||||
&& height < axisLen)
|
||||
{
|
||||
if (NULL != _intersection)
|
||||
{
|
||||
const float t1 = height / axisLen;
|
||||
float pointOnAxis[3];
|
||||
bx::vec3Lerp(pointOnAxis, _cylinder.m_pos, _cylinder.m_end, t1);
|
||||
|
||||
bx::vec3Move(_intersection->m_pos, point);
|
||||
|
||||
float tmp[3];
|
||||
bx::vec3Sub(tmp, point, pointOnAxis);
|
||||
bx::vec3Norm(_intersection->m_normal, tmp);
|
||||
|
||||
_intersection->m_dist = ss;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_capsule)
|
||||
{
|
||||
const float rdota = bx::vec3Dot(_ray.m_pos, axis);
|
||||
const float pp = rdota - pdota;
|
||||
const float t1 = pp / axisLen;
|
||||
|
||||
float pointOnAxis[3];
|
||||
bx::vec3Lerp(pointOnAxis, _cylinder.m_pos, _cylinder.m_end, t1);
|
||||
|
||||
float axisToRay[3];
|
||||
bx::vec3Sub(axisToRay, _ray.m_pos, pointOnAxis);
|
||||
|
||||
if (_cylinder.m_radius < bx::vec3Length(axisToRay)
|
||||
&& 0.0f > ss)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Sphere sphere;
|
||||
sphere.m_radius = _cylinder.m_radius;
|
||||
|
||||
bx::vec3Move(sphere.m_center, 0.0f >= height
|
||||
? _cylinder.m_pos
|
||||
: _cylinder.m_end
|
||||
);
|
||||
|
||||
return intersect(_ray, sphere, _intersection);
|
||||
}
|
||||
|
||||
Plane plane;
|
||||
float pos[3];
|
||||
|
||||
if (0.0f >= height)
|
||||
{
|
||||
bx::vec3Neg(plane.m_normal, axis);
|
||||
bx::vec3Move(pos, _cylinder.m_pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
bx::vec3Move(plane.m_normal, axis);
|
||||
bx::vec3Move(pos, _cylinder.m_end);
|
||||
}
|
||||
|
||||
plane.m_dist = -bx::vec3Dot(pos, plane.m_normal);
|
||||
|
||||
Intersection tmpIntersection;
|
||||
_intersection = NULL != _intersection ? _intersection : &tmpIntersection;
|
||||
|
||||
if (intersect(_ray, plane, _intersection) )
|
||||
{
|
||||
float tmp[3];
|
||||
bx::vec3Sub(tmp, pos, _intersection->m_pos);
|
||||
return bx::vec3Dot(tmp, tmp) <= rsq;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool intersect(const Ray& _ray, const Plane& _plane, Intersection* _intersection)
|
||||
{
|
||||
float equation = bx::vec3Dot(_ray.m_pos, _plane.m_normal) + _plane.m_dist;
|
||||
if (0.0f > equation)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float ndotd = bx::vec3Dot(_ray.m_dir, _plane.m_normal);
|
||||
if (0.0f < ndotd)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NULL != _intersection)
|
||||
{
|
||||
bx::vec3Move(_intersection->m_normal, _plane.m_normal);
|
||||
|
||||
float tt = -equation/ndotd;
|
||||
_intersection->m_dist = tt;
|
||||
|
||||
getPointAt(_intersection->m_pos, _ray, tt);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool intersect(const Ray& _ray, const Sphere& _sphere, Intersection* _intersection)
|
||||
{
|
||||
float rs[3];
|
||||
bx::vec3Sub(rs, _ray.m_pos, _sphere.m_center);
|
||||
|
||||
const float bb = bx::vec3Dot(rs, _ray.m_dir);
|
||||
if (0.0f < bb)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const float aa = bx::vec3Dot(_ray.m_dir, _ray.m_dir);
|
||||
const float cc = bx::vec3Dot(rs, rs) - bx::fsq(_sphere.m_radius);
|
||||
|
||||
const float discriminant = bb*bb - aa*cc;
|
||||
|
||||
if (0.0f >= discriminant)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const float sqrtDiscriminant = bx::fsqrt(discriminant);
|
||||
const float invA = 1.0f / aa;
|
||||
const float tt = -(bb + sqrtDiscriminant)*invA;
|
||||
|
||||
if (0.0f >= tt)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NULL != _intersection)
|
||||
{
|
||||
_intersection->m_dist = tt;
|
||||
|
||||
float point[3];
|
||||
getPointAt(point, _ray, tt);
|
||||
bx::vec3Move(_intersection->m_pos, point);
|
||||
|
||||
float tmp[3];
|
||||
bx::vec3Sub(tmp, point, _sphere.m_center);
|
||||
bx::vec3Norm(_intersection->m_normal, tmp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool intersect(const Ray& _ray, const Tris& _triangle, Intersection* _intersection)
|
||||
{
|
||||
float edge10[3];
|
||||
bx::vec3Sub(edge10, _triangle.m_v1, _triangle.m_v0);
|
||||
|
||||
float edge02[3];
|
||||
bx::vec3Sub(edge02, _triangle.m_v0, _triangle.m_v2);
|
||||
|
||||
float normal[3];
|
||||
bx::vec3Cross(normal, edge02, edge10);
|
||||
|
||||
float vo[3];
|
||||
bx::vec3Sub(vo, _triangle.m_v0, _ray.m_pos);
|
||||
|
||||
float dxo[3];
|
||||
bx::vec3Cross(dxo, _ray.m_dir, vo);
|
||||
|
||||
const float det = bx::vec3Dot(normal, _ray.m_dir);
|
||||
|
||||
if (det > 0.0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const float invDet = 1.0f/det;
|
||||
const float bz = bx::vec3Dot(dxo, edge02) * invDet;
|
||||
const float by = bx::vec3Dot(dxo, edge10) * invDet;
|
||||
const float bx = 1.0f - by - bz;
|
||||
|
||||
if (bx < 0.0f || by < 0.0f || bz < 0.0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NULL != _intersection)
|
||||
{
|
||||
bx::vec3Norm(_intersection->m_normal, normal);
|
||||
|
||||
const float tt = bx::vec3Dot(normal, vo) * invDet;
|
||||
_intersection->m_dist = tt;
|
||||
|
||||
getPointAt(_intersection->m_pos, _ray, tt);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -12,17 +12,57 @@ struct Aabb
|
|||
float m_max[3];
|
||||
};
|
||||
|
||||
struct Cylinder
|
||||
{
|
||||
float m_pos[3];
|
||||
float m_end[3];
|
||||
float m_radius;
|
||||
};
|
||||
|
||||
struct Disk
|
||||
{
|
||||
float m_center[3];
|
||||
float m_normal[3];
|
||||
float m_radius;
|
||||
};
|
||||
|
||||
struct Obb
|
||||
{
|
||||
float m_mtx[16];
|
||||
};
|
||||
|
||||
struct Plane
|
||||
{
|
||||
float m_normal[3];
|
||||
float m_dist;
|
||||
};
|
||||
|
||||
struct Ray
|
||||
{
|
||||
float m_pos[3];
|
||||
float m_dir[3];
|
||||
};
|
||||
|
||||
struct Sphere
|
||||
{
|
||||
float m_center[3];
|
||||
float m_radius;
|
||||
};
|
||||
|
||||
struct Tris
|
||||
{
|
||||
float m_v0[3];
|
||||
float m_v1[3];
|
||||
float m_v2[3];
|
||||
};
|
||||
|
||||
struct Intersection
|
||||
{
|
||||
float m_pos[3];
|
||||
float m_normal[3];
|
||||
float m_dist;
|
||||
};
|
||||
|
||||
/// Convert axis aligned bounding box to oriented bounding box.
|
||||
void aabbToObb(Obb& _obb, const Aabb& _aabb);
|
||||
|
||||
|
@ -43,7 +83,7 @@ void aabbExpand(Aabb& _aabb, float _factor);
|
|||
|
||||
/// Returns 0 is two AABB don't overlap, otherwise returns flags of overlap
|
||||
/// test.
|
||||
uint32_t aabbOverlapTest(Aabb& _aabb0, Aabb& _aabb1);
|
||||
uint32_t aabbOverlapTest(const Aabb& _aabb0, const Aabb& _aabb1);
|
||||
|
||||
/// Calculate oriented bounding box.
|
||||
void calcObb(Obb& _obb, const void* _vertices, uint32_t _numVertices, uint32_t _stride, uint32_t _steps = 17);
|
||||
|
@ -54,4 +94,25 @@ void calcMaxBoundingSphere(Sphere& _sphere, const void* _vertices, uint32_t _num
|
|||
/// Calculate minimum bounding sphere.
|
||||
void calcMinBoundingSphere(Sphere& _sphere, const void* _vertices, uint32_t _numVertices, uint32_t _stride, float _step = 0.01f);
|
||||
|
||||
/// Make screen space ray from x, y coordinate and inverse view-projection matrix.
|
||||
Ray makeRay(float _x, float _y, const float* _invVp);
|
||||
|
||||
/// Intersect ray / aabb.
|
||||
bool intersect(const Ray& _ray, const Aabb& _aabb, Intersection* _intersection = NULL);
|
||||
|
||||
/// Intersect ray / cylinder.
|
||||
bool intersect(const Ray& _ray, const Cylinder& _cylinder, bool _capsule, Intersection* _intersection = NULL);
|
||||
|
||||
/// Intersect ray / disk.
|
||||
bool intersect(const Ray& _ray, const Disk& _disk, Intersection* _intersection = NULL);
|
||||
|
||||
/// Intersect ray / plane.
|
||||
bool intersect(const Ray& _ray, const Plane& _plane, Intersection* _intersection = NULL);
|
||||
|
||||
/// Intersect ray / sphere.
|
||||
bool intersect(const Ray& _ray, const Sphere& _sphere, Intersection* _intersection = NULL);
|
||||
|
||||
/// Intersect ray / triangle.
|
||||
bool intersect(const Ray& _ray, const Tris& _triangle, Intersection* _intersection = NULL);
|
||||
|
||||
#endif // BOUNDS_H_HEADER_GUARD
|
||||
|
|
Loading…
Reference in a new issue