c# - 如何围绕点缩放 Matrix4x4?
问题描述
我正在 Unity 中编写一个自定义编辑器窗口,我希望能够在其中滚动/滚动并拖动视图。为此,我一直设置GUI.matrix
为Matrix4x4.TRS(offset, Quaternion.identity, Vector3.one * scale)
,我可以控制offset
和scale
。这很好用,除非在滚动进/出时,它会锚定窗口的左上角。我希望它锚定在鼠标的位置上。
如果这只需要在缩放时更改偏移量,那就太好了 - 我只是不确定偏移量应该是多少。Matrix4x4
s超出了我的数学舒适区。
这是我目前处理缩放的方式:
if (Event.current.type == EventType.ScrollWheel)
{
_scale *= Math.Sign(Event.current.delta.y) == 1 ? 1.1f : 1f / 1.1f;
_offset += Math.Sign(Event.current.delta.y) * /*What do I put here?*/;
}
解决方案
让我们尝试了解 GUI 矩阵的作用。它表示一个转换,它在世界空间(您的 GUI 对象所在的位置)中获取坐标并将它们转换为 GUI 空间(或多或少与您的窗口对齐)。由于我们没有旋转,我们可以很容易地解释构造矩阵TRS()
对世界空间点的作用pWorld
:
pGUI = scale * pWorld + offset
现在您要更改scale
为scaleNew
. 这样做时,您希望在鼠标下保持相同的世界位置。
如果你的鼠标位置是在 GUI 空间中给出的(例如 from Event.current.mousePosition
),那么我们首先需要找到对应的世界空间点:
v3World = (1.0 / scaleOld) * (v3GUI - offsetOld)
我们想在鼠标下修复这个点,即:
v3GUI = scaleNew * v3World + offsetNew
v3GUI = scaleNew / scaleOld * (v3GUI - offsetOld) + offsetNew
我们可以解决这个问题以获得新的偏移量:
v3GUI = scaleNew / scaleOld * v3GUI - scaleNew / scaleOld * offsetOld + offsetNew
(1 - scaleNew / scaleOld) * v3GUI + scaleNew / scaleOld * offsetOld = offsetNew
就是这样。
Btw, you can also do this with matrix operations alone. This is what GUIUtility.ScaleAroundPivot()
does. This is how it looks:
newMatrix = T(v3GUI) * S(newScale / oldScale) * T(-v3GUI) * oldMatrix
T
represents a translation and S
a scaling. The translation pair T(v3GUI)
and T(-v3GUI)
move the temporary origin of the coordinate system to your mouse position and perform the scaling from there. You could then directly read offset and scale from this matrix.
推荐阅读
- kotlin - Gradle 包装器导致“类路径中的 JAR 文件应该具有相同的版本”错误
- html - 如何交叉检查html中的提示输入
- javascript - 为什么不同架构下 Javascript 的字节码(v8 引擎)生成不同
- unity3d - 斜坡上的树干漂浮在统一地形上
- go - GOPATH入口是相对的,必须是绝对路径,怎么解决
- python - VS Code 中 django 的 Virtualenv 不起作用,我做错了什么?
- javascript - 条形图y轴中的酒窝js多个值类型
- docker - Gitlab CI 挂在 npm run build 上(webpack 生产命令)
- c++ - 自底向上归并排序的实现
- vhdl - 这是编写 VHDL 异步复位的有效方法吗?