swift - 将屏幕坐标转换为 Metal 的标准化设备坐标
问题描述
我正在尝试使用用户触摸来渲染 2D 三角形。所以,我会让用户触摸屏幕上的三个点,这些点将用作三角形的顶点。
解决方案
您已经知道您需要从顶点着色器返回剪辑空间坐标(技术上不是标准化的设备坐标)。问题是如何以及从何处从 UIKit 坐标到 Metal 的剪辑空间坐标。
让我们从定义这些不同的空间开始。请注意,在下面,为了简单起见,我实际上使用 NDC 坐标,因为在这种特殊情况下,我们不会通过返回顶点位置来引入透视w != 1
。(这里我指w
的是剪辑空间位置的坐标;在下面的讨论中,w
总是指视图宽度)。
我们将顶点传递到我们的顶点着色器中任何方便的空间(这通常称为模型空间)。由于我们在 2D 中工作,我们不需要对世界空间进行通常的一系列转换,然后是眼睛空间。本质上,UIKit 视图的坐标是我们的模型空间、世界空间和眼睛空间合而为一。
我们需要某种正交投影矩阵来从这个空间移动到剪辑空间。如果我们去掉与 z 轴相关的不必要部分,并假设我们的视图边界的原点是 (0, 0),我们会得出以下转换:
我们可以将此矩阵传递给我们的顶点着色器,或者我们可以在将顶点发送到 GPU 之前进行转换。考虑到所涉及的数据很少,此时这真的无关紧要。事实上,使用矩阵有点浪费,因为我们可以通过乘法和加法来变换每个坐标。这是在 Metal 顶点函数中的样子:
float2 inverseViewSize(1.0f / width, 1.0f / height); // passed in a buffer
float clipX = (2.0f * in.position.x * inverseViewSize.x) - 1.0f;
float clipY = (2.0f * -in.position.y * inverseViewSize.y) + 1.0f;
float4 clipPosition(clipX, clipY, 0.0f, 1.0f);
只是为了验证我们从这个变换中得到了正确的结果,让我们插入我们视图的左上角和右下角点,以确保它们最终到达剪辑空间的末端(通过线性,如果这些点正确变换,那么所有其他人都会):
这些点看起来是正确的,所以我们完成了。如果您担心此转换引入的明显失真,请注意它会被光栅化之前发生的视口转换完全取消。
推荐阅读
- python - 在 Python 列表中使用一个字符串两次
- gcc - 为什么 `bool` 数据类型会使我的数据结构对 avr-gdb 不可读?
- python - 将 TriangulatePoints 与 SFM 与 Python 结合使用
- python - 如何减少我的代码的运行时间来计算 20000000 以下的所有素数的总和
- android - 为 cmake 执行外部原生构建,
- python - 为 CentOS 7 安装 python-dev|python-devel(安装 matplotlib 错误)
- .net - 当我将 Web 应用程序发布到 IIS 并将其部署到另一台设备上时,为什么会出现 System.StackOverflowException?
- wso2 - RegistryEventingServiceComponent 错误实例化注册表事件源和 CarbonServerManager WSO2 Carbon 初始化失败
- distributed-computing - 在监控主机之间分配子元素或顶级父元素
- python - Python 分发和打包,入口点设置