Gizmo raycasting implemented

This commit is contained in:
parax0 2015-08-17 14:10:42 -04:00
parent 44d0900125
commit 5977225aca
15 changed files with 301 additions and 94 deletions

View File

@ -34,7 +34,7 @@ CVector3f CAABox::Center() const
return (mMax - ((mMax - mMin) * 0.5f)); return (mMax - ((mMax - mMin) * 0.5f));
} }
CVector3f CAABox::GetSize() const CVector3f CAABox::Size() const
{ {
return (mMax - mMin); return (mMax - mMin);
} }
@ -49,14 +49,24 @@ CVector3f CAABox::Max() const
return mMax; return mMax;
} }
void CAABox::SetMin(const CVector3f& min)
{
mMin = min;
}
void CAABox::SetMax(const CVector3f& max)
{
mMax = max;
}
bool CAABox::IsNull() const bool CAABox::IsNull() const
{ {
return (GetSize() == CVector3f::skZero); return (Size() == CVector3f::skZero);
} }
bool CAABox::IsInfinite() const bool CAABox::IsInfinite() const
{ {
return (GetSize() == CVector3f::skInfinite); return (Size() == CVector3f::skInfinite);
} }
void CAABox::ExpandBounds(const CVector3f& vtx) void CAABox::ExpandBounds(const CVector3f& vtx)
@ -76,6 +86,13 @@ void CAABox::ExpandBounds(const CAABox& AABox)
ExpandBounds(AABox.mMax); ExpandBounds(AABox.mMax);
} }
void CAABox::ExpandBy(const CVector3f& amount)
{
CVector3f halfAmount = amount / 2.f;
mMin -= halfAmount;
mMax += halfAmount;
}
CAABox CAABox::Transformed(const CTransform4f& transform) const CAABox CAABox::Transformed(const CTransform4f& transform) const
{ {
CAABox AABox; CAABox AABox;

View File

@ -19,14 +19,17 @@ public:
CAABox(CInputStream& input); CAABox(CInputStream& input);
void Write(COutputStream& Output); void Write(COutputStream& Output);
CVector3f Center() const; CVector3f Center() const;
CVector3f GetSize() const; CVector3f Size() const;
CVector3f Min() const; CVector3f Min() const;
CVector3f Max() const; CVector3f Max() const;
void SetMin(const CVector3f& min);
void SetMax(const CVector3f& max);
bool IsNull() const; bool IsNull() const;
bool IsInfinite() const; bool IsInfinite() const;
void ExpandBounds(const CVector3f& vtx); void ExpandBounds(const CVector3f& vtx);
void ExpandBounds(const CAABox& AABox); void ExpandBounds(const CAABox& AABox);
void ExpandBy(const CVector3f& amount);
CAABox Transformed(const CTransform4f& transform) const; CAABox Transformed(const CTransform4f& transform) const;
bool IsPointInBox(const CVector3f& Point) const; bool IsPointInBox(const CVector3f& Point) const;

View File

@ -60,7 +60,7 @@ float CVector3f::Magnitude() const
float CVector3f::SquaredMagnitude() const float CVector3f::SquaredMagnitude() const
{ {
return (powf(x,2) + powf(y,2) + powf(z,2)); return Dot(*this);
} }
CVector3f CVector3f::Normalized() const CVector3f CVector3f::Normalized() const

View File

@ -144,6 +144,69 @@ std::pair<bool,float> RayBoxIntersection(const CRay& Ray, const CAABox& Box)
return std::pair<bool,float>(Hit, lowt); return std::pair<bool,float>(Hit, lowt);
} }
std::pair<bool,float> RayLineIntersection(const CRay& ray, const CVector3f& pointA,
const CVector3f& pointB, float threshold)
{
// http://geomalgorithms.com/a07-_distance.html
// http://www.gamedev.net/topic/589705-rayline-intersection-in-3d/
CVector3f u = ray.Direction();
CVector3f v = pointB - pointA;
CVector3f w = ray.Origin() - pointA;
float a = u.Dot(u);
float b = u.Dot(v);
float c = v.Dot(v);
float d = u.Dot(w);
float e = v.Dot(w);
float D = a * c - b * b;
float sc, sN, sD = D;
float tc, tN, tD = D;
if (D < FLT_EPSILON) {
sN = 0.f;
sD = 1.f;
tN = e;
tD = c;
}
else {
sN = b * e - c * d;
tN = a * e - b * d;
if (sN < 0.f) {
sN = 0.f;
tN = e;
tD = c;
}
}
if (tN < 0.f) {
tN = 0.f;
if (-d < 0.f)
sN = 0.f;
else {
sN = -d;
sD = a;
}
}
else if (tN > tD) {
tN = tD;
if (-d + b < 0.f)
sN = 0.f;
else {
sN = -d + b;
sD = a;
}
}
sc = (fabs(sN) < FLT_EPSILON ? 0.f : sN / sD);
tc = (fabs(tN) < FLT_EPSILON ? 0.f : tN / tD);
CVector3f dP = w + (u * sc) - (v * tc);
bool hit = (dP.Magnitude() <= threshold);
return std::pair<bool,float>(hit, sc);
}
std::pair<bool,float> RayTriangleIntersection(const CRay& Ray, std::pair<bool,float> RayTriangleIntersection(const CRay& Ray,
const CVector3f& vtxA, const CVector3f& vtxB, const CVector3f& vtxA, const CVector3f& vtxB,
const CVector3f& vtxC, bool AllowBackfaces) const CVector3f& vtxC, bool AllowBackfaces)

View File

@ -16,6 +16,9 @@ float Distance(const CVector3f& A, const CVector3f& B);
std::pair<bool,float> RayBoxIntersection(const CRay& Ray, const CAABox& Box); std::pair<bool,float> RayBoxIntersection(const CRay& Ray, const CAABox& Box);
std::pair<bool,float> RayLineIntersection(const CRay& ray, const CVector3f& pointA,
const CVector3f& pointB, float threshold = 0.02f);
std::pair<bool,float> RayTriangleIntersection(const CRay& Ray, const CVector3f& PointA, std::pair<bool,float> RayTriangleIntersection(const CRay& Ray, const CVector3f& PointA,
const CVector3f& PointB, const CVector3f& PointC, const CVector3f& PointB, const CVector3f& PointC,
bool AllowBackfaces = false); bool AllowBackfaces = false);

View File

@ -151,7 +151,7 @@ void CDrawUtil::DrawWireCube(const CAABox& kAABox, const CColor& kColor)
// Calculate model matrix // Calculate model matrix
CTransform4f Transform; CTransform4f Transform;
Transform.Scale(kAABox.GetSize()); Transform.Scale(kAABox.Size());
Transform.Translate(kAABox.Center()); Transform.Translate(kAABox.Center());
CGraphics::sMVPBlock.ModelMatrix = Transform.ToMatrix4f(); CGraphics::sMVPBlock.ModelMatrix = Transform.ToMatrix4f();
CGraphics::UpdateMVPBlock(); CGraphics::UpdateMVPBlock();

View File

@ -3,9 +3,8 @@
#include <Common/Math.h> #include <Common/Math.h>
#include <Core/CDrawUtil.h> #include <Core/CDrawUtil.h>
std::pair<bool,float> SSurface::IntersectsRay(const CRay& Ray, const CTransform4f& Transform) std::pair<bool,float> SSurface::IntersectsRay(const CRay& Ray, float LineThreshold)
{ {
//CDrawUtil::DrawWireCube(AABox.Transformed(Transform), CColor::skRed);
bool Hit = false; bool Hit = false;
float HitDist; float HitDist;
@ -14,6 +13,7 @@ std::pair<bool,float> SSurface::IntersectsRay(const CRay& Ray, const CTransform4
SPrimitive *pPrim = &Primitives[iPrim]; SPrimitive *pPrim = &Primitives[iPrim];
u32 NumVerts = pPrim->Vertices.size(); u32 NumVerts = pPrim->Vertices.size();
// Triangles
if ((pPrim->Type == eGX_Triangles) || (pPrim->Type == eGX_TriangleFan) || (pPrim->Type == eGX_TriangleStrip)) if ((pPrim->Type == eGX_Triangles) || (pPrim->Type == eGX_TriangleFan) || (pPrim->Type == eGX_TriangleStrip))
{ {
u32 NumTris; u32 NumTris;
@ -23,14 +23,6 @@ std::pair<bool,float> SSurface::IntersectsRay(const CRay& Ray, const CTransform4
else else
NumTris = NumVerts - 2; NumTris = NumVerts - 2;
CColor LineColor;
if (pPrim->Type == eGX_Triangles)
LineColor = CColor::skRed;
else if (pPrim->Type == eGX_TriangleStrip)
LineColor = CColor::skYellow;
else if (pPrim->Type == eGX_TriangleFan)
LineColor = CColor::skGreen;
for (u32 iTri = 0; iTri < NumTris; iTri++) for (u32 iTri = 0; iTri < NumTris; iTri++)
{ {
CVector3f vtxA, vtxB, vtxC; CVector3f vtxA, vtxB, vtxC;
@ -82,7 +74,38 @@ std::pair<bool,float> SSurface::IntersectsRay(const CRay& Ray, const CTransform4
} }
} }
// todo: Intersection tests for line primitives // Lines
if ((pPrim->Type == eGX_Lines) || (pPrim->Type == eGX_LineStrip))
{
u32 NumLines;
if (pPrim->Type == eGX_Lines)
NumLines = NumVerts / 2;
else
NumLines = NumVerts - 1;
for (u32 iLine = 0; iLine < NumLines; iLine++)
{
CVector3f vtxA, vtxB;
// Get the two vertices that make up the current line
u32 index = (pPrim->Type == eGX_Lines ? iLine * 2 : iLine);
vtxA = pPrim->Vertices[index].Position;
vtxB = pPrim->Vertices[index+1].Position;
// Intersection test
std::pair<bool,float> result = Math::RayLineIntersection(Ray, vtxA, vtxB, LineThreshold);
if (result.first)
{
if ((!Hit) || (result.second < HitDist))
{
Hit = true;
HitDist = result.second;
}
}
}
}
} }
return std::pair<bool,float>(Hit, HitDist); return std::pair<bool,float>(Hit, HitDist);

View File

@ -33,7 +33,7 @@ struct SSurface
TriangleCount = 0; TriangleCount = 0;
} }
std::pair<bool,float> IntersectsRay(const CRay& Ray, const CTransform4f& Transform = CTransform4f::skIdentity); std::pair<bool,float> IntersectsRay(const CRay& Ray, float LineThreshold = 0.02f);
}; };
#endif // SSURFACE_H #endif // SSURFACE_H

View File

@ -112,7 +112,7 @@ SRayIntersection CModelNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID)
out.AssetIndex = AssetID; out.AssetIndex = AssetID;
CRay TransformedRay = Ray.Transformed(Transform().Inverse()); CRay TransformedRay = Ray.Transformed(Transform().Inverse());
std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, Transform()); std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay);
if (Result.first) if (Result.first)
{ {

View File

@ -213,7 +213,7 @@ SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID)
CRay TransformedRay = Ray.Transformed(Transform().Inverse()); CRay TransformedRay = Ray.Transformed(Transform().Inverse());
CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel()); CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel());
std::pair<bool,float> Result = pModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, Transform()); std::pair<bool,float> Result = pModel->GetSurface(AssetID)->IntersectsRay(TransformedRay);
if (Result.first) if (Result.first)
{ {
@ -267,8 +267,8 @@ void CScriptNode::GeneratePosition()
CScriptNode *pNode = mpScene->ScriptNodeByID(link.ObjectID); CScriptNode *pNode = mpScene->ScriptNodeByID(link.ObjectID);
pNode->GeneratePosition(); pNode->GeneratePosition();
mPosition = pNode->GetAbsolutePosition(); mPosition = pNode->GetAbsolutePosition();
mPosition.z += (pNode->AABox().GetSize().z / 2.f); mPosition.z += (pNode->AABox().Size().z / 2.f);
mPosition.z += (AABox().GetSize().z / 2.f); mPosition.z += (AABox().Size().z / 2.f);
mPosition.z += 2.f; mPosition.z += 2.f;
} }

View File

@ -95,7 +95,7 @@ SRayIntersection CStaticNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID)
out.AssetIndex = AssetID; out.AssetIndex = AssetID;
CRay TransformedRay = Ray.Transformed(Transform().Inverse()); CRay TransformedRay = Ray.Transformed(Transform().Inverse());
std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, Transform()); std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay);
if (Result.first) if (Result.first)
{ {

View File

@ -1,4 +1,5 @@
#include "CGizmo.h" #include "CGizmo.h"
#include <Common/Math.h>
#include <Core/CRenderer.h> #include <Core/CRenderer.h>
#include <Core/CResCache.h> #include <Core/CResCache.h>
@ -6,7 +7,7 @@ CGizmo::CGizmo()
{ {
LoadModels(); LoadModels();
mMode = eRotate; SetMode(eTranslate);
mSelectedAxes = eNone; mSelectedAxes = eNone;
mGizmoSize = 1.f; mGizmoSize = 1.f;
mCameraDist = 0.f; mCameraDist = 0.f;
@ -31,29 +32,15 @@ void CGizmo::AddToRenderer(CRenderer *pRenderer)
// Transform is updated every frame even if the user doesn't modify the gizmo // Transform is updated every frame even if the user doesn't modify the gizmo
// in order to account for scale changes based on camera distance // in order to account for scale changes based on camera distance
UpdateTransform(); UpdateTransform();
SModelPart *pPart = mpCurrentParts;
// Determine which SModelPart array to use
SModelPart *pParts;
u32 numParts;
if (mMode == eTranslate) {
pParts = smTranslateModels;
numParts = 6;
} else if (mMode == eRotate) {
pParts = smRotateModels;
numParts = 4;
} else if (mMode == eScale) {
pParts = smScaleModels;
numParts = 7;
}
// Add all parts to renderer // Add all parts to renderer
for (u32 iPart = 0; iPart < numParts; iPart++) for (u32 iPart = 0; iPart < mNumCurrentParts; iPart++)
{ {
CModel *pModel = pParts->pModel; CModel *pModel = pPart->pModel;
// Determine whether to use the mat set for regular (0) or highlight (1) // Determine whether to use the mat set for regular (0) or highlight (1)
bool isHighlighted = (mSelectedAxes & pParts->modelAxes) == pParts->modelAxes; bool isHighlighted = (mSelectedAxes & pPart->modelAxes) == pPart->modelAxes;
u32 setID = (isHighlighted ? 1 : 0); u32 setID = (isHighlighted ? 1 : 0);
// Add to renderer... // Add to renderer...
@ -62,7 +49,7 @@ void CGizmo::AddToRenderer(CRenderer *pRenderer)
else else
pRenderer->AddOpaqueMesh(this, iPart, pModel->AABox().Transformed(mTransform), eDrawAsset); pRenderer->AddOpaqueMesh(this, iPart, pModel->AABox().Transformed(mTransform), eDrawAsset);
pParts++; pPart++;
} }
} }
@ -72,26 +59,13 @@ void CGizmo::DrawAsset(ERenderOptions options, u32 asset)
CGraphics::UpdateMVPBlock(); CGraphics::UpdateMVPBlock();
// Determine which SModelPart array to use // Determine which SModelPart array to use
SModelPart *pParts; if (asset >= mNumCurrentParts) return;
u32 numParts; SModelPart *pPart = mpCurrentParts;
if (mMode == eTranslate) {
pParts = smTranslateModels;
numParts = 6;
} else if (mMode == eRotate) {
pParts = smRotateModels;
numParts = 4;
} else if (mMode == eScale) {
pParts = smScaleModels;
numParts = 7;
}
if (asset >= numParts) return;
// Draw model // Draw model
bool isHighlighted = (mSelectedAxes & pParts[asset].modelAxes) == pParts[asset].modelAxes; bool isHighlighted = (mSelectedAxes & pPart[asset].modelAxes) == pPart[asset].modelAxes;
u32 setID = (isHighlighted ? 1 : 0); u32 setID = (isHighlighted ? 1 : 0);
pParts[asset].pModel->Draw((ERenderOptions) 0, setID); pPart[asset].pModel->Draw((ERenderOptions) 0, setID);
} }
void CGizmo::DrawRotationOutline() void CGizmo::DrawRotationOutline()
@ -135,6 +109,80 @@ void CGizmo::UpdateForCamera(const CCamera &camera)
mBillboardRotation = CQuaternion::FromAxisAngle(angle, axis); mBillboardRotation = CQuaternion::FromAxisAngle(angle, axis);
} }
bool CGizmo::IntersectsRay(const CRay &ray)
{
// todo: fix raycasting for rotate gizmo; currently it can hit the invisible back side of the model
CRay localRay = ray.Transformed(mTransform.Inverse());
float threshold = 0.02f * mGizmoSize * mCameraDist;
// Do raycast on each model
SModelPart *pPart = mpCurrentParts;
struct SResult {
SModelPart *pPart;
float dist;
};
std::list<SResult> results;
for (u32 iPart = 0; iPart < mNumCurrentParts; iPart++)
{
if (!pPart->enableRayCast) continue;
CModel *pModel = pPart->pModel;
// Ray/Model AABox test - allow buffer room because lines are small
CAABox AABox = pModel->AABox();
AABox.ExpandBy(CVector3f::skOne);
bool modelBoxCheck = Math::RayBoxIntersection(localRay, AABox).first;
if (modelBoxCheck)
{
bool hit = false;
float dist;
for (u32 iSurf = 0; iSurf < pModel->GetSurfaceCount(); iSurf++)
{
// Skip surface/box check
SSurface *pSurf = pModel->GetSurface(iSurf);
std::pair<bool,float> surfCheck = pSurf->IntersectsRay(localRay, 0.05f);
if (surfCheck.first)
{
if ((!hit) || (surfCheck.second < dist))
dist = surfCheck.second;
hit = true;
}
}
if (hit)
{
SResult result;
result.pPart = pPart;
result.dist = dist;
results.push_back(result);
}
}
pPart++;
}
// Results list empty = no hits
if (results.empty())
{
mSelectedAxes = eNone;
return false;
}
// Otherwise, we have at least one hit - sort results and set selected axes
results.sort([](const SResult& a, SResult& b) -> bool
{
return (a.dist < b.dist);
});
mSelectedAxes = results.front().pPart->modelAxes;
return true;
}
CGizmo::EGizmoMode CGizmo::Mode() CGizmo::EGizmoMode CGizmo::Mode()
{ {
return mMode; return mMode;
@ -143,6 +191,24 @@ CGizmo::EGizmoMode CGizmo::Mode()
void CGizmo::SetMode(EGizmoMode mode) void CGizmo::SetMode(EGizmoMode mode)
{ {
mMode = mode; mMode = mode;
switch (mode)
{
case eTranslate:
mpCurrentParts = smTranslateModels;
mNumCurrentParts = 9;
break;
case eRotate:
mpCurrentParts = smRotateModels;
mNumCurrentParts = 4;
break;
case eScale:
mpCurrentParts = smScaleModels;
mNumCurrentParts = 10;
break;
}
} }
void CGizmo::SetPosition(const CVector3f& position) void CGizmo::SetPosition(const CVector3f& position)
@ -150,31 +216,42 @@ void CGizmo::SetPosition(const CVector3f& position)
mPosition = position; mPosition = position;
} }
void CGizmo::ResetSelectedAxes()
{
mSelectedAxes = eNone;
}
// ************ PRIVATE STATIC ************ // ************ PRIVATE STATIC ************
void CGizmo::LoadModels() void CGizmo::LoadModels()
{ {
if (!smModelsLoaded) if (!smModelsLoaded)
{ {
smTranslateModels[CGIZMO_TRANSLATE_X] = SModelPart(eX, (CModel*) gResCache.GetResource("../resources/editor/TranslateGizmoX.CMDL")); smTranslateModels[CGIZMO_TRANSLATE_X] = SModelPart(eX, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateX.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_Y] = SModelPart(eY, (CModel*) gResCache.GetResource("../resources/editor/TranslateGizmoY.CMDL")); smTranslateModels[CGIZMO_TRANSLATE_Y] = SModelPart(eY, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateY.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_Z] = SModelPart(eZ, (CModel*) gResCache.GetResource("../resources/editor/TranslateGizmoZ.CMDL")); smTranslateModels[CGIZMO_TRANSLATE_Z] = SModelPart(eZ, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateZ.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_XY] = SModelPart(eXY, (CModel*) gResCache.GetResource("../resources/editor/TranslateGizmoXY.CMDL")); smTranslateModels[CGIZMO_TRANSLATE_LINES_XY] = SModelPart(eXY, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateLinesXY.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_XZ] = SModelPart(eXZ, (CModel*) gResCache.GetResource("../resources/editor/TranslateGizmoXZ.CMDL")); smTranslateModels[CGIZMO_TRANSLATE_LINES_XZ] = SModelPart(eXZ, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateLinesXZ.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_YZ] = SModelPart(eYZ, (CModel*) gResCache.GetResource("../resources/editor/TranslateGizmoYZ.CMDL")); smTranslateModels[CGIZMO_TRANSLATE_LINES_YZ] = SModelPart(eYZ, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateLinesYZ.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_POLY_XY] = SModelPart(eXY, false, (CModel*) gResCache.GetResource("../resources/editor/TranslatePolyXY.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_POLY_XZ] = SModelPart(eXZ, false, (CModel*) gResCache.GetResource("../resources/editor/TranslatePolyXZ.CMDL"));
smTranslateModels[CGIZMO_TRANSLATE_POLY_YZ] = SModelPart(eYZ, false, (CModel*) gResCache.GetResource("../resources/editor/TranslatePolyYZ.CMDL"));
smRotateModels[CGIZMO_ROTATE_X] = SModelPart(eX, (CModel*) gResCache.GetResource("../resources/editor/RotateGizmoX.CMDL")); smRotateModels[CGIZMO_ROTATE_X] = SModelPart(eX, true, (CModel*) gResCache.GetResource("../resources/editor/RotateX.CMDL"));
smRotateModels[CGIZMO_ROTATE_Y] = SModelPart(eY, (CModel*) gResCache.GetResource("../resources/editor/RotateGizmoY.CMDL")); smRotateModels[CGIZMO_ROTATE_Y] = SModelPart(eY, true, (CModel*) gResCache.GetResource("../resources/editor/RotateY.CMDL"));
smRotateModels[CGIZMO_ROTATE_Z] = SModelPart(eZ, (CModel*) gResCache.GetResource("../resources/editor/RotateGizmoZ.CMDL")); smRotateModels[CGIZMO_ROTATE_Z] = SModelPart(eZ, true, (CModel*) gResCache.GetResource("../resources/editor/RotateZ.CMDL"));
smRotateModels[CGIZMO_ROTATE_XYZ] = SModelPart(eXYZ, (CModel*) gResCache.GetResource("../resources/editor/RotateGizmoXYZ.CMDL")); smRotateModels[CGIZMO_ROTATE_XYZ] = SModelPart(eXYZ, false, (CModel*) gResCache.GetResource("../resources/editor/RotateXYZ.CMDL"));
smRotateClipOutline = SModelPart(eNone, (CModel*) gResCache.GetResource("../resources/editor/RotateGizmoClipOutline.CMDL")); smRotateClipOutline = SModelPart(eNone, false, (CModel*) gResCache.GetResource("../resources/editor/RotateClipOutline.CMDL"));
smScaleModels[CGIZMO_SCALE_X] = SModelPart(eX, (CModel*) gResCache.GetResource("../resources/editor/ScaleGizmoX.CMDL")); smScaleModels[CGIZMO_SCALE_X] = SModelPart(eX, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleX.CMDL"));
smScaleModels[CGIZMO_SCALE_Y] = SModelPart(eY, (CModel*) gResCache.GetResource("../resources/editor/ScaleGizmoY.CMDL")); smScaleModels[CGIZMO_SCALE_Y] = SModelPart(eY, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleY.CMDL"));
smScaleModels[CGIZMO_SCALE_Z] = SModelPart(eZ, (CModel*) gResCache.GetResource("../resources/editor/ScaleGizmoZ.CMDL")); smScaleModels[CGIZMO_SCALE_Z] = SModelPart(eZ, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleZ.CMDL"));
smScaleModels[CGIZMO_SCALE_XY] = SModelPart(eXY, (CModel*) gResCache.GetResource("../resources/editor/ScaleGizmoXY.CMDL")); smScaleModels[CGIZMO_SCALE_LINES_XY] = SModelPart(eXY, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleLinesXY.CMDL"));
smScaleModels[CGIZMO_SCALE_XZ] = SModelPart(eXZ, (CModel*) gResCache.GetResource("../resources/editor/ScaleGizmoXZ.CMDL")); smScaleModels[CGIZMO_SCALE_LINES_XZ] = SModelPart(eXZ, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleLinesXZ.CMDL"));
smScaleModels[CGIZMO_SCALE_YZ] = SModelPart(eYZ, (CModel*) gResCache.GetResource("../resources/editor/ScaleGizmoYZ.CMDL")); smScaleModels[CGIZMO_SCALE_LINES_YZ] = SModelPart(eYZ, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleLinesYZ.CMDL"));
smScaleModels[CGIZMO_SCALE_XYZ] = SModelPart(eXYZ, (CModel*) gResCache.GetResource("../resources/editor/ScaleGizmoXYZ.CMDL")); smScaleModels[CGIZMO_SCALE_POLY_XY] = SModelPart(eXY, false, (CModel*) gResCache.GetResource("../resources/editor/ScalePolyXY.CMDL"));
smScaleModels[CGIZMO_SCALE_POLY_XZ] = SModelPart(eXZ, false, (CModel*) gResCache.GetResource("../resources/editor/ScalePolyXZ.CMDL"));
smScaleModels[CGIZMO_SCALE_POLY_YZ] = SModelPart(eYZ, false, (CModel*) gResCache.GetResource("../resources/editor/ScalePolyYZ.CMDL"));
smScaleModels[CGIZMO_SCALE_XYZ] = SModelPart(eXYZ, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleXYZ.CMDL"));
smModelsLoaded = true; smModelsLoaded = true;
} }
@ -215,7 +292,7 @@ void CGizmo::UpdateTransform()
// ************ STATIC MEMBER INITIALIZATION ************ // ************ STATIC MEMBER INITIALIZATION ************
bool CGizmo::smModelsLoaded = false; bool CGizmo::smModelsLoaded = false;
CGizmo::SModelPart CGizmo::smTranslateModels[6]; CGizmo::SModelPart CGizmo::smTranslateModels[9];
CGizmo::SModelPart CGizmo::smRotateModels[4]; CGizmo::SModelPart CGizmo::smRotateModels[4];
CGizmo::SModelPart CGizmo::smScaleModels[7]; CGizmo::SModelPart CGizmo::smScaleModels[10];
CGizmo::SModelPart CGizmo::smRotateClipOutline; CGizmo::SModelPart CGizmo::smRotateClipOutline;

View File

@ -12,9 +12,12 @@
#define CGIZMO_TRANSLATE_X 0 #define CGIZMO_TRANSLATE_X 0
#define CGIZMO_TRANSLATE_Y 1 #define CGIZMO_TRANSLATE_Y 1
#define CGIZMO_TRANSLATE_Z 2 #define CGIZMO_TRANSLATE_Z 2
#define CGIZMO_TRANSLATE_XY 3 #define CGIZMO_TRANSLATE_LINES_XY 3
#define CGIZMO_TRANSLATE_XZ 4 #define CGIZMO_TRANSLATE_LINES_XZ 4
#define CGIZMO_TRANSLATE_YZ 5 #define CGIZMO_TRANSLATE_LINES_YZ 5
#define CGIZMO_TRANSLATE_POLY_XY 6
#define CGIZMO_TRANSLATE_POLY_XZ 7
#define CGIZMO_TRANSLATE_POLY_YZ 8
#define CGIZMO_ROTATE_X 0 #define CGIZMO_ROTATE_X 0
#define CGIZMO_ROTATE_Y 1 #define CGIZMO_ROTATE_Y 1
#define CGIZMO_ROTATE_Z 2 #define CGIZMO_ROTATE_Z 2
@ -22,10 +25,13 @@
#define CGIZMO_SCALE_X 0 #define CGIZMO_SCALE_X 0
#define CGIZMO_SCALE_Y 1 #define CGIZMO_SCALE_Y 1
#define CGIZMO_SCALE_Z 2 #define CGIZMO_SCALE_Z 2
#define CGIZMO_SCALE_XY 3 #define CGIZMO_SCALE_LINES_XY 3
#define CGIZMO_SCALE_XZ 4 #define CGIZMO_SCALE_LINES_XZ 4
#define CGIZMO_SCALE_YZ 5 #define CGIZMO_SCALE_LINES_YZ 5
#define CGIZMO_SCALE_XYZ 6 #define CGIZMO_SCALE_POLY_XY 6
#define CGIZMO_SCALE_POLY_XZ 7
#define CGIZMO_SCALE_POLY_YZ 8
#define CGIZMO_SCALE_XYZ 9
class CGizmo : public IRenderable class CGizmo : public IRenderable
{ {
@ -66,27 +72,31 @@ private:
bool mFlipScaleY; bool mFlipScaleY;
bool mFlipScaleZ; bool mFlipScaleZ;
// Static
struct SModelPart struct SModelPart
{ {
EGizmoAxes modelAxes; EGizmoAxes modelAxes;
bool enableRayCast;
CModel *pModel; CModel *pModel;
CToken modelToken; CToken modelToken;
SModelPart() {} SModelPart() {}
SModelPart(EGizmoAxes axes, CModel *_pModel) : SModelPart(EGizmoAxes axes, bool rayCastOn, CModel *_pModel) :
modelAxes(axes), pModel(_pModel), modelToken(_pModel) {} modelAxes(axes), enableRayCast(rayCastOn), pModel(_pModel), modelToken(_pModel) {}
}; };
SModelPart *mpCurrentParts;
u32 mNumCurrentParts;
// Static
static bool smModelsLoaded; static bool smModelsLoaded;
static SModelPart smTranslateModels[6]; static SModelPart smTranslateModels[9];
static SModelPart smRotateModels[4]; static SModelPart smRotateModels[4];
static SModelPart smScaleModels[7]; static SModelPart smScaleModels[10];
static SModelPart smRotateClipOutline; static SModelPart smRotateClipOutline;
public: public:
CGizmo(); CGizmo();
~CGizmo(); ~CGizmo();
void AddToRenderer(CRenderer *pRenderer); void AddToRenderer(CRenderer *pRenderer);
void DrawAsset(ERenderOptions options, u32 asset); void DrawAsset(ERenderOptions options, u32 asset);
void DrawRotationOutline(); void DrawRotationOutline();
@ -99,6 +109,7 @@ public:
EGizmoMode Mode(); EGizmoMode Mode();
void SetMode(EGizmoMode mode); void SetMode(EGizmoMode mode);
void SetPosition(const CVector3f& position); void SetPosition(const CVector3f& position);
void ResetSelectedAxes();
// Protected // Protected
protected: protected:

View File

@ -135,6 +135,10 @@ void CWorldEditor::ViewportRayCast(CRay Ray)
{ {
if (!ui->MainViewport->IsMouseInputActive()) if (!ui->MainViewport->IsMouseInputActive())
{ {
// Gizmo ray check
mGizmoHovering = mGizmo.IntersectsRay(Ray);
// Scene ray check
SRayIntersection Result = mpSceneManager->SceneRayCast(Ray); SRayIntersection Result = mpSceneManager->SceneRayCast(Ray);
if (Result.Hit) if (Result.Hit)
@ -151,8 +155,11 @@ void CWorldEditor::ViewportRayCast(CRay Ray)
ResetHover(); ResetHover();
} }
else else
{
mGizmo.ResetSelectedAxes();
ResetHover(); ResetHover();
} }
}
CRenderer* CWorldEditor::Renderer() CRenderer* CWorldEditor::Renderer()
{ {
@ -347,7 +354,9 @@ void CWorldEditor::UpdateCursor()
{ {
if (ui->MainViewport->IsCursorVisible()) if (ui->MainViewport->IsCursorVisible())
{ {
if ((mpHoverNode) && (mpHoverNode->NodeType() != eStaticNode)) if (mGizmoHovering)
ui->MainViewport->SetCursorState(Qt::SizeAllCursor);
else if ((mpHoverNode) && (mpHoverNode->NodeType() != eStaticNode))
ui->MainViewport->SetCursorState(Qt::PointingHandCursor); ui->MainViewport->SetCursorState(Qt::PointingHandCursor);
else else
ui->MainViewport->SetCursorState(Qt::ArrowCursor); ui->MainViewport->SetCursorState(Qt::ArrowCursor);
@ -359,7 +368,7 @@ void CWorldEditor::UpdateStatusBar()
// Would be cool to do more frequent status bar updates with more info. Unfortunately, this causes lag. // Would be cool to do more frequent status bar updates with more info. Unfortunately, this causes lag.
QString StatusText = ""; QString StatusText = "";
if (mpHoverNode) if (!mGizmoHovering && mpHoverNode)
{ {
if (mpHoverNode->NodeType() != eStaticNode) if (mpHoverNode->NodeType() != eStaticNode)
StatusText = QString::fromStdString(mpHoverNode->Name()); StatusText = QString::fromStdString(mpHoverNode->Name());

View File

@ -33,6 +33,7 @@ class CWorldEditor : public QMainWindow
CTimer mFrameTimer; CTimer mFrameTimer;
bool mDrawSky; bool mDrawSky;
bool mShowGizmo; bool mShowGizmo;
bool mGizmoHovering;
CVector3f mHoverPoint; CVector3f mHoverPoint;
CSceneNode *mpHoverNode; CSceneNode *mpHoverNode;