gpt4 book ai didi

ios - "ShaderTypes.h"中演示的 Metal 着色器类型顶点和缓冲区最佳实践

转载 作者:行者123 更新时间:2023-11-28 10:48:29 24 4
gpt4 key购买 nike

这是完整的 shadertypes.h 文件。我将把它分解成我无法理解的部分。

#ifndef ShaderTypes_h
#define ShaderTypes_h

//Part 1 Compiler flags
#ifdef __METAL_VERSION__
#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#define NSInteger metal::int32_t
#else
#import <Foundation/Foundation.h>
#endif

#include <simd/simd.h>

//Part 2 buffer index
typedef NS_ENUM(NSInteger, BufferIndex)
{
BufferIndexMeshPositions = 0,
BufferIndexMeshGenerics = 1,
BufferIndexUniforms = 2
};

//Part 3 vertex attribute and position
typedef NS_ENUM(NSInteger, VertexAttribute)
{
VertexAttributePosition = 0,
VertexAttributeTexcoord = 1,
};

//Part 4 texture index color
typedef NS_ENUM(NSInteger, TextureIndex)
{
TextureIndexColor = 0,
};

//Part 5 uniforms
typedef struct
{
matrix_float4x4 projectionMatrix;
matrix_float4x4 modelViewMatrix;
} Uniforms;

#endif /* ShaderTypes_h */

第 1 部分

#ifdef __METAL_VERSION__
#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#define NSInteger metal::int32_t
#else
#import <Foundation/Foundation.h>
#endif
//A bunch of definitions go after this
#endif

我的困惑主要在于为什么我们要编写所有这些代码。它似乎在检查用户是否有 Metal ,但它定义的这个 NS_ENUM 是什么?为什么要定义一个 metal 变量?而粉底是有条件进口的吗?

第 2 部分

typedef NS_ENUM(NSInteger, BufferIndex)
{
BufferIndexMeshPositions = 0,
BufferIndexMeshGenerics = 1,
BufferIndexUniforms = 2
};

不太确定这是在做什么,尤其是因为我找不到任何人在任何地方明确引用它们。

第 3 部分

typedef NS_ENUM(NSInteger, VertexAttribute)
{
VertexAttributePosition = 0,
VertexAttributeTexcoord = 1,
};

这个有一点更明确的用法,因为它在 .metal 文件中被引用

typedef struct
{
float3 position [[attribute(VertexAttributePosition)]];
float2 texCoord [[attribute(VertexAttributeTexcoord)]];
} Vertex;

以及顶点描述符代码的属性部分

    mtlVertexDescriptor.attributes[VertexAttribute.position.rawValue].format = MTLVertexFormat.float3
mtlVertexDescriptor.attributes[VertexAttribute.position.rawValue].offset = 0
mtlVertexDescriptor.attributes[VertexAttribute.position.rawValue].bufferIndex = BufferIndex.meshPositions.rawValue
...

它似乎以某种方式跟踪各种元素的索引,而不是像缓冲区一样。

第 4 部分

这是我得到的,因为它在此处的渲染中被引用

renderEncoder.setFragmentTexture(colorMap, index: TextureIndex.color.rawValue)

还有这里的shader

fragment float4 fragmentShader(..., texture2d<half> colorMap     [[ texture(TextureIndexColor) ]]){

我有点明白这个(减去 NSEnum 部分)但是我不明白只为一件事做这件事是个好习惯。

第 5 部分

这实际上是我理解的唯一一个它看起来像是所有统一组件的结构,这很有意义,因为它存储了统一的实际类型,允许着色器也暴露给该结构作为渲染器。


我想最终我想知道为什么采用这种方法以及为什么它是 Apple 建议的最佳实践。我认为以这种方式做事有点有意义,除了 Metal 似乎更适合 objective-c,尽管它看起来像 swift。

最佳答案

这是一个 header ,旨在由 Metal 着色器代码和应用程​​序代码(Objective-C 或通过桥接 Swift)共享。必须在这两种语言之间共享它需要一点小心。

#ifdef __METAL_VERSION__ 测试确定它正在编译的语言。对于 Metal,定义了几个宏。对于 Objective-C,它导入 Foundation。 (当然,在编译 Metal 代码时不能导入 Foundation。)

在他们的 (Objective-)C 头文件中,Apple 通常使用 NS_ENUM() 宏来声明枚举。该宏是在 Foundation header 中定义的,因此可以在将此 header 编译为应用程序代码时使用它。它没有在 Metal header 中定义,因此如果它想使用它(就像它所做的那样),这个 header 需要为自己定义它。宏的 Foundation 版本很有用,因为它检测编译器功能,如果可用则使用类型化枚举,如果不可用则使用常规枚举。在这个 header 中,Apple 正在为 Metal 着色器语言实现相同的宏。由于毫无疑问编译器是否支持类型化枚举(它支持),因此只有一个宏定义利用了该功能。

在 header 的后面,他们计划使用 NSInteger 类型。这是由应用程序代码的 Foundation header 定义的。由于他们想对 Metal 使用相同的代码,但该类型未在此处定义,因此他们需要在此 header 中定义它。不过,他们做出了一些奇怪的选择。首先,他们使用宏而不是 typedef。其次,他们将其定义为等同于 int32_t(在 metal 命名空间中)。这很奇怪,因为应用程序代码将是 64 位的(Metal 不适用于 32 位应用程序)导致 NSInteger 成为 64 位整数类型(相当于 int64_t)。因此,这两个世界将不同意 NSInteger 的大小,因此所有基于它的枚举。这有点糟糕,但考虑到这些枚举的实际使用方式,可能不会导致真正的问题。

将枚举简单地基于 int 可能会更好,它在所有 Apple 环境中都是 32 位的。

第 2、3 和 4 部分都很相似。使用“符号”常量而不仅仅是魔数(Magic Number)(即代码中的整数文字)通常是一种很好的做法。它不易出错并提高了可读性。这些部分只是定义了一些这样的符号常量,供 Metal 代码和应用程​​序代码共享。事实上,其中一些名称未在您正在检查的特定示例项目中使用,这表明 Apple 对多个示例项目或类似项目使用了相同的 header 。

关于ios - "ShaderTypes.h"中演示的 Metal 着色器类型顶点和缓冲区最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47257504/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com