diff --git a/examples/29-debugdraw/debugdraw.cpp b/examples/29-debugdraw/debugdraw.cpp index 86f4c4186..09da5499d 100644 --- a/examples/29-debugdraw/debugdraw.cpp +++ b/examples/29-debugdraw/debugdraw.cpp @@ -602,6 +602,27 @@ public: showExampleDialog(this); + ImGui::SetNextWindowPos( + ImVec2(m_width - m_width / 5.0f - 10.0f, 10.0f) + , ImGuiCond_FirstUseEver + ); + ImGui::SetNextWindowSize( + ImVec2(m_width / 5.0f, m_height / 3.0f) + , ImGuiCond_FirstUseEver + ); + ImGui::Begin("Settings" + , NULL + , 0 + ); + + static float amplitudeMul = 0.0f; + ImGui::SliderFloat("Amplitude", &litudeMul, 0.0f, 1.0f); + + static float timeScale = 1.0f; + ImGui::SliderFloat("T scale", &timeScale, -1.0f, 1.0f); + + ImGui::End(); + imguiEndFrame(); int64_t now = bx::getHPCounter() - m_timeOffset; @@ -664,7 +685,8 @@ public: dde.draw(aabb); dde.pop(); - float time = float(now/freq); + static float time = 0.0f; + time += deltaTime*timeScale; Obb obb; bx::mtxRotateX(obb.mtx, time); @@ -848,12 +870,12 @@ public: constexpr float kStepX = 3.0f; constexpr float kStepZ = 3.0f; - const float px = 0.0f; - const float py = 1.0f; - const float pz = 10.0f; - const float xx = bx::sin(time*0.39f) * 1.03f + px; - const float yy = bx::cos(time*0.79f) * 1.03f + py; - const float zz = bx::cos(time) * 1.03f + pz; + const float px = -5.0f*kStepX; + const float py = 1.0f; + const float pz = 20.0f; + const float xx = amplitudeMul*bx::sin(time*0.39f) * 1.03f + px; + const float yy = amplitudeMul*bx::cos(time*0.79f) * 1.03f + py; + const float zz = amplitudeMul*bx::cos(time) * 1.03f + pz; // Sphere --- { @@ -959,6 +981,96 @@ public: dde.draw(diskB); } + { + Sphere sphereA = { { px+kStepX*5.0f, py, pz+kStepZ*0.0f }, 0.5f }; + + Obb obbB; + bx::mtxSRT(obbB.mtx + , 1.0f + , 0.25f + , 0.25f + , bx::toRad(10.0f) + , bx::toRad(30.0f) + , bx::toRad(70.0f) + , xx+kStepX*5.0f + , yy + , zz+kStepZ*0.0f + ); + + olp = overlap(sphereA, obbB); + + dde.setColor(olp ? kOverlap : 0xffffffff); + dde.setWireframe(false); + dde.draw(sphereA); + + dde.setColor(olp ? kOverlap : 0xffffffff); + dde.setWireframe(true); + dde.draw(obbB); + } + + { + Sphere sphereA = { { px+kStepX*6.0f, py, pz+kStepZ*0.0f }, 0.5f }; + + Capsule capsuleB = + { + { xx+kStepX*5.9f, yy-1.0f, zz+kStepZ*0.0f+0.1f }, + { xx+kStepX*6.0f, yy+1.0f, zz+kStepZ*0.0f }, + 0.2f, + }; + + olp = overlap(sphereA, capsuleB); + + dde.setColor(olp ? kOverlap : 0xffffffff); + dde.setWireframe(false); + dde.draw(sphereA); + + dde.setColor(olp ? kOverlap : 0xffffffff); + dde.setWireframe(true); + dde.draw(capsuleB); + } + + { + Sphere sphereA = { { px+kStepX*7.0f, py, pz+kStepZ*0.0f }, 0.5f }; + + Cylinder cylinderB = + { + { xx+kStepX*6.9f, yy-1.0f, zz+kStepZ*0.0f+0.1f }, + { xx+kStepX*7.0f, yy+1.0f, zz+kStepZ*0.0f }, + 0.2f, + }; + + olp = overlap(sphereA, cylinderB); + + dde.setColor(olp ? kOverlap : 0xffffffff); + dde.setWireframe(false); + dde.draw(sphereA); + + dde.setColor(olp ? kOverlap : 0xffffffff); + dde.setWireframe(true); + dde.draw(cylinderB); + } + + { + Sphere sphereA = { { px+kStepX*8.0f, py, pz+kStepZ*0.0f }, 0.5f }; + + Cone coneB = + { + { xx+kStepX*7.9f, yy-1.0f, zz+kStepZ*0.0f+0.1f }, + { xx+kStepX*8.0f, yy+1.0f, zz+kStepZ*0.0f }, + 0.25f, + }; + + olp = overlap(sphereA, coneB); + + dde.setColor(olp ? kOverlap : 0xffffffff); + dde.setWireframe(false); + dde.draw(sphereA); + + dde.setColor(olp ? kOverlap : 0xffffffff); + dde.setWireframe(true); + dde.draw(coneB); + } + // AABB --- { Aabb aabbA, aabbB; diff --git a/examples/common/bounds.cpp b/examples/common/bounds.cpp index 4c9a874c6..6eb1efe5e 100644 --- a/examples/common/bounds.cpp +++ b/examples/common/bounds.cpp @@ -3,6 +3,7 @@ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause */ +#include #include #include #include "bounds.h" @@ -24,58 +25,16 @@ Vec3 getCenter(const Triangle& _triangle) return mul(add(add(_triangle.v0, _triangle.v1), _triangle.v2), 1.0f/3.0f); } -void toAabb(Aabb& _outAabb, const Vec3& _center, const Vec3& _extent) +void toAabb(Aabb& _outAabb, const bx::Vec3& _extents) { - _outAabb.min = sub(_center, _extent); - _outAabb.max = add(_center, _extent); + _outAabb.min = neg(_extents); + _outAabb.max = _extents; } -void toAabb(Aabb& _outAabb, const Obb& _obb) +void toAabb(Aabb& _outAabb, const Vec3& _center, const Vec3& _extents) { - Vec3 xyz = { 1.0f, 1.0f, 1.0f }; - Vec3 tmp = mul(xyz, _obb.mtx); - - _outAabb.min = tmp; - _outAabb.max = tmp; - - for (uint32_t ii = 1; ii < 8; ++ii) - { - xyz.x = ii & 1 ? -1.0f : 1.0f; - xyz.y = ii & 2 ? -1.0f : 1.0f; - xyz.z = ii & 4 ? -1.0f : 1.0f; - tmp = mul(xyz, _obb.mtx); - - _outAabb.min = min(_outAabb.min, tmp); - _outAabb.max = max(_outAabb.max, tmp); - } -} - -void toAabb(Aabb& _outAabb, const Sphere& _sphere) -{ - const float radius = _sphere.radius; - _outAabb.min = sub(_sphere.center, radius); - _outAabb.max = add(_sphere.center, radius); -} - -void toAabb(Aabb& _outAabb, const Disk& _disk) -{ - // Reference(s): - // - https://web.archive.org/web/20181113055756/http://iquilezles.org/www/articles/diskbbox/diskbbox.htm - // - const Vec3 nsq = mul(_disk.normal, _disk.normal); - const Vec3 one = { 1.0f, 1.0f, 1.0f }; - const Vec3 tmp = sub(one, nsq); - const float inv = 1.0f / (tmp.x*tmp.y*tmp.z); - - const Vec3 extent = - { - _disk.radius * tmp.x * sqrt( (nsq.x + nsq.y * nsq.z) * inv), - _disk.radius * tmp.y * sqrt( (nsq.y + nsq.z * nsq.x) * inv), - _disk.radius * tmp.z * sqrt( (nsq.z + nsq.x * nsq.y) * inv), - }; - - _outAabb.min = sub(_disk.center, extent); - _outAabb.max = add(_disk.center, extent); + _outAabb.min = sub(_center, _extents); + _outAabb.max = add(_center, _extents); } void toAabb(Aabb& _outAabb, const Cylinder& _cylinder) @@ -107,6 +66,60 @@ void toAabb(Aabb& _outAabb, const Cylinder& _cylinder) _outAabb.max = max(maxP, maxE); } +void toAabb(Aabb& _outAabb, const Disk& _disk) +{ + // Reference(s): + // - https://web.archive.org/web/20181113055756/http://iquilezles.org/www/articles/diskbbox/diskbbox.htm + // + const Vec3 nsq = mul(_disk.normal, _disk.normal); + const Vec3 one = { 1.0f, 1.0f, 1.0f }; + const Vec3 tmp = sub(one, nsq); + const float inv = 1.0f / (tmp.x*tmp.y*tmp.z); + + const Vec3 extent = + { + _disk.radius * tmp.x * sqrt( (nsq.x + nsq.y * nsq.z) * inv), + _disk.radius * tmp.y * sqrt( (nsq.y + nsq.z * nsq.x) * inv), + _disk.radius * tmp.z * sqrt( (nsq.z + nsq.x * nsq.y) * inv), + }; + + _outAabb.min = sub(_disk.center, extent); + _outAabb.max = add(_disk.center, extent); +} + +void toAabb(Aabb& _outAabb, const Obb& _obb) +{ + Vec3 xyz = { 1.0f, 1.0f, 1.0f }; + Vec3 tmp = mul(xyz, _obb.mtx); + + _outAabb.min = tmp; + _outAabb.max = tmp; + + for (uint32_t ii = 1; ii < 8; ++ii) + { + xyz.x = ii & 1 ? -1.0f : 1.0f; + xyz.y = ii & 2 ? -1.0f : 1.0f; + xyz.z = ii & 4 ? -1.0f : 1.0f; + tmp = mul(xyz, _obb.mtx); + + _outAabb.min = min(_outAabb.min, tmp); + _outAabb.max = max(_outAabb.max, tmp); + } +} + +void toAabb(Aabb& _outAabb, const Sphere& _sphere) +{ + const float radius = _sphere.radius; + _outAabb.min = sub(_sphere.center, radius); + _outAabb.max = add(_sphere.center, radius); +} + +void toAabb(Aabb& _outAabb, const Triangle& _triangle) +{ + _outAabb.min = min(_triangle.v0, _triangle.v1, _triangle.v2); + _outAabb.max = max(_triangle.v0, _triangle.v1, _triangle.v2); +} + void aabbTransformToObb(Obb& _obb, const Aabb& _aabb, const float* _mtx) { toObb(_obb, _aabb); @@ -387,10 +400,9 @@ void buildFrustumPlanes(Plane* _result, const float* _viewProj) Plane* plane = _result; for (uint32_t ii = 0; ii < 6; ++ii) { - const float len = length(plane->normal); + const float invLen = 1.0f/length(plane->normal); plane->normal = normalize(plane->normal); - float invLen = 1.0f / len; - plane->dist *= invLen; + plane->dist *= invLen; ++plane; } } @@ -867,23 +879,190 @@ void calcPlane(Plane& _outPlane, const Triangle& _triangle) calcPlane(_outPlane, _triangle.v0, _triangle.v1, _triangle.v2); } -Vec3 closestPoint(const Plane& _plane, const Vec3& _pos) +struct Range1 { - const float dist = distance(_plane, _pos); - return sub(_pos, mul(_plane.normal, dist) ); + float start; + float end; +}; + +bool overlap(const Range1& _a, const Range1& _b) +{ + return _a.end > _b.start + && _b.end > _a.start + ; } -Vec3 closestPoint(const Aabb& _aabb, const Vec3& _pos) +float projectToAxis(const Vec3& _axis, const Vec3& _point) { - return clamp(_pos, _aabb.min, _aabb.max); + return dot(_axis, _point); } -Vec3 closestPoint(const Triangle& _triangle, const Vec3& _pos) +Range1 projectToAxis(const Vec3& _axis, const Aabb& _aabb) +{ + const float extent = bx::abs(dot(abs(_axis), getExtents(_aabb) ) ); + const float center = dot( _axis , getCenter (_aabb) ); + return + { + center - extent, + center + extent, + }; +} + +Range1 projectToAxis(const Vec3& _axis, const Triangle& _triangle) +{ + const float a0 = dot(_axis, _triangle.v0); + const float a1 = dot(_axis, _triangle.v1); + const float a2 = dot(_axis, _triangle.v2); + return + { + min(a0, a1, a2), + max(a0, a1, a2), + }; +} + +struct Srt +{ + Quaternion rotation; + Vec3 translation; + Vec3 scale; +}; + +Srt toSrt(const void* _mtx) +{ + Srt result; + + const float* mtx = (const float*)_mtx; + + result.translation = { mtx[12], mtx[13], mtx[14] }; + + float xx = mtx[ 0]; + float xy = mtx[ 1]; + float xz = mtx[ 2]; + float yx = mtx[ 4]; + float yy = mtx[ 5]; + float yz = mtx[ 6]; + float zx = mtx[ 8]; + float zy = mtx[ 9]; + float zz = mtx[10]; + + result.scale = + { + sqrt(xx*xx + xy*xy + xz*xz), + sqrt(yx*yx + yy*yy + yz*yz), + sqrt(zx*zx + zy*zy + zz*zz), + }; + + const Vec3 invScale = rcp(result.scale); + + xx *= invScale.x; + xy *= invScale.x; + xz *= invScale.x; + yx *= invScale.y; + yy *= invScale.y; + yz *= invScale.y; + zx *= invScale.z; + zy *= invScale.z; + zz *= invScale.z; + + const float trace = xx + yy + zz; + + if (0.0f < trace) + { + const float invS = 0.5f * rsqrt(trace + 1.0f); + result.rotation = + { + (yz - zy) * invS, + (zx - xz) * invS, + (xy - yx) * invS, + 0.25f / invS, + }; + } + else + { + if (xx > yy + && xx > zz) + { + const float invS = 0.5f * sqrt(max(1.0f + xx - yy - zz, 1e-8f) ); + result.rotation = + { + 0.25f / invS, + (xy + yx) * invS, + (xz + zx) * invS, + (yz - zy) * invS, + }; + } + else if (yy > zz) + { + const float invS = 0.5f * sqrt(max(1.0f + yy - xx - zz, 1e-8f) ); + result.rotation = + { + (xy + yx) * invS, + 0.25f / invS, + (yz + zy) * invS, + (zx - xz) * invS, + }; + } + else + { + const float invS = 0.5f * sqrt(max(1.0f + zz - xx - yy, 1e-8f) ); + result.rotation = + { + (xz + zx) * invS, + (yz + zy) * invS, + 0.25f / invS, + (xy - yx) * invS, + }; + } + } + + return result; +} + +struct LineSegment +{ + Vec3 pos; + Vec3 end; +}; + +Vec3 closestPoint(const LineSegment& _line, const Vec3& _point) +{ + const Vec3 axis = sub(_line.end, _line.pos); + const float lengthSq = dot(axis, axis); + const float tt = clamp(projectToAxis(axis, sub(_point, _line.pos) ) / lengthSq, 0.0f, 1.0f); + return mad(axis, { tt, tt, tt }, _line.pos); +} + +Vec3 closestPoint(const Plane& _plane, const Vec3& _point) +{ + const float dist = distance(_plane, _point); + return sub(_point, mul(_plane.normal, dist) ); +} + +Vec3 closestPoint(const Aabb& _aabb, const Vec3& _point) +{ + return clamp(_point, _aabb.min, _aabb.max); +} + +Vec3 closestPoint(const Obb& _obb, const Vec3& _point) +{ + Srt srt = toSrt(_obb.mtx); + + const Vec3 obbSpacePos = mul(sub(_point, srt.translation), invert(srt.rotation) ); + + Aabb aabb; + toAabb(aabb, srt.scale); + + const Vec3 pos = closestPoint(aabb, obbSpacePos); + + return add(mul(pos, srt.rotation), srt.translation); +} + +Vec3 closestPoint(const Triangle& _triangle, const Vec3& _point) { Plane plane; calcPlane(plane, _triangle); - const Vec3 pos = closestPoint(plane, _pos); + const Vec3 pos = closestPoint(plane, _point); const Vec3 uvw = barycentric(_triangle, pos); return cartesian(_triangle, clamp(uvw, {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}) ); @@ -942,8 +1121,8 @@ bool overlap(const Sphere& _sphere, const Cylinder& _cylinder) bool overlap(const Sphere& _sphere, const Capsule& _capsule) { - BX_UNUSED(_sphere, _capsule); - return false; + const Vec3 pos = closestPoint(LineSegment{_capsule.pos, _capsule.end}, _sphere.center); + return overlap(_sphere, Sphere{pos, _capsule.radius}); } bool overlap(const Sphere& _sphere, const Cone& _cone) @@ -967,8 +1146,8 @@ bool overlap(const Sphere& _sphere, const Disk& _disk) bool overlap(const Sphere& _sphere, const Obb& _obb) { - BX_UNUSED(_sphere, _obb); - return false; + const Vec3 pos = closestPoint(_obb, _sphere.center); + return overlap(_sphere, pos); } bool overlap(const Aabb& _aabb, const Vec3& _pos) @@ -1040,8 +1219,23 @@ bool overlap(const Aabb& _aabb, const Plane& _plane) return bx::abs(dist) <= radius; } +static constexpr Vec3 kAxis[] = +{ + { 1.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f }, +}; + bool overlap(const Aabb& _aabb, const Triangle& _triangle) { + Aabb triAabb; + toAabb(triAabb, _triangle); + + if (!overlap(_aabb, triAabb) ) + { + return false; + } + Plane plane; calcPlane(plane, _triangle); @@ -1050,8 +1244,35 @@ bool overlap(const Aabb& _aabb, const Triangle& _triangle) return false; } - BX_UNUSED(_aabb, _triangle); - return false; + const Vec3 center = getCenter(_aabb); + const Vec3 v0 = sub(_triangle.v0, center); + const Vec3 v1 = sub(_triangle.v1, center); + const Vec3 v2 = sub(_triangle.v2, center); + + const Vec3 edge[] = + { + sub(v1, v0), + sub(v2, v1), + sub(v0, v2), + }; + + for (uint32_t ii = 0; ii < 3; ++ii) + { + for (uint32_t jj = 0; jj < 3; ++jj) + { + const Vec3 axis = cross(kAxis[ii], edge[jj]); + + const Range1 aabbR = projectToAxis(axis, _aabb); + const Range1 triR = projectToAxis(axis, _triangle); + + if (!overlap(aabbR, triR) ) + { + return false; + } + } + } + + return true; } bool overlap(const Aabb& _aabb, const Cylinder& _cylinder) diff --git a/examples/common/bounds.h b/examples/common/bounds.h index 87019e6b7..e1a83f433 100644 --- a/examples/common/bounds.h +++ b/examples/common/bounds.h @@ -82,7 +82,16 @@ bx::Vec3 getExtents(const Aabb& _aabb); bx::Vec3 getCenter(const Triangle& _triangle); /// -void toAabb(Aabb& _outAabb, const bx::Vec3& _center, const bx::Vec3& _extent); +void toAabb(Aabb& _outAabb, const bx::Vec3& _extents); + +/// +void toAabb(Aabb& _outAabb, const bx::Vec3& _center, const bx::Vec3& _extents); + +/// Convert cylinder to axis aligned bounding box. +void toAabb(Aabb& _outAabb, const Cylinder& _cylinder); + +/// Convert disk to axis aligned bounding box. +void toAabb(Aabb& _outAabb, const Disk& _disk); /// Convert oriented bounding box to axis aligned bounding box. void toAabb(Aabb& _outAabb, const Obb& _obb); @@ -90,11 +99,8 @@ void toAabb(Aabb& _outAabb, const Obb& _obb); /// Convert sphere to axis aligned bounding box. void toAabb(Aabb& _outAabb, const Sphere& _sphere); -/// Convert disk to axis aligned bounding box. -void toAabb(Aabb& _outAabb, const Disk& _disk); - -/// Convert cylinder to axis aligned bounding box. -void toAabb(Aabb& _outAabb, const Cylinder& _cylinder); +/// Convert triangle to axis aligned bounding box. +void toAabb(Aabb& _outAabb, const Triangle& _triangle); /// Calculate axis aligned bounding box. void toAabb(Aabb& _outAabb, const void* _vertices, uint32_t _numVertices, uint32_t _stride);