- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我即将将利用C++编写的OpenGL的iOS应用移植到Apple的Metal。目标是完全摆脱OpenGL,并用Metal取代它。
OpenGL代码是分层的,我试图替换渲染器,即实际调用OpenGL函数的类。但是,整个代码库都使用GLM数学库来表示向量和矩阵。
例如,有一个摄像机类提供视图和投影矩阵。它们都为glm::mat4
类型,并被简单地传递到GLSL顶点着色器,在这里它们与GLSL给出的mat4
数据类型兼容。我想利用该相机类,因为它将这些矩阵发送到Metal顶点着色器。现在,我不确定glm::mat4
是否与Metal的float4x4
兼容。
我没有一个可以在其中进行测试的有效示例,因为我实际上只是从Metal入手,在网上找不到任何有用的东西。
所以我的问题如下:
glm::mat4
和glm::vec4
)是否与Metal的float4x4
/ float4
兼容? 最佳答案
总体而言,答案是是,GLM非常适合使用Apple Metal的应用程序。但是,有几件事需要考虑。评论中已经暗示了其中一些内容。
首先,Metal Programming Guide提到
Metal将其归一化设备坐标(NDC)系统定义为2x2x1立方体,其中心位于(0,0,0.5)
这意味着Metal NDC坐标与OpenGL NDC坐标不同,因为OpenGL将NDC坐标系定义为2x2x2立方体,其中心位于(0, 0, 0)
,即有效OpenGL NDC坐标必须在
// Valid OpenGL NDC coordinates
-1 <= x <= 1
-1 <= y <= 1
-1 <= z <= 1
因为GLM最初是为OpenGL量身定制的,所以它的
glm::ortho
和
glm::perspective
函数创建投影矩阵,将坐标转换为OpenGL NDC坐标。因此,有必要将这些坐标调整为“金属”。
this博客文章中概述了如何实现这一目标。
GLM_FORCE_DEPTH_ZERO_TO_ONE
,提到的GLM投影矩阵函数将转换坐标以与Metal / Vulkan的NDC坐标系统一起使用。因此,该
#define
将解决具有不同NDC坐标系的问题。
sizeof
和
alignof
运算符来确定大小和对齐方式。有趣的是,Metal着色器支持两个运算符。以下是GLM和Metal的两个示例:
// Size and alignment of some GLM example data types
glm::vec2 : size: 8, alignment: 4
glm::vec3 : size: 12, alignment: 4
glm::vec4 : size: 16, alignment: 4
glm::mat4 : size: 64, alignment: 4
// Size and alignment of some of Metal example data types
float2 : size: 8, alignment: 8
float3 : size: 16, alignment: 16
float4 : size: 16, alignment: 16
float4x4 : size: 64, alignment: 16
packed_float2 : size: 8, alignment: 4
packed_float3 : size: 12, alignment: 4
packed_float4 : size: 16, alignment: 4
从上表可以看出,GLM向量数据类型在大小和对齐方式上与Metal的打包向量数据类型非常匹配。但是请注意,4x4矩阵数据类型在对齐方式上不匹配。
typedef struct
{
glm::mat4 modelViewProjectionMatrix;
glm::vec2 windowScale;
glm::vec4 edgeColor;
glm::vec4 selectionColor;
} SolidWireframeUniforms;
此结构在头文件中定义,该头文件包含在客户端(即CPU端)代码中需要的位置。为了能够在“金属”顶点着色器侧使用这些值,我们需要一个相应的数据结构。在此示例的情况下,“金属”顶点着色器部分如下所示:
#include <metal_matrix>
#include <metal_stdlib>
using namespace metal;
struct SolidWireframeUniforms
{
float4x4 modelViewProjectionMatrix;
packed_float2 windowScale;
packed_float4 edgeColor;
packed_float4 selectionColor;
};
// VertexShaderInput struct defined here...
// VertexShaderOutput struct defined here...
vertex VertexShaderOutput solidWireframeVertexShader(VertexShaderInput input [[stage_in]], constant SolidWireframeUniforms &uniforms [[buffer(1)]])
{
VertexShaderOutput output;
// vertex shader code
}
为了将数据从客户端代码传输到Metal着色器,将统一的结构打包到缓冲区中。以下代码显示了如何创建和更新该缓冲区:
- (void)createUniformBuffer
{
_uniformBuffer = [self.device newBufferWithBytes:(void*)&_uniformData length:sizeof(SolidWireframeUniforms) options:MTLResourceCPUCacheModeDefaultCache];
}
- (void)updateUniforms
{
dispatch_semaphore_wait(_bufferAccessSemaphore, DISPATCH_TIME_FOREVER);
SolidWireframeUniforms* uniformBufferContent = (SolidWireframeUniforms*)[_uniformBuffer contents];
memcpy(uniformBufferContent, &_uniformData, sizeof(SolidWireframeUniforms));
dispatch_semaphore_signal(_bufferAccessSemaphore);
}
请注意用于更新缓冲区的
memcpy
调用。如果GLM和Metal数据类型的大小和对齐方式不匹配,则可能会出错。由于我们只是将Objective-C结构的每个字节复制到缓冲区,然后在Metal着色器端,再次解释该数据,如果数据结构不匹配,则数据将在Metal着色器端被误解。
104 bytes
|<--------------------------------------------------------------------------->|
| |
| 64 bytes 8 bytes 16 bytes 16 bytes |
| modelViewProjectionMatrix windowScale edgeColor selectionColor |
|<------------------------->|<----------->|<--------------->|<--------------->|
| | | | |
+--+--+--+------------+--+--+--+-------+--+--+-----------+--+--+----------+---+
Byte index | 0| 1| 2| ... |62|63|64| ... |71|72| ... |87|88| ... |103|
+--+--+--+------------+--+--+--+-------+--+--+-----------+--+--+----------+---+
^ ^ ^
| | |
| | +-- Is a multiple of 4, aligns with glm::vec4 / packed_float4
| |
| +-- Is a multiple of 4, aligns with glm::vec4 / packed_float4
|
+-- Is a multiple of 4, aligns with glm::vec2 / packed_float2
除了4x4 matix对齐方式以外,其他所有条件都匹配良好。 4x4矩阵的未对齐在这里没有问题,在上述内存布局中可见。但是,如果统一结构得到修改,则对齐或大小可能会成为问题,并且可能需要填充以使其正常工作。
SolidWireframeUniforms
结构中出现的最大对齐方式是16,所以似乎统一缓冲区的长度也必须是16的倍数。
- (NSUInteger)roundUpToNextMultipleOf16:(NSUInteger)number
{
NSUInteger remainder = number % 16;
if(remainder == 0)
{
return number;
}
return number + 16 - remainder;
}
现在,我们使用上述函数来计算统一缓冲区的长度,该函数将更改缓冲区创建方法(如上所述),如下所示:
- (void)createUniformBuffer
{
NSUInteger bufferLength = [self roundUpToNextMultipleOf16:sizeof(SolidWireframeUniforms)];
_uniformBuffer = [self.device newBufferWithBytes:(void*)&_uniformData length:bufferLength options:MTLResourceCPUCacheModeDefaultCache];
}
那应该解决上述断言检测到的问题。
关于ios - GLM数学库是否与Apple的 Metal 着色语言兼容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54930382/
如何将 glm::vec4 转换为 glm::vec3? 仅需要 x、y、z - 可以删除 w 组件。 在 GLSL 中,这可以通过 .xyz[1] 完成,但在 glm 中,这会导致编译错误: err
我正在使用 R 中的 h2o 包通过 h2o.glm() 函数来适应 GLM。在具有 l1 正则化惩罚的 GLM 中评估特征重要性的一种合理方法是监视参数进入线性预测器(即模型)的顺序,因为 l1 惩
我在从最新版本的 R 中的 glm 计算 OR 置信区间时遇到问题,但我以前没有遇到过这个问题。与任何 glm 在哪里 family="binomial" ,无论模型多么简单,我都可以轻松提取摘要和
我需要在我的 glm 图上添加 95% 的置信区间。 当我执行 multiline=T 时(因为我需要在同一个地 block 上进行 2 次处理,所以我这样做了),间隔消失了。我怎样才能让他们回来?
对于上下文,我一直在学习 OpenGL,并且学习了透视投影。花了整整一个小时试图弄清楚为什么我的三角金字塔没有正确显示,直到我注意到我的一个矩阵乘法(使用 operator* for glm::mat
你能告诉我 返回了什么吗? glm$残差和 残留物(glm)其中 glm 是一个准泊松对象。例如我将如何使用 glm$y 和 glm$linear.predictors 创建它们。 glm$残差
这是关于理解 glm 源码的。我想知道 glm 是否对它的类进行了零初始化并进行了尝试。是的,glm::vec3 和 glm::mat4 被初始化,即使没有提供构造函数值。然后我想了解它是如何完成的并
我正在尝试使用 probit 模型重现其他人的工作。不幸的是,我没有太多关于他们方法的信息,只有他们的起始数据和他们的模型图。 当我在 ggplot 中绘制数据并使用 geom_smooth(meth
我有一个 ModelMatrix 类,其中我有一个 glm::vec3 定义为 glm::vec3 *position = nullptr; 然后我得到了一个setter方法 void ModelMa
我想标准化生物数据集的变量。我需要使用不同的响应变量运行 glm、glm.nb 和 lm。 该数据集包含按地块划分的给定树种的数量(所有地块大小相同)和一系列定性变量:植被类型、土壤类型和牛的存在/不
我正在使用著名的 OpenGL 框架创建一个漂亮的图形引擎,但突然遇到了一个意想不到的问题(就像所有问题一样)。 我必须创建一个函数来修改 glm::mat3 中的特定值。为此,我创建了一个简单的函数
其他答案似乎有一些相关信息,但没有解决我遇到的问题。 从我在 Xcode 中的项目中,我选择了“将文件添加到项目”并选择了整个 glm 子文件夹(我被告知这是使用 glm 所需的全部)。然后,在我的
像下面这样计算四元数时, 你能解释一下 1.0f means.. 是什么意思吗? 我认为它可能是 x 轴的 90 度。 glm::angleAxis(3.141592... / 2, glm::dv
这可能真的很简单,但我已经下载了 glm 的正确软件包 glm-0.9.9-a2,但我不知道如何安装。说明要么太复杂,要么太简单。 我无法通过使用包管理器或将存储库添加到 aptitude 或 Ana
我无法理解使用 glm 的效果编码。举个例子: data('mpg') mpg$trans = as.factor(mpg$trans) levels(mpg$trans) [1] "auto(av)
我正在尝试在 R 中重现二项式 glm 的结果。 考虑来自此处的数据 http://www.ats.ucla.edu/stat/r/dae/logit.htm mydata <- read.csv("
ChatGPT已经火了一段时间了,国内也出现了一些平替,其中比较容易使用的是ChatGLM-6B: https://github.com/THUDM/ChatGLM-6B ,主要是能够让我们基于
我一直在阅读code R 使用它来拟合广义线性模型 (GLM),因为 R 的源代码是免费提供的。使用的算法称为迭代重新加权最小二乘法 (IRLS),这是一种有据可查的算法。对于每次迭代,都会调用 Fo
我读过 glmnet 可以在没有正则化的情况下使用,即它可以用作常规 glm。我正在写一篇论文并试图避免使用许多不同的包,因此使用 glmnet 进行常规的 glm 逻辑回归拟合会很方便。谁能帮我?
我正在尝试使用 glm( family='binomial') 来拟合逻辑回归. 这是模型: model<-glm(f_ocur~altitud+UTM_X+UTM_Y+j_sin+j_cos+tem
我是一名优秀的程序员,十分优秀!