Updated ImGuizmo.

This commit is contained in:
Branimir Karadžić
2016-09-11 09:11:32 -07:00
parent c8c2be5bf1
commit a99c23f649
2 changed files with 97 additions and 34 deletions

View File

@@ -1,5 +1,5 @@
// https://github.com/CedricGuillemet/ImGuizmo
// v 1.02 WIP
// v 1.03 WIP
//
// The MIT License(MIT)
//
@@ -25,17 +25,18 @@
//
// -------------------------------------------------------------------------------------------
// History :
// 2016/09/09 Hatched negative axis. Snapping. Documentation update.
// 2016/09/04 Axis switch and translation plan autohiding. Scale transform stability improved
// 2016/09/01 Mogwai changed to Manipulate. Draw debug cube. Fixed inverted scale. Mixing scale and translation/rotation gives bad results.
// 2016/08/31 First version
//
// -------------------------------------------------------------------------------------------
// Future:
// Future (no order):
//
// - Multi view
// - display rotation/translation/scale infos in local/world space and not only local
// - finish local/world matrix application
// - snap
// - OPERATION as bitmask
//
// -------------------------------------------------------------------------------------------
// Example
@@ -73,7 +74,7 @@
// if (ImGui::RadioButton("World", mCurrentGizmoMode == ImGuizmo::WORLD))
// mCurrentGizmoMode = ImGuizmo::WORLD;
//
// ImGuizmo::Mogwai(gCurrentCamera->mView.m16, gCurrentCamera->mProjection.m16, mCurrentGizmoOperation, mCurrentGizmoMode, gizmoMatrix.m16);
// ImGuizmo::Manipulate(gCurrentCamera->mView.m16, gCurrentCamera->mProjection.m16, mCurrentGizmoOperation, mCurrentGizmoMode, gizmoMatrix.m16);
//
#pragma once
@@ -128,5 +129,5 @@ namespace ImGuizmo
WORLD
};
void Manipulate(const float *view, const float *projection, OPERATION operation, MODE mode, float *matrix, float *deltaMatrix = 0);
void Manipulate(const float *view, const float *projection, OPERATION operation, MODE mode, float *matrix, float *deltaMatrix = 0, float *snap = 0);
};

View File

@@ -530,6 +530,7 @@ namespace ImGuizmo
// scale
vec_t mScale;
vec_t mScaleValueOrigin;
float mSaveMousePosx;
// save axis factor when using gizmo
bool mBelowAxisLimit[3];
@@ -550,7 +551,7 @@ namespace ImGuizmo
static const ImU32 selectionColor = 0xFF1080FF;
static const ImU32 inactiveColor = 0x99999999;
static const ImU32 translationLineColor = 0xAAAAAAAA;
static const char *translationInfoMask[] = { "X : %5.2f", "Y : %5.2f", "Z : %5.2f", "X : %5.2f Y : %5.2f", "Y : %5.2f Z : %5.2f", "X : %5.2f Z : %5.2f", "X : %5.2f Y : %5.2f Z : %5.2f" };
static const char *translationInfoMask[] = { "X : %5.3f", "Y : %5.3f", "Z : %5.3f", "X : %5.3f Y : %5.3f", "Y : %5.3f Z : %5.3f", "X : %5.3f Z : %5.3f", "X : %5.3f Y : %5.3f Z : %5.3f" };
static const char *scaleInfoMask[] = { "X : %5.2f", "Y : %5.2f", "Z : %5.2f", "XYZ : %5.2f" };
static const char *rotationInfoMask[] = { "X : %5.2f deg %5.2f rad", "Y : %5.2f deg %5.2f rad", "Z : %5.2f deg %5.2f rad", "Screen : %5.2f deg %5.2f rad" };
static const int translationInfoIndex[] = { 0,0,0, 1,0,0, 2,0,0, 0,1,0, 0,2,0, 1,2,0, 0,1,2 };
@@ -558,6 +559,7 @@ namespace ImGuizmo
static const float quadMax = 0.8f;
static const float quadUV[8] = { quadMin, quadMin, quadMin, quadMax, quadMax, quadMax, quadMax, quadMin };
static const int halfCircleSegmentCount = 64;
static const float snapTension = 0.5f;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
@@ -763,6 +765,39 @@ namespace ImGuizmo
}
}
static void ComputeSnap(float*value, float *snap)
{
if (*snap <= FLT_EPSILON)
return;
float modulo = fmodf(*value, *snap);
float moduloRatio = fabsf(modulo) / *snap;
if (moduloRatio < snapTension)
*value -= modulo;
else if (moduloRatio >(1.f - snapTension))
*value = *value - modulo + *snap * ((*value<0.f) ? -1.f : 1.f);
}
static void ComputeSnap(vec_t& value, float *snap)
{
for (int i = 0; i < 3; i++)
{
ComputeSnap(&value[i], &snap[i]);
}
}
static float ComputeAngleOnPlan()
{
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
vec_t localPos = Normalized(gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position);
vec_t perpendicularVector;
perpendicularVector.Cross(gContext.mRotationVectorSource, gContext.mTranslationPlan);
perpendicularVector.Normalize();
float acosAngle = Clamp(Dot(localPos, gContext.mRotationVectorSource), -0.9999f, 0.9999f);
float angle = acosf(acosAngle);
angle *= (Dot(localPos, perpendicularVector) < 0.f) ? 1.f : -1.f;
return angle;
}
static void DrawRotationGizmo(int type)
{
ImDrawList* drawList = gContext.mDrawList;
@@ -818,6 +853,16 @@ namespace ImGuizmo
}
}
static void DrawHatchedAxis(const vec_t& axis)
{
for (int j = 1; j < 10; j++)
{
ImVec2 baseSSpace2 = worldToPos(axis * 0.05f * (float)(j * 2) * gContext.mScreenFactor, gContext.mMVP);
ImVec2 worldDirSSpace2 = worldToPos(axis * 0.05f * (float)(j * 2 + 1) * gContext.mScreenFactor, gContext.mMVP);
gContext.mDrawList->AddLine(baseSSpace2, worldDirSSpace2, 0x80000000, 6.f);
}
}
static void DrawScaleGizmo(int type)
{
ImDrawList* drawList = gContext.mDrawList;
@@ -853,9 +898,12 @@ namespace ImGuizmo
drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, 0xFF404040, 6.f);
drawList->AddCircleFilled(worldDirSSpaceNoScale, 10.f, 0xFF404040);
}
drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 6.f);
drawList->AddCircleFilled(worldDirSSpace, 10.f, colors[i + 1]);
if (gContext.mAxisFactor[i] < 0.f)
DrawHatchedAxis(dirPlaneX * scaleDisplay[i]);
}
}
@@ -877,9 +925,9 @@ namespace ImGuizmo
drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), 0xFF000000, tmps);
drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), 0xFFFFFFFF, tmps);
}
}
static void DrawTranslationGizmo(int type)
{
ImDrawList* drawList = gContext.mDrawList;
@@ -905,6 +953,9 @@ namespace ImGuizmo
ImVec2 worldDirSSpace = worldToPos(dirPlaneX * gContext.mScreenFactor, gContext.mMVP);
drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 6.f);
if (gContext.mAxisFactor[i] < 0.f)
DrawHatchedAxis(dirPlaneX);
}
// draw plane
@@ -1047,7 +1098,7 @@ namespace ImGuizmo
return type;
}
static void HandleTranslation(float *matrix, float *deltaMatrix, int& type)
static void HandleTranslation(float *matrix, float *deltaMatrix, int& type, float *snap)
{
ImGuiIO& io = ImGui::GetIO();
@@ -1056,9 +1107,11 @@ namespace ImGuizmo
{
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
// compute delta
vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor;
vec_t delta = newOrigin - gContext.mModel.v.position;
// 1 axis constraint
if (gContext.mCurrentOperation >= MOVE_X && gContext.mCurrentOperation <= MOVE_Z)
{
@@ -1068,8 +1121,15 @@ namespace ImGuizmo
delta = axisValue * lengthOnAxis;
}
// snap
if (snap)
{
vec_t cumulativeDelta = gContext.mModel.v.position + delta - gContext.mMatrixOrigin;
ComputeSnap(cumulativeDelta, snap);
delta = gContext.mMatrixOrigin + cumulativeDelta - gContext.mModel.v.position;
}
// compute matrix & delta
gContext.mTranslationPlanOrigin += delta;
matrix_t deltaMatrixTranslation;
deltaMatrixTranslation.Translation(delta);
if (deltaMatrix)
@@ -1103,7 +1163,7 @@ namespace ImGuizmo
}
}
static void HandleScale(float *matrix, float *deltaMatrix, int& type)
static void HandleScale(float *matrix, float *deltaMatrix, int& type, float *snap)
{
ImGuiIO& io = ImGui::GetIO();
@@ -1125,6 +1185,7 @@ namespace ImGuizmo
gContext.mScale.Set(1.f, 1.f, 1.f);
gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor);
gContext.mScaleValueOrigin = makeVect(gContext.mModelSource.v.right.Length(), gContext.mModelSource.v.up.Length(), gContext.mModelSource.v.dir.Length());
gContext.mSaveMousePosx = io.MousePos.x;
}
}
// scale
@@ -1150,10 +1211,21 @@ namespace ImGuizmo
}
else
{
float scaleDelta = io.MouseDelta.x * 0.01f;
float scaleDelta = (io.MousePos.x - gContext.mSaveMousePosx) * 0.01f;
gContext.mScale.Set(max(1.f + scaleDelta, 0.001f));
}
// snap
if (snap)
{
float scaleSnap[] = { snap[0], snap[0], snap[0] };
ComputeSnap(gContext.mScale, scaleSnap);
}
// no 0 allowed
for (int i = 0; i < 3;i++)
gContext.mScale[i] = max(gContext.mScale[i], 0.001f);
// compute matrix & delta
matrix_t deltaMatrixScale;
deltaMatrixScale.Scale(gContext.mScale * gContext.mScaleValueOrigin);
@@ -1170,21 +1242,7 @@ namespace ImGuizmo
}
}
static float ComputeAngleOnPlan()
{
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
vec_t localPos = Normalized(gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position);
vec_t perpendicularVector;
perpendicularVector.Cross(gContext.mRotationVectorSource, gContext.mTranslationPlan);
perpendicularVector.Normalize();
float acosAngle = Clamp(Dot(localPos, gContext.mRotationVectorSource), -0.9999f, 0.9999f);
float angle = acosf(acosAngle);
angle *= (Dot(localPos, perpendicularVector) < 0.f) ? 1.f : -1.f;
return angle;
}
static void HandleRotation(float *matrix, float *deltaMatrix, int& type)
static void HandleRotation(float *matrix, float *deltaMatrix, int& type, float *snap)
{
ImGuiIO& io = ImGui::GetIO();
@@ -1210,7 +1268,11 @@ namespace ImGuizmo
if (gContext.mbUsing)
{
gContext.mRotationAngle = ComputeAngleOnPlan();
if (snap)
{
float snapInRadian = snap[0] * DEG2RAD;
ComputeSnap(&gContext.mRotationAngle, &snapInRadian);
}
vec_t rotationAxisLocalSpace;
rotationAxisLocalSpace.TransformVector(makeVect(gContext.mTranslationPlan.x, gContext.mTranslationPlan.y, gContext.mTranslationPlan.z, 0.f), gContext.mModelInverse);
@@ -1268,7 +1330,7 @@ namespace ImGuizmo
float validScale[3];
for (int i = 0; i < 3; i++)
{
if (fabsf(scale[i]) < FLT_EPSILON)
if (fabsf(scale[i] < FLT_EPSILON))
validScale[i] = 0.001f;
else
validScale[i] = scale[i];
@@ -1279,7 +1341,7 @@ namespace ImGuizmo
mat.v.position.Set(translation[0], translation[1], translation[2], 1.f);
}
void Manipulate(const float *view, const float *projection, OPERATION operation, MODE mode, float *matrix, float *deltaMatrix)
void Manipulate(const float *view, const float *projection, OPERATION operation, MODE mode, float *matrix, float *deltaMatrix, float *snap)
{
ComputeContext(view, projection, matrix, mode);
@@ -1293,13 +1355,13 @@ namespace ImGuizmo
switch (operation)
{
case ROTATE:
HandleRotation(matrix, deltaMatrix, type);
HandleRotation(matrix, deltaMatrix, type, snap);
break;
case TRANSLATE:
HandleTranslation(matrix, deltaMatrix, type);
HandleTranslation(matrix, deltaMatrix, type, snap);
break;
case SCALE:
HandleScale(matrix, deltaMatrix, type);
HandleScale(matrix, deltaMatrix, type, snap);
break;
}
}