《Metal》官方文档翻译007--图形渲染:渲染命令编码器(上)

本章介绍如何创建和使用MTLRenderCommandEncoder以及MTLParallelRenderCommandEncoder用于将图形渲染命令编码到命令缓冲区中的对象。MTLRenderCommandEncoder命令描述了一个图形渲染管道,如图5-1所示。

图5-1 Metal图形呈现管道

一个MTLRenderCommandEncoder对象表示一个渲染命令编码器。一个MTLParallelRenderCommandEncoder对象使单个渲染遍可以分解成多个单独的MTLRenderCommandEncoder对象,每个对象可以分配给一个不同的线程。然后,来自不同渲染命令编码器的命令被链接在一起并以一致且可预测的顺序执行,如针对渲染通过的多线程所述

创建和使用渲染命令编码器

要创建,初始化和使用单个渲染命令编码器:

1:创建一个MTLRenderPassDescriptor对象来定义一个附件集合,该附件作为渲染过程的命令缓冲区中的图形命令的渲染目的地。通常,您创建一个MTLRenderPassDescriptor对象一次,并在应用程序呈现一帧时重用该对象。请参阅创建渲染通过描述符

2:MTLRenderCommandEncoder通过调用指定的渲染遍历描述符的renderCommandEncoderWithDescriptor:方法来创建对象MTLCommandBuffer。请参阅使用渲染通过描述符创建渲染命令编码器

3:创建一个MTLRenderPipelineState对象以定义一个或多个绘图调用的图形渲染管线(包括着色器,混合,多采样和可见性测试)的状态。要使用此渲染流水线状态绘制图元,请调用其setRenderPipelineState:方法
MTLRenderCommandEncoder。有关详细信息,请参阅创建渲染管道状态

4:设置渲染命令编码器使用的纹理,缓冲区和采样器,如为渲染命令编码器指定资源所述

5:调用MTLRenderCommandEncoder方法来指定额外的固定功能状态,包括深度和模板状态,如固定功能状态操作中所述

6:最后,调用MTLRenderCommandEncoder绘制图形基元的方法,如“ 图形几何基元”中所述

创建渲染通过描述符

一个MTLRenderPassDescriptor对象表示编码渲染命令的目的地,它是附件的集合。渲染遍历描述符的属性可以包括用于彩色像素数据的多达四个附件的阵列,用于深度像素数据的一个附件和用于模版像素数据的一个附件。的renderPassDescriptor便利方法创建一个MTLRenderPassDescriptor带有颜色,深度,和使用默认安装状态模版附件属性对象。该visibilityResultBuffer属性指定设备可以更新的缓冲区,以指示是否有任何样品通过深度和模板测试 - 有关详细信息,请参阅固定功能状态操作

每个单独的附件,包括将被写入的纹理由附件描述符表示。对于附件描述符,必须适当地选择关联纹理的像素格式以存储颜色,深度或模板数据。对于颜色附加描述符,请MTLRenderPassColorAttachmentDescriptor使用可呈现颜色的像素格式。对于深度附件描述符,请MTLRenderPassDepthAttachmentDescriptor使用深度可渲染像素格式,例如MTLPixelFormatDepth32Float。对于模板附件描述符,MTLRenderPassStencilAttachmentDescriptor使用模板可渲染像素格式,例如MTLPixelFormatStencil8

纹理在设备上每个像素实际使用的内存量并不总是与Metal框架代码中纹理像素格式的大小匹配,因为设备添加了填充以进行对齐或其他目的。有关每个像素格式实际使用的内存量以及附件大小和数量的限制,请参阅“ Metal特征集表”一章。

加载和存储操作

loadActionstoreAction附接描述符的属性指定在开始或一个渲染通道的端部执行的动作。(对于MTLParallelRenderCommandEncoder,加载和存储操作发生在整个命令的边界,而不是每个MTLRenderCommandEncoder对象的边界。有关详细信息,请参阅多个线程进行渲染传递。)

可能的loadAction值包括:

如果您的应用程序将呈现给定帧的附件的所有像​​素,请使用默认加载操作MTLLoadActionDontCare。该MTLLoadActionDontCare操作允许GPU避免加载纹理的现有内容,确保最佳性能。否则,您可以使用该MTLLoadActionClear操作来清除附件的以前内容或MTLLoadActionLoad保留它们的操作。该MTLLoadActionClear动作也避免了加载现有的纹理内容,但是会导致以纯色填充目的地的费用。

可能的storeAction值包括:

对于颜色附件,MTLStoreActionStore操作是默认存储操作,因为应用程序在渲染通过结束时几乎总是保留附件中的最终颜色值。对于深度和模板附件,MTLStoreActionDontCare是默认存储操作,因为这些附件通常在渲染遍完成后通常不需要保留。

指定清除负载动作

如果loadAction附件描述符的属性设置为MTLLoadActionClear,则在渲染过程开始时将清除值写入指定附件描述符中的每个像素。清算价值属性取决于附件的类型。

示例:使用加载和存储操作创建渲染传递描述符

清单5-1创建了一个带有颜色和深度附件的简单渲染遍历描述符。首先,创建两个纹理对象,一个具有可呈现颜色的像素格式,另一个具有深度像素格式。接下来renderPassDescriptorMTLRenderPassDescriptor创建一个默认渲染传递描述符的方便方法。然后通过属性访问颜色和深度附件MTLRenderPassDescriptor。纹理和动作被设置colorAttachments[0],代表第一个颜色附件(在数组的索引0)和深度附件。

清单5-1 使用颜色和深度附件创建渲染通过描述符

MTLTextureDescriptor * colorTexDesc = [MTLTextureDescriptor

texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm

width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];

id <MTLTexture> colorTex = [device newTextureWithDescriptor:colorTexDesc];

MTLTextureDescriptor * depthTexDesc = [MTLTextureDescriptor

texture2DDescriptorWithPixelFormat:MTLPixelFormatDepth32Float

width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];

id <MTLTexture> depthTex = [device newTextureWithDescriptor:depthTexDesc];

MTLRenderPassDescriptor * renderPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];

renderPassDesc.colorAttachments [0] .texture = colorTex;

renderPassDesc.colorAttachments [0] .loadAction = MTLLoadActionClear;

renderPassDesc.colorAttachments [0] .storeAction = MTLStoreActionStore;

renderPassDesc.colorAttachments [0] .clearColor = MTLClearColorMake(0.0,1.0,0.0,1.0);

renderPassDesc.depthAttachment.texture = depthTex;

renderPassDesc.depthAttachment.loadAction = MTLLoadActionClear;

renderPassDesc.depthAttachment.storeAction = MTLStoreActionStore;

renderPassDesc.depthAttachment.clearDepth = 1.0;

示例:创建多采样渲染的渲染通过描述符

要使用该MTLStoreActionMultisampleResolve操作,您必须将该texture属性设置为多采样类型的纹理,该resolveTexture属性将包含多重采样解析操作的结果。(如果texture不支持多重采样,然后多重采样解析操作的结果是不确定的。)的resolveLevelresolveSliceresolveDepthPlane性能也可以用于多重采样解析操作来指定的mipmap水平,立方体切片,和多重采样纹理的深度平面,分别。在大多数情况下,默认值resolveLevel,resolveSlice以及resolveDepthPlane是可用的。在清单5-2,初始创建附件,然后它的loadAction,storeAction,texture,和resolveTexture属性被设置为支持多重采样的决心。

清单5-2 设置具有多次采样解析的附件的属性

MTLTextureDescriptor * colorTexDesc = [MTLTextureDescriptor

texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm

width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];

id <MTLTexture> colorTex = [device newTextureWithDescriptor:colorTexDesc];

MTLTextureDescriptor * msaaTexDesc = [MTLTextureDescriptor

texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm

width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];

msaaTexDesc.textureType = MTLTextureType2DMultisample;

msaaTexDesc.sampleCount = sampleCount; //必须> 1

id <MTLTexture> msaaTex = [device newTextureWithDescriptor:msaaTexDesc];

MTLRenderPassDescriptor * renderPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];

renderPassDesc.colorAttachments [0] .texture = msaaTex;

renderPassDesc.colorAttachments [0] .resolveTexture = colorTex;

renderPassDesc.colorAttachments [0] .loadAction = MTLLoadActionClear;

renderPassDesc.colorAttachments [0] .storeAction = MTLStoreActionMultisampleResolve;

renderPassDesc.colorAttachments [0] .clearColor = MTLClearColorMake(0.0,1.0,0.0,1.0);

使用渲染通过描述符创建渲染命令编码器

创建渲染传递描述符并指定其属性后,使用对象的renderCommandEncoderWithDescriptor:方法MTLCommandBuffer创建一个render命令编码器,如清单5-3所示。

清单5-3 使用渲染通过描述符创建渲染命令编码器

id <MTLRenderCommandEncoder> renderCE = [commandBuffer

renderCommandEncoderWithDescriptor:renderPassDesc];

用核心动画显示呈现的内容

Core Animation定义了这个CAMetalLayer类,它是针对其内容使用Metal呈现的层支持视图的专门行为而设计的。甲CAMetalLayer对象表示关于内容(位置和尺寸)的几何形状的信息,它的视觉属性(背景色,边框和阴影),和由Metal所使用的资源以呈现在彩色附件的内容。它还封装了内容呈现的时间,以便内容可以在可用或在指定的时间一直显示。有关核心动画的更多信息,请参阅核心动画编程指南

核心动画还定义了CAMetalDrawable可显示资源的对象的协议。该CAMetalDrawable协议扩展MTLDrawable并提供符合MTLTexture协议的对象,因此可以将其用作渲染命令的目的地。要渲染成一个
CAMetalLayer对象,您应该CAMetalDrawable为每个渲染遍获取一个新对象,获取MTLTexture它提供的对象,并使用该纹理创建颜色附件。与颜色附件不同,深度或模板附件的创建和销毁是昂贵的。如果您需要深度或模板附件,请创建它们一次,然后在每次渲染框架时重用它们。

通常,您可以使用该layerClass方法将其指定CAMetalLayer为您自己的自定义UIView子类的后盾层类型,如清单5-4所示。否则,您可以CAMetalLayer使用其init方法创建一个,并将图层包含在现有视图中。

清单5-4 使用CAMetalLayer作为UIView子类的后盾层

+ (id) layerClass {
return [CAMetalLayer class];
}

要显示由Metal在图层中呈现的内容,您必须CAMetalDrawable从CAMetalLayer对象获取可显示的资源(对象),然后通过将其附加到MTLRenderPassDescriptor对象来渲染到该资源中的纹理。为此,您首先设置CAMetalLayer描述其提供的可绘制资源的对象的属性,然后在nextDrawable每次开始渲染新框架时调用其方法。如果CAMetalLayer属性未设置,nextDrawable方法调用失败。以下CAMetalLayer属性描述可绘制对象:

  • device属性声明MTLDevice资源创建的对象。

  • pixelFormat属性声明纹理的像素格式。支持的值是MTLPixelFormatBGRA8Unorm(默认值)和MTLPixelFormatBGRA8Unorm_sRGB

  • drawableSize属性声明了设备像素中纹理的尺寸。为了确保您的应用程序以显示的精确尺寸呈现内容(无需在某些设备上进行附加采样阶段),请在计算图层所需的大小时,将目标屏幕nativeScalenativeBounds属性考虑在内。

  • framebufferOnly属性声明纹理是否只能用作附件(YES),或者它是否也可以用于纹理采样和像素读取/写入操(NO)。如果YES,层对象可以优化显示纹理。对于大多数应用,建议的值为YES。

  • presentsWithTransaction属性声明是否使用标准的Core Animation事务机制(YES)更新了层渲染资源的更改,或者与异常更新(NO默认值)异常更新。

如果nextDrawable方法成功,它返回一个CAMetalDrawable具有以下只读属性的对象:

重要提示: 只有一小部分可绘制的资源,因此长帧渲染时间可能暂时耗尽这些资源,并导致nextDrawable方法调用阻止其CPU线程直到该方法完成。为了避免昂贵的CPU停止,请在调用对象的nextDrawable方法之前执行不需要可绘制资源的所有每帧操作CAMetalLayer。

要在渲染完成后显示可绘制对象的内容,您必须通过调用可绘制对象的present方法将其提交给Core Animation 。要同步与负责其呈现命令缓冲区完成一个绘制的介绍,你可以调用的presentDrawable:还是
presentDrawable:atTime:一个上方便的方法MTLCommandBuffer对象。这些方法使用调度处理程序(请参阅注册处理程序块进行命令缓冲区执行)来调用drawable的present方法,该方法涵盖大多数场景。该presentDrawable:atTime:方法进一步控制何时显示可绘制。

创建渲染管道状态

要使用MTLRenderCommandEncoder对象编码渲染命令,必须首先指定一个MTLRenderPipelineState对象来定义任何绘图调用的图形状态。渲染流水线状态对象是一个长寿命的持久对象,可以在渲染命令编码器之外创建,提前高速缓存,并重用于多个渲染命令编码器。当描述相同的图形状态集时,重新使用先前创建的渲染流水线状态对象可以避免重新评估并将指定状态转换为GPU命令的昂贵的操作。

渲染管道状态是一个不可变的对象。要创建渲染流水线状态,您首先创建并配置一个MTLRenderPipelineDescriptor描述呈现管道状态的属性的可变对象。然后,使用描述符创建一个MTLRenderPipelineState对象。

创建和配置渲染流水线描述符

要创建一个渲染流水线状态,首先创建一个MTLRenderPipelineDescriptor对象,该对象具有描述在渲染过程中要使用的图形渲染流水线状态的属性,如图5-2所示。colorAttachments新MTLRenderPipelineDescriptor对象的属性包含一个对象数组MTLRenderPipelineColorAttachmentDescriptor,每个描述符表示一个颜色附加状态,它指定该附件的混合操作和因子,如“ 渲染流水线附件描述符中的配置混合”中所详述。附件描述符还指定附件的像素格式,它必须与渲染流水线描述符的纹理与相应附件索引的像素格式匹配,否则发生错误。

图5-2 从描述符创建渲染管道状态

除了配置颜色附件之外,还要为MTLRenderPipelineDescriptor对象设置这些属性:

从描述符创建渲染管道状态

创建渲染流水线描述符并指定其属性后,使用它创建MTLRenderPipelineState对象。因为创建渲染流水线状态可能需要昂贵的图形状态评估和可能的指定图形着色器的编译,所以您可以使用阻塞或异步方法来以最适合您应用程序设计的方式安排此类工作。

创建MTLRenderPipelineState对象时,您还可以选择创建反映数据,以显示管道的着色器函数及其参数的详细信息。该newRenderPipelineStateWithDescriptor:options:reflection:error:newRenderPipelineStateWithDescriptor:options:completionHandler:方法提供这些数据。如果不使用反射数据,请避免使用。有关如何分析反射数据的更多信息,请参阅在运行时确定功能详细信息

创建后MTLRenderPipelineState的对象,调用setRenderPipelineState:
的方法MTLRenderCommandEncoder来渲染管线状态在渲染使用命令编码器相关联。

清单5-5演示了创建一个调用的渲染管道状态对象pipeline。

MTLRenderPipelineDescriptor * renderPipelineDesc =
                         [[MTLRenderPipelineDescriptor alloc] init];
renderPipelineDesc.vertexFunction = vertFunc;
renderPipelineDesc.fragmentFunction = fragFunc;
renderPipelineDesc.colorAttachments [0] .pixelFormat = MTLPixelFormatRGBA8Unorm;

//从MTLRenderPipelineDescriptor创建MTLRenderPipelineState
NSError * errors = nil;
id <MTLRenderPipelineState> pipeline = [device
     newRenderPipelineStateWithDescriptor:
renderPipelineDesc error:&errors];
assert(pipeline &&!errors);

//设置MTLRenderCommandEncoder的流水线状态
[renderCE setRenderPipelineState:pipeline];

变量vertFunc和fragFunc是被指定为称为渲染流水线状态描述符的性质着色器的功能renderPipelineDesc。同时调用对象的newRenderPipelineStateWithDescriptor:error:方法MTLDevice使用流水线状态描述符来创建渲染管道状态对象。调用指定与render命令编码器一起使用的对象的setRenderPipelineState:方法。MTLRenderCommandEncoderMTLRenderPipelineState

注意: 因为一个MTLRenderPipelineState对象创建成本很高,所以当你想要使用相同的图形状态时,应该重用它。

在渲染管道附件描述符中配置混合

混合使用高度可配置的混合操作来将片段功能(源)返回的输出与附件(目标)中的像素值进行混合。混合操作决定了源和目标值如何与混合因子相结合。

要为颜色附件配置混合,请设置以下MTLRenderPipelineColorAttachmentDescriptor属性:

了解混合因素和操作

四个交融因素是指恒定混合颜色值:MTLBlendFactorBlendColor,
MTLBlendFactorOneMinusBlendColor,MTLBlendFactorBlendAlpha,和MTLBlendFactorOneMinusBlendAlpha。调用setBlendColorRed:green:blue:alpha:的方法MTLRenderCommandEncoder,以指定与这些混合因子使用的恒定的颜色和α值,如在固定功能状态的操作

一些混合操作通过将源值乘以源MTLBlendFactor值(缩写为SBF),将目标值乘以目标混合因子(DBF),并使用由该MTLBlendOperation值表示的算术来组合结果来组合分段值。(如果该混合操作是任一MTLBlendOperationMin或MTLBlendOperationMax下,SBF和DBF混合因子被忽略。)例如,MTLBlendOperationAdd对于既rgbBlendOperation和alphaBlendOperation性质定义了用于RGB和α值以下添加剂混合操作:

  • RGB =(Source.rgb * sourceRGBBlendFactor)+(Dest.rgb * destinationRGBBlendFactor)
  • Alpha =(Source.a * sourceAlphaBlendFactor)+(Dest.a * destinationAlphaBlendFactor)

在默认混合行为中,源会完全覆盖目的地。这种行为等同于同时设置sourceRGBBlendFactor并sourceAlphaBlendFactor以MTLBlendFactorOne和destinationRGBBlendFactor和destinationAlphaBlendFactor到MTLBlendFactorZero。这种行为在数学上表示为:

  • RGB =(Source.rgb * 1.0)+(Dest.rgb * 0.0
  • A =(Source.a * 1.0)+(Dest.a * 0.0)

另一种常用的混合操作,其中源alpha定义剩余多少目的地颜色,可以用数学表达为:

  • RGB =(Source.rgb * 1.0)+(Dest.rgb *(1 - Source.a))
  • A =(Source.a * 1.0)+(Dest.a *(1 - Source.a))

使用自定义混合配置

清单5-6显示了使用混合操作MTLBlendOperationAdd,源混合因子MTLBlendFactorOne和目标混合因子的自定义混合配置的代码MTLBlendFactorOneMinusSourceAlpha。
colorAttachments[0]是具有MTLRenderPipelineColorAttachmentDescriptor指定混合配置的属性的对象。

清单5-6 指定自定义混合配置

MTLRenderPipelineDescriptor * renderPipelineDesc =

[[MTLRenderPipelineDescriptor alloc] init];

renderPipelineDesc.colorAttachments [0] .blendingEnabled = YES;

renderPipelineDesc.colorAttachments [0] .rgbBlendOperation = MTLBlendOperationAdd;

renderPipelineDesc.colorAttachments [0] .alphaBlendOperation = MTLBlendOperationAdd;

renderPipelineDesc.colorAttachments [0] .sourceRGBBlendFactor = MTLBlendFactorOne;

 renderPipelineDesc.colorAttachments [0] .sourceAlphaBlendFactor = MTLBlendFactorOne;

   renderPipelineDesc.colorAttachments [0] .destinationRGBBlendFactor =

MTLBlendFactorOneMinusSourceAlpha;

 renderPipelineDesc.colorAttachments [0] .destinationAlphaBlendFactor =

MTLBlendFactorOneMinusSourceAlpha;

NSError * errors = nil;

id <MTLRenderPipelineState> pipeline = [device

newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&errors];

为渲染命令编码器指定资源

MTLRenderCommandEncoder本节讨论的方法指定用作顶点和片段着色器函数的参数的资源,它们由对象中的属性vertexFunction和fragmentFunction属性指定MTLRenderPipelineState。这些方法将渲染资源(缓冲区,纹理和采样器)分配给atInderender命令编码器中的相应参数表index(),如图5-3所示。

图5-3 渲染命令编码器的参数表

以下setVertex*方法将一个或多个资源分配给顶点着色器函数的相应参数。

这些setFragment*方法类似地将一个或多个资源分配给片段着色器函数的相应参数。

在Metal着色语言源代码中指定资源位置的属性限定词必须与Metal框架方法中的参数表索引相匹配。在清单5-7中,分别为顶点着色器定义了两个分别为0和1的缓冲区(posBuf和texCoordBuf)。

列表5-7 Metal框架:为顶点函数指定资源

[renderEnc setVertexBuffer:posBuf offset:0 atIndex:0];
[renderEnc setVertexBuffer:texCoordBuf offset:0 atIndex:1];

在清单5-8中,函数签名具有与属性相应的预选赛参数buffer(0)和buffer(1)。

清单5-8 Metal着色语言:顶点函数参数匹配框架参数表指数

vertex VertexOutput metal_vert(float4 *posData [[ buffer(0) ]],
                           float2 *texCoordData [[ buffer(1) ]])

类似地,在清单5-9,(缓冲器,纹理和一个采样器fragmentColorBuf,shadeTex以及sampler,分别地),所有索引为0,针对片段着色器定义。

清单5-9 Metal框架:为片段函数指定资源

[renderEnc setFragmentBuffer:fragmentColorBuf offset:0 atIndex:0];
[renderEnc setFragmentTexture:shadeTex atIndex:0];
[renderEnc setFragmentSamplerState:sampler atIndex:0];

在清单5-10,函数签名具有与属性限定符相应参数buffer(0),texture(0)以及sampler(0)分别。

清单5-10 Metal着色语言:片段函数参数匹配框架参数表指数

fragment float4 metal_frag(VertexOutput in [[stage_in]], float4 *fragColorData [[ buffer(0) ]], texture2d<float> shadeTexValues [[ texture(0) ]], sampler samplerValues [[ sampler(0) ]] )

数据组织的顶点描述符

在Metal框架代码中,MTLVertexDescriptor每个流水线状态可以有一个描述输入到顶点着色器功能的数据的组织,并在着色语言和框架代码之间共享资源位置信息。

在Metal着色语言代码中,每顶点输入(例如标量或整数或浮点值向量)可以组织在一个结构中,可以在一个使用[[ stage_in ]]属性限定符声明的参数中传递,如VertexInput结构为例如顶点功能vertexMath在清单5-11。每顶点输入结构的每个字段都有[[ attribute(index) ]]限定符,它指定了顶点属性参数表中的索引。

清单5-11 Metal着色语言:带有属性指数的顶点函数输入

struct VertexInput {
float2    position [[ attribute(0) ]];
float4    color    [[ attribute(1) ]];
float2    uv1      [[ attribute(2) ]];
float2    uv2      [[ attribute(3) ]];
};

struct VertexOutput {
float4 pos [[ position ]];
float4 color;
};

vertex VertexOutput vertexMath(VertexInput in [[ stage_in ]])
{
  VertexOutput out;
  out.pos = float4(in.position.x, in.position.y, 0.0, 1.0);

  float sum1 = in.uv1.x + in.uv2.x;
  float sum2 = in.uv1.y + in.uv2.y;
  out.color = in.color + float4(sum1, sum2, 0.0f, 0.0f);
  return out;
}

要使用[[ stage_in ]]限定符引用着色器函数输入,请描述一个MTLVertexDescriptor对象,然后将其设置为其 vertexDescriptor属性MTLRenderPipelineState。MTLVertexDescriptor有两个属性:attributeslayouts

所述attributes的属性MTLVertexDescriptor是一个MTLVertexAttributeDescriptorArray用于定义每一顶点属性如何在被映射到一个顶点函数参数的缓冲器组织对象。该attributes属性可以支持访问在同一缓冲区内交错的多个属性(如顶点坐标,表面法线和纹理坐标)。阴影语言代码中成员的顺序不必在框架代码的缓冲区中保留。数组中的每个顶点属性描述符具有以下属性,它们提供了一个顶点着色器功能信息来定位和加载参数数据:

图5-4显示了一个MTLVertexAttributeDescriptorArrayMetal框架代码,它实现了与清单5-11中vertexMath着色语言代码中顶点函数的输入相对应的交错缓冲区。

图5-4 具有顶点属性描述符的缓冲区组织

清单5-12显示了对应于图5-4所示的交错缓冲区的Metal框架代码。

清单5-12 Metal框架:使用顶点描述符来访问交织数据

id <MTLFunction> vertexFunc = [library newFunctionWithName:@“vertexMath”];            
MTLRenderPipelineDescriptor * pipelineDesc =       
                         [[MTLRenderPipelineDescriptor alloc] init]; 
MTLVertexDescriptor * vertexDesc = [[MTLVertexDescriptor alloc] init]; 

vertexDesc.attributes [0] .format = MTLVertexFormatFloat2; 
vertexDesc.attributes [0] .bufferIndex = 0; 
vertexDesc.attributes [0] .offset = 0; 
vertexDesc.attributes [1] .format = MTLVertexFormatFloat4; 
vertexDesc.attributes [1] .bufferIndex = 0; 
vertexDesc.attributes [1] .offset = 2 * sizeof(float); // 8 bytes 
vertexDesc.attributes [2] .format = MTLVertexFormatFloat2; 
vertexDesc.attributes [2] .bufferIndex = 0;
vertexDesc.attributes [2] .offset = 8 * sizeof(float); // 32字节
vertexDesc.attributes [3] .format = MTLVertexFormatFloat2; 
vertexDesc.attributes [3] .bufferIndex = 0; 
vertexDesc.attributes [3] .offset = 6 * sizeof(float); // 24 bytes 
vertexDesc.layouts [0] .stride = 10 * sizeof(float); // 40 bytes 
vertexDesc.layouts [0] .stepFunction = MTLVertexStepFunctionPerVertex; 

pipelineDesc.vertexDescriptor = vertexDesc; 
pipelineDesc.vertexFunction = vertFunc;

MTLVertexAttributeDescriptor对象attributes数组中的每个对象都MTLVertexDescriptor对应VertexInput于着色器函数中的索引结构成员。attributes[1].bufferIndex = 0指定参数表中索引号为0的缓冲区的使用。(在这个例子中,每个MTLVertexAttributeDescriptor都有相同的bufferIndex,所以每个引用在参数表中的索引0处的相同的顶点缓冲区。)offset值指定顶点内的数据的位置,因此attributes[1].offset = 2 * sizeof(float)将相应数据的起始位置从8启动缓冲区。format选择这些值以匹配着色器函数中的数据类型,因此attributes[1].format = MTLVertexFormatFloat4指定使用四个浮点值。

layouts物业MTLVertexDescriptor是一个MTLVertexBufferLayoutDescriptorArray。对于每一个MTLVertexBufferLayoutDescriptorlayouts,属性指定如何顶点和属性数据是从对应的取出MTLBuffer时Metal绘制图元在参数表中。(有关绘图图元,看到绘制几何图元。)的stepFunction属性的MTLVertexBufferLayoutDescriptor判断是否获取属性数据的每个顶点,对于一些数量的实例,或者仅仅一次。如果stepFunction设置为获取某些数量的实例的属性数据,则stepRate属性MTLVertexBufferLayoutDescriptor决定了多少个实例。该stride属性指定两个顶点的数据之间的距离(以字节为单位)。

图5-5描述了MTLVertexBufferLayoutDescriptor对应于清单5-12中的代码。layouts[0]指定如何从缓冲区参数表中的相应索引0获取顶点数据。layouts[0].stride指定两个顶点的数据之间的40个字节的距离。的值layouts[0].stepFunction,MTLVertexStepFunctionPerVertex时,指定绘图时的属性数据被取为每个顶点。如果值stepFunction是MTLVertexStepFunctionPerInstance,所述stepRate属性确定多久属性数据被取出。例如,如果stepRate为1,则为每个实例获取数据; 如果stepRate是2,对于每两个实例,等等。

图5-5 具有顶点缓冲区布局描述符的缓冲区组织

下一页
上一页

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容