我正在尝试使用用户触摸来渲染一个二维三角形。因此,我将让用户在屏幕上触摸三个点,并将这些点用作三角形的顶点。
w!= 1
的顶点位置引入透视。(这里我指的是剪辑空间位置的w
坐标;在接下来的讨论中,w
始终指视图宽度)。
我们将顶点传递到方便的空间中(通常称为模型空间)中的顶点着色器中。由于我们在2D中工作,因此不需要通常的从世界空间到眼睛空间的一系列变换。实际上,UIKit视图的坐标是我们的模型空间、世界空间和眼睛空间的全部。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);
为了验证我们从这个转换中获得正确的结果,让我们插入视图的左上角和右下角点,以确保它们最终位于剪辑空间的极端位置(通过线性性,如果这些点正确地变换,那么所有其他点也将如此):
这些观点是正确的,所以我们完成了。如果你担心这种转换引入的明显扭曲,注意它正好被视口变换抵消了,在光栅化之前发生。
float2 convert_to_metal_coordinates(float2 point, float2 viewSize) {
float2 inverseViewSize = 1 / viewSize;
float clipX = (2.0f * point.x * inverseViewSize.x) - 1.0f;
float clipY = (2.0f * -point.y * inverseViewSize.y) + 1.0f;
return float2(clipX, clipY);
}
bounds
(即viewSize
)通过顶点函数的缓冲参数传递给Metal。请注意保留HTML标签。func convertToMetalCoordinates(point: CGPoint, viewSize: CGSize) -> simd_float2 {
let inverseViewSize = CGSize(width: 1.0 / viewSize.width, height: 1.0 / viewSize.height)
let clipX = Float((2.0 * point.x * inverseViewSize.width) - 1.0)
let clipY = Float((2.0 * -point.y * inverseViewSize.height) + 1.0)
return simd_float2(clipX, clipY)
}