课程名称 | PAOGD | 任课老师 | 郑贵锋 |
---|---|---|---|
年级 | 16 | 专业(方向) | 软件工程(计算机应用方向) |
学号 | 16340132 | 姓名 | 梁颖霖 |
电话 | 13680473185 | [email protected] | |
开始日期 | 2019/4/27 | 完成日期 | 2019/5/2 |
HW3 OpenGL初步
apt-get install g++ cmake git
apt-get install libsoil-dev libglm-dev libassimp-dev libglew-dev libglfw3-dev libxinerama-dev libxcursor-dev libxi-dev
git clone https://github.com/JoeyDeVries/LearnOpenGL.git
cd LearnOpenGL
mkdir build
cd build
cmake ..
make -j8
编译完成后,各章节Demo可执行文件会在build/bin 目录下
下载安装CMake
打开到文件的目录下,这里我以加载模型的demo作为尝试
查看并重新编写CMakeList.txt,修改成编译单个工程的
在vs17中打开vs解决方案,编译完成后,生成了bin文件夹,里面就放着我们所运行的demo可执行文件
这里提示缺少assimp.dll,故需要下载assimp源码来生成一下。这里同样用到cmake生成build文件,再在vs17中编译生成。
执行exe文件即可,查看demo的运作
obj文件是3D模型文件格式。OBJ文件是一种文本文件,可以直接打开进行查看和编辑修改。
obj格式有4种数据,分别以一下字母开头:
这里,我们使用Blender所制造的模型导出成.obj文件,再在OpenGL中来控制这个模型的动作逻辑等。Blender偏向于可视化构造模型动画,而OpenGL则是用编码的手段来控制模型的动作,两者之间可以互相转换。
我们的顶点坐标起始于局部空间(Local Space),在这里它称为局部坐标(Local Coordinate),它在之后会变为世界坐标(World Coordinate),观察坐标(View Coordinate),裁剪坐标(Clip Coordinate),并最后以屏幕坐标(Screen Coordinate)的形式结束。
局部空间是指物体所在的坐标空间,即对象最开始所在的地方。想象你在一个建模软件(比如说Blender)中创建了一个立方体。你创建的立方体的原点有可能位于(0, 0, 0),即便它有可能最后在程序中处于完全不同的位置。甚至有可能你创建的所有模型都以(0, 0, 0)为初始位置。所以,你的模型的所有顶点都是在局部空间中:它们相对于你的物体来说都是局部的。
我们想为每一个物体定义一个位置,从而能在更大的世界当中放置它们。世界空间中的坐标正如其名:是指顶点相对于(游戏)世界的坐标。如果你希望将物体分散在世界上摆放(特别是非常真实的那样),这就是你希望物体变换到的空间。物体的坐标将会从局部变换到世界空间;该变换是由模型矩阵(Model Matrix)实现的。
观察空间经常被人们称之OpenGL的摄像机(Camera)(所以有时也称为摄像机空间(Camera Space)或视觉空间(Eye Space))。观察空间是将世界空间坐标转化为用户视野前方的坐标而产生的结果。因此观察空间就是从摄像机的视角所观察到的空间。而这通常是由一系列的位移和旋转的组合来完成,平移/旋转场景从而使得特定的对象被变换到摄像机的前方。这些组合在一起的变换通常存储在一个观察矩阵(View Matrix)里,它被用来将世界坐标变换到观察空间。
在一个顶点着色器运行的最后,OpenGL期望所有的坐标都能落在一个特定的范围内,且任何在这个范围之外的点都应该被裁剪掉(Clipped)。被裁剪掉的坐标就会被忽略,所以剩下的坐标就将变为屏幕上可见的片段。这也就是裁剪空间(Clip Space)名字的由来。因为将所有可见的坐标都指定在-1.0到1.0的范围内不是很直观,所以我们会指定自己的坐标集(Coordinate Set)并将它变换回标准化设备坐标系,就像OpenGL期望的那样。
OpenGL变换实际上是通过矩阵乘法来实现。不管是移动、旋转还是缩放大小,都是通过在当前矩阵的基础上乘以一个新的矩阵来达到目的。首先通过glMatrixMode()方法设置投影矩阵和模型观察矩阵,而后面的绘制过程,就是在模型矩阵中产生不同的点,形成各种图形,然后通过选择的投影矩阵投影到屏幕上,被我们观察到。所以对图形的各种操作也能够看成是对坐标系的变换。
在main函数中,glfwGetKey()
来进行获取
GLFW_PRESS表示当按键按下即进入if判断条件
if (glfwGetKey(window, GLFW_KEY_J) == GLFW_PRESS) {
// do sth
}
else if (glfwGetKey(window, GLFW_KEY_K) == GLFW_PRESS) {
// do sth
}
else if (glfwGetKey(window, GLFW_KEY_L) == GLFW_PRESS) {
// do sth
}
绕z轴旋转
这里利用的是glm::rotate(),
model是初始的单位矩阵,来对其做变换,可以绕x,y,z轴来进行变换,第二个参数是旋转的角度。
这里我根据时间来对旋转的角度来做增减操作,从而控制模型的旋转。
if (glfwGetKey(window, GLFW_KEY_J) == GLFW_PRESS) {
int count = 1;
while (!glfwWindowShouldClose(window)) {
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(0.0f, -1.25f, 0.0f));
model = glm::scale(model, glm::vec3(0.10f, 0.10f, 0.10f));
// 计数
count = (count + 1)%370;
Sleep(500);
printf("%f\n", 1.0f * count);
model = glm::rotate(model, 1.0f * count,
glm::vec3(0.0f, 1.0f, 0.0f));
ourShader.setMat4("model", model);
ourModel.Draw(ourShader);
glfwSwapBuffers(window);
glfwPollEvents();
// clear
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) break;
}
}
沿着水平方向往复移动
这里利用的是glm::translate(),
model是初始的单位矩阵,来对其做变换,根据后面的向量来进行平移变换。
这里我根据时间来对x坐标来做增减操作,从而控制模型的移动
else if (glfwGetKey(window, GLFW_KEY_K) == GLFW_PRESS) {
float length = 0;
int flag = 1;
while (!glfwWindowShouldClose(window)) {
if (length > 1.4) {
flag = -1;
}
if (length < -1.4) {
flag = 1;
}
length += flag * 0.1f;
Sleep(500);
printf("%f\n", length);
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(length, -1.25f, 0.0f));
model = glm::scale(model, glm::vec3(0.1f, 0.1f, 0.1f));
ourShader.setMat4("model", model);
ourModel.Draw(ourShader);
glfwSwapBuffers(window);
glfwPollEvents();
// clear
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) break;
}
}
在一定范围内不断放大缩小
这里利用的是glm::scale(),
model是初始的单位矩阵,来对其做变换,根据后面的向量来进行大小变换。
这里我根据时间来对放大系数来做增减操作,从而控制模型的缩放
else if (glfwGetKey(window, GLFW_KEY_L) == GLFW_PRESS) {
float scale_q = 0.1;
int flag = 1;
while (!glfwWindowShouldClose(window)) {
if (scale_q >= 0.15) {
flag = -1;
}
if (scale_q <= 0.05) {
flag = 1;
}
scale_q += flag * 0.01f;
Sleep(500);
printf("%f\n", scale_q);
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(0.0f, -1.25f, 0.0f));
model = glm::scale(model, glm::vec3(scale_q, scale_q, scale_q));
ourShader.setMat4("model", model);
ourModel.Draw(ourShader);
glfwSwapBuffers(window);
glfwPollEvents();
// clear
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) break;
}
}
ourShader.setMat4("model", model);
ourModel.Draw(ourShader);
glfwSwapBuffers(window);
glfwPollEvents();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
为了方便我们的操作调试,我加入了Q键来中止上述的动画
if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) break;