如何在 C 中正确初始化模型矩阵?

Posted

技术标签:

【中文标题】如何在 C 中正确初始化模型矩阵?【英文标题】:How to properly initialize a model matrix in C? 【发布时间】:2018-04-04 14:42:34 【问题描述】:

我尝试转换我通过here 提出的问题的代码。

但是当我尝试运行它时,我遇到了一个异常,它指向 this(CGLM,用于 C 中的 OpenGL 数学因为 GLM 是仅限 C++ 的库)库。

C++ 代码运行良好,运行完美,但为什么在 C 中崩溃。

这是使用'CGLM'的代码的C sn-p(这是崩溃的代码):-

glUseProgram(shaderProgram);
mat4 model =

     1.0f, 0.0f, 0.0f, 0.0f ,
     0.0f, 1.0f, 0.0f, 0.0f ,
     0.0f, 0.0f, 1.0f, 0.0f ,
     0.0f, 0.0f, 0.0f, 1.0f ,
;
mat4 projection;
glm_ortho(0.0f, (GLfloat)(WIDTH), (GLfloat)(HEIGHT), 0.0f, -1.0f, 1.0f, projection);

vect2 scale =  2.0f, 2.0f ;
vect2 position =  50.0f, 0.0f ;
vec4 color =  1.0f, 1.0f, 1.0f, 0.5f ;
GLfloat rotation = 0.0f;

glm_translate(model, (vec3) position[0], position[1], 0.0f );

glm_translate(model, (vec3) 0.5f * scale[0], 0.5f * scale[1], 0.0f );
glm_rotate(model, rotation, (vec3) 0.0f, 0.0f, 1.0f ); // Why is this function crashing?
glm_translate(model, (vec3) -0.5f * scale[0], -0.5f * scale[1], 0.0f );

glm_scale(model, (vec3) scale[0] * width, scale[1] * height, 1.0f );

glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, (GLfloat *)projection);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, (GLfloat *)model);
glUniform4f(glGetUniformLocation(shaderProgram, "spriteColor"), color[0], color[1], color[2], color[3]);

这里是使用GLM的代码的C++ sn-p:-

glUseProgram(shaderProgram);
glm::mat4 model(1.0f);
glm::mat4 projection = glm::ortho(0.0f, static_cast<GLfloat>(WIDTH), static_cast<GLfloat>(HEIGHT), 0.0f, -1.0f, 1.0f);

glm::vec2 scale = glm::vec2(2.0f, 2.0f);
glm::vec2 position = glm::vec2(50.0f, 0.0f);
glm::vec4 color = glm::vec4(1.0f, 1.0f, 1.0f, 0.5f);
GLfloat rotation = 0.0f;

model = glm::translate(model, glm::vec3(position, 0.0f));

model = glm::translate(model, glm::vec3(0.5f * scale.x, 0.5f * scale.y, 0.0f));
model = glm::rotate(model, rotation, glm::vec3(0.0f, 0.0f, 1.0f));
model = glm::translate(model, glm::vec3(-0.5f * scale.x, -0.5f * scale.y, 0.0f));

model = glm::scale(model, glm::vec3(scale * glm::vec2(width, height), 1.0f));

glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
glUniform4f(glGetUniformLocation(shaderProgram, "spriteColor"), color.x, color.y, color.z, color.w);

【问题讨论】:

那么,你得到了什么异常,在你的代码中的哪一点? '在 spritetest.exe 中的 0x010F59C7 处引发异常:0xC0000005:访问冲突读取位置 0xFFFFFFFF' 在我运行后立即由编译器说,指向此处:- github.com/recp/cglm/blob/master/include/cglm/vec4.h#L169 由编译器?当然不是。但实际上,使用调试器并锁定堆栈跟踪 @derhass 我刚刚将链接添加到导致异常的行。 为什么glUniform... 调用会以 cglm 向量加法结束?这没有意义。 【参考方案1】:

见CGLM documentation

根据getting started

需要对齐:vec4 和 mat4 需要 16 字节对齐,因为 vec4 和 mat4 操作由 SIMD 指令向量化 (SSE/AVX)。

所以你需要像这样初始化单位矩阵:

mat4 model;
glm_mat4_identity(model);
....
mat4 projection;
glm_mat4_identity(projection);
glm_ortho(0.0f, (GLfloat)(WIDTH), (GLfloat)(HEIGHT), 0.0f, -1.0f, 1.0f, projection);

【讨论】:

但是为什么还是崩溃呢? 哪个源代码行? 这个就在这里model = glm::translate(model, glm::vec3(-0.5f * scale.x, -0.5f * scale.y, 0.0f)); 'C' 没有任何异常。异常是一个 C++ 特性。它崩溃了 - glm 代码,使用程序集编写以加速性能会导致未定义的行为,因为数据未正确初始化(对齐)。 C 不是 C++ 更接近于汇编,所以尽量避免使用 (vec3) .... 之类的技巧,这不是使用 std::initialized_list 的构造函数调用,这与 C++ 中的不同。跨度> 它并没有真正计量,汇编代码需要对齐的内存。 (vec3) 0.0f, 0.0f, 1.0f 这是一个堆栈对象数组,编译器跨越了元素。汇编函数期望数组上的内存地址具有精确对齐。简单地不要传递形参数组,使用变量。

以上是关于如何在 C 中正确初始化模型矩阵?的主要内容,如果未能解决你的问题,请参考以下文章

如何从字符串 C# 初始化 2d 字符矩阵

Opengl 未使用着色器正确绘制 - 矩阵设置/初始化问题?

如何正确初始化 C++11 中的数据成员?

C语言中怎么定义个线性表

在 C 中将多维数组作为参数传递

在c中的结构中初始化多维数组