metal 初始和画三角形

本文 https://github.com/AlanGeIT/Metal
 
另外一个 https://github.com/loyinglin/LearnMetal
 
 
@interface Renderer : NSObject<MTKViewDelegate> 要继承这个接口 
1、helloworld 设置清屏颜色
 属性
id<MTLDevice> _device;
id<MTLCommandQueue> _commandQueue;    
 
初始化
_device = mtkView.device;
_commandQueue = [_device newCommandQueue];
 
/// 每当视图需要渲染时调用
- (void)drawInMTKView:(nonnull MTKView *)view
{
    Color color = [self makeFancyColor];
    // 设置清屏颜色
    view.clearColor = MTLClearColorMake(color.red, color.green, color.blue, color.alpha);
    id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
    commandBuffer.label = @"MyCommand";
    MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
    if(renderPassDescriptor != nil) {
        id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
        renderEncoder.label = @"MyRenderEncoder";
        [renderEncoder endEncoding];
        [commandBuffer presentDrawable:view.currentDrawable];
    }
    // 在这里完成渲染并将命令缓冲区提交给GPU
    [commandBuffer commit];
}

 

2、
四个属性
@implementation AAPLRenderer
{
//我们用来渲染的设备(又名GPU)
id<MTLDevice> _device;

 
// 我们的渲染管道有顶点着色器和片元着色器 它们存储在.metal shader 文件中
id<MTLRenderPipelineState> _pipelineState;

//命令队列,从命令缓存区获取
id<MTLCommandQueue> _commandQueue;

//当前视图大小,这样我们才可以在渲染通道使用这个视图
vector_uint2 _viewportSize;
}
 
//初始化MTKView
- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView
{
    self = [super init];
    if(self)
    {
        NSError *error = NULL;

        _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;
}

metal

#include <metal_stdlib>
//使用命名空间 Metal
using namespace metal;

// 导入Metal shader 代码和执行Metal API命令的C代码之间共享的头
#import "AAPLShaderTypes.h"

// 顶点着色器输出和片段着色器输入
//结构体
typedef struct
{
    //处理空间的顶点信息
    float4 clipSpacePosition [[position]];
    //颜色
    float4 color;
} RasterizerData;

//顶点着色函数
vertex RasterizerData
vertexShader(uint vertexID [[vertex_id]],
             constant AAPLVertex *vertices [[buffer(AAPLVertexInputIndexVertices)]],
             constant vector_uint2 *viewportSizePointer [[buffer(AAPLVertexInputIndexViewportSize)]])
{
    out.clipSpacePosition = vector_float4(0.0, 0.0, 0.0, 1.0);
    float2 pixelSpacePosition = vertices[vertexID].position.xy;
    vector_float2 viewportSize = vector_float2(*viewportSizePointer);
    out.clipSpacePosition.xy = pixelSpacePosition / (viewportSize / 2.0);
    out.color = vertices[vertexID].color;
    return out;
}


fragment float4 fragmentShader(RasterizerData in [[stage_in]])
{
    return in.color;
}

 

//每当视图需要渲染帧时调用
- (void)drawInMTKView:(nonnull MTKView *)view
{
    static const AAPLVertex triangleVertices[] =
    {
        // 2D 顶点,    RGBA 颜色值
        { {  250,  -250 }, { 1, 0, 0, 1 } },
        { { -250,  -250 }, { 0, 1, 0, 1 } },
        { {    0,   250 }, { 0, 0, 1, 1 } },
    };

    //为当前渲染的每个渲染传递创建一个新的命令缓冲区
    id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
    commandBuffer.label = @"MyCommand";
    MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;

    //判断渲染目标是否为空
    if(renderPassDescriptor != nil)
    {
        //创建渲染命令编码器,这样我们才可以渲染到something
        id<MTLRenderCommandEncoder> renderEncoder =[commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
        //渲染器名称
        renderEncoder.label = @"MyRenderEncoder";
        //区别于hello的
        MTLViewport viewPort = {
            0.0,0.0,_viewportSize.x,_viewportSize.y,-1.0,1.0
        };
        [renderEncoder setViewport:viewPort];

        [renderEncoder setRenderPipelineState:_pipelineState];

        [renderEncoder setVertexBytes:triangleVertices
                               length:sizeof(triangleVertices)
                              atIndex:AAPLVertexInputIndexVertices];

        [renderEncoder setVertexBytes:&_viewportSize
                               length:sizeof(_viewportSize)
                              atIndex:AAPLVertexInputIndexViewportSize];

        [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle
                          vertexStart:0
                          vertexCount:3];

        //表示已该编码器生成的命令都已完成,并且从NTLCommandBuffer中分离
        [renderEncoder endEncoding];

        //一旦框架缓冲区完成,使用当前可绘制的进度表
        [commandBuffer presentDrawable:view.currentDrawable];
    }

    //最后,在这里完成渲染并将命令缓冲区推送到GPU
    [commandBuffer commit];
}

 

posted @ 2022-02-04 22:31  cnchengv  阅读(93)  评论(0编辑  收藏  举报