在OpenGL中移动加载进去的机器人模型

在OpenGL中,可以通过Assimp库来加载设计师已经建模好的3D模型,或者通过逐行读取模型数据也能达到同样的效果。在加载模型的过程中,最通用的一种模型格式是obj,不管是maya,3dsmax,还是blender,c4d,solidworks,都可以导出obj这种格式的模型,obj模型是一种文本格式,即意味着可以用记事本或者notepad++打开并编辑它,下图为notepad++下看到的模型数据。

在OpenGL中移动加载进去的机器人模型_第1张图片

   obj格式有4种数据,分别以以下字母开头:

  • v:顶点
  • vt:纹理坐标
  • vn:顶点法向量
  • f :面

这就是为什么上图全是以"V"开头的一行行数据,它的后面还有一行行vt,vn,f,最简单的obj模型可以不包含vt和vn,仅仅由v和f组成。如何加载模型可以看LearnOpenGL CN网站的教程,或者是网上其他逐行加载obj模型的代码。本文只讲述如何移动加载进去的模型。

在老版本的OpenGL中,可以通过glRotate和glTranslate来旋转和移动模型,但在3.3版本之后,这样的方法是不起作用的,在LearnOpenGL CN中,作者通过定义一个四元矩阵,再将其值传给着色器的方法来实现旋转缩放那张笑脸图片,教程链接:https://learnopengl-cn.github.io/01%20Getting%20started/07%20Transformations/,代码片段如下:

main.cpp

glm::mat4 trans;    // 定义一个4*4的矩阵
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));     // 缩放

shader.vs

..........此处省略...........
uniform mat4 transform;    // 定义4*4矩阵类型的uniform变量

void main()
{
    gl_Position = transform * vec4(aPos, 1.0f);    // 通过这行代码达到旋转缩放效果
    TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
}

 

通过本案例,我们可以用相同的方式来移动加载进去的3d模型而不仅仅是一张笑脸图片。我们可以定义一个矩阵,储存我们要进行的移动或是旋转,缩放动作,再将这个值传给模型矩阵,移动模型在世界坐标系中的位置。下面是QT中的参考代码,在LearnOpenGL CN中的教程中,定义矩阵用的是glm::mat4,与QT中有些差异,但整体思想是相同的。

// QOpenGLWidget中
QMatrix4x4 scaling;    // 定义一个4*4的矩阵
scaling.translate(QVector3D(0.0f, -1.0f, 0.0f));    // 移动
scaling.scale(0.01);    // 缩放
..........................................................

// 着色器中
gl_Position = projection * view * model * vec4(aPos, 1.0f);

当然移动一个模型是毫无意义的,通常在工业机器人场景中,需要将建模好的机器人动起来。比如一个机器人模型,通常是以关节为单位将它拆分,再在OpenGL中加载进全部的关节模型并恢复到原来的位置。在创建模型的时候尤其要注意,所有的关节不能都以基座标为坐标原点,这样会造成在移动单个关节的时候会以基座标为中心移动,每个关节应该以自己为中心。

下面的代码展示了在QT下如何旋转机器人的六个关节轴,通过信号槽连接QSlider实现滑条控制各关节轴的旋转:

// draw and rotate axes
  QMatrix4x4 scaling;    // 定义缩放大小及位置,所有的关节以此为标准
  scaling.translate(QVector3D(0.0f, -1.0f, 0.0f));
  scaling.scale(modelScaling);    // modelScaling是缩放系数,一般是一个比较小的小数

  QMatrix4x4 rotBase = scaling;
  rotBase.translate(0.0f, -2.0f, -6.0f);
  rotBase.rotate(180.0f, 1.0f, 0.0f, 0.0f);
  ResourceManager::getShader("model").use().setMatrix4f("model", rotBase);        // 使用着色器传递模型矩阵数据
  axis_base->draw(ResourceManager::getShader("model"));    // 加载并draw出关节底座

  QMatrix4x4 rot1 = rotBase;
  rot1.translate(0.0f, -2.45f, 0.0f);
  rot1.rotate(rotAngle1,0.0f, 1.0f, 0.0f);    // rotAngle1为关节1的旋转角度
  ResourceManager::getShader("model").use().setMatrix4f("model", rot1);
  axis_1->draw(ResourceManager::getShader("model"));

  QMatrix4x4 rot2 = rot1;
  rot2.translate(-2.55f, -3.0f, 0.0f);
  rot2.rotate(rotAngle2,1.0f, 0.0f ,0.0f);
  ResourceManager::getShader("model").use().setMatrix4f("model", rot2);
  axis_2->draw(ResourceManager::getShader("model"));

  QMatrix4x4 rot3 = rot2;
  rot3.translate(0.0f, -17.662f, 0.0f);
  rot3.rotate(rotAngle3,1.0f, 0.0f, 0.0f);
  ResourceManager::getShader("model").use().setMatrix4f("model", rot3);
  axis_3->draw(ResourceManager::getShader("model"));

  QMatrix4x4 rot4 = rot3;
  rot4.translate(0.0f, -16.43f, 0.0f);
  rot4.rotate(rotAngle4,1.0f, 0.0f, 0.0f);
  ResourceManager::getShader("model").use().setMatrix4f("model", rot4);
  axis_4->draw(ResourceManager::getShader("model"));

  QMatrix4x4 rot5 = rot4;
  rot5.translate(-1.602f, -2.217f, 0.0f);
  rot5.rotate(rotAngle5,0.0f, 1.0f, 0.0f);
  ResourceManager::getShader("model").use().setMatrix4f("model", rot5);
  axis_5->draw(ResourceManager::getShader("model"));

  QMatrix4x4 rot6 = rot5;
  rot6.translate(-2.309f, -1.67f, 0.0f);
  rot6.rotate(rotAngle6,1.0f, 0.0f, 0.0f);
  ResourceManager::getShader("model").use().setMatrix4f("model", rot6);
  axis_6->draw(ResourceManager::getShader("model"));

 

你可能感兴趣的:(OpenGL)