美文网首页
Metal(三)- Swift案例:三角形绘制

Metal(三)- Swift案例:三角形绘制

作者: Henry________ | 来源:发表于2020-09-01 22:58 被阅读0次

相比于上一篇helloWorld,这一篇内容增加了顶点数据和Metal的内容。

效果图

绘制流程:


绘制流程

具体代码实现

1,Metal文件

#import "HrShaderType.h"

typedef struct {
    //处理空间的顶点信息
    //position是关键字,类似于GLSL中的gl_Position
    float4 clipSpacePosition [[position]];

    //颜色
    float4 color;
} RasterizerData;
vertex函数
vertex RasterizerData vertexShader(uint vertexId [[vertex_id]],
                                   constant HRVertex *vertexs [[buffer(VertexInputIndexVertices)]],
                                   constant vector_float2 *viewportSize [[buffer(VertexInputIndexViewPortSize)]]) 
{
    RasterizerData out;
    
    out.clipSpacePosition = vertexs[vertexId].position;
    //把我们输入的颜色直接赋值给输出颜色.通过这种方式将颜色数据桥接到片元着色器
    out.color = vertexs[vertexId].color;
    
    return out;
}
  • vertex:函数限定符,限定该函数为顶点函数
  • RasterizerData:函数返回值,会将该参数经过光栅化后传递到片元函数
  • vertexShader:函数自定义名称
  • uint vertexId [[vertex_id]]:
    • uint变量类型:无符号32位整型;
    • vertexId变量名;
    • [[vertex_id]]属性修饰符:代表顶点编号固定写法,开发者不得修改
  • constant HRVertex *vertexs [[buffer(VertexInputIndexVertices)]]:
    • constant变量限定符:存储在GPU的常量缓存区中;
    • HRVertex:变量类型; vertexs:变量名;
fragment函数
fragment float4 fragmentShader(RasterizerData in [[stage_in]]) {
    //返回该像素点的色值
    return in.color;
}
  • fragment函数限定符:片元函数
  • float4:返回值,代表颜色RGBA
  • fragmentShader:函数名
  • RasterizerData in [[stage_in]]:
    • RasterizerData变量类型;
    • in变量名;
    • [[stage_in]]属性修饰符:片元着色函数使用的单个片元输入数据是由顶点着色函数输出.然后经过光栅化生成的.

2,桥接文件

由于需要在Swift文件中使用OC头文件,需要通过桥接文件XXX-Bridging-Header来导入.h文件

//定义了基本的向量、矩阵、四元数,该头文件同时存在于Metal Shader / swift | Objc中,方便相互传递数据
#include <simd/simd.h>

//该文件作用:通过文件引入的方式,将一些自定义的类型声明既传递到swift文件,同时也传递到metal文件中
typedef struct {
    vector_float4 position;
    vector_float4 color;
} HRVertex;

typedef enum {
    //顶点数据
    VertexInputIndexVertices = 0,
    //视图大小
    VertexInputIndexViewPortSize = 1,
}VertexInputIndex;

3,自定义Render渲染类

后续用到的相关全局参数
    private var _device : MTLDevice?
    private var commandQueue : MTLCommandQueue?
    private var pielineState : MTLRenderPipelineState!
    private var viewPortSize : vector_uint2 = vector_uint2(x: 0, y: 0)
初始化
init(view: MTKView) {
        super.init()
        _device = view.device
        
        //1. 通过device创建commandQueue
        commandQueue = _device?.makeCommandQueue()
        
        //2. 加载metal文件
        //2.1 makeDefaultLibrary:加载项目中所有.metal文件,当然也可以使用其他API来指定metal文件
        let library = _device?.makeDefaultLibrary()
        //2.2 从库中加载顶点函数、片元函数
        let vertexShader = library?.makeFunction(name: "vertexShader")
        let fragShader = library?.makeFunction(name: "fragmentShader")
        
        //3. 创建渲染管道描述符
        //3.1
        let pielineDes = MTLRenderPipelineDescriptor()
        //3.2 管道名称:可用于调试
        pielineDes.label = "MyMTLRenderPipelineDescriptor"
        //3.2 可编程函数,用于处理渲染过程中每个顶点、片元
        pielineDes.vertexFunction = vertexShader
        pielineDes.fragmentFunction = fragShader
        //3.3 确定渲染管线中颜色附着点0的颜色组件;使用当前view颜色组件
        pielineDes.colorAttachments[0].pixelFormat = view.colorPixelFormat
        
        //4 创建渲染管线状态
        do {
            try pielineState = _device?.makeRenderPipelineState(descriptor: pielineDes)
        } catch {
            //如果我们没有正确设置管道描述符,则管道状态创建可能失败
            print("pielineState failed \(error)")
        }  
    }
Delegate-drawSize
func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
        viewPortSize.x = uint(size.width)
        viewPortSize.y = uint(size.height)
    }
Delegate-draw
func draw(in view: MTKView) {
        //设置view的clearColor
        view.clearColor = MTLClearColor(red: 0, green: 0, blue: 0, alpha: 1.0)
        
        //5. 为每一次渲染创建一个新的命令缓冲区
        let commandBuffer = commandQueue?.makeCommandBuffer()
        commandBuffer?.label = "MyCommandBuffer"
        
        //6. 用于保存渲染过程中的一组结果,渲染命令编码器描述符
        if let des = view.currentRenderPassDescriptor {
            //7. 创建渲染命令编码器,通过它来进行渲染的配置
            let encoder = commandBuffer?.makeRenderCommandEncoder(descriptor: des)
            encoder?.label = "MyCommandEncoder"
            
            //8. 设置视口
            encoder?.setViewport(MTLViewport(originX: 0, originY: 0,
                                             width: Double(viewPortSize.x),
                                             height: Double(viewPortSize.y),
                                             znear: -1.0, zfar: 1.0))
            //9. 设置当前渲染管道状态对象
            encoder?.setRenderPipelineState(pielineState)
            
            //10. 载入顶点数据
            //通过VertexInputIndexVertices将数据传递到顶点函数的对应buffer中
            encoder?.setVertexBytes(triangleVertices,
                                    length: triangleVertices.count * MemoryLayout<HRVertex>.size,
                                    index: Int(VertexInputIndexVertices.rawValue))
            
            encoder?.setVertexBytes(&viewPortSize,
                                    length: MemoryLayout<vector_uint2>.size,
                                    index: Int(VertexInputIndexViewPortSize.rawValue))
            
            
            
            //11. 绘制动作
            /*
                type: 设置图元链接方式
                    case point = 0
                    case line = 1
                    case lineStrip = 2  //线环
                    case triangle = 3   //三角形
                    case triangleStrip = 4  //三角形扇
             */
            encoder?.drawPrimitives(type: .triangle,
                                    vertexStart: 0,
                                    vertexCount: triangleVertices.count)
            
            //12. 结束编码
            encoder?.endEncoding()
            
            //13. 锁定缓存区, 等待缓冲区处理完成后绘制
            if let currentDrawable = view.currentDrawable{
                commandBuffer?.present(currentDrawable)
            }
        }
        
        //14. 将命令缓存区提交给GPU
        commandBuffer?.commit()
    }
Buffer方式导入顶点数据

上方代码使用的是直接导入的方式将顶点数据导入顶点函数。当然还有其他方式,比如使用Buffer的方式来导入。

init(view: MTKView) {
...
// 将数据放入buffer中,但是buffer是有大小上限:4KB
        vertexBuffer = _device?.makeBuffer(bytes: triangleVertices,
                                         length: triangleVertices.count * MemoryLayout<HRVertex>.size,
                                         options: .storageModeShared)
}

func draw(in view: MTKView) {
// 通过buffer的方式载入顶点数据
    encoder?.setVertexBuffer(vertexBuffer,
                                     offset: 0,
                                     index: Int(VertexInputIndexVertices.rawValue))
}
  • 由于buffer最大可存储4KB的数据,所以不适合大量数据的导入

4,渲染类的使用

override func viewDidLoad() {
        super.viewDidLoad()
        
        //1.获取MTKView
        if let vv = self.view as? MTKView{
            _view = vv
            //2.创建设备(GPU)
            _view?.device = MTLCreateSystemDefaultDevice()
            
            //3.render工具类创建
            _render = HrRender(view: _view)
            
            //4.mtkview的代理设置
            _view?.delegate = _render
            
            //5.初始化视图大小
            //drawableSize当前view的可视区域
            _render?.mtkView(vv, drawableSizeWillChange: _view.drawableSize)
        }
    }

demo-github地址

相关文章

  • Metal案例:绘制三角形

    效果图如下: 在Metal案例分析中我们已经介绍过了Metal案例的构建流程。其实绘制三角形案例中,大致流程是一致...

  • Metal(三)- Swift案例:三角形绘制

    相比于上一篇helloWorld,这一篇内容增加了顶点数据和Metal的内容。 绘制流程: 具体代码实现 1,Me...

  • Metal 案例02:绘制三角形

    本案例的目的在于理解Metal中使用着色器绘制三角形的流程 整体效果图如下 整体的流程图如下 与Metal 入门级...

  • Metal 入门级02:绘制三角形

    OpenGL + OpenGL ES +Metal 系列文章汇总 本案例的目的在于理解Metal中使用着色器绘制三...

  • Metal Sample Code (Hello Triang

    通过Metal绘制一个简单的三角形,效果如下: Shader 首先,我们需要创建一个.h文件以及.metal文件,...

  • Metal 案例03:大批量顶点数据的图形渲染

    本案例的目的在于理解顶点数据的两种存储方式以及它们的区别和应用场景 在Metal 案例02:加载三角形案例中,顶点...

  • 005 - OpenGL绘制三角形案例

    案例主要目的是绘制一个三角形,在蓝色背景下绘制一个红色的三角形 OpenGL在Mac Xcode的搭建: ,还不知...

  • Metal 加载纹理

    本案例的讲解是在 Metal 绘制网格 案例基础上的讲解。 首先说明下改案例需要的几个类: CQMetalText...

  • Metal应用--绘制大量顶点

    这个案例中,我们用Metal Shading Language绘制一个图形,如下所示: 在这个案例中,我们可以看到...

  • Metal 2

    Metal 2 绘制一个三角形 理解 :顶点函数,图元装配,光栅化,片元函数,逐片段操作 步骤一 :创建一个bri...

网友评论

      本文标题:Metal(三)- Swift案例:三角形绘制

      本文链接:https://www.haomeiwen.com/subject/pywbsktx.html