万向节死锁
万向节死锁(Gimbal Lock)是用欧拉角定义旋转时,产生的在某一情况下旋转轴重合导致的系统丢失自由度的情况,一种最简单的解决方式是调整三维软件中的旋转轴顺序来避免该情况发生。
也就是说当中间轴旋转至90°的时候就会 导致另外两个轴重合,这时候就可以把最不可能旋转90°的轴放到中间。还有一个解决办法是使用世界坐标系来控制旋转。
其本质就是:物体角度状态与欧拉角坐标并非一一对应关系。某些位置状态并不唯一确定一组欧拉角坐标。
参考https://www.bilibili.com/video/BV1Nr4y1j7kn?vd_source=8739e23f74da97a4bd8b25457db40474
矩阵的缩放,平移和旋转以及传递矩阵给着色器
glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);
// 译注:下面就是矩阵初始化的一个例子,如果使用的是0.9.9及以上版本
// 下面这行代码就需要改为:
// glm::mat4 trans = glm::mat4(1.0f)
// 之后将不再进行提示
// glm::mat4 trans;
trans = glm::translate(trans, glm::vec3(1.0f, 1.0f, 0.0f));//平移矩阵
// trans = glm::rotate(trans, glm::radians(90.0f), glm::vec3(0.0, 0.0, 1.0));//旋转矩阵,第二个参数要转换成弧度
// trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5));//缩放矩阵
// vec = trans * vec;
// std::cout << vec.x <<" "<< vec.y<<" " << vec.z << std::endl;
unsigned int transformLoc = glGetUniformLocation(myshader->ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
//第一个参数是uniform的位置值。
//第二个参数告诉OpenGL我们将要发送多少个矩阵
//第三个参数询问我们是否希望对我们的矩阵进行转置(Transpose)ring)
//最后一个参数是真正的矩阵数据,但是GLM并不是把它们的矩阵储存为OpenGL所希望接受的那种,因此我们要先用GLM的自带的函数value_ptr来变换这些数据。
练习
- 使用应用在箱子上的最后一个变换,尝试将其改变为先旋转,后位移。看看发生了什么,试着想想为什么会发生这样的事情:参考解答
先平移和先旋转的旋转中心点是不一样的,先旋转的话中心就是(0.5,0.5),先平移的话中心就是(0.75,0.25),所以结果很大差异
- 尝试再次调用glDrawElements画出第二个箱子,只使用变换将其摆放在不同的位置。让这个箱子被摆放在窗口的左上角,并且会不断的缩放(而不是旋转)。(
sin
函数在这里会很有用,不过注意使用sin
函数时应用负值会导致物体被翻转):参考解答
画完第一个三角形以后接着输入下面这些代码
trans = glm::mat4(1.0f);
float scaleAmountf = (sin(glfwGetTime())*0.5+0.5);
trans = glm::translate(trans, glm::vec3(-0.5f, 0.5f, 0.0f));//先平移
trans = glm::scale(trans, glm::vec3(scaleAmountf, scaleAmountf, 1.0f));//再缩放
transformLoc = glGetUniformLocation(myshader->ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);