diff --git a/src/ui/TransformManipulator.cpp b/src/ui/TransformManipulator.cpp index d84ed1f..464f6e2 100644 --- a/src/ui/TransformManipulator.cpp +++ b/src/ui/TransformManipulator.cpp @@ -366,7 +366,11 @@ void TransformManipulator::DrawScaleGizmo(ImDrawList* dl, const pxr::GfMatrix4d& dl->AddLine(pivSS,tipSS,col,kScaleLineThick); dl->AddCircleFilled(tipSS,kScaleCircleRadius,col,16); } - dl->AddCircleFilled(pivSS,kCenterCircleRadius+1.f,kColCenter,16); + // Center dot: axis 3 = uniform scale handle + bool centerActive = (m_dragAxis==3||m_hoveredAxis==3); + ImU32 centerCol = centerActive ? kColHover : kColCenter; + float centerR = centerActive ? kCenterCircleRadius+3.f : kCenterCircleRadius+1.f; + dl->AddCircleFilled(pivSS,centerR,centerCol,16); } // ============================================================================ @@ -431,9 +435,25 @@ bool TransformManipulator::HandleInput(const pxr::GfMatrix4d& vp, // Hover update if (!m_isDragging && hovered) { - m_hoveredAxis=(m_mode==ManipulatorMode::Rotate) - ?HitTestRotateRings(vp,pivot,sf,camEye,imgPos,vW,vH,mouse,axes) - :HitTestAxes (vp,pivot,sf, imgPos,vW,vH,mouse,axes); + if (m_mode==ManipulatorMode::Rotate) { + m_hoveredAxis=HitTestRotateRings(vp,pivot,sf,camEye,imgPos,vW,vH,mouse,axes); + } else { + // Scale center check FIRST: the pivot is an endpoint of all three + // axis segments, so HitTestAxes always hits an axis (typically X) + // when the mouse is at the center. Check the center dot before + // falling through to the per-axis test. + m_hoveredAxis=-1; + if (m_mode==ManipulatorMode::Scale) { + ImVec2 pivSS; + if (WorldToScreen(pivot,vp,vW,vH,imgPos,pivSS)) { + float dx=mouse.x-pivSS.x, dy=mouse.y-pivSS.y; + if (std::sqrt(dx*dx+dy*dy)=0) { m_isDragging=true; m_dragAxis=hit; consumed=true; @@ -513,10 +546,19 @@ bool TransformManipulator::HandleInput(const pxr::GfMatrix4d& vp, m_dragRotateObjectSpace=(m_transformSpace==TransformSpace::Object); } else if (m_mode==ManipulatorMode::Scale) { - // usdtweak: _axisLine = GfLine(pivot, objectTransform.GetRow3(axis)) - m_dragScaleAxisLine=pxr::GfLine(pivot,axes[m_dragAxis]); - pxr::GfVec3d rpt; - pxr::GfFindClosestPoints(ray,m_dragScaleAxisLine,&rpt,&m_dragScaleOriginOnAxis); + if (m_dragAxis<3) { + // Single-axis scale: project onto world-space axis line + m_dragScaleAxisLine=pxr::GfLine(pivot,axes[m_dragAxis]); + pxr::GfVec3d rpt; + pxr::GfFindClosestPoints(ray,m_dragScaleAxisLine,&rpt,&m_dragScaleOriginOnAxis); + } else { + // Uniform scale (axis 3): mouse starts at the center circle, + // so the axis-line origin parameter oT ≈ 0 and cT/oT blows up. + // Use screen-space pixel delta instead: store drag-start mouse + // position in m_dragScaleOriginOnAxis.x/y, compute ratio as + // 1 + deltaX * sensitivity each frame. + m_dragScaleOriginOnAxis={double(mouse.x),double(mouse.y),0.0}; + } } } } @@ -527,7 +569,7 @@ bool TransformManipulator::HandleInput(const pxr::GfMatrix4d& vp, if (m_isDragging) { consumed=true; if (ImGui::IsMouseDown(ImGuiMouseButton_Left)) { - if (m_dragAxis<0||m_dragAxis>2) { m_isDragging=false;m_dragAxis=-1;return consumed; } + if (m_dragAxis<0||m_dragAxis>3) { m_isDragging=false;m_dragAxis=-1;return consumed; } pxr::GfRay ray=ComputeMouseRay(vp,mouse,imgPos,vW,vH); @@ -632,14 +674,25 @@ bool TransformManipulator::HandleInput(const pxr::GfMatrix4d& vp, // robust when the pivot is not at the world origin. // ----------------------------------------------------------------- else if (m_mode==ManipulatorMode::Scale) { - pxr::GfVec3d rpt,cur; - pxr::GfFindClosestPoints(ray,m_dragScaleAxisLine,&rpt,&cur); - double oT=0,cT=0; - m_dragScaleAxisLine.FindClosestPoint(m_dragScaleOriginOnAxis,&oT); - m_dragScaleAxisLine.FindClosestPoint(cur,&cT); - double ratio=(std::abs(oT)>1e-6)?cT/oT:1.0; pxr::GfVec3f ns=m_dragOriginalScale; - ns[m_dragAxis]=std::max(0.001f,float(double(m_dragOriginalScale[m_dragAxis])*ratio)); + if (m_dragAxis<3) { + // Single-axis: project onto world-space axis line. + pxr::GfVec3d rpt,cur; + pxr::GfFindClosestPoints(ray,m_dragScaleAxisLine,&rpt,&cur); + double oT=0,cT=0; + m_dragScaleAxisLine.FindClosestPoint(m_dragScaleOriginOnAxis,&oT); + m_dragScaleAxisLine.FindClosestPoint(cur,&cT); + double ratio=(std::abs(oT)>1e-6)?cT/oT:1.0; + ns[m_dragAxis]=std::max(0.001f,float(double(m_dragOriginalScale[m_dragAxis])*ratio)); + } else { + // Uniform scale: screen-space pixel delta → ratio. + // Right drag = grow, left drag = shrink. + // 200px right ≈ ×2 (sensitivity 0.005 per pixel). + double deltaX=double(mouse.x)-m_dragScaleOriginOnAxis[0]; + double ratio=std::max(0.001,1.0+deltaX*0.005); + for (int i=0;i<3;++i) + ns[i]=std::max(0.001f,float(double(m_dragOriginalScale[i])*ratio)); + } ApplyScale(ns); m_dragStartScale=ns; }