Implemented KRTriangle3 class.
Implemented swept sphere - mesh intersection testing / sphereCast functionality. - Not yet fully tested or optimized. --HG-- branch : nfb
This commit is contained in:
@@ -388,6 +388,10 @@
|
||||
E4F027E11697BFFF00D4427D /* KRAudioBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F027DD1697BFFF00D4427D /* KRAudioBuffer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
E4F027F71698115600D4427D /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4F027F61698115600D4427D /* AudioToolbox.framework */; };
|
||||
E4F027FA1698116000D4427D /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4F027F91698116000D4427D /* AudioToolbox.framework */; };
|
||||
E4F89BB418A6DB1200015637 /* KRTriangle3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4F89BB218A6DB1200015637 /* KRTriangle3.cpp */; };
|
||||
E4F89BB518A6DB1200015637 /* KRTriangle3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4F89BB218A6DB1200015637 /* KRTriangle3.cpp */; };
|
||||
E4F89BB618A6DB1200015637 /* KRTriangle3.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F89BB318A6DB1200015637 /* KRTriangle3.h */; };
|
||||
E4F89BB718A6DB1200015637 /* KRTriangle3.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F89BB318A6DB1200015637 /* KRTriangle3.h */; };
|
||||
E4F975321536220900FD60B2 /* KRNode.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F975311536220900FD60B2 /* KRNode.h */; settings = {ATTRIBUTES = (); }; };
|
||||
E4F975331536220900FD60B2 /* KRNode.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F975311536220900FD60B2 /* KRNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
E4F975361536221C00FD60B2 /* KRNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4F975351536221C00FD60B2 /* KRNode.cpp */; };
|
||||
@@ -685,6 +689,8 @@
|
||||
E4F027DD1697BFFF00D4427D /* KRAudioBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KRAudioBuffer.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
E4F027F61698115600D4427D /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/AudioToolbox.framework; sourceTree = DEVELOPER_DIR; };
|
||||
E4F027F91698116000D4427D /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
|
||||
E4F89BB218A6DB1200015637 /* KRTriangle3.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRTriangle3.cpp; sourceTree = "<group>"; };
|
||||
E4F89BB318A6DB1200015637 /* KRTriangle3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRTriangle3.h; sourceTree = "<group>"; };
|
||||
E4F975311536220900FD60B2 /* KRNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KRNode.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
E4F975351536221C00FD60B2 /* KRNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = KRNode.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
|
||||
/* End PBXFileReference section */
|
||||
@@ -948,6 +954,8 @@
|
||||
E4EC73C01720B1FF0065299F /* KRVector4.h */,
|
||||
E48CF940173453990005EBBB /* KRFloat.cpp */,
|
||||
E48CF941173453990005EBBB /* KRFloat.h */,
|
||||
E4F89BB218A6DB1200015637 /* KRTriangle3.cpp */,
|
||||
E4F89BB318A6DB1200015637 /* KRTriangle3.h */,
|
||||
);
|
||||
name = Math;
|
||||
sourceTree = "<group>";
|
||||
@@ -1369,6 +1377,7 @@
|
||||
E48B68171697794F00D99917 /* KRAudioSource.h in Headers */,
|
||||
E4F027C916979CCD00D4427D /* KRAudioManager.h in Headers */,
|
||||
E4F027E01697BFFF00D4427D /* KRAudioBuffer.h in Headers */,
|
||||
E4F89BB618A6DB1200015637 /* KRTriangle3.h in Headers */,
|
||||
E4943233169E08D200BCB891 /* KRAmbientZone.h in Headers */,
|
||||
E499BF1B16AE747C007FCDBE /* KRVector2.h in Headers */,
|
||||
E499BF1E16AE751E007FCDBE /* KRSceneManager.h in Headers */,
|
||||
@@ -1447,6 +1456,7 @@
|
||||
E4F027CA16979CCD00D4427D /* KRAudioManager.h in Headers */,
|
||||
E4F027D116979CE200D4427D /* KRAudioSample.h in Headers */,
|
||||
E4F027E11697BFFF00D4427D /* KRAudioBuffer.h in Headers */,
|
||||
E4F89BB718A6DB1200015637 /* KRTriangle3.h in Headers */,
|
||||
E4943234169E08D200BCB891 /* KRAmbientZone.h in Headers */,
|
||||
E414F9AF1694DA37000B3D58 /* KRUnknown.h in Headers */,
|
||||
E45E03BD18790DD1006DA23F /* PVRTTexture.h in Headers */,
|
||||
@@ -1717,6 +1727,7 @@
|
||||
E4924C2B15EE96AB00B965C6 /* KROctreeNode.cpp in Sources */,
|
||||
E404702018695DD200F01F42 /* KRTextureKTX.cpp in Sources */,
|
||||
E40BA45415EFF79500D7C3DD /* KRAABB.cpp in Sources */,
|
||||
E4F89BB418A6DB1200015637 /* KRTriangle3.cpp in Sources */,
|
||||
E488399415F928CA00BD66D5 /* KRBundle.cpp in Sources */,
|
||||
E488399C15F92BE000BD66D5 /* KRBundleManager.cpp in Sources */,
|
||||
E4B175AC161F5A1000B8FB80 /* KRTexture.cpp in Sources */,
|
||||
@@ -1808,6 +1819,7 @@
|
||||
E40F9833184A7BAC00CFA4D8 /* KRSprite.cpp in Sources */,
|
||||
E4CA10EA1637BD2B005D9400 /* KRTexturePVR.cpp in Sources */,
|
||||
E4CA10F01637BD58005D9400 /* KRTextureTGA.cpp in Sources */,
|
||||
E4F89BB518A6DB1200015637 /* KRTriangle3.cpp in Sources */,
|
||||
E4CA11791639CC90005D9400 /* KRViewport.cpp in Sources */,
|
||||
E41843921678704000DBD6CF /* KRCollider.cpp in Sources */,
|
||||
E4324BAF16444E120043185B /* KRParticleSystemNewtonian.cpp in Sources */,
|
||||
|
||||
@@ -279,6 +279,42 @@ bool KRAABB::intersectsRay(const KRVector3 &v1, const KRVector3 &dir) const
|
||||
return true; /* ray hits box */
|
||||
}
|
||||
|
||||
bool KRAABB::intersectsSphere(const KRVector3 ¢er, float radius) const
|
||||
{
|
||||
// Arvo's Algorithm
|
||||
|
||||
float squaredDistance = 0;
|
||||
|
||||
// process X
|
||||
if (center.x < min.x) {
|
||||
float diff = center.x - min.x;
|
||||
squaredDistance += diff * diff;
|
||||
} else if (center.x > max.x) {
|
||||
float diff = center.x - max.x;
|
||||
squaredDistance += diff * diff;
|
||||
}
|
||||
|
||||
// process Y
|
||||
if (center.y < min.y) {
|
||||
float diff = center.y - min.y;
|
||||
squaredDistance += diff * diff;
|
||||
} else if (center.y > max.y) {
|
||||
float diff = center.y - max.y;
|
||||
squaredDistance += diff * diff;
|
||||
}
|
||||
|
||||
// process Z
|
||||
if (center.z < min.z) {
|
||||
float diff = center.z - min.z;
|
||||
squaredDistance += diff * diff;
|
||||
} else if (center.z > max.z) {
|
||||
float diff = center.z - max.z;
|
||||
squaredDistance += diff * diff;
|
||||
}
|
||||
|
||||
return squaredDistance <= radius;
|
||||
}
|
||||
|
||||
void KRAABB::encapsulate(const KRAABB & b)
|
||||
{
|
||||
if(b.min.x < min.x) min.x = b.min.x;
|
||||
|
||||
@@ -35,6 +35,7 @@ public:
|
||||
|
||||
bool intersectsLine(const KRVector3 &v1, const KRVector3 &v2) const;
|
||||
bool intersectsRay(const KRVector3 &v1, const KRVector3 &dir) const;
|
||||
bool intersectsSphere(const KRVector3 ¢er, float radius) const;
|
||||
void encapsulate(const KRAABB & b);
|
||||
|
||||
KRAABB& operator =(const KRAABB& b);
|
||||
|
||||
@@ -99,14 +99,17 @@ bool KRCollider::lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &h
|
||||
loadModel();
|
||||
if(m_models.size()) {
|
||||
if(getBounds().intersectsLine(v0, v1)) {
|
||||
KRHitInfo hitinfo_model_space;
|
||||
if(hitinfo.didHit()) {
|
||||
hitinfo_model_space = KRHitInfo(KRMat4::Dot(getInverseModelMatrix(), hitinfo.getPosition()), KRMat4::DotNoTranslate(getInverseModelMatrix(), hitinfo.getNormal()), hitinfo.getNode());
|
||||
}
|
||||
KRVector3 v0_model_space = KRMat4::Dot(getInverseModelMatrix(), v0);
|
||||
KRVector3 v1_model_space = KRMat4::Dot(getInverseModelMatrix(), v1);
|
||||
KRHitInfo hitinfo_model_space;
|
||||
if(hitinfo.didHit()) {
|
||||
KRVector3 hit_position_model_space = KRMat4::Dot(getInverseModelMatrix(), hitinfo.getPosition());
|
||||
hitinfo_model_space = KRHitInfo(hit_position_model_space, KRMat4::DotNoTranslate(getInverseModelMatrix(), hitinfo.getNormal()), (hit_position_model_space - v0_model_space).magnitude(), hitinfo.getNode());
|
||||
}
|
||||
|
||||
if(m_models[0]->lineCast(v0_model_space, v1_model_space, hitinfo_model_space)) {
|
||||
hitinfo = KRHitInfo(KRMat4::Dot(getModelMatrix(), hitinfo_model_space.getPosition()), KRVector3::Normalize(KRMat4::DotNoTranslate(getModelMatrix(), hitinfo_model_space.getNormal())), this);
|
||||
KRVector3 hit_position_world_space = KRMat4::Dot(getModelMatrix(), hitinfo_model_space.getPosition());
|
||||
hitinfo = KRHitInfo(hit_position_world_space, KRVector3::Normalize(KRMat4::DotNoTranslate(getModelMatrix(), hitinfo_model_space.getNormal())), (hit_position_world_space - v0).magnitude(), this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -121,14 +124,38 @@ bool KRCollider::rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &h
|
||||
loadModel();
|
||||
if(m_models.size()) {
|
||||
if(getBounds().intersectsRay(v0, dir)) {
|
||||
KRHitInfo hitinfo_model_space;
|
||||
if(hitinfo.didHit()) {
|
||||
hitinfo_model_space = KRHitInfo(KRMat4::Dot(getInverseModelMatrix(), hitinfo.getPosition()), KRVector3::Normalize(KRMat4::DotNoTranslate(getInverseModelMatrix(), hitinfo.getNormal())), hitinfo.getNode());
|
||||
}
|
||||
KRVector3 v0_model_space = KRMat4::Dot(getInverseModelMatrix(), v0);
|
||||
KRVector3 dir_model_space = KRVector3::Normalize(KRMat4::DotNoTranslate(getInverseModelMatrix(), dir));
|
||||
KRHitInfo hitinfo_model_space;
|
||||
if(hitinfo.didHit()) {
|
||||
KRVector3 hit_position_model_space = KRMat4::Dot(getInverseModelMatrix(), hitinfo.getPosition());
|
||||
hitinfo_model_space = KRHitInfo(KRMat4::Dot(getInverseModelMatrix(), hitinfo.getPosition()), KRVector3::Normalize(KRMat4::DotNoTranslate(getInverseModelMatrix(), hitinfo.getNormal())), (hit_position_model_space - v0_model_space).magnitude(), hitinfo.getNode());
|
||||
}
|
||||
|
||||
if(m_models[0]->rayCast(v0_model_space, dir_model_space, hitinfo_model_space)) {
|
||||
hitinfo = KRHitInfo(KRMat4::Dot(getModelMatrix(), hitinfo_model_space.getPosition()), KRVector3::Normalize(KRMat4::DotNoTranslate(getModelMatrix(), hitinfo_model_space.getNormal())), this);
|
||||
KRVector3 hit_position_world_space = KRMat4::Dot(getModelMatrix(), hitinfo_model_space.getPosition());
|
||||
hitinfo = KRHitInfo(hit_position_world_space, KRVector3::Normalize(KRMat4::DotNoTranslate(getModelMatrix(), hitinfo_model_space.getNormal())), (hit_position_world_space - v0).magnitude(), this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KRCollider::sphereCast(const KRVector3 &v0, const KRVector3 &v1, float radius, KRHitInfo &hitinfo, unsigned int layer_mask)
|
||||
{
|
||||
if(layer_mask & m_layer_mask) { // Only test if layer masks have a common bit set
|
||||
loadModel();
|
||||
if(m_models.size()) {
|
||||
KRAABB sphereCastBounds = KRAABB(
|
||||
KRVector3(KRMIN(v0.x, v1.x) - radius, KRMIN(v0.y, v1.y) - radius, KRMIN(v0.z, v1.z) - radius),
|
||||
KRVector3(KRMAX(v0.x, v1.x) + radius, KRMAX(v0.y, v1.y) + radius, KRMAX(v0.z, v1.z) + radius)
|
||||
);
|
||||
|
||||
if(getBounds().intersects(sphereCastBounds)) {
|
||||
if(m_models[0]->sphereCast(getModelMatrix(), v0, v1, radius, hitinfo)) {
|
||||
hitinfo = KRHitInfo(hitinfo.getPosition(), hitinfo.getNormal(), hitinfo.getDistance(), this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ public:
|
||||
|
||||
bool lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo, unsigned int layer_mask);
|
||||
bool rayCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo, unsigned int layer_mask);
|
||||
bool sphereCast(const KRVector3 &v0, const KRVector3 &v1, float radius, KRHitInfo &hitinfo, unsigned int layer_mask);
|
||||
|
||||
unsigned int getLayerMask();
|
||||
void setLayerMask(unsigned int layer_mask);
|
||||
|
||||
@@ -36,23 +36,23 @@ KRHitInfo::KRHitInfo()
|
||||
{
|
||||
m_position = KRVector3::Zero();
|
||||
m_normal = KRVector3::Zero();
|
||||
m_distance = 0.0f;
|
||||
m_node = NULL;
|
||||
}
|
||||
|
||||
KRHitInfo::KRHitInfo(const KRVector3 &position, const KRVector3 &normal, KRNode *node)
|
||||
KRHitInfo::KRHitInfo(const KRVector3 &position, const KRVector3 &normal, const float distance, KRNode *node)
|
||||
{
|
||||
m_position = position;
|
||||
if(m_position == KRVector3::Zero()) {
|
||||
KRContext::Log(KRContext::LOG_LEVEL_ERROR, "Zero position hitinfo");
|
||||
}
|
||||
m_normal = normal;
|
||||
m_distance = distance;
|
||||
m_node = node;
|
||||
}
|
||||
|
||||
KRHitInfo::KRHitInfo(const KRVector3 &position, const KRVector3 &normal)
|
||||
KRHitInfo::KRHitInfo(const KRVector3 &position, const KRVector3 &normal, const float distance)
|
||||
{
|
||||
m_position = position;
|
||||
m_normal = normal;
|
||||
m_distance = distance;
|
||||
m_node = NULL;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,11 @@ KRVector3 KRHitInfo::getNormal() const
|
||||
return m_normal;
|
||||
}
|
||||
|
||||
float KRHitInfo::getDistance() const
|
||||
{
|
||||
return m_distance;
|
||||
}
|
||||
|
||||
KRNode *KRHitInfo::getNode() const
|
||||
{
|
||||
return m_node;
|
||||
@@ -85,6 +90,7 @@ KRHitInfo& KRHitInfo::operator =(const KRHitInfo& b)
|
||||
{
|
||||
m_position = b.m_position;
|
||||
m_normal = b.m_normal;
|
||||
m_distance = b.m_distance;
|
||||
m_node = b.m_node;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -39,12 +39,13 @@ class KRNode;
|
||||
class KRHitInfo {
|
||||
public:
|
||||
KRHitInfo();
|
||||
KRHitInfo(const KRVector3 &position, const KRVector3 &normal);
|
||||
KRHitInfo(const KRVector3 &position, const KRVector3 &normal, KRNode *node);
|
||||
KRHitInfo(const KRVector3 &position, const KRVector3 &normal, const float distance);
|
||||
KRHitInfo(const KRVector3 &position, const KRVector3 &normal, const float distance, KRNode *node);
|
||||
~KRHitInfo();
|
||||
|
||||
KRVector3 getPosition() const;
|
||||
KRVector3 getNormal() const;
|
||||
float getDistance() const;
|
||||
KRNode *getNode() const;
|
||||
bool didHit() const;
|
||||
|
||||
@@ -55,6 +56,7 @@ private:
|
||||
KRNode *m_node;
|
||||
KRVector3 m_position;
|
||||
KRVector3 m_normal;
|
||||
float m_distance;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "KRMesh.h"
|
||||
|
||||
#include "KRVector3.h"
|
||||
#include "KRTriangle3.h"
|
||||
#include "KRShader.h"
|
||||
#include "KRShaderManager.h"
|
||||
#include "KRContext.h"
|
||||
@@ -981,94 +982,41 @@ KRMesh::model_format_t KRMesh::getModelFormat() const
|
||||
return f;
|
||||
}
|
||||
|
||||
bool KRMesh::rayCast(const KRVector3 &line_v0, const KRVector3 &dir, const KRVector3 &tri_v0, const KRVector3 &tri_v1, const KRVector3 &tri_v2, const KRVector3 &tri_n0, const KRVector3 &tri_n1, const KRVector3 &tri_n2, KRHitInfo &hitinfo)
|
||||
bool KRMesh::rayCast(const KRVector3 &start, const KRVector3 &dir, const KRTriangle3 &tri, const KRVector3 &tri_n0, const KRVector3 &tri_n1, const KRVector3 &tri_n2, KRHitInfo &hitinfo)
|
||||
{
|
||||
// algorithm based on Dan Sunday's implementation at http://geomalgorithms.com/a06-_intersect-2.html
|
||||
const float SMALL_NUM = 0.00000001; // anything that avoids division overflow
|
||||
KRVector3 u, v, n; // triangle vectors
|
||||
KRVector3 w0, w; // ray vectors
|
||||
float r, a, b; // params to calc ray-plane intersect
|
||||
|
||||
// get triangle edge vectors and plane normal
|
||||
u = tri_v1 - tri_v0;
|
||||
v = tri_v2 - tri_v0;
|
||||
n = KRVector3::Cross(u, v); // cross product
|
||||
if (n == KRVector3::Zero()) // triangle is degenerate
|
||||
return false; // do not deal with this case
|
||||
|
||||
w0 = line_v0 - tri_v0;
|
||||
a = -KRVector3::Dot(n, w0);
|
||||
b = KRVector3::Dot(n,dir);
|
||||
if (fabs(b) < SMALL_NUM) { // ray is parallel to triangle plane
|
||||
if (a == 0)
|
||||
return false; // ray lies in triangle plane
|
||||
else {
|
||||
return false; // ray disjoint from plane
|
||||
}
|
||||
}
|
||||
|
||||
// get intersect point of ray with triangle plane
|
||||
r = a / b;
|
||||
if (r < 0.0) // ray goes away from triangle
|
||||
return false; // => no intersect
|
||||
// for a segment, also test if (r > 1.0) => no intersect
|
||||
|
||||
|
||||
KRVector3 hit_point = line_v0 + dir * r; // intersect point of ray and plane
|
||||
|
||||
// is hit_point inside triangle?
|
||||
float uu, uv, vv, wu, wv, D;
|
||||
uu = KRVector3::Dot(u,u);
|
||||
uv = KRVector3::Dot(u,v);
|
||||
vv = KRVector3::Dot(v,v);
|
||||
w = hit_point - tri_v0;
|
||||
wu = KRVector3::Dot(w,u);
|
||||
wv = KRVector3::Dot(w,v);
|
||||
D = uv * uv - uu * vv;
|
||||
|
||||
// get and test parametric coords
|
||||
float s, t;
|
||||
s = (uv * wv - vv * wu) / D;
|
||||
if (s < 0.0 || s > 1.0) // hit_point is outside triangle
|
||||
return false;
|
||||
t = (uv * wu - uu * wv) / D;
|
||||
if (t < 0.0 || (s + t) > 1.0) // hit_point is outside triangle
|
||||
return false;
|
||||
|
||||
float new_hit_distance_sqr = (hit_point - line_v0).sqrMagnitude();
|
||||
float prev_hit_distance_sqr = (hitinfo.getPosition() - line_v0).sqrMagnitude();
|
||||
|
||||
KRVector3 hit_point;
|
||||
if(tri.rayCast(start, dir, hit_point)) {
|
||||
// ---===--- hit_point is in triangle ---===---
|
||||
|
||||
|
||||
if(new_hit_distance_sqr < prev_hit_distance_sqr || !hitinfo.didHit()) {
|
||||
float new_hit_distance = (hit_point - start).magnitude();
|
||||
if(new_hit_distance < hitinfo.getDistance() || !hitinfo.didHit()) {
|
||||
// Update the hitinfo object if this hit is closer than the prior hit
|
||||
|
||||
// Interpolate between the three vertex normals, performing a 3-way lerp of tri_n0, tri_n1, and tri_n2
|
||||
float distance_v0 = (tri_v0 - hit_point).magnitude();
|
||||
float distance_v1 = (tri_v1 - hit_point).magnitude();
|
||||
float distance_v2 = (tri_v2 - hit_point).magnitude();
|
||||
float distance_v0 = (tri[0] - hit_point).magnitude();
|
||||
float distance_v1 = (tri[1] - hit_point).magnitude();
|
||||
float distance_v2 = (tri[2] - hit_point).magnitude();
|
||||
float distance_total = distance_v0 + distance_v1 + distance_v2;
|
||||
distance_v0 /= distance_total;
|
||||
distance_v1 /= distance_total;
|
||||
distance_v2 /= distance_total;
|
||||
KRVector3 normal = KRVector3::Normalize(tri_n0 * (1.0 - distance_v0) + tri_n1 * (1.0 - distance_v1) + tri_n2 * (1.0 - distance_v2));
|
||||
|
||||
hitinfo = KRHitInfo(hit_point, normal);
|
||||
hitinfo = KRHitInfo(hit_point, normal, new_hit_distance);
|
||||
return true;
|
||||
} else {
|
||||
return false; // Either no hit, or the hit was farther than an existing hit
|
||||
return false; // The hit was farther than an existing hit
|
||||
}
|
||||
|
||||
} else {
|
||||
// Dit not hit the triangle
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
bool KRMesh::rayCast(const KRVector3 &line_v0, const KRVector3 &dir, int tri_index0, int tri_index1, int tri_index2, KRHitInfo &hitinfo) const
|
||||
{
|
||||
return rayCast(line_v0, dir, getVertexPosition(tri_index0), getVertexPosition(tri_index1), getVertexPosition(tri_index2), getVertexNormal(tri_index0), getVertexNormal(tri_index1), getVertexNormal(tri_index2), hitinfo);
|
||||
}
|
||||
*/
|
||||
|
||||
bool KRMesh::rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo) const
|
||||
bool KRMesh::rayCast(const KRVector3 &start, const KRVector3 &dir, KRHitInfo &hitinfo) const
|
||||
{
|
||||
m_pData->lock();
|
||||
bool hit_found = false;
|
||||
@@ -1084,7 +1032,9 @@ bool KRMesh::rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitin
|
||||
tri_vert_index[1] = getTriangleVertexIndex(submesh_index, triangle_index*3 + 1);
|
||||
tri_vert_index[2] = getTriangleVertexIndex(submesh_index, triangle_index*3 + 2);
|
||||
|
||||
if(rayCast(v0, dir, getVertexPosition(tri_vert_index[0]), getVertexPosition(tri_vert_index[1]), getVertexPosition(tri_vert_index[2]), getVertexNormal(tri_vert_index[0]), getVertexNormal(tri_vert_index[1]), getVertexNormal(tri_vert_index[2]), hitinfo)) hit_found = true;
|
||||
KRTriangle3 tri = KRTriangle3(getVertexPosition(tri_vert_index[0]), getVertexPosition(tri_vert_index[1]), getVertexPosition(tri_vert_index[2]));
|
||||
|
||||
if(rayCast(start, dir, tri, getVertexNormal(tri_vert_index[0]), getVertexNormal(tri_vert_index[1]), getVertexNormal(tri_vert_index[2]), hitinfo)) hit_found = true;
|
||||
}
|
||||
break;
|
||||
/*
|
||||
@@ -1111,6 +1061,94 @@ bool KRMesh::rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitin
|
||||
return hit_found;
|
||||
}
|
||||
|
||||
|
||||
bool KRMesh::sphereCast(const KRMat4 &model_to_world, const KRVector3 &v0, const KRVector3 &v1, float radius, KRHitInfo &hitinfo) const
|
||||
{
|
||||
m_pData->lock();
|
||||
KRHitInfo new_hitinfo;
|
||||
KRVector3 dir = KRVector3::Normalize(v1 - v0);
|
||||
|
||||
bool hit_found = false;
|
||||
for(int submesh_index=0; submesh_index < getSubmeshCount(); submesh_index++) {
|
||||
int vertex_count = getVertexCount(submesh_index);
|
||||
switch(getModelFormat()) {
|
||||
case KRENGINE_MODEL_FORMAT_TRIANGLES:
|
||||
case KRENGINE_MODEL_FORMAT_INDEXED_TRIANGLES:
|
||||
for(int triangle_index=0; triangle_index < vertex_count / 3; triangle_index++) {
|
||||
int tri_vert_index[3]; // FINDME, HACK! This is not very efficient for indexed collider meshes...
|
||||
tri_vert_index[0] = getTriangleVertexIndex(submesh_index, triangle_index*3);
|
||||
tri_vert_index[1] = getTriangleVertexIndex(submesh_index, triangle_index*3 + 1);
|
||||
tri_vert_index[2] = getTriangleVertexIndex(submesh_index, triangle_index*3 + 2);
|
||||
|
||||
KRTriangle3 tri = KRTriangle3(getVertexPosition(tri_vert_index[0]), getVertexPosition(tri_vert_index[1]), getVertexPosition(tri_vert_index[2]));
|
||||
|
||||
if(sphereCast(model_to_world, v0, dir, radius, tri, getVertexNormal(tri_vert_index[0]), getVertexNormal(tri_vert_index[1]), getVertexNormal(tri_vert_index[2]), new_hitinfo)) hit_found = true;
|
||||
}
|
||||
break;
|
||||
/*
|
||||
|
||||
NOTE: Not yet supported:
|
||||
|
||||
case KRENGINE_MODEL_FORMAT_STRIP:
|
||||
case KRENGINE_MODEL_FORMAT_INDEXED_STRIP:
|
||||
for(int triangle_index=0; triangle_index < vertex_count - 2; triangle_index++) {
|
||||
int tri_vert_index[3];
|
||||
tri_vert_index[0] = getTriangleVertexIndex(submesh_index, vertex_start + triangle_index*3);
|
||||
tri_vert_index[1] = getTriangleVertexIndex(submesh_index, vertex_start + triangle_index*3 + 1);
|
||||
tri_vert_index[2] = getTriangleVertexIndex(submesh_index, vertex_start + triangle_index*3 + 2);
|
||||
|
||||
if(sphereCast(model_to_world, v0, v1, getVertexPosition(vertex_start + triangle_index), getVertexPosition(vertex_start + triangle_index+1), getVertexPosition(vertex_start + triangle_index+2), getVertexNormal(vertex_start + triangle_index), getVertexNormal(vertex_start + triangle_index+1), getVertexNormal(vertex_start + triangle_index+2), new_hitinfo)) hit_found = true;
|
||||
}
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_pData->unlock();
|
||||
|
||||
|
||||
if(hit_found) {
|
||||
if(new_hitinfo.getDistance() <= (v1 - v0).magnitude()) {
|
||||
// The hit was between v1 and v2
|
||||
hitinfo = new_hitinfo;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // Either no hit, or the hit was beyond v1
|
||||
}
|
||||
|
||||
bool KRMesh::sphereCast(const KRMat4 &model_to_world, const KRVector3 &start, const KRVector3 &dir, float radius, const KRTriangle3 &tri, const KRVector3 &tri_n0, const KRVector3 &tri_n1, const KRVector3 &tri_n2, KRHitInfo &hitinfo)
|
||||
{
|
||||
|
||||
// bool sphereCast(const KRVector3 &start, const KRVector3 &dir, float radius, KRVector3 &hit_point, float &hit_distance) const;
|
||||
|
||||
KRVector3 new_hit_point;
|
||||
float new_hit_distance;
|
||||
|
||||
KRTriangle3 world_tri = KRTriangle3(KRMat4::Dot(model_to_world, tri[0]), KRMat4::Dot(model_to_world, tri[1]), KRMat4::Dot(model_to_world, tri[2]));
|
||||
|
||||
if(world_tri.sphereCast(start, dir, radius, new_hit_point, new_hit_distance)) {
|
||||
if(!hitinfo.didHit() || hitinfo.getDistance() > new_hit_distance) {
|
||||
|
||||
// Interpolate between the three vertex normals, performing a 3-way lerp of tri_n0, tri_n1, and tri_n2
|
||||
float distance_v0 = (tri[0] - new_hit_point).magnitude();
|
||||
float distance_v1 = (tri[1] - new_hit_point).magnitude();
|
||||
float distance_v2 = (tri[2] - new_hit_point).magnitude();
|
||||
float distance_total = distance_v0 + distance_v1 + distance_v2;
|
||||
distance_v0 /= distance_total;
|
||||
distance_v1 /= distance_total;
|
||||
distance_v2 /= distance_total;
|
||||
KRVector3 normal = KRVector3::Normalize(KRMat4::DotNoTranslate(model_to_world, (tri_n0 * (1.0 - distance_v0) + tri_n1 * (1.0 - distance_v1) + tri_n2 * (1.0 - distance_v2))));
|
||||
|
||||
hitinfo = KRHitInfo(new_hit_point, normal, new_hit_distance);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KRMesh::lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo) const
|
||||
{
|
||||
m_pData->lock();
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
|
||||
class KRMaterial;
|
||||
class KRNode;
|
||||
class KRTriangle3;
|
||||
|
||||
|
||||
class KRMesh : public KRResource {
|
||||
@@ -208,6 +209,7 @@ public:
|
||||
|
||||
bool lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo) const;
|
||||
bool rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo) const;
|
||||
bool sphereCast(const KRMat4 &model_to_world, const KRVector3 &v0, const KRVector3 &v1, float radius, KRHitInfo &hitinfo) const;
|
||||
|
||||
static int GetLODCoverage(const std::string &name);
|
||||
private:
|
||||
@@ -217,8 +219,8 @@ private:
|
||||
|
||||
void getSubmeshes();
|
||||
|
||||
// bool rayCast(const KRVector3 &line_v0, const KRVector3 &dir, int tri_index0, int tri_index1, int tri_index2, KRHitInfo &hitinfo) const;
|
||||
static bool rayCast(const KRVector3 &line_v0, const KRVector3 &dir, const KRVector3 &tri_v0, const KRVector3 &tri_v1, const KRVector3 &tri_v2, const KRVector3 &tri_n0, const KRVector3 &tri_n1, const KRVector3 &tri_n2, KRHitInfo &hitinfo);
|
||||
static bool rayCast(const KRVector3 &start, const KRVector3 &dir, const KRTriangle3 &tri, const KRVector3 &tri_n0, const KRVector3 &tri_n1, const KRVector3 &tri_n2, KRHitInfo &hitinfo);
|
||||
static bool sphereCast(const KRMat4 &model_to_world, const KRVector3 &start, const KRVector3 &dir, float radius, const KRTriangle3 &tri, const KRVector3 &tri_n0, const KRVector3 &tri_n1, const KRVector3 &tri_n2, KRHitInfo &hitinfo);
|
||||
|
||||
int m_lodCoverage; // This LOD level is activated when the bounding box of the model will cover less than this percent of the screen (100 = highest detail model)
|
||||
vector<KRMaterial *> m_materials;
|
||||
|
||||
@@ -132,3 +132,25 @@ bool KROctree::rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hit
|
||||
}
|
||||
return hit_found;
|
||||
}
|
||||
|
||||
bool KROctree::sphereCast(const KRVector3 &v0, const KRVector3 &v1, float radius, KRHitInfo &hitinfo, unsigned int layer_mask)
|
||||
{
|
||||
bool hit_found = false;
|
||||
std::vector<KRCollider *> outer_colliders;
|
||||
|
||||
for(std::set<KRNode *>::iterator outer_nodes_itr=m_outerSceneNodes.begin(); outer_nodes_itr != m_outerSceneNodes.end(); outer_nodes_itr++) {
|
||||
KRCollider *collider = dynamic_cast<KRCollider *>(*outer_nodes_itr);
|
||||
if(collider) {
|
||||
outer_colliders.push_back(collider);
|
||||
}
|
||||
}
|
||||
for(std::vector<KRCollider *>::iterator itr=outer_colliders.begin(); itr != outer_colliders.end(); itr++) {
|
||||
if((*itr)->sphereCast(v0, v1, radius, hitinfo, layer_mask)) hit_found = true;
|
||||
}
|
||||
|
||||
if(m_pRootNode) {
|
||||
if(m_pRootNode->sphereCast(v0, v1, radius, hitinfo, layer_mask)) hit_found = true;
|
||||
}
|
||||
return hit_found;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
|
||||
bool lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo, unsigned int layer_mask);
|
||||
bool rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo, unsigned int layer_mask);
|
||||
bool sphereCast(const KRVector3 &v0, const KRVector3 &v1, float radius, KRHitInfo &hitinfo, unsigned int layer_mask);
|
||||
|
||||
private:
|
||||
KROctreeNode *m_pRootNode;
|
||||
|
||||
@@ -251,3 +251,39 @@ bool KROctreeNode::rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo
|
||||
|
||||
return hit_found;
|
||||
}
|
||||
|
||||
bool KROctreeNode::sphereCast(const KRVector3 &v0, const KRVector3 &v1, float radius, KRHitInfo &hitinfo, unsigned int layer_mask)
|
||||
{
|
||||
bool hit_found = false;
|
||||
/*
|
||||
// FINDME, TODO - Adapt this optimization to work with sphereCasts
|
||||
|
||||
if(hitinfo.didHit() && v1 != hitinfo.getPosition()) {
|
||||
// Optimization: If we already have a hit, only search for hits that are closer
|
||||
hit_found = sphereCast(v0, hitinfo.getPosition(), radius, hitinfo, layer_mask);
|
||||
} else {
|
||||
*/
|
||||
KRAABB swept_bounds = KRAABB(KRVector3(KRMIN(v0.x, v1.x) - radius, KRMIN(v0.y, v1.y) - radius, KRMIN(v0.z, v1.z) - radius), KRVector3(KRMAX(v0.x, v1.x) + radius, KRMAX(v0.y, v1.y) + radius, KRMAX(v0.z, v1.z) + radius));
|
||||
// FINDME, TODO - Investigate AABB - swept sphere intersections or OBB - AABB intersections: "if(getBounds().intersectsSweptSphere(v0, v1, radius)) {"
|
||||
if(getBounds().intersects(swept_bounds)) {
|
||||
|
||||
for(std::set<KRNode *>::iterator nodes_itr=m_sceneNodes.begin(); nodes_itr != m_sceneNodes.end(); nodes_itr++) {
|
||||
KRCollider *collider = dynamic_cast<KRCollider *>(*nodes_itr);
|
||||
if(collider) {
|
||||
if(collider->sphereCast(v0, v1, radius, hitinfo, layer_mask)) hit_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i<8; i++) {
|
||||
if(m_children[i]) {
|
||||
if(m_children[i]->sphereCast(v0, v1, radius, hitinfo, layer_mask)) {
|
||||
hit_found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// }
|
||||
|
||||
return hit_found;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,8 @@ public:
|
||||
|
||||
bool lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo, unsigned int layer_mask);
|
||||
bool rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo, unsigned int layer_mask);
|
||||
bool sphereCast(const KRVector3 &v0, const KRVector3 &v1, float radius, KRHitInfo &hitinfo, unsigned int layer_mask);
|
||||
|
||||
private:
|
||||
|
||||
KRAABB m_bounds;
|
||||
|
||||
@@ -552,3 +552,9 @@ bool KRScene::rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hiti
|
||||
return m_nodeTree.rayCast(v0, dir, hitinfo, layer_mask);
|
||||
}
|
||||
|
||||
bool KRScene::sphereCast(const KRVector3 &v0, const KRVector3 &v1, float radius, KRHitInfo &hitinfo, unsigned int layer_mask)
|
||||
{
|
||||
return m_nodeTree.sphereCast(v0, v1, radius, hitinfo, layer_mask);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ public:
|
||||
|
||||
bool lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo, unsigned int layer_mask);
|
||||
bool rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo, unsigned int layer_mask);
|
||||
bool sphereCast(const KRVector3 &v0, const KRVector3 &v1, float radius, KRHitInfo &hitinfo, unsigned int layer_mask);
|
||||
|
||||
void renderFrame(float deltaTime, int width, int height);
|
||||
void render(KRCamera *pCamera, unordered_map<KRAABB, int> &visibleBounds, const KRViewport &viewport, KRNode::RenderPass renderPass, bool new_frame);
|
||||
|
||||
278
KREngine/kraken/KRTriangle3.cpp
Normal file
278
KREngine/kraken/KRTriangle3.cpp
Normal file
@@ -0,0 +1,278 @@
|
||||
//
|
||||
// KRTriangle.cpp
|
||||
// Kraken
|
||||
//
|
||||
// Created by Kearwood Gilbert on 2/8/2014.
|
||||
// Copyright (c) 2014 Kearwood Software. All rights reserved.
|
||||
//
|
||||
|
||||
#include "KRTriangle3.h"
|
||||
#include "KRVector3.h"
|
||||
|
||||
KRTriangle3::KRTriangle3(const KRVector3 &v1, const KRVector3 &v2, const KRVector3 &v3)
|
||||
{
|
||||
m_c[0] = v1;
|
||||
m_c[1] = v2;
|
||||
m_c[2] = v3;
|
||||
}
|
||||
|
||||
KRTriangle3::KRTriangle3(const KRTriangle3 &tri)
|
||||
{
|
||||
m_c[0] = tri[0];
|
||||
m_c[1] = tri[1];
|
||||
m_c[3] = tri[3];
|
||||
}
|
||||
|
||||
|
||||
KRTriangle3::~KRTriangle3()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool KRTriangle3::operator ==(const KRTriangle3& b) const
|
||||
{
|
||||
return m_c[0] == b[0] && m_c[1] == b[1] && m_c[2] == b[2];
|
||||
}
|
||||
|
||||
bool KRTriangle3::operator !=(const KRTriangle3& b) const
|
||||
{
|
||||
return m_c[0] != b[0] || m_c[1] != b[1] || m_c[2] != b[2];
|
||||
}
|
||||
|
||||
KRTriangle3& KRTriangle3::operator =(const KRTriangle3& b)
|
||||
{
|
||||
|
||||
m_c[0] = b[0];
|
||||
m_c[1] = b[1];
|
||||
m_c[3] = b[3];
|
||||
return *this;
|
||||
}
|
||||
|
||||
KRVector3& KRTriangle3::operator[](unsigned i)
|
||||
{
|
||||
return m_c[i];
|
||||
}
|
||||
|
||||
KRVector3 KRTriangle3::operator[](unsigned i) const
|
||||
{
|
||||
return m_c[i];
|
||||
}
|
||||
|
||||
|
||||
bool KRTriangle3::rayCast(const KRVector3 &start, const KRVector3 &dir, KRVector3 &hit_point) const
|
||||
{
|
||||
// algorithm based on Dan Sunday's implementation at http://geomalgorithms.com/a06-_intersect-2.html
|
||||
const float SMALL_NUM = 0.00000001; // anything that avoids division overflow
|
||||
KRVector3 u, v, n; // triangle vectors
|
||||
KRVector3 w0, w; // ray vectors
|
||||
float r, a, b; // params to calc ray-plane intersect
|
||||
|
||||
// get triangle edge vectors and plane normal
|
||||
u = m_c[1] - m_c[0];
|
||||
v = m_c[2] - m_c[0];
|
||||
n = KRVector3::Cross(u, v); // cross product
|
||||
if (n == KRVector3::Zero()) // triangle is degenerate
|
||||
return false; // do not deal with this case
|
||||
|
||||
w0 = start - m_c[0];
|
||||
a = -KRVector3::Dot(n, w0);
|
||||
b = KRVector3::Dot(n,dir);
|
||||
if (fabs(b) < SMALL_NUM) { // ray is parallel to triangle plane
|
||||
if (a == 0)
|
||||
return false; // ray lies in triangle plane
|
||||
else {
|
||||
return false; // ray disjoint from plane
|
||||
}
|
||||
}
|
||||
|
||||
// get intersect point of ray with triangle plane
|
||||
r = a / b;
|
||||
if (r < 0.0) // ray goes away from triangle
|
||||
return false; // => no intersect
|
||||
// for a segment, also test if (r > 1.0) => no intersect
|
||||
|
||||
|
||||
KRVector3 plane_hit_point = start + dir * r; // intersect point of ray and plane
|
||||
|
||||
// is plane_hit_point inside triangle?
|
||||
float uu, uv, vv, wu, wv, D;
|
||||
uu = KRVector3::Dot(u,u);
|
||||
uv = KRVector3::Dot(u,v);
|
||||
vv = KRVector3::Dot(v,v);
|
||||
w = plane_hit_point - m_c[0];
|
||||
wu = KRVector3::Dot(w,u);
|
||||
wv = KRVector3::Dot(w,v);
|
||||
D = uv * uv - uu * vv;
|
||||
|
||||
// get and test parametric coords
|
||||
float s, t;
|
||||
s = (uv * wv - vv * wu) / D;
|
||||
if (s < 0.0 || s > 1.0) // plane_hit_point is outside triangle
|
||||
return false;
|
||||
t = (uv * wu - uu * wv) / D;
|
||||
if (t < 0.0 || (s + t) > 1.0) // plane_hit_point is outside triangle
|
||||
return false;
|
||||
|
||||
// plane_hit_point is inside the triangle
|
||||
hit_point = plane_hit_point;
|
||||
return true;
|
||||
}
|
||||
|
||||
KRVector3 KRTriangle3::calculateNormal() const
|
||||
{
|
||||
KRVector3 v1 = m_c[1] - m_c[0];
|
||||
KRVector3 v2 = m_c[2] - m_c[0];
|
||||
|
||||
return KRVector3::Normalize(KRVector3::Cross(v1, v2));
|
||||
}
|
||||
|
||||
bool _intersectSphere(const KRVector3 &rO, const KRVector3 &rV, const KRVector3 &sO, float sR, float &distance)
|
||||
{
|
||||
// From: http://archive.gamedev.net/archive/reference/articles/article1026.html
|
||||
|
||||
// TODO - Move to another class?
|
||||
KRVector3 Q = sO - rO;
|
||||
float c = Q.magnitude();
|
||||
float v = KRVector3::Dot(Q, rV);
|
||||
float d = sR * sR - (c * c - v * v);
|
||||
|
||||
// If there was no intersection, return -1
|
||||
|
||||
if(d < 0.0) return false;
|
||||
|
||||
// Return the distance to the [first] intersecting point
|
||||
|
||||
distance = v - sqrt(d);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _sameSide(const KRVector3 &p1, const KRVector3 &p2, const KRVector3 &a, const KRVector3 &b)
|
||||
{
|
||||
// TODO - Move to KRVector3 class?
|
||||
// From: http://stackoverflow.com/questions/995445/determine-if-a-3d-point-is-within-a-triangle
|
||||
|
||||
KRVector3 cp1 = KRVector3::Cross(b - a, p1 - a);
|
||||
KRVector3 cp2 = KRVector3::Cross(b - a, p2 - a);
|
||||
if(KRVector3::Dot(cp1, cp2) >= 0) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
KRVector3 _closestPointOnLine(const KRVector3 &a, const KRVector3 &b, const KRVector3 &p)
|
||||
{
|
||||
// From: http://stackoverflow.com/questions/995445/determine-if-a-3d-point-is-within-a-triangle
|
||||
|
||||
// Determine t (the length of the vector from ‘a’ to ‘p’)
|
||||
|
||||
KRVector3 c = p - a;
|
||||
KRVector3 V = KRVector3::Normalize(b - a);
|
||||
float d = (a - b).magnitude();
|
||||
float t = KRVector3::Dot(V, c);
|
||||
|
||||
// Check to see if ‘t’ is beyond the extents of the line segment
|
||||
|
||||
if (t < 0) return a;
|
||||
if (t > d) return b;
|
||||
|
||||
// Return the point between ‘a’ and ‘b’
|
||||
|
||||
return a + V * t;
|
||||
}
|
||||
|
||||
KRVector3 KRTriangle3::closestPointOnTriangle(const KRVector3 &p) const
|
||||
{
|
||||
KRVector3 a = m_c[0];
|
||||
KRVector3 b = m_c[1];
|
||||
KRVector3 c = m_c[2];
|
||||
|
||||
KRVector3 Rab = _closestPointOnLine(a, b, p);
|
||||
KRVector3 Rbc = _closestPointOnLine(b, c, p);
|
||||
KRVector3 Rca = _closestPointOnLine(c, a, p);
|
||||
|
||||
// return closest [Rab, Rbc, Rca] to p;
|
||||
float sd_Rab = (p - Rab).sqrMagnitude();
|
||||
float sd_Rbc = (p - Rbc).sqrMagnitude();
|
||||
float sd_Rca = (p - Rca).sqrMagnitude();
|
||||
|
||||
if(sd_Rab < sd_Rbc && sd_Rab < sd_Rca) {
|
||||
return Rab;
|
||||
} else if(sd_Rbc < sd_Rab && sd_Rbc < sd_Rca) {
|
||||
return sd_Rbc;
|
||||
} else {
|
||||
return sd_Rca;
|
||||
}
|
||||
}
|
||||
|
||||
bool KRTriangle3::sphereCast(const KRVector3 &start, const KRVector3 &dir, float radius, KRVector3 &hit_point, float &hit_distance) const
|
||||
{
|
||||
// Dir must be normalized
|
||||
const float SMALL_NUM = 0.00000001f; // anything that avoids division overflow
|
||||
|
||||
KRVector3 tri_normal = calculateNormal();
|
||||
|
||||
float d = KRVector3::Dot(tri_normal, m_c[0]);
|
||||
float e = KRVector3::Dot(tri_normal, start) - radius;
|
||||
float cotangent_distance = e - d;
|
||||
|
||||
KRVector3 plane_intersect;
|
||||
float plane_intersect_distance;
|
||||
|
||||
// Detect an embedded plane, caused by a sphere that is already intersecting the plane.
|
||||
if(cotangent_distance <= 0 && cotangent_distance >= -radius * 2.0f) {
|
||||
// Embedded plane - Sphere is already intersecting the plane.
|
||||
// Use the point closest to the origin of the sphere as the intersection
|
||||
plane_intersect = start - tri_normal * (cotangent_distance + radius);
|
||||
plane_intersect_distance = 0.0f;
|
||||
} else {
|
||||
// Sphere is not intersecting the plane
|
||||
// Determine the first point hit by the swept sphere on the triangle's plane
|
||||
|
||||
float denom = KRVector3::Dot(tri_normal, dir);
|
||||
|
||||
if(fabs(denom) < SMALL_NUM) {
|
||||
return false; // dir is co-planar with the triangle; no intersection
|
||||
}
|
||||
|
||||
plane_intersect_distance = -(cotangent_distance / denom);
|
||||
plane_intersect = start + dir * plane_intersect_distance;
|
||||
}
|
||||
|
||||
if(containsPoint(plane_intersect)) {
|
||||
// Triangle contains point
|
||||
hit_point = plane_intersect;
|
||||
hit_distance = plane_intersect_distance;
|
||||
return true;
|
||||
} else {
|
||||
// Triangle does not contain point, cast ray back to sphere from closest point on triangle edge or vertice
|
||||
KRVector3 closest_point = closestPointOnTriangle(hit_point);
|
||||
float reverse_hit_distance;
|
||||
if(_intersectSphere(closest_point, -dir, start, radius, reverse_hit_distance)) {
|
||||
// Reverse cast hit sphere
|
||||
hit_distance = reverse_hit_distance;
|
||||
hit_point = closest_point - dir * reverse_hit_distance;
|
||||
return true;
|
||||
} else {
|
||||
// Reverse cast did not hit sphere
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool KRTriangle3::containsPoint(const KRVector3 &p) const
|
||||
{
|
||||
// From: http://stackoverflow.com/questions/995445/determine-if-a-3d-point-is-within-a-triangle
|
||||
|
||||
const float SMALL_NUM = 0.00000001f; // anything that avoids division overflow
|
||||
// KRVector3 A = m_c[0], B = m_c[1], C = m_c[2];
|
||||
if (_sameSide(p, m_c[0], m_c[1], m_c[2]) && _sameSide(p, m_c[1], m_c[0], m_c[2]) && _sameSide(p, m_c[2], m_c[0], m_c[1])) {
|
||||
KRVector3 vc1 = KRVector3::Cross(m_c[0] - m_c[1], m_c[0] - m_c[2]);
|
||||
if(fabs(KRVector3::Dot(m_c[0] - p, vc1)) <= SMALL_NUM) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
63
KREngine/kraken/KRTriangle3.h
Normal file
63
KREngine/kraken/KRTriangle3.h
Normal file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// KRTriangle.h
|
||||
// KREngine
|
||||
//
|
||||
// Copyright 2012 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#ifndef KRTRIANGLE3_H
|
||||
#define KRTRIANGLE3_H
|
||||
|
||||
#include "KRVector3.h"
|
||||
|
||||
class KRTriangle3
|
||||
{
|
||||
public:
|
||||
KRTriangle3(const KRTriangle3 &tri);
|
||||
KRTriangle3(const KRVector3 &v1, const KRVector3 &v2, const KRVector3 &v3);
|
||||
~KRTriangle3();
|
||||
|
||||
KRVector3 calculateNormal() const;
|
||||
|
||||
bool operator ==(const KRTriangle3& b) const;
|
||||
bool operator !=(const KRTriangle3& b) const;
|
||||
KRTriangle3& operator =(const KRTriangle3& b);
|
||||
KRVector3& operator[](unsigned i);
|
||||
KRVector3 operator[](unsigned i) const;
|
||||
|
||||
|
||||
bool rayCast(const KRVector3 &start, const KRVector3 &dir, KRVector3 &hit_point) const;
|
||||
bool sphereCast(const KRVector3 &start, const KRVector3 &dir, float radius, KRVector3 &hit_point, float &hit_distance) const;
|
||||
|
||||
bool containsPoint(const KRVector3 &p) const;
|
||||
KRVector3 closestPointOnTriangle(const KRVector3 &p) const;
|
||||
private:
|
||||
|
||||
KRVector3 m_c[3];
|
||||
};
|
||||
|
||||
#endif // KRTRIANGLE3_H
|
||||
Reference in New Issue
Block a user