着色器怎么选
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了着色器怎么选相关的知识,希望对你有一定的参考价值。
参考技术A 着色器(Shader)主要有顶点着色器(Vertex Shader)和像素着色器(Pixel Shader)两种。其中Vertex Shader(顶点着色器)主要负责顶点的几何关系等的运算,Pixel Shader(像素着色器)主要负责片源颜色等的计算。
着色器在离线渲染领域已经出现了多年,并且广泛应用于电影等方面,而即时渲染领域的着色器则是在微软推出Shader Model后才被首次引入。比较流行的Shader language着色器语言有HLSL,GLSL,RM等。
手动编译金属着色器
【中文标题】手动编译金属着色器【英文标题】:Manually Compile Metal Shaders 【发布时间】:2015-11-24 17:57:55 【问题描述】:我有兴趣摆脱 Xcode 并在混合语言应用程序的项目中手动编译 Metal 着色器。
不过,我不知道该怎么做。 Xcode 隐藏了着色器编译和随后在运行时加载到应用程序中的细节(您只需调用device.newDefaultLibrary()
)。这甚至可能吗,还是我必须使用运行时着色器编译来达到我的目的?
【问题讨论】:
这个例子可能对你有帮助:github.com/n-yoda/metal-without-xcode 【参考方案1】:通常,您可以通过三种方式在 Metal 中加载着色器库:
通过MTLDevice newLibraryWithSource:options:error:
或newLibraryWithSource:options:completionHandler:
方法从着色器源代码使用运行时着色器编译。尽管纯粹主义者可能会回避运行时编译,但此选项具有最小的实际开销,因此是完全可行的。避免使用此选项的主要实际原因可能是避免将着色器源代码作为应用程序的一部分提供,以保护您的 IP。
使用MTLLibrary newLibraryWithFile:error:
或newLibraryWithData:error:
方法加载已编译的二进制库。按照Using Command Line Utilities to Build a Library 中的说明在构建时创建这些单独的二进制库。
让 Xcode 在构建时将各种 *.metal
文件编译到可通过 MTLDevice newDefaultLibrary
获得的默认库中。
【讨论】:
是否可以在运行时以编程方式编写着色器,然后在运行时编译它? 是的。只需生成 MSL 源代码,并使用上面列出的第一种方法进行编译。【参考方案2】:这是从字符串创建顶点和片段程序的实际代码;使用它可以让您在运行时编译着色器(显示在着色器字符串方法后面的代码中)。
为了避免使用转义序列(例如 n...),我使用了 STRINGIFY 宏。为了解决它对使用双引号的限制,我编写了一个块,它接受一个头文件名数组并从中创建导入语句。然后将它们插入到适当位置的着色器中;我对包含语句做了同样的事情。它简化并加快了有时相当长的列表的插入。
合并此代码不仅允许您根据本地化选择要使用的特定着色器,而且在必要时还可用于更新应用的着色器,而无需更新应用。您只需创建并发布一个包含着色器代码的文本文件,您的应用可以对其进行预编程以作为着色器源进行引用。
#if !defined(_STRINGIFY)
#define __STRINGIFY( _x ) # _x
#define _STRINGIFY( _x ) __STRINGIFY( _x )
#endif
typedef NSString *(^StringifyArrayOfIncludes)(NSArray <NSString *> *includes);
static NSString *(^stringifyHeaderFileNamesArray)(NSArray <NSString *> *) = ^(NSArray <NSString *> *includes)
NSMutableString *importStatements = [NSMutableString new];
[includes enumerateObjectsUsingBlock:^(NSString * _Nonnull include, NSUInteger idx, BOOL * _Nonnull stop)
[importStatements appendString:@"#include <"];
[importStatements appendString:include];
[importStatements appendString:@">\n"];
];
return [NSString new];
;
typedef NSString *(^StringifyArrayOfHeaderFileNames)(NSArray <NSString *> *headerFileNames);
static NSString *(^stringifyIncludesArray)(NSArray *) = ^(NSArray *headerFileNames)
NSMutableString *importStatements = [NSMutableString new];
[headerFileNames enumerateObjectsUsingBlock:^(NSString * _Nonnull headerFileName, NSUInteger idx, BOOL * _Nonnull stop)
[importStatements appendString:@"#import "];
[importStatements appendString:@_STRINGIFY("")];
[importStatements appendString:headerFileName];
[importStatements appendString:@_STRINGIFY("")];
[importStatements appendString:@"\n"];
];
return [NSString new];
;
- (NSString *)shader
NSString *includes = stringifyIncludesArray(@[@"metal_stdlib", @"simd/simd.h"]);
NSString *imports = stringifyHeaderFileNamesArray(@[@"ShaderTypes.h"]);
NSString *code = [NSString stringWithFormat:@"%s",
_STRINGIFY(
using namespace metal;
typedef struct
float scale_factor;
float display_configuration;
Uniforms;
typedef struct
float4 renderedCoordinate [[position]];
float2 textureCoordinate;
TextureMappingVertex;
vertex TextureMappingVertex mapTexture(unsigned int vertex_id [[ vertex_id ]],
constant Uniforms &uniform [[ buffer(1) ]])
float4x4 renderedCoordinates;
float4x2 textureCoordinates;
if (uniform.display_configuration == 0 ||
uniform.display_configuration == 2 ||
uniform.display_configuration == 4 ||
uniform.display_configuration == 6)
renderedCoordinates = float4x4(float4( -1.0, -1.0, 0.0, 1.0 ),
float4( 1.0, -1.0, 0.0, 1.0 ),
float4( -1.0, 1.0, 0.0, 1.0 ),
float4( 1.0, 1.0, 0.0, 1.0 ));
textureCoordinates = float4x2(float2( 0.0, 1.0 ),
float2( 2.0, 1.0 ),
float2( 0.0, 0.0 ),
float2( 2.0, 0.0 ));
else if (uniform.display_configuration == 1 ||
uniform.display_configuration == 3 ||
uniform.display_configuration == 5 ||
uniform.display_configuration == 7)
renderedCoordinates = float4x4(float4( -1.0, -1.0, 0.0, 1.0 ),
float4( -1.0, 1.0, 0.0, 1.0 ),
float4( 1.0, -1.0, 0.0, 1.0 ),
float4( 1.0, 1.0, 0.0, 1.0 ));
if (uniform.display_configuration == 1 ||
uniform.display_configuration == 5)
textureCoordinates = float4x2(float2( 0.0, 1.0 ),
float2( 1.0, 1.0 ),
float2( 0.0, -1.0 ),
float2( 1.0, -1.0 ));
else if (uniform.display_configuration == 3 ||
uniform.display_configuration == 7)
textureCoordinates = float4x2(float2( 0.0, 2.0 ),
float2( 1.0, 2.0 ),
float2( 0.0, 0.0 ),
float2( 1.0, 0.0 ));
TextureMappingVertex outVertex;
outVertex.renderedCoordinate = float4(uniform.scale_factor, uniform.scale_factor , 1.0f, 1.0f ) * renderedCoordinates[vertex_id];
outVertex.textureCoordinate = textureCoordinates[vertex_id];
return outVertex;
fragment half4 displayTexture(TextureMappingVertex mappingVertex [[ stage_in ]],
texture2d<float, access::sample> texture [[ texture(0) ]],
sampler samplr [[sampler(0)]],
constant Uniforms &uniform [[ buffer(1) ]])
if (uniform.display_configuration == 1 ||
uniform.display_configuration == 2 ||
uniform.display_configuration == 4 ||
uniform.display_configuration == 6 ||
uniform.display_configuration == 7)
mappingVertex.textureCoordinate.x = 1 - mappingVertex.textureCoordinate.x;
if (uniform.display_configuration == 2 ||
uniform.display_configuration == 6)
mappingVertex.textureCoordinate.y = 1 - mappingVertex.textureCoordinate.y;
if (uniform.scale_factor < 1.0)
mappingVertex.textureCoordinate.y += (texture.get_height(0) - (texture.get_height(0) * uniform.scale_factor));
half4 new_texture = half4(texture.sample(samplr, mappingVertex.textureCoordinate));
return new_texture;
)];
return [NSString stringWithFormat:@"%@\n%@", includes, imports, code];
/*
* Metal setup: Library
*/
__autoreleasing NSError *error = nil;
NSString* librarySrc = [self shader];
if(!librarySrc)
[NSException raise:@"Failed to read shaders" format:@"%@", [error localizedDescription]];
_library = [_device newLibraryWithSource:librarySrc options:nil error:&error];
if(!_library)
[NSException raise:@"Failed to compile shaders" format:@"%@", [error localizedDescription]];
id <MTLFunction> vertexProgram = [_library newFunctionWithName:@"mapTexture"];
id <MTLFunction> fragmentProgram = [_library newFunctionWithName:@"displayTexture"];
.
.
.
【讨论】:
以上是关于着色器怎么选的主要内容,如果未能解决你的问题,请参考以下文章