# Using a Render Pipeline to Render Primitives
Render a simple 2D triangle.
## Overview
In [Using Metal to Draw a View’s Contents](https://developer.apple.com/documentation/metal/basic_tasks_and_concepts/using_metal_to_draw_a_view_s_contents), you learned how to set up an `MTKView` object and to change the view's contents using a render pass.
That sample simply erased the view's contents to a background color.
This sample shows you how to configure a render pipeline and use it as part of the render pass to draw a simple 2D colored triangle into the view.
The sample supplies a position and color for each vertex, and the render pipeline uses that data to render the triangle, interpolating color values between the colors specified for the triangle's vertices.

The Xcode project contains schemes for running the sample on macOS, iOS, and tvOS.
## Understand the Metal Render Pipeline
A *render pipeline* processes drawing commands and writes data into a render pass’s targets.
A render pipeline has many stages, some programmed using shaders and others with fixed or configurable behavior.
This sample focuses on the three main stages of the pipeline: the vertex stage, the rasterization stage, and the fragment stage.
The vertex stage and fragment stage are programmable, so you write functions for them in Metal Shading Language (MSL).
The rasterization stage has fixed behavior.
**Figure 1** Main stages of the Metal graphics render pipeline

Rendering starts with a drawing command, which includes a vertex count and what kind of primitive to render. For example, here's the drawing command from this sample:
``` objective-c
// Draw the triangle.
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle
vertexStart:0
vertexCount:3];
```
The vertex stage provides data for each vertex. When enough vertices have been processed, the render pipeline rasterizes the primitive, determining which pixels in the render targets lie within the boundaries of the primitive. The fragment stage determines the values to write into the render targets for those pixels.
In the rest of this sample, you will see how to write the vertex and fragment functions, how to create the render pipeline state object, and finally, how to encode a draw command that uses this pipeline.
## Decide How Data is Processed by Your Custom Render Pipeline
A vertex function generates data for a single vertex and a fragment function generates data for a single fragment, but you decide how they work.
You configure the stages of the pipeline with a goal in mind, meaning that you know what you want the pipeline to generate and how it generates those results.
Decide what data to pass into your render pipeline and what data is passed to later stages of the pipeline. There are typically three places where you do this:
- The inputs to the pipeline, which are provided by your app and passed to the vertex stage.
- The outputs of the vertex stage, which is passed to the rasterization stage.
- The inputs to the fragment stage, which are provided by your app or generated by the rasterization stage.
In this sample, the input data for the pipeline is the position of a vertex and its color. To demonstrate the kind of transformation you typically perform in a vertex function, input coordinates are defined in a custom coordinate space, measured in pixels from the center of the view. These coordinates need to be translated into Metal's coordinate system.
Declare an `AAPLVertex` structure, using SIMD vector types to hold the position and color data.
To share a single definition for how the structure is laid out in memory, declare the structure in a common header and import it in both the Metal shader and the app.
``` objective-c
typedef struct
{
vector_float2 position;
vector_float4 color;
} AAPLVertex;
```
SIMD types are commonplace in Metal Shading Language, and you should also use them in your app using the simd library.
SIMD types contain multiple channels of a particular data type, so declaring the position as a `vector_float2` means it contains two 32-bit float values (which will hold the x and y coordinates.)
Colors are stored using a `vector_float4`, so they have four channels – red, green, blue, and alpha.
In the app, the input data is specified using a constant array:
``` objective-c
static const AAPLVertex triangleVertices[] =
{
// 2D positions, RGBA colors
{ { 250, -250 }, { 1, 0, 0, 1 } },
{ { -250, -250 }, { 0, 1, 0, 1 } },
{ { 0, 250 }, { 0, 0, 1, 1 } },
};
```
The vertex stage generates data for a vertex, so it needs to provide a color and a transformed position.
Declare a `RasterizerData` structure containing a position and a color value, again using SIMD types.
``` metal
struct RasterizerData
{
// The [[position]] attribute of this member indicates that this value
// is the clip space position of the vertex when this structure is
// returned from the vertex function.
float4 position [[position]];
// Since this member does not have a special attribute, the rasterizer
// interpolates its value with the values of the other triangle vertices
// and then passes the interpolated value to the fragment shader for each
// fragment in the triangle.
float4 color;
};
```
The output position (described in detail below) must be defined as a `vector_float4`. The color is declared as it was in the input data structure.
You need to tell Metal which field in the rasterization data provides position data, because Metal doesn't enforce any particular naming convention for fields in your struct.
Annotate the `position` field with the `[[position]]` attribute qualifier to declare that this field holds the output position.
The fragment function simply passes the rasterization stage's data to later stages so it doesn't need any additional arguments.
## Declare the Vertex Function
Declare the vertex function, including its input arguments and the data it outputs.
Much like compute functions were declared using the `kernel` keyword, you declare a vertex function using the `vertex` keyword.
``` metal
vertex RasterizerData
vertexShader(uint vertexID [[vertex_id]],
constant AAPLVertex *vertices [[buffer(AAPLVertexInputIndexVertices)]],
constant vector_uint2 *viewportSizePointer [[buffer(AAPLVertexInputIndexViewportSize)]])
```
The first argument, `vertexID`, uses the `[[vertex_id]]` attribute qualifier, which is another Metal keyword.
When you execute a render command, the GPU calls your vertex function multiple times, generating a unique value for each vertex.
The second argument, `vertices`, is an array that contains the vertex data, using the `AAPLVertex` struct previously defined.
To transform the position into Metal's coordinates, the function needs the size of the viewport (in pixels) that the triangle is being drawn into, so this is stored in the `viewportSizePointer` argument.
The second and third arguments have the `[[buffer(n)]]` attribute qualifier.
By default, Metal assigns slots in the argument table for each parameter automatically.
When you add the `[[buffer(n)]]` qualifier to a buffer argument, you tell Metal explicitly which slot to use.
Declaring slots explicitly can make it easier to revise your shaders without also needing to change your app code.
Declare the constants for the two indicies in the shared header file.
The function's output is a `RasterizerData` struct.
## Write the Vertex Function
Your vertex function must generate both fields of the output struct.
Use the `vertexID` argument to index into the `vertices` array and read the input data for the vertex.
Also, retrieve the viewport dimensions.
``` metal
float2 pixelSpacePosition = vertices[vertexID].position.xy;
// Get the viewport siz


新华
- 粉丝: 1w+
- 资源: 628
最新资源
- 基于多智能体事件触发的一致性控制:状态轨迹、控制输入与事件触发图详解(附参考图形),基于多智能体事件触发的一致性控制:状态轨迹、控制输入与事件触发机制详解及图形展示,多智能体事件触发、一致性控制 状态
- 基于BP神经网络结合高阶累积量的信号识别技术:实现BPSK、QPSK、8PSK、32QAM信号的准确识别与Matlab实现详解,BP神经网络结合高阶累积量信号识别技术:实现BPSK、QPSK、8PSK
- 大学生校园社团小程序源码云开发前后端完整代码.zip
- 高性能直流无刷电机参数详解:外径41mm,转速高达6000rpm,功率达200W,槽满率67.5%,效率80.7%,最大输出功率达320W,高性能直流无刷电机参数详解:转速高达6000rpm,功率达2
- 小麦种子图像分类数据集【已标注,约2,000张数据】
- 校园帮-WeChat-基于微信小程序的“校园帮”系统设计与实现(毕业论文)
- 多功能工具箱微信小程序源码.zip
- 狼人杀微信娱乐游戏小程序源码.zip
- 基于BP神经网络的回归预测:多个输出数据的分析与MATLAB代码实现,基于BP神经网络的多元输出数据回归预测技术研究与实践-以MATLAB代码为例,基于BP神经网络的多个输出数据的回归预测 matl
- 云开发谁是卧底线下小游戏发牌助手微信小程序源码.zip
- 最新版去水印小程序源码.zip
- 探索各类光波场的仿真与可视化:MATLAB的应用与实践,深入探索:各类光波场在MATLAB环境下的仿真研究与应用,各类光波场的MATLAB仿真 ,光波场仿真; MATLAB仿真; 仿真分析; 模拟;
- https://upload.csdn.net/creation/uploadResources?spm=1011.2124.3001.5646
- 应用商店-安卓-基于Android的应用商店设计与实现(毕业论文)
- 基于高斯过程回归算法的精准时间序列区间预测技术,高斯过程回归在时序区间预测中的应用与研究,基于高斯过程回归(GPR)的时间序列区间预测 ,基于高斯过程回归(GPR); 时间序列; 区间预测,基于高斯过
- 多相交错图腾柱PFC的C代码实现:优化算法与电流纹波控制技术,深度探究多相交错图腾柱PFC的C代码实现:优化算法以减小电流纹波,多相交错图腾柱PFC,C代码实现,电流纹波小 ,多相交错图腾柱PFC
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈


