目录
实验目的与要求
- 掌握根据层级结构深度遍历层级树的方法
- 掌握采用堆栈的方式在父子和兄弟节点直接传递变换矩阵的方法。
实验过程及内容
理论背景
在上一次的上机实验课中,我们已经掌握了简单的每个父节点最多只有一个子节点层级建模方法,本节课中我们将学习在更复杂的层级模型中使用堆栈的方式来保存和恢复节点变换矩阵的方法。和上次实验使用的简单层级结构不同,本次实验的节点在完成自己和子孙节点的绘制以后需要恢复父节点的变换矩阵,因为该节点的兄弟节点需要父节点的变换矩阵。
本次上机课要使用的模型和层次结构参考下图:
在上图的层级结构中,头节点完成绘制以后,它的兄弟节点左上臂,右上臂,左上腿,右上腿等节点同样需要父节点躯干的变换矩阵,所以在绘制节点之前需要使用堆栈保存父节点的变化矩阵,在绘制兄弟节点之前从堆栈恢复父节点的变换矩阵。
实验内容
1.参考上次上机课的内容绘制每一个节点,完成torso(), head(), left_upper_arm(), left_lower_arm(), right_upper_arm(), right_lower_arm(), left_upper_leg(), left_lower_leg(), right_upper_leg(), right_lower_leg()函数。
2.按深度优先顺序,既 “躯干 -> 头 -> 左上臂 -> 左小臂 -> 右上臂 -> 右下臂 -> 左上腿 -> 左下腿 -> 右上腿 -> 右下腿”的顺序完成层级树的遍历,完成display()函数。
节点的绘制可以参考上次上机实验课的节点绘制方法,以本次的躯干绘制为例:
计算好变换矩阵之后,使用darwMesh函数进行绘制。
层级树的遍历绘制和堆栈使用参考如下躯干和头部的绘制:
主要参考函数
1.Void torso() 该函数完成躯干节点的绘制
2.上次实验课的display()函数,该函数调用每个节点的绘制方法,同时构建各个节点的局部变化矩阵;同时参考本文档实验内容的层级结构遍历和绘制伪代码完成本次上机课的display()函数。
示例和练习
1)示例代码中已经实现了躯干绘制代码,在display()函数中添加代码
可以绘制出躯干的效果如(a),将整个实验内容完成可以得到(b)的效果
2)示例代码中已经实现部分键盘触发功能,学生只需选择1、2或3触发相应部件操作;如图(c)所示,选中需要操作的节点以后,通过键盘A键和S键完成机器模型的变化。u/shift+u、i/shift+i和o/shift+o可以改变观察视角。
实验代码
实验补充二——main.cpp
#include "Angel.h"
#include "TriMesh.h"
#include "Camera.h"
#include <vector>
#include <string>
#include <algorithm>
#include <assert.h>
struct openGLObject
{
// 顶点数组对象
GLuint vao;
// 顶点缓存对象
GLuint vbo;
// 着色器程序
GLuint program;
// 着色器文件
std::string vshader;
std::string fshader;
// 着色器变量
GLuint pLocation;
GLuint cLocation;
GLuint nLocation;
// 投影变换变量
GLuint modelLocation;
GLuint viewLocation;
GLuint projectionLocation;
// 阴影变量
GLuint shadowLocation;
};
int WIDTH = 600;
int HEIGHT = 600;
int mainWindow;
class MatrixStack {
int _index;
int _size;
glm::mat4* _matrices;
public:
MatrixStack(int numMatrices = 100) :_index(0), _size(numMatrices)
{
_matrices = new glm::mat4[numMatrices];
}
~MatrixStack()
{
delete[]_matrices;
}
void push(const glm::mat4& m) {
assert(_index + 1 < _size);
_matrices[_index++] = m;
}
glm::mat4& pop() {
assert(_index - 1 >= 0);
_index--;
return _matrices[_index];
}
};
#define White glm::vec3(1.0, 1.0, 1.0)
#define Yellow glm::vec3(1.0, 1.0, 0.0)
#define Green glm::vec3(0.0, 1.0, 0.0)
#define Cyan glm::vec3(0.0, 1.0, 1.0)
#define Magenta glm::vec3(1.0, 0.0, 1.0)
#define Red glm::vec3(1.0, 0.0, 0.0)
#define Black glm::vec3(0.0, 0.0, 0.0)
#define Blue glm::vec3(0.0, 0.0, 1.0)
#define Brown glm::vec3(0.5, 0.5, 0.5)
struct Robot
{
// 关节大小
float TORSO_HEIGHT = 4.0;
float TORSO_WIDTH = 2.5;
float UPPER_ARM_HEIGHT = 2.5;
float LOWER_ARM_HEIGHT = 1.8;
float UPPER_ARM_WIDTH = 0.8;
float LOWER_ARM_WIDTH = 0.5;
float UPPER_LEG_HEIGHT = 2.8;
float LOWER_LEG_HEIGHT = 2.2;
float UPPER_LEG_WIDTH = 1.0;
float LOWER_LEG_WIDTH = 0.5;
float HEAD_HEIGHT = 1.8;
float HEAD_WIDTH = 1.5;
// 关节角和菜单选项值
enum {
Torso, // 躯干
Head, // 头部
RightUpperArm, // 右大臂
RightLowerArm, // 右小臂
LeftUpperArm, // 左大臂
LeftLowerArm, // 左小臂
RightUpperLeg, // 右大腿
RightLowerLeg, // 右小腿
LeftUpperLeg, // 左大腿
LeftLowerLeg, // 左小腿
};
// 关节角大小
GLfloat theta[10] = {
0.0, // Torso
0.0, // Head
0.0, // RightUpperArm
0.0, // RightLowerArm
0.0, // LeftUpperArm
0.0, // LeftLowerArm
0.0, // RightUpperLeg
0.0, // RightLowerLeg
0.0, // LeftUpperLeg
0.0 // LeftLowerLeg
};
};
Robot robot;
// 被选中的物体
int Selected_mesh = robot.Torso;
TriMesh* Torso = new TriMesh();
TriMesh* Head = new TriMesh();
TriMesh* RightUpperArm = new TriMesh();
TriMesh* RightLowerArm = new TriMesh();
TriMesh* LeftUpperArm = new TriMesh();
TriMesh* LeftLowerArm = new TriMesh();
TriMesh* RightUpperLeg = new TriMesh();
TriMesh* RightLowerLeg = new TriMesh();
TriMesh* LeftUpperLeg = new TriMesh();
TriMesh* LeftLowerLeg = new TriMesh();
openGLObject TorsoObject;
openGLObject HeadObject;
openGLObject RightUpperArmObject;
openGLObject RightLowerArmObject;
openGLObject LeftUpperArmObject;
openGLObject LeftLowerArmObject;
openGLObject RightUpperLegObject;
openGLObject RightLowerLegObject;
openGLObject LeftUpperLegObject;
openGLObject LeftLowerLegObject;
Camera* camera = new Camera();
// 获取生成的所有模型,用于结束程序时释放内存
std::vector<TriMesh*> meshList;
void drawMesh(glm::mat4 modelMatrix, TriMesh* mesh, openGLObject object) {
glBindVertexArray(object.vao);
glUseProgram(object.program);
// 父节点矩阵 * 本节点局部变换矩阵
glUniformMatrix4fv(object.modelLocation, 1, GL_FALSE, &modelMatrix[0][0]);
glUniformMatrix4fv(object.viewLocation, 1, GL_FALSE, &camera->viewMatrix[0][0]);
glUniformMatrix4fv(object.projectionLocation, 1, GL_FALSE, &camera->projMatrix[0][0]);
glUniform1f(object.shadowLocation, 0);
// 绘制
glDrawArrays(GL_TRIANGLES, 0, mesh->getPoints().size());
}
// 躯体
void torso(glm::mat4 modelMatrix)
{
// 本节点局部变换矩阵
glm::mat4 instance = glm::mat4(1.0);
instance = glm::translate(instance, glm::vec3(0.0, 0.5 * robot.TORSO_HEIGHT, 0.0));
instance = glm::scale(instance, glm::vec3(robot.TORSO_WIDTH, robot.TORSO_HEIGHT, robot.TORSO_WIDTH));
// 乘以来自父物体的模型变换矩阵,绘制当前物体
drawMesh(modelMatrix * instance, Torso, TorsoObject);
}
// 头部
void head(glm::mat4 modelMatrix)
{
// 本节点局部变换矩阵
glm::mat4 instance = glm::mat4(1.0);
instance = glm::translate(instance, glm::vec3(0.0, 0.5 * robot.HEAD_HEIGHT, 0.0));
instance = glm::scale(instance, glm::vec3(robot.HEAD_WIDTH, robot.HEAD_HEIGHT, robot.HEAD_WIDTH));
// 乘以来自父物体的模型变换矩阵,绘制当前物体
drawMesh(modelMatrix * instance, Head, HeadObject);
}
// 左大臂
void left_upper_arm(glm::mat4 modelMatrix)
{
// 本节点局部变换矩阵
glm::mat4 instance = glm::mat4(1.0);
instance = glm::translate(instance, glm::vec3(0.0, -0.5 * robot.UPPER_ARM_HEIGHT, 0.0));
instance = glm::scale(instance, glm::vec3(robot.UPPER_ARM_WIDTH, robot.UPPER_ARM_HEIGHT, robot.UPPER_ARM_WIDTH));
// 乘以来自父物体的模型变换矩阵,绘制当前物体
drawMesh(modelMatrix * instance, LeftUpperArm, LeftUpperArmObject);
}
// @TODO: 左小臂
void left_lower_arm(glm::mat4 modelMatrix)
{
// 本节点局部变换矩阵
glm::mat4 instance = glm::mat4(1.0);
instance = glm::translate(instance, glm::vec3(0.0, -0.5 * robot.LOWER_ARM_HEIGHT, 0.0));
instance = glm::scale(instance, glm::vec3(robot.LOWER_ARM_WIDTH, robot.LOWER_ARM_HEIGHT, robot.LOWER_ARM_WIDTH));
// 乘以来自父物体的模型变换矩阵,绘制当前物体
drawMesh(modelMatrix * instance, LeftLowerArm, LeftLowerArmObject);
}
// @TODO: 右大臂
void right_upper_arm(glm::mat4 modelMatrix)
{
// 本节点局部变换矩阵
glm::mat4 instance = glm::mat4(1.0);
instance = glm::translate(instance, glm::vec3(0.0, -0.5 * robot.UPPER_ARM_HEIGHT, 0.0));
instance = glm::scale(instance, glm::vec3(robot.UPPER_ARM_WIDTH, robot.UPPER_ARM_HEIGHT, robot.UPPER_ARM_WIDTH));
// 乘以来自父物体的模型变换矩阵,绘制当前物体
drawMesh(modelMatrix * instance, RightUpperArm, RightUpperArmObject);
}
// @TODO: 右小臂
void right_lower_arm(glm::mat4 modelMatrix)
{
// 本节点局部变换矩阵
glm::mat4 instance = glm::mat4(1.0);
instance = glm::translate(instance, glm::vec3(0.0, -0.5 * robot.LOWER_ARM_HEIGHT, 0.0));
instance = glm::scale(instance, glm::vec3(robot.LOWER_ARM_WIDTH, robot.LOWER_ARM_HEIGHT, robot.LOWER_ARM_WIDTH));
// 乘以来自父物体的模型变换矩阵,绘制当前物体
drawMesh(modelMatrix * instance, RightLowerArm, RightLowerArmObject);
}
// @TODO: 左大腿
void left_upper_leg(glm::mat4 modelMatrix)
{
// 本节点局部变换矩阵
glm::mat4 instance = glm::mat4(1.0);
instance = glm::translate(instance, glm::vec3(0.0, -0.5 * robot.UPPER_LEG_HEIGHT, 0.0));
instance = glm::scale(instance, glm::vec3(robot.UPPER_LEG_WIDTH, robot.UPPER_LEG_HEIGHT, robot.UPPER_LEG_WIDTH));
// 乘以来自父物体的模型变换矩阵,绘制当前物体
drawMesh(modelMatrix * instance, LeftUpperLeg, LeftUpperLegObject);
}
// @TODO: 左小腿
void left_lower_leg(glm::mat4 modelMatrix)
{
// 本节点局部变换矩阵
glm::mat4 instance = glm::mat4(1.0);
instance = glm::translate(instance, glm::vec3(0.0, -0.5 * robot.LOWER_LEG_HEIGHT, 0.0));
instance = glm::scale(instance, glm::vec3(robot.LOWER_LEG_WIDTH, robot.LOWER_LEG_HEIGHT, robot.LOWER_LEG_WIDTH));
// 乘以来自父物体的模型变换矩阵,绘制当前物体
drawMesh(modelMatrix * instance, LeftLowerLeg, LeftLowerLegObject);
}
// @TODO: 右大腿
void right_upper_leg(glm::mat4 modelMatrix)
{
// 本节点局部变换矩阵
glm::mat4 instance = glm::mat4(1.0);
instance = glm::translate(instance, glm::vec3(0.0, -0.5 * robot.UPPER_LEG_HEIGHT, 0.0));
instance = glm::scale(instance, glm::vec3(robot.UPPER_LEG_WIDTH, robot.UPPER_LEG_HEIGHT, robot.UPPER_LEG_WIDTH));
// 乘以来自父物体的模型变换矩阵,绘制当前物体
drawMesh(modelMatrix * instance, RightUpperLeg, RightUpperLegObject);
}
// @TODO: 右小腿
void right_lower_leg(glm::mat4 modelMatrix)
{
// 本节点局部变换矩阵
glm::mat4 instance = glm::mat4(1.0);
instance = glm::translate(instance, glm::vec3(0.0, -0.5 * robot.LOWER_LEG_HEIGHT, 0.0));
instance = glm::scale(instance, glm::vec3(robot.LOWER_LEG_WIDTH, robot.LOWER_LEG_HEIGHT, robot.LOWER_LEG_WIDTH));
// 乘以来自父物体的模型变换矩阵,绘制当前物体
drawMesh(modelMatrix * instance, RightLowerLeg, RightLowerLegObject);
}
void bindObjectAndData(TriMesh* mesh, openGLObject& object, const std::string& vshader, const std::string& fshader) {
// 创建顶点数组对象
glGenVertexArrays(1, &object.vao); // 分配1个顶点数组对象
glBindVertexArray(object.vao); // 绑定顶点数组对象
// 创建并初始化顶点缓存对象
glGenBuffers(1, &object.vbo);
glBindBuffer(GL_ARRAY_BUFFER, object.vbo);
glBufferData(GL_ARRAY_BUFFER,
(mesh->getPoints().size() + mesh->getColors().size() + mesh->getNormals().size()) * sizeof(glm::vec3),
NULL,
GL_STATIC_DRAW);
// 修改完TriMesh.cpp的代码成后再打开下面注释,否则程序会报错
glBufferSubData(GL_ARRAY_BUFFER, 0, mesh->getPoints().size() * sizeof(glm::vec3), &mesh->getPoints()[0]);
glBufferSubData(GL_ARRAY_BUFFER, mesh->getPoints().size() * sizeof(glm::vec3), mesh->getColors().size() * sizeof(glm::vec3), &mesh->getColors()[0]);
glBufferSubData(GL_ARRAY_BUFFER, (mesh->getPoints().size() + mesh->getColors().size()) * sizeof(glm::vec3), mesh->getNormals().size() * sizeof(glm::vec3), &mesh->getNormals()[0]);
object.vshader = vshader;
object.fshader = fshader;
object.program = InitShader(object.vshader.c_str(), object.fshader.c_str());
// 从顶点着色器中初始化顶点的坐标
object.pLocation = glGetAttribLocation(object.program, "vPosition");
glEnableVertexAttribArray(object.pLocation);
glVertexAttribPointer(object.pLocation, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
// 从顶点着色器中初始化顶点的颜色
object.cLocation = glGetAttribLocation(object.program, "vColor");
glEnableVertexAttribArray(object.cLocation);
glVertexAttribPointer(object.cLocation, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(mesh->getPoints().size() * sizeof(glm::vec3)));
// 从顶点着色器中初始化顶点的法向量
object.nLocation = glGetAttribLocation(object.program, "vNormal");
glEnableVertexAttribArray(object.nLocation);
glVertexAttribPointer(object.nLocation, 3,
GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET((mesh->getPoints().size() + mesh->getColors().size()) * sizeof(glm::vec3)));
// 获得矩阵位置
object.modelLocation = glGetUniformLocation(object.program, "model");
object.viewLocation = glGetUniformLocation(object.program, "view");
object.projectionLocation = glGetUniformLocation(object.program, "projection");
object.shadowLocation = glGetUniformLocation(object.program, "isShadow");
}
void bindLightAndMaterial(TriMesh* mesh, openGLObject& object, Light* light, Camera* camera) {
// 传递相机的位置
glUniform3fv(glGetUniformLocation(object.program, "eye_position"), 1, &camera->eye[0]);
// 传递物体的材质
glm::vec4 meshAmbient = mesh->getAmbient();
glm::vec4 meshDiffuse = mesh->getDiffuse();
glm::vec4 meshSpecular = mesh->getSpecular();
float meshShininess = mesh->getShininess();
glUniform4fv(glGetUniformLocation(object.program, "material.ambient"), 1, &meshAmbient[0]);
glUniform4fv(glGetUniformLocation(object.program, "material.diffuse"), 1, &meshDiffuse[0]);
glUniform4fv(glGetUniformLocation(object.program, "material.specular"), 1, &meshSpecular[0]);
glUniform1f(glGetUniformLocation(object.program, "material.shininess"), meshShininess);
// 传递光源信息
glm::vec4 lightAmbient = light->getAmbient();
glm::vec4 lightDiffuse = light->getDiffuse();
glm::vec4 lightSpecular = light->getSpecular();
glm::vec3 lightPosition = light->getTranslation();
glUniform4fv(glGetUniformLocation(object.program, "light.ambient"), 1, &lightAmbient[0]);
glUniform4fv(glGetUniformLocation(object.program, "light.diffuse"), 1, &lightDiffuse[0]);
glUniform4fv(glGetUniformLocation(object.program, "light.specular"), 1, &lightSpecular[0]);
glUniform3fv(glGetUniformLocation(object.program, "light.position"), 1, &lightPosition[0]);
}
void init()
{
std::string vshader, fshader;
// 读取着色器并使用
vshader = "shaders/vshader.glsl";
fshader = "shaders/fshader.glsl";
// 设置物体的大小(初始的旋转和位移都为0)
Torso->generateCube(Blue);
Head->generateCube(Green);
RightUpperArm->generateCube(Yellow);
LeftUpperArm->generateCube(Yellow);
RightUpperLeg->generateCube(Brown);
LeftUpperLeg->generateCube(Brown);
RightLowerArm->generateCube(Red);
LeftLowerArm->generateCube(Red);
RightLowerLeg->generateCube(Cyan);
LeftLowerLeg->generateCube(Cyan);
// 将物体的顶点数据传递
bindObjectAndData(Torso, TorsoObject, vshader, fshader);
bindObjectAndData(Head, HeadObject, vshader, fshader);
bindObjectAndData(RightUpperArm, RightUpperArmObject, vshader, fshader);
bindObjectAndData(LeftUpperArm, LeftUpperArmObject, vshader, fshader);
bindObjectAndData(RightUpperLeg, RightUpperLegObject, vshader, fshader);
bindObjectAndData(LeftUpperLeg, LeftUpperLegObject, vshader, fshader);
bindObjectAndData(RightLowerArm, RightLowerArmObject, vshader, fshader);
bindObjectAndData(LeftLowerArm, LeftLowerArmObject, vshader, fshader);
bindObjectAndData(RightLowerLeg, RightLowerLegObject, vshader, fshader);
bindObjectAndData(LeftLowerLeg, LeftLowerLegObject, vshader, fshader);
glClearColor(1.0, 1.0, 1.0, 1.0);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 相机矩阵计算
camera->updateCamera();
camera->viewMatrix = camera->getViewMatrix();
camera->projMatrix = camera->getProjectionMatrix(false);
// 物体的变换矩阵
glm::mat4 modelMatrix = glm::mat4(1.0);
// 保持变换矩阵的栈
MatrixStack mstack;
// 躯干(这里我们希望机器人的躯干只绕Y轴旋转,所以只计算了RotateY)
modelMatrix = glm::translate(modelMatrix, glm::vec3(0.0, 0.0, 0.0));
modelMatrix = glm::rotate(modelMatrix, glm::radians(robot.theta[robot.Torso]), glm::vec3(0.0, 1.0, 0.0));
torso(modelMatrix);
mstack.push(modelMatrix); // 保存躯干变换矩阵
// 头部(这里我们希望机器人的头部只绕Y轴旋转,所以只计算了RotateY)
modelMatrix = glm::translate(modelMatrix, glm::vec3(0.0, robot.TORSO_HEIGHT, 0.0));
modelMatrix = glm::rotate(modelMatrix, glm::radians(robot.theta[robot.Head]), glm::vec3(0.0, 1.0, 0.0));
head(modelMatrix);
modelMatrix = mstack.pop(); // 恢复躯干变换矩阵
// =========== 左臂 ===========
mstack.push(modelMatrix); // 保存躯干变换矩阵
// 左大臂(这里我们希望机器人的左大臂只绕Z轴旋转,所以只计算了RotateZ,后面同理)
modelMatrix = glm::translate(modelMatrix, glm::vec3(-0.5 * robot.TORSO_WIDTH - 0.5 * robot.UPPER_ARM_WIDTH, robot.TORSO_HEIGHT, 0.0));
modelMatrix = glm::rotate(modelMatrix, glm::radians(robot.theta[robot.LeftUpperArm]), glm::vec3(0.0, 0.0, 1.0));
left_upper_arm(modelMatrix);
// @TODO: 左小臂
modelMatrix = glm::translate(modelMatrix, glm::vec3(0.0, -robot.UPPER_ARM_HEIGHT, 0.0));
modelMatrix = glm::rotate(modelMatrix, glm::radians(robot.theta[robot.LeftLowerArm]), glm::vec3(1.0, 0.0, 0.0));
left_lower_arm(modelMatrix);
modelMatrix = mstack.pop(); // 恢复躯干变换矩阵
// =========== 右臂 ===========
mstack.push(modelMatrix); // 保存躯干变换矩阵
// @TODO: 右大臂
modelMatrix = glm::translate(modelMatrix, glm::vec3(0.5 * robot.TORSO_WIDTH + 0.5 * robot.UPPER_ARM_WIDTH, robot.TORSO_HEIGHT, 0.0));
modelMatrix = glm::rotate(modelMatrix, glm::radians(robot.theta[robot.RightUpperArm]), glm::vec3(1.0, .0, 0.0));
right_upper_arm(modelMatrix);
// @TODO: 右小臂
modelMatrix = glm::translate(modelMatrix, glm::vec3(0.0, -robot.UPPER_ARM_HEIGHT, 0.0));
modelMatrix = glm::rotate(modelMatrix, glm::radians(robot.theta[robot.RightLowerArm]), glm::vec3(1.0, 0.0, 0.0));
right_lower_arm(modelMatrix);
modelMatrix = mstack.pop(); // 恢复躯干变换矩阵
// =========== 左腿 ===========
mstack.push(modelMatrix); // 保存躯干变换矩阵
// @TODO: 左大腿
modelMatrix = glm::translate(modelMatrix, glm::vec3(-0.35 * robot.TORSO_WIDTH, 0.0, 0.0));
modelMatrix = glm::rotate(modelMatrix, glm::radians(robot.theta[robot.LeftUpperLeg]), glm::vec3(1.0, 0.0, 0.0));
left_upper_leg(modelMatrix);
// @TODO: 左小腿
modelMatrix = glm::translate(modelMatrix, glm::vec3(0.0, -robot.UPPER_LEG_HEIGHT, 0.0));
modelMatrix = glm::rotate(modelMatrix, glm::radians(robot.theta[robot.LeftLowerLeg]), glm::vec3(1.0, 0.0, 0.0));
left_lower_leg(modelMatrix);
modelMatrix = mstack.pop(); // 恢复躯干变换矩阵
// =========== 右腿 ===========
mstack.push(modelMatrix); // 保存躯干变换矩阵
// @TODO: 右大腿
modelMatrix = glm::translate(modelMatrix, glm::vec3(0.35 * robot.TORSO_WIDTH, 0.0, 0.0));
modelMatrix = glm::rotate(modelMatrix, glm::radians(robot.theta[robot.RightUpperLeg]), glm::vec3(1.0, 0.0, 0.0));
right_upper_leg(modelMatrix);
// @TODO: 右小腿
modelMatrix = glm::translate(modelMatrix, glm::vec3(0.0, -robot.UPPER_LEG_HEIGHT, 0.0));
modelMatrix = glm::rotate(modelMatrix, glm::radians(robot.theta[robot.RightLowerLeg]), glm::vec3(1.0, 0.0, 0.0));
right_lower_leg(modelMatrix);
modelMatrix = mstack.pop(); // 恢复躯干变换矩阵
}
void printHelp()
{
std::cout << "================================================" << std::endl << std::endl;
std::cout << "Use right click to open Menu." << std::endl;
std::cout << "================================================" << std::endl << std::endl;
std::cout << "Keyboard Usage" << std::endl;
std::cout <<
"[Window]" << std::endl <<
"ESC: Exit" << std::endl <<
"h: Print help message" << std::endl <<
std::endl <<
"[Part]" << std::endl <<
"1: Torso" << std::endl <<
"2: Head" << std::endl <<
"3: RightUpperArm" << std::endl <<
"4: RightLowerArm" << std::endl <<
"5: LeftUpperArm" << std::endl <<
"6: LeftLowerArm" << std::endl <<
"7: RightUpperLeg" << std::endl <<
"8: RightLowerLeg" << std::endl <<
"9: LeftUpperLeg" << std::endl <<
"0: LeftLowerLeg" << std::endl <<
std::endl <<
"[Model]" << std::endl <<
"a/A: Increase rotate angle" << std::endl <<
"s/S: Decrease rotate angle" << std::endl <<
std::endl <<
"[Camera]" << std::endl <<
"SPACE: Reset camera parameters" << std::endl <<
"u/U: Increase/Decrease the rotate angle" << std::endl <<
"i/I: Increase/Decrease the up angle" << std::endl <<
"o/O: Increase/Decrease the camera radius" << std::endl << std::endl;
}
// 键盘响应函数
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
float tmp;
glm::vec4 ambient;
if (action == GLFW_PRESS) {
switch (key)
{
case GLFW_KEY_ESCAPE: exit(EXIT_SUCCESS); break;
case GLFW_KEY_Q: exit(EXIT_SUCCESS); break;
case GLFW_KEY_1: Selected_mesh = robot.Torso; break;
case GLFW_KEY_2: Selected_mesh = robot.Head; break;
case GLFW_KEY_3: Selected_mesh = robot.RightUpperArm; break;
case GLFW_KEY_4: Selected_mesh = robot.RightLowerArm; break;
case GLFW_KEY_5: Selected_mesh = robot.LeftUpperArm; break;
case GLFW_KEY_6: Selected_mesh = robot.LeftLowerArm; break;
case GLFW_KEY_7: Selected_mesh = robot.RightUpperLeg; break;
case GLFW_KEY_8: Selected_mesh = robot.RightLowerLeg; break;
case GLFW_KEY_9: Selected_mesh = robot.LeftUpperLeg; break;
case GLFW_KEY_0: Selected_mesh = robot.LeftLowerLeg; break;
// 通过按键旋转
case GLFW_KEY_A:
robot.theta[Selected_mesh] += 5.0;
if (robot.theta[Selected_mesh] > 360.0)
robot.theta[Selected_mesh] -= 360.0;
break;
case GLFW_KEY_S:
robot.theta[Selected_mesh] -= 5.0;
if (robot.theta[Selected_mesh] < 0.0)
robot.theta[Selected_mesh] += 360.0;
break;
default:
camera->keyboard(key, action, mode);
break;
}
}
}
void cleanData() {
// 释放内存
delete camera;
camera = NULL;
for (int i = 0; i < meshList.size(); i++) {
meshList[i]->cleanData();
delete meshList[i];
}
meshList.clear();
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
int main(int argc, char** argv)
{
// 初始化GLFW库,必须是应用程序调用的第一个GLFW函数
glfwInit();
// 配置GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// 配置窗口属性
GLFWwindow* window = glfwCreateWindow(600, 600, "学号_姓名_实验补充2", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, key_callback);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// 调用任何OpenGL的函数之前初始化GLAD
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// Init mesh, shaders, buffer
init();
// 输出帮助信息
printHelp();
// 启用深度测试
glEnable(GL_DEPTH_TEST);
while (!glfwWindowShouldClose(window))
{
display();
// 交换颜色缓冲 以及 检查有没有触发什么事件(比如键盘输入、鼠标移动等)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
cleanData();
return 0;
}
// 每当窗口改变大小,GLFW会调用这个函数并填充相应的参数供你处理。
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
(by 归忆)