【深圳大学计算机图形学】实验补充一 层级建模-机械手臂

目录

实验目的与要求

实验过程及内容

理论背景

实验内容

示例和练习

实验代码

实验补充一——main.cpp


实验目的与要求

  1. 了解层级建模基本概念
  2. 掌握简单平移,缩放,旋转的矩阵构建
  3. 了解变换矩阵在层级模型父子节点间的传递关系

实验过程及内容

理论背景

层次模型是指用树型(层次)结构表示实体类型及实体间联系的数据模型称为层次模型(Hierarchical Model)。

以实例代码中的机械手臂为例,其对应的层次模型表示如下

在对层次模型中的节点进行操作的时候,此操作不但会影响该节点的位置和方向,同样会影响该节点的所有子孙节点。

如在机械手臂模型中,底座的操作会影响整个模型,但是小臂的操作只影响自己。

实验内容

  1. 绘制每一个节点,完成base(),upper_arm(),lower_arm()三个函数。
  2. 构建子节点局部变化矩阵,使底座绕y轴旋转,大小臂绕z轴旋转,且大臂的旋转中心为大臂与底座的关节,小臂的旋转中心为大小臂的关节。根据遍历顺序完成display()函数。

节点的绘制以底座为例:

实验中按照层次模型深度优先遍历顺序,按照(底座,大臂,小臂)的顺序对节点进行绘制。注意,子节点的变换矩阵等于父节点的变换矩阵乘以子节点的局部变换矩阵。

示例和练习

1)示例代码中已经实现了base()函数,在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 "MeshPainter.h"

#include <vector>
#include <string>

#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)


int WIDTH = 600;
int HEIGHT = 600;

int mainWindow;

TriMesh* cube = new TriMesh();

Camera* camera = new Camera();
Light* light = new Light();
MeshPainter *painter = new MeshPainter();

// 这个用来回收和删除我们创建的物体对象
std::vector<TriMesh *> meshList;


// 关节角
enum{
    Base      = 0,
    LowerArm  = 1,
    UpperArm  = 2,
    NumAngles = 3
};
int     Axis = Base;
GLfloat Theta[NumAngles] = {0.0};

// 菜单选项值
const int Quit = 4;


// 尺寸参数
const GLfloat BASE_HEIGHT      = 0.2;
const GLfloat BASE_WIDTH       = 0.5;
const GLfloat UPPER_ARM_HEIGHT = 0.3;
const GLfloat UPPER_ARM_WIDTH  = 0.2;
const GLfloat LOWER_ARM_HEIGHT = 0.4;
const GLfloat LOWER_ARM_WIDTH  = 0.1;

// 绘制底座
void base(glm::mat4 modelView)
{
    // 按长宽高缩放正方体,平移至合适位置
	glm::mat4 instance = glm::mat4(1.0);
	instance = glm::translate(instance, glm::vec3(0.0, BASE_HEIGHT / 2, 0.0));
	instance = glm::scale(instance, glm::vec3(BASE_WIDTH, BASE_HEIGHT, BASE_WIDTH));

	// 绘制,由于我们只有一个立方体数据,所以这里可以直接指定绘制painter中存储的第0个立方体
	painter->drawMesh(0, modelView * instance, light, camera);
	
}


// 绘制大臂
void upper_arm(glm::mat4 modelView)
{
	// @TODO: 参考底座的绘制,在此添加代码绘制大臂

	// 创建一个模型矩阵实例,初始化为单位矩阵
	glm::mat4 instance = glm::mat4(1.0);

	// 平移到大臂中心位置
	instance = glm::translate(instance, glm::vec3(0.0, UPPER_ARM_HEIGHT / 2, 0.0));

	// 缩放大臂,使其具有指定的宽度、高度和宽度
	instance = glm::scale(instance, glm::vec3(UPPER_ARM_WIDTH, UPPER_ARM_HEIGHT, UPPER_ARM_WIDTH));

	// 绘制,由于只有一个立方体数据,这里直接指定绘制painter中存储的第0个立方体
	painter->drawMesh(0, modelView * instance, light, camera);
}

// 绘制小臂
void lower_arm(glm::mat4 modelView)
{
	// @TODO: 参考底座的绘制,在此添加代码绘制小臂

	// 创建一个模型矩阵实例,初始化为单位矩阵
	glm::mat4 instance = glm::mat4(1.0);

	// 平移到小臂中心位置
	instance = glm::translate(instance, glm::vec3(0.0, LOWER_ARM_HEIGHT / 2, 0.0));

	// 缩放小臂,使其具有指定的宽度、高度和宽度
	instance = glm::scale(instance, glm::vec3(LOWER_ARM_WIDTH, LOWER_ARM_HEIGHT, LOWER_ARM_WIDTH));

	// 绘制,由于只有一个立方体数据,这里直接指定绘制painter中存储的第0个立方体
	painter->drawMesh(0, modelView * instance, light, camera);
}


void init()
{
	std::string vshader, fshader;
	// 读取着色器并使用
	vshader = "shaders/vshader.glsl";
	fshader = "shaders/fshader.glsl";

	//创建机器臂的基础立方体
	cube->setNormalize(false);
	cube->generateCube();
	cube->setTranslation(glm::vec3(0.0, 0.0, 0.0));
	cube->setRotation(glm::vec3(0.0, 0.0, 0.0));
	cube->setScale(glm::vec3(1.0, 1.0, 1.0));
	// 加到painter中
	// 指定纹理与着色器,因为不用纹理图片所以就传个空字符串进去了
	painter->addMesh(cube, "Cube", "", vshader, fshader);
	meshList.push_back(cube);
	
	glClearColor(1.0, 1.0, 1.0, 1.0);
}

void display()
{
	// #ifdef __APPLE__ // 解决 macOS 10.15 显示画面缩小问题
	// glViewport(0, 0, WIDTH * 2, HEIGHT * 2);
	// #endif
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// 绘制底座 
	glm::mat4 modelView = glm::mat4(1.0);

	// 稍微下移一下,让机器人整体居中在原点
	modelView = glm::translate(modelView, glm::vec3(0.0, -BASE_HEIGHT, 0.0));

	// 底座旋转矩阵
	modelView = glm::rotate(modelView, glm::radians(Theta[Base]), glm::vec3(0.0, 1.0, 0.0));

	base(modelView); // 首先绘制底座

	// @TODO: 在此添加代码完成整个机械手臂绘制
	// 大臂变换矩阵
	modelView = glm::translate(modelView, glm::vec3(0.0, BASE_HEIGHT, 0.0));
	modelView = glm::rotate(modelView, glm::radians(Theta[UpperArm]), glm::vec3(0.0, 0.0, 1.0));

	// 绘制大臂
	upper_arm(modelView);

	// 小臂变换矩阵
	modelView = glm::translate(modelView, glm::vec3(0.0, UPPER_ARM_HEIGHT, 0.0));
	modelView = glm::rotate(modelView, glm::radians(Theta[LowerArm]), glm::vec3(0.0, 0.0, 1.0));

	// 绘制小臂    
	lower_arm(modelView);
}



void printHelp()
{
	std::cout << "================================================" << std::endl;
	std::cout << "Use mouse to controll the light position (drag)." << std::endl;
	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:		Base" << std::endl <<
		"2:		LowerArm" << std::endl <<
		"3:		UpperArm" << 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: Axis = Base; break;
		case GLFW_KEY_2: Axis = UpperArm; break;
		case GLFW_KEY_3: Axis = LowerArm; break;
		// 通过按键旋转
		case GLFW_KEY_A: 
			Theta[Axis] += 5.0;
			if (Theta[Axis] > 360.0)
				Theta[Axis] -= 360.0;
			break;
		case GLFW_KEY_S:
			Theta[Axis] -= 5.0;
			if (Theta[Axis] < 0.0)
				Theta[Axis] += 360.0;
			break;
		default:
			camera->keyboard(key, action, mode);
			break;
		}
	}
}


void cleanData() {
	// 释放内存
	
	delete camera;
	camera = NULL;

	delete light;
	light = NULL;

	painter->cleanMeshes();

	delete painter;
	painter = NULL;
	
	for (int i=0; i<meshList.size(); i++) {
		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, "2021150047_胡云飞_实验补充1", 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);
	// 启用混合
	glEnable(GL_BLEND);
	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 归忆)

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

归忆_AC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值