Metal学习资料,渲染管线、坐标空间和着色器
所属分类:ios | 发布于 2024-12-21
前言、学习资料
杂乱的资料网上有很多,系统的学习推荐 《Metal by Tutorials, Beginning Game Engine Development With Metal》。
官方地址:Metal by Tutorials,目前是第四版,需付费购买,不过在网上可以搜到免费的pdf。
书籍源码:https://github.com/kodecocodes/met-materials
中文系列教程:Metal 入门学习,后记,经过实践,发现这个教程深涩难懂,不过那几个介绍概念的文章还是蛮有用的。
一、渲染管线
渲染管线每个阶段的抽象展示:
二、坐标空间
一个顶点在渲染中,通常会经历6个坐标空间:
1. 物体局部空间
2. 世界空间: 世界空间的中心位置在(0, 0, 0)
3. 相机空间:在相机空间中,相机本身是在(0, 0, 0),而世界的中心是对着它们拍照的拿着相机的人。当相机移动时,相机的位置一直保持在(0, 0, 0),其它物体会相对相机移动。
4. 裁剪空间:这个空间存在的意义是:我们需要转换一个3D场景投影到一个2D场景。裁剪空间是一个立方体,并准备好扁平处理。
5. 规格化设备空间:NDC(Normalized Device Coordinate),投影到裁剪空间时创建了一个半w尺寸的立方体盒子,在光栅化时,GPU会转换w到正交坐标系+d的点,x和y轴的取值范围规格化到-1到1,而z轴的取值范围规格化到0到1。
6. 屏幕空间:现在GPU已经有一个正交化+的立方体了。它会把裁剪空间平面化,并且转换到屏幕坐标系中,准备好显示到设备的屏幕中。(比如在iPhone16,屏幕空间分别率应该是2532*1170)。
几个空间坐标变化大致如下:
Metal的坐标系
1、Metal默认坐标系是标准化坐标系。
这意味着默认情况下看到的是一个以(0, 0, 0.5)为中心的 2x2x1 的立方体。
如果考虑z = 0平面,则 (-1, -1, 0)为左下角,(1, -1, 0)为右下角,(0, 0, 0)为中心,(-1, 1, 0) 为左上角,(1, 1, 0)为右上角。
2. 顶点坐标系是四维的(x, y, z, w),原点在画布的正中心。采用左手坐标系。
3. 纹理坐标系是二维的(x, y), 原点在图片的左上角
三、几个重要概念:
像素:一个图形由许多许多像素组成。
顶点着色器:将原图像的3D坐标转换成适应屏幕的3D坐标,同时建立需要绘制的顶点坐标 与 需要采样的纹理坐标的映射关系。在开发中,我们需要预先设好顶点坐标与纹理坐标的映射,供系统内部光栅化处理,最后传到片段着色器中。
纹理:用于被采样器采样,给片段着色器上色的图像。在开发中,我们需要读取图像的字节,动用接口生成纹理。
片段着色器:基于顶点着色器的输出、纹理的采样结果,输出一个个着色后的像素,这些像素组成了一整个图像。在开发中,我们需要根据顶点着色器输出(光栅化处理后)的数据、纹理数据,对纹理进行采样,并输出该光栅化像素对应的rbga。
四、Vertex Function
输入:由用户自定义,通过setVertexBuffer(buffer: offset: index) 或者 setVertexBytes(bytes: length: index)传入,数据结构无明显限制,含有Vertex Function的输出所必须得信息即可。
输出:一般有以下两种格式,第一种格式用于绘制三角形、正方形等几何图形;第二种格式用于“贴图”或涉及Texture的处理。
// for draw triangle
struct RasterizerData
{
float4 position [[position]];
float4 color;
};
// for draw texture
struct RasterizerTexureData
{
float4 position [[position]];
float2 textureCoordinate;
};
五、Fragment Function
输入:一是复用传入过来光栅器的数据([[stage_in]]标识),二是用户设置的Buffer(无格式要求)和Texture(有格式要求),通过setFragmentBuffer(buffer: offset: index), setFragmentBytes(bytes: length: index),setFragmentTexture(texture: index)等设置。
输出:float4+(顶点的RGBA颜色)。Fregment Function之后没有课编程的环节,再返回也就没有意义了。