准备工作

  • Metal渲染的构建流程, 请参考:Metal之简单渲染动态切换屏幕颜色
  • Metal三角形的渲染显示与渲染构建流程大体一致, 本文主要介绍以下方面的修改和实现:
    ① metal渲染文件
    ② 创建C 与 OC 的桥接函数
    ③ initWithMetalKitView方法中需要加载metal文件
    ④ drawInMTKView方法中加载三角形数据
  • Metal三角形的渲染显示是基于世界坐标系下。

渲染流程

一、metal渲染文件
  • command + N --> Metal File 创建metal着色器文件, 新建metal文件:YDWShaders.metal

  • 定义顶点着色器输入和片元着色器输入,相当于OpenGL ES中的varying修饰的变量,即桥接变量;
// 顶点着色器输出和片段着色器输入
// 结构体
typedef struct {// 处理空间的顶点信息float4 clipSpacePosition [[position]];// 颜色float4 color;} RasterizerData;
  • 定义顶点着色器函数和片元着色器函数:
    ① 处理顶点数据: 执行坐标系转换,将生成的顶点剪辑空间写入到返回值中; 将顶点颜色值传递给返回值;
    ② 初始化输出剪辑空间位置: 索引到我们的数组位置以获得当前顶点, 我们的位置是在像素维度中指定的, 每个顶点着色器的输出位置在剪辑空间中(也称为归一化设备坐标空间,NDC),剪辑空间中的(-1,-1)表示视口的左下角,而(1,1)表示视口的右上角, 计算和写入 XY值到我们的剪辑空间的位置.为了从像素空间中的位置转换到剪辑空间的位置,我们将像素坐标除以视口的大小的一半;
    ③ 把输入的颜色直接赋值给输出颜色, 这个值将于构成三角形的顶点的其他颜色值插值, 从而为片段着色器中的每个片段生成颜色值;
//顶点着色器函数
/*vertex:修饰符,表示是顶点着色器RasterizerData:返回值vertexShader:函数名称,可自定义vertexID:metal自己反馈的idvertices:1)告诉存储的位置buffer 2)告诉传递数据的入口是CJLVertexInputIndexVerticesvertices 和 viewportSizePointer 都是通过CJLRenderer 传递进来的*/
vertex RasterizerData
vertexShader(uint vertexID [[vertex_id]],constant CJLVertex *vertices [[buffer(CJLVertexInputIndexVertices)]],constant vector_uint2 *viewportSizePointer [[buffer(CJLVertexInputIndexViewportSize)]]) {// 定义outRasterizerData out; // 初始化输出剪辑空间位置out.clipSpacePosition = vertices[vertexID].position;// 把输入的颜色直接赋值给输出颜色. 这个值将于构成三角形的顶点的其他颜色值插值,从而为片段着色器中的每个片段生成颜色值out.color = vertices[vertexID].color;// 完成,将结构体传递到管道中下一个阶段return out;
}/*fragment:修饰符,表示是片元着色器float4:返回值,即颜色值RGBAfragmentShader:函数名称,可自定义RasterizerData:参数类型(可修改)in:形参变量(可修改)[[stage_in]]:属性修饰符,表示单个片元输入(由定点函数输出)(不可修改),相当于OpenGL ES中的varying*/
fragment float4 fragmentShader(RasterizerData in [[stage_in]]) {// 返回输入的片元颜色return in.color;
}
二、创建C与OC的桥接文件

该头文件的目的是为了c代码与OC代码可以共享与 shader 和 C 代码 为了确保Metal Shader缓存区索引能够匹配 Metal API Buffer 设置的集合调用

  • 定义缓存区索引值,表示向metal着色器传递数据的入口枚举值,相当于OpenGL ES中GLSL语言定义的顶点坐标入口position
// 缓存区索引值 共享与shader和C代码, 为了确保Metal Shader缓存区索引能够匹配 Metal API Buffer 设置的集合调用
typedef enum YDWVertexInputIndex {// 顶点YDWVertexInputIndexVertices     = 0,// 视图大小YDWVertexInputIndexViewportSize = 1,
} YDWVertexInputIndex;
  • 定义图形数据的结构体,包含顶点和颜色值,类似于OpenGL ES中的顶点数据的结构体
// 结构体: 顶点/颜色值
typedef struct {// 像素空间的位置// 像素中心点(100,100)vector_float4 position;// RGBA颜色vector_float4 color;
} YDWVertex;
三、initWithMetalKitView方法中需要加载metal文件
  • 获取GPU设备device
  • 加载.metal着色器文件
  • 配置用于创建管道状态的管道描述符
  • 同步创建并返回渲染管线状态对象
  • 创建命令队列
// 初始化MTKView- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView {self = [super init];if(self) {NSError *error = NULL;// 获取GPU 设备_device = mtkView.device;// 在项目中加载所有的(.metal)着色器文件// 从bundle中获取.metal文件id<MTLLibrary> defaultLibrary = [_device newDefaultLibrary];// 从库中加载顶点函数id<MTLFunction> vertexFunction = [defaultLibrary newFunctionWithName:@"vertexShader"];// 从库中加载片元函数id<MTLFunction> fragmentFunction = [defaultLibrary newFunctionWithName:@"fragmentShader"];// 配置用于创建管道状态的管道MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];// 管道名称pipelineStateDescriptor.label = @"Simple Pipeline";// 可编程函数,用于处理渲染过程中的各个顶点pipelineStateDescriptor.vertexFunction = vertexFunction;// 可编程函数,用于处理渲染过程中各个片段/片元pipelineStateDescriptor.fragmentFunction = fragmentFunction;// 一组存储颜色数据的组件pipelineStateDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat;// 同步创建并返回渲染管线状态对象_pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error];// 判断是否返回了管线状态对象if (!_pipelineState) {// 如果没有正确设置管道描述符,则管道状态创建可能失败NSLog(@"Failed to created pipeline state, error %@", error);return nil;}// 创建命令队列_commandQueue = [_device newCommandQueue];}return self;
}
四、drawInMTKView方法中加载三角形数据
  • 顶点数据/颜色数据
 // 顶点数据/颜色数据static const YDWVertex triangleVertices[] = {// 顶点, RGBA 颜色值{ {  0.5, -0.25, 0.0, 1.0 }, { 1, 0, 0, 1 } },{ { -0.5, -0.25, 0.0, 1.0 }, { 0, 1, 0, 1 } },{ { -0.0f, 0.25, 0.0, 1.0 }, { 0, 0, 1, 1 } },};
  • 为当前渲染的每个渲染传递创建一个新的命令缓冲区
 // 为当前渲染的每个渲染传递创建一个新的命令缓冲区id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];// 指定缓存区名称commandBuffer.label = @"MyCommand";
  • 创建命令描述符
 MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
  • 创建渲染命令编码器
 // 创建渲染命令编码器,这样才可以渲染到somethingid<MTLRenderCommandEncoder> renderEncoder =[commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];// 渲染器名称renderEncoder.label = @"MyRenderEncoder";
  • 设置我们绘制的可绘制区域:
    视口指定Metal渲染内容的drawable区域。 视口是具有x和y偏移,宽度和高度以及近和远平面的3D区域。
    为管道分配自定义视口需要通过调用setViewport:方法将MTLViewport结构编码为渲染命令编码器。 如果未指定视口,Metal会设置一个默认视口,其大小与用于创建渲染命令编码器的drawable相同。
 MTLViewport viewPort = {0.0,0.0,_viewportSize.x,_viewportSize.y,-1.0,1.0};[renderEncoder setViewport:viewPort];
  • 设置当前渲染管道状态对象
[renderEncoder setRenderPipelineState:_pipelineState];
  • 从应用程序OC代码中发送数据给 Metal 顶点着色器函数
    顶点数据+颜色数据: 指向要传递给着色器的内存的指针, 想要传递的数据的内存大小;
    一个整数索引,它对应于我们的“vertexShader”函数中的缓冲区属性限定符的索引。
// 指向要传递给着色器的内存的指针
// 想要传递的数据的内存大小
// 一个整数索引,它对应于“vertexShader”函数中的缓冲区属性限定符的索引
[renderEncoder setVertexBytes:triangleVerticeslength:sizeof(triangleVertices)atIndex:YDWVertexInputIndexVertices];// 发送到顶点着色函数中,视图大小// 视图大小内存空间大小// 对应的索引
[renderEncoder setVertexBytes:&_viewportSizelength:sizeof(_viewportSize)atIndex:YDWVertexInputIndexViewportSize];
  • 画出三角形的3个顶点:
     // @method drawPrimitives:vertexStart:vertexCount:// @brief 在不使用索引列表的情况下,绘制图元// @param 绘制图形组装的基元类型// @param 从哪个位置数据开始绘制,一般为0// @param 每个图元的顶点个数,绘制的图型顶点数量/*MTLPrimitiveTypePoint = 0, 点MTLPrimitiveTypeLine = 1, 线段MTLPrimitiveTypeLineStrip = 2, 线环MTLPrimitiveTypeTriangle = 3,  三角形MTLPrimitiveTypeTriangleStrip = 4, 三角型扇*/[renderEncoder drawPrimitives:MTLPrimitiveTypeTrianglevertexStart:0vertexCount:3];
  • 结束编码: 表示已该编码器生成的命令都已完成, 且从NTLCommandBuffer中分离
[renderEncoder endEncoding];
  • 一旦框架缓冲区完成,使用当前可绘制的进度表
[commandBuffer presentDrawable:view.currentDrawable];
  • 命令缓冲区提交GPU进行显示
[commandBuffer commit];

效果展示

完整示例

Metal之基于世界坐标系下渲染绘制三角形

Metal之渲染绘制三角形相关推荐

  1. viewpager初始化fragment没有绘制_NDK OpenGL ES渲染系列 之 绘制三角形

    前言 新的知识学习都是循序渐进的,从基础到复杂.前面OpenGL ES概念 已经介绍了OpenGL ES的相关概念,这篇文章开始我们就正式开始OpenGL ES渲染系列第一站---绘制三角形.绘制三角 ...

  2. 【OpenGL】十五、OpenGL 绘制三角形 ( 绘制 GL_TRIANGLE_FAN 三角形扇 )

    文章目录 一.绘制 GL_TRIANGLE_FAN 三角形 1.绘制 3 个点的情况 2.绘制 4 个点的情况 3.绘制 5 个点的情况 4.绘制 6 个点的情况 二.相关资源 一.绘制 GL_TRI ...

  3. 【OpenGL】十四、OpenGL 绘制三角形 ( 绘制 GL_TRIANGLE_STRIP 三角形 | GL_TRIANGLE_STRIP 三角形绘制分析 )

    文章目录 一.绘制 GL_TRIANGLE_STRIP 三角形 二.GL_TRIANGLE_STRIP 三角形绘制分析 三.相关资源 一.绘制 GL_TRIANGLE_STRIP 三角形 该模式绘制首 ...

  4. 【OpenGL】十三、OpenGL 绘制三角形 ( 绘制单个三角形 | 三角形绘制顺序 | 绘制多个三角形 )

    文章目录 一.绘制三角形 二.三角形绘制顺序 1.绘制正面 2.三个点逆时针方向排列 3.三个点顺时针方向排列 4.设置点的正面方向 三.绘制多个三角形 四.相关资源 一.绘制三角形 三角形绘制即绘制 ...

  5. Android OpenGL ES(十)绘制三角形Triangle .

    三角形为OpenGL ES支持的面,同样创建一个DrawTriangle Activity,定义6个顶点使用三种不同模式来绘制三角形: float vertexArray[] = {-0.8f, -0 ...

  6. OpenGL绘制三角形

    OpenGL绘制三角形 1. 可编程渲染管线 2. 标准化设备坐标(Normalized Device Coordinates) 3. 三角形顶点数据输入 4. 顶点着色器(Vertex Shader ...

  7. OPenGL 学习笔记之 VAO VBO EBO 以及SHADER 并使用其绘制三角形

    译注 在学习此节之前,建议将这三个单词先记下来: 顶点数组对象:Vertex Array Object,VAO 顶点缓冲对象:Vertex Buffer Object,VBO 索引缓冲对象:Eleme ...

  8. Vulkan的基本概念:如何使用Vulkan绘制三角形?

    应用开发者可以使用 Vulkan来打造在GPU上执行命令的应用,大幅降低开销.与 EGL 和 GLES 相比,Vulkan 还可以更直接地映射到当前图形硬件中的功能,最大限度地降低驱动程序的出错概率, ...

  9. Direct3D 11 总结 —— 4 绘制三角形

    介绍 本文主要介绍如何使用 direct3D 11 绘制三角形. pipeline 介绍 从 msdn 的文章,可以获得 direct3D 的 pipeline 如下图所示,对于本文只需要设置红框内的 ...

最新文章

  1. shell shocked什么意思_Shell 启动类型探究 ── login interactive
  2. JavaScript的正则表达式实现邮箱校验
  3. 从上往下 流式布局_揭秘做好网站结构优化的4步(下)
  4. ML之kNN:k最近邻kNN算法的简介、应用、经典案例之详细攻略
  5. 自由自在意式手工冰淇淋,健康时尚的美味零食
  6. TortoiseGit- 创建本地新分支,提交推送到远程,本地新分支合并到工作分支,提交到远程工作分支等。...
  7. react学习(45)----react组件
  8. HTML5中的audio在手机端和微信端的不能自动播放
  9. esxi服务器与虚拟机时间不符,vsphere6.7-虚拟机与ESXI时间同步
  10. html怎样获取用户手机号码,小程序如何获取用户手机号?
  11. python3程序设计基础答案刘德山_!求大学python3程序设计基础答案 刘德山主编 网上找不到 希望大家帮帮忙...
  12. Android NDK开发之 与NEON相关的库
  13. 麒麟OS新版本,老国产平台机器都装不了,情何以堪?
  14. Arcgis Android 基本概念 - 浅谈
  15. 将ArcMap中的符号样式导出的供ArcPad使用
  16. 触动精灵 alilib
  17. [Ynoi2016]炸脖龙I/Nephren Ruq Insania
  18. 写给需要面试经验的交互设计师(下)
  19. 也谈说话这件事--《好好说话》读后感
  20. c语言指针读书笔记,《C与指针》读书笔记一

热门文章

  1. 「SDOI2016」储能表(数位dp)
  2. ldap集成nginx
  3. day_work_02
  4. java基础之访问控制符
  5. Vue学习笔记进阶篇——Render函数
  6. Json字符串和Json对象的简单总结
  7. [转]PHP程序61条面向对象分析设计的经验原则
  8. XHTML和HTMl区别
  9. a卡显存测试软件_官方游戏性能堪比RTX 3080 苏姿丰:RX 6000 Big Navi是史上最强A卡...
  10. 安装Ubuntu 18.04后的一些操作