ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

matrix_transform.inl文件报错assert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0));

2021-12-24 10:35:02  阅读:191  来源: 互联网

标签:std rMat 1.0 matrix 矩阵 报错 tf GL glm


OpenGL系列文章目录

文章目录


前言

当在openGL中使用glm库报错:
assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0));

在这里插入图片描述

一、matrix_transform.inl文件报错

1.报错位置

下图中三个绿色框中的代码出错了,
在这里插入图片描述

2.定位问题

原来这句代码引起问题:

projMat = glm::perspective(glm::radians(60.0f), aspect, 0.01f, 1000.f);

在这里插入图片描述
在这里插入图片描述
上图中x值发生了异常,-nan(ind)
在这里插入图片描述
可能的情况:

          1.分母为”0”,如果分母为零,自然时不能得到一个确定的数字的。

          2.对负数开平方。

          3.有些编译器在对无穷大与无穷小的计算时也会出现此类情况。

3.问题解决

估计是在以下计算中得到无穷大或者无穷小或者分母无穷接近0的情况了

rMat = glm::rotate(glm::mat4(1.f), 1.75f * tf, glm::vec3(1.f, 0.f, 0.f));
rMat = glm::rotate(rMat, 1.75f * tf, glm::vec3(0.f, 1.f, 0.f));
rMat = glm::rotate(rMat, 1.75f * tf, glm::vec3(0.f, 0.f, 1.f));
projMat = glm::perspective(glm::radians(60.0f), aspect, 0.01f, 1000.f);

我把代码修改成下面,就没有报错了

        //旋转矩阵,绕x轴旋转
		rMat = glm::rotate(glm::mat4(1.f), glm::radians(40.f) * tf, glm::vec3(1.f, 0.f, 0.f));
		 //rMat = glm::rotate(glm::mat4(1.f), 1.75f * tf, glm::vec3(1.f, 0.f, 0.f));
		//旋转矩阵,绕y轴旋转
		rMat = glm::rotate(rMat, glm::radians(50.f) * tf, glm::vec3(0.f, 1.f, 0.f));
		 //rMat = glm::rotate(rMat, 1.75f * tf, glm::vec3(0.f, 1.f, 0.f));
		//旋转矩阵,绕z轴旋转
		rMat = glm::rotate(rMat, glm::radians(60.f) * tf, glm::vec3(0.f, 0.f, 1.f));
		 //rMat = glm::rotate(rMat, 1.75f * tf, glm::vec3(0.f, 0.f, 1.f));

代码

#include "glew/glew.h"
#include "glfw/glfw3.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "Utils.h"
#include <iostream>
#include <string>
#include <fstream>

using namespace std;

//#define GLM_FORCE_RADIANS

static const int Screen_Width = 1920;
static const int Screen_Height = 1080;

static const int numberVAOs = 1;
static const int numberVBOs = 2;

GLuint renderingProgram = 0;
GLuint vao[numberVAOs] = { 0 };
GLuint vbo[numberVBOs] = { 0 };

float cameraX = 0.f, cameraY = 0.f, cameraZ = 0.f;
float cubeX = 0.f, cubeY = 0.f, cubeZ = 0.f;

int g_width = 0, g_height = 0, g_displayLoopi = 0;
float aspect = 0.f;
float tf = 0.f;

GLuint mvLoc = 0, projLoc = 0;

glm::mat4 mMat(1.f), vMat(1.f), mvMat(1.f), projMat(1.f), tMat(1.f), rMat(1.f);

void setupVertices()
{
	float vertexPositions[108] =
	{ 
		-1.0f,  1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
		1.0f, -1.0f, -1.0f, 1.0f,  1.0f, -1.0f, -1.0f,  1.0f, -1.0f,
		1.0f, -1.0f, -1.0f, 1.0f, -1.0f,  1.0f, 1.0f,  1.0f, -1.0f,
		1.0f, -1.0f,  1.0f, 1.0f,  1.0f,  1.0f, 1.0f,  1.0f, -1.0f,
		1.0f, -1.0f,  1.0f, -1.0f, -1.0f,  1.0f, 1.0f,  1.0f,  1.0f,
		-1.0f, -1.0f,  1.0f, -1.0f,  1.0f,  1.0f, 1.0f,  1.0f,  1.0f,
		-1.0f, -1.0f,  1.0f, -1.0f, -1.0f, -1.0f, -1.0f,  1.0f,  1.0f,
		-1.0f, -1.0f, -1.0f, -1.0f,  1.0f, -1.0f, -1.0f,  1.0f,  1.0f,
		-1.0f, -1.0f,  1.0f,  1.0f, -1.0f,  1.0f,  1.0f, -1.0f, -1.0f,
		1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,  1.0f,
		-1.0f,  1.0f, -1.0f, 1.0f,  1.0f, -1.0f, 1.0f,  1.0f,  1.0f,
		1.0f,  1.0f,  1.0f, -1.0f,  1.0f,  1.0f, -1.0f,  1.0f, -1.0f
	};

	glGenVertexArrays(numberVAOs, vao);
	glBindVertexArray(vao[0]);

	glGenBuffers(numberVBOs, vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
}

//窗口大小改变时比例位置不变
void window_size_callback(GLFWwindow* window, int newWidth, int newHeight)
{
	aspect = (float)newWidth / (float)newHeight;
	glViewport(0, 0, newWidth, newHeight);
	//必须要创建透视投影矩阵计算公式,否则第一帧渲染时,立方体不在视口中 :1.0472 radians = 60 degrees
	//glm::perspective使用模板定义,所以函数各个参数类型要一致  1.0472f
	projMat = glm::perspective(glm::radians(60.0f), aspect, 0.01f, 1000.f);
	//projMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.f);
}

void init(GLFWwindow* window)
{
	renderingProgram = Utils::createShaderProgram("vertShader.glsl", "fragShader.glsl");
	/*GLFW在这里和这里解释文档中的两个坐标系。
		简而言之,窗口坐标是相对于监视器和 / 或窗口的,并且以不一定对应于真实屏幕像素的人造单元给出。 当DPI缩放被激活时(例如,在带有视网膜显示器的Mac上),情况尤其如此。
		与窗口坐标相比,帧缓冲区的大小与像素相关,以便与glViewport OpenGLs要求相匹配。
		请注意,在某些系统上,窗口坐标和像素坐标可以相同,但这不一定是正确的。*/
	glfwGetFramebufferSize(window, &g_width, &g_height);
	aspect = (float)g_width / (float)g_height;

	//必须要创建透视投影矩阵计算公式,否则第一帧渲染时,立方体不在视口中 :1.0472 radians = 60 degrees
	//glm::perspective使用模板定义,所以函数各个参数类型要一致
	projMat = glm::perspective(1.0472f, aspect, 0.01f, 1000.f);

	cameraX = 0.f;
	cameraY = 0.f;
	cameraZ = 32.f;

	setupVertices();
}

void display(GLFWwindow* window, float currentTime)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glClearColor(0.f, 0.7f, 1.f, 1.f);

	//启动着色器程序,在GPU上安装GLSL代码,这不会运行着色器程序,
	glUseProgram(renderingProgram);

	//获取uniform变量在着色器程序中的位置序号,通过该序号可以设置一致变量的值,如果没有该变量则返回-1
	mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix");
	projLoc = glGetUniformLocation(renderingProgram, "proj_matrix");

	//移动相机矩阵
	vMat = glm::translate(glm::mat4(1.f), glm::vec3(cameraX, cameraY, cameraZ));

	//更改一个uniform矩阵变量或数组的值。要更改的uniform变量的位置由location指定,location的值应该由glGetUniformLocation函数返回
	// 将透视矩阵和MV 矩阵复制给相应的统一变量
	/*通过一致变量(uniform修饰的变量)引用将一致变量值传入渲染管线。
		location : uniform的位置。
		count : 需要加载数据的数组元素的数量或者需要修改的矩阵的数量。
		transpose : 指明矩阵是列优先(column major)矩阵(GL_FALSE)还是行优先(row major)矩阵(GL_TRUE)。
		value : 指向由count个元素的数组的指针。
	*/
	glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projMat));
	//glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat));

	for (g_displayLoopi = 0; g_displayLoopi < 36; g_displayLoopi++)
	{
		tf = currentTime + g_displayLoopi;
		//平移矩阵
		tMat = glm::translate(glm::mat4(1.f), glm::vec3(glm::sin(.35f * tf) * 8.f, glm::cos(.52f * tf) * 8.f, glm::sin(.70f * tf) * 8.f));
		//旋转矩阵,绕x轴旋转
		rMat = glm::rotate(glm::mat4(1.f), glm::radians(40.f) * tf, glm::vec3(1.f, 0.f, 0.f));
		 //rMat = glm::rotate(glm::mat4(1.f), 1.75f * tf, glm::vec3(1.f, 0.f, 0.f));
		//旋转矩阵,绕y轴旋转
		rMat = glm::rotate(rMat, glm::radians(50.f) * tf, glm::vec3(0.f, 1.f, 0.f));
		 //rMat = glm::rotate(rMat, 1.75f * tf, glm::vec3(0.f, 1.f, 0.f));
		//旋转矩阵,绕z轴旋转
		rMat = glm::rotate(rMat, glm::radians(60.f) * tf, glm::vec3(0.f, 0.f, 1.f));
		 //rMat = glm::rotate(rMat, 1.75f * tf, glm::vec3(0.f, 0.f, 1.f));

		/*请注意最后一行中的矩阵乘法——
		操作中tMat 和rMat 的顺序很重要。它计算两个变换的结合,平移放在左边,旋转放在右边。
		当顶点随后乘以此矩阵时,计算从右到左进行,这意味着首先完成旋转,然后才是平移。
		变换的应用顺序很重要,改变顺序会导致不同的行为。图4.7 显示了为立方体设置了动画后
		显示的一些帧。*/
		mMat = tMat * rMat;
		//如果mMat和vMat位置变化,将看不到立方体
		mvMat = mMat * vMat;

		//更改一个uniform矩阵变量或数组的值。要更改的uniform变量的位置由location指定,location的值应该由glGetUniformLocation函数返回
	// 将透视矩阵和MV 矩阵复制给相应的统一变量
		glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat));
		glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projMat));

		//glBindVertexArray(vao[0]);
		glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
		//指定了渲染时索引值为 index 的顶点属性数组的数据格式和位置
	/*Parameters
	index
		指定要修改的顶点属性的索引值

		size
		指定每个顶点属性的组件数量。必须为1、2、3或者4。初始值为4。(梦维:如position是由3个(x, y, z)组成,而颜色是4个(r, g, b, a))

		type
		指定数组中每个组件的数据类型。可用的符号常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT,初始值为GL_FLOAT。

		normalized
		指定当被访问时,固定点数据值是否应该被归一化(GL_TRUE)或者直接转换为固定点值(GL_FALSE)。

		stride
		指定连续顶点属性之间的偏移量。如果为0,那么顶点属性会被理解为:它们是紧密排列在一起的。初始值为0。

		pointer
		指定一个指针,指向数组中第一个顶点属性的第一个组件。初始值为0。
		*/
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
		glEnableVertexAttribArray(0);

		//开启深度测试
		glEnable(GL_DEPTH_TEST);
		//指定用于深度缓冲比较值;
		glDepthFunc(GL_LEQUAL);
		glDrawArrays(GL_TRIANGLES, 0, 36);

	}
}

int main(int argc, char** argv)
{
	int glfwStates = glfwInit();
	if (glfwStates == GLFW_FALSE)
	{
		cout << "GLFW initialize failed, invoke glfwInit()......Error file:" << __FILE__ << "......Error line:" << __LINE__ << std::endl;
		glfwTerminate();
		exit(EXIT_FAILURE);
	}

	/*因为我们要使用OpenGL 4.6,所以我们把GLFW_CONTEXT_VERSION_MAJOR和GLFW_CONTEXT_VERSION_MINOR对应的hint都设置为4和6。
	因为我们要使用OpenGL核心模式(这个后面会提到更多),所以我们把GLFW_OPENGL_PROFILE对应的hint设置为GLFW_OPENGL_CORE_PROFILE,
	表示使用OpenGL核心模式。最后,把GLFW_RESIZABLE对应的hint设置为GLFW_FALSE,表示窗口不允许用户调整大小。
	之所以这样做是因为如果允许用户调整大小,大小发生变化后,窗口的绘制区域默认不变(依然是原来窗口的区域),
	也就是说窗口上绘制的图像的大小、位置不会发生改变。为了避免这种现象发生,我们就简单地不让用户调整窗口大小
	(当然也有更好的方法,就是用GLFW设置一个窗口大小的回调函数,但这样比较简单)。*/
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
	glfwWindowHint(GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_PROFILE);

	GLFWwindow* window = glfwCreateWindow(Screen_Width, Screen_Height, "Draw multiple cubes", nullptr, nullptr);
	if (!window)
	{
		cout << "GLFW create window failed, invoke glfwCreateWindow()......Error file:" << __FILE__ << "......Error line:" << __LINE__ << std::endl;
		glfwTerminate();
		exit(EXIT_FAILURE);
	}

	/*此函数使调用线程上的指定窗口的 OpenGL 或 OpenGL ES 上下文成为当前上下文。
	  一次只能在单个线程上使上下文成为当前上下文,并且每个线程一次只能有一个当前上下文。
	  在线程之间移动上下文时,必须先使其在旧线程上变为非当前状态,然后再在新线程上变为当前状态。
	*/
	glfwMakeContextCurrent(window);
	//glfwSetFramebufferSizeCallback()和glfwSetWindowSizeCallback区别
	//glfwSetFramebufferSizeCallback(window, window_size_callback);
	glfwSetWindowSizeCallback(window, window_size_callback);

	int glewStates = glewInit();
	if (GLEW_OK != glewStates)
	{
		cout << "GLEW initialize failed, invoke glewInit()......Error file:" << __FILE__ << "......Error line:" << __LINE__ << std::endl;
		glfwTerminate();
		exit(EXIT_FAILURE);
	}

	/*此函数设置当前 OpenGL 或 OpenGL ES 上下文的交换间隔,即从调用glfwSwapBuffers开始等待的屏幕更新次数,
	  然后再交换缓冲区并返回。这有时称为垂直同步、垂直回扫同步或仅vsync。
	  支持WGL_EXT_swap_control_tear和GLX_EXT_swap_control_tear扩展的上下文也接受负交换间隔,这允许驱动程序立即交换,
	  即使帧到达有点晚。您可以使用glfwExtensionSupported检查这些扩展。
	  上下文必须在调用线程上是最新的。在没有当前上下文的情况下调用此函数将导致GLFW_NO_CURRENT_CONTEXT错误。
	  此功能不适用于 Vulkan。如果您使用 Vulkan 进行渲染,请改为查看交换链的当前模式。
	*/
	glfwSwapInterval(1);

	init(window);

	while (!glfwWindowShouldClose(window))
	{
		display(window, (float)glfwGetTime());
		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glfwDestroyWindow(window);
	glfwTerminate();
	exit(EXIT_SUCCESS);

	return 0;
}

运行结果

在这里插入图片描述

源码下载

源码下载地址

标签:std,rMat,1.0,matrix,矩阵,报错,tf,GL,glm
来源: https://blog.csdn.net/aoxuestudy/article/details/122121529

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有