Gizmo raycasting implemented
This commit is contained in:
parent
44d0900125
commit
5977225aca
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
191
UI/CGizmo.cpp
191
UI/CGizmo.cpp
|
@ -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;
|
||||||
|
|
35
UI/CGizmo.h
35
UI/CGizmo.h
|
@ -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:
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue