http://blog.csdn.net/yulinxx/article/details/59538755
在上篇的基础上,添加键盘的控制,实现物体的缩放,平移,旋转操作
分析:
放大: 当摄像机沿Z轴靠近物体,则物体显示会变大,反之则小
左右平移: 摄像机往左移,则看到的物体往右移
旋转: 以相机到物体的距离为半径进行旋转
当旋转后,再平移,比如相机到了b位置,再平移,以绿线为向量进行平移. 已知相机到物体的向量,已知相机的向上up向量0,1,0,可以叉乘得到垂直的绿线向量,再以此向量进行平移即可.
旋转后的放大缩小,则以相机到物体的向量进行平移.
代码如下:
定义两个全局变量:
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f); // 相机位置
glm::vec3 cameraTarg = glm::vec3(0.0f, 0.0f, 0.0f); // 物体位置
WSAD移动相机, QE旋转相机,X还原视图
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <SOIL/SOIL.h>
#include "Shader.h"
#pragma comment(lib, "SOIL.lib")
#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "glew32s.lib")
#pragma comment (lib, "glfw3.lib")
#pragma comment (lib, "glfw3dll.lib")
#pragma comment (lib, "glew32mxs.lib")
#pragma comment (lib, "assimp.lib")
#define WIDTH 800
#define HEIGH 600
GLfloat g_nX = 0;
GLfloat g_nY = 0;
GLfloat g_nZ = 0;
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 cameraTarg = glm::vec3(0.0f, 0.0f, 0.0f);
//glm::mat4 view; // 视图矩阵
GLfloat fRotateAngle = 0.0f;
void keyFun(GLFWwindow* pWnd, int nKey, int nScanCode, int nAction, int nMode);
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* pWnd = glfwCreateWindow(WIDTH, HEIGH, "OGL Geometry Shader", nullptr, nullptr);
glfwMakeContextCurrent(pWnd);
glfwSetKeyCallback(pWnd, keyFun);
glewExperimental = GL_TRUE;
glewInit();
glViewport(0, 0, WIDTH, HEIGH);
GLfloat fPoint[] = {
0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.6f, 0.0f, 0.0f, 1.0f, 1.0f,
-0.2f, -0.5f, 0.0f, 0.0f, 0.4f, 1.0f,
- 0.8f, 0.3f, 0.0f, 1.0f, 0.30f, 1.0f };
GLuint nVAO, nVBO;
glGenVertexArrays(1, &nVAO);
glBindVertexArray(nVAO);
{
glGenBuffers(1, &nVBO);
glBindBuffer(GL_ARRAY_BUFFER, nVBO);
{
glBufferData(GL_ARRAY_BUFFER, sizeof(fPoint), fPoint, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); // vertex
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6* sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1); // color
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6* sizeof(GLfloat), (GLvoid*)(3 * sizeof(GL_FLOAT)));
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glBindVertexArray(0);
glEnable(GL_PROGRAM_POINT_SIZE);
//Shader shader("./Shader/vertex.vx", "./Shader/geo.geo", "./Shader/frag.fg");
Shader shader("./Shader/vertex.vx", "./Shader/frag.fg");
shader.userShaderProg();
glm::mat4 model; // 模型矩阵
glm::mat4 view; // 视图矩阵
// 后移(观察点与物体在同一平面) 否则无法显示物体
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
// 投影矩阵 视角 宽高比 近 远截面
glm::mat4 proj = glm::perspective(45.0f, GLfloat(WIDTH / HEIGH), 0.1f, 100.0f);
// 获取Shader中 uniform 变量位置
GLint nModelLoc = glGetUniformLocation(shader.getProg(), "model");
GLint nViewLoc = glGetUniformLocation(shader.getProg(), "view");
GLint nProjLoc = glGetUniformLocation(shader.getProg(), "projection");
// 将矩阵传至Shader
glUniformMatrix4fv(nModelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(nViewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(nProjLoc, 1, GL_FALSE, glm::value_ptr(proj));
GLfloat radius = 6.0f;
while (!glfwWindowShouldClose(pWnd))
{
glfwPollEvents();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLfloat camX = sin(glfwGetTime()) * radius;
GLfloat camZ = cos(glfwGetTime()) * radius;
view = glm::lookAt(cameraPos, cameraTarg, glm::vec3(0.0, 1.0, 0.0));
glUniformMatrix4fv(nViewLoc, 1, GL_FALSE, glm::value_ptr(view));
glBindVertexArray(nVAO);
{
//glDrawArrays(GL_TRIANGLES, 0, sizeof(fPoint) / sizeof(GLfloat) / 6);
//glDrawArrays(GL_POINTS, 0, sizeof(fPoint) / sizeof(GLfloat) / 6);
glDrawArrays(GL_LINE_STRIP, 0, sizeof(fPoint) / sizeof(GLfloat) / 6);
}
glBindVertexArray(0);
glfwSwapBuffers(pWnd);
}
return 0;
}
void keyFun(GLFWwindow* pWnd, int nKey, int nScanCode, int nAction, int nMode)
{
if (nAction == GLFW_PRESS)
{
if (nKey == GLFW_KEY_W )
{
// 物体到相机的单位向量
glm::vec3 direction = glm::normalize(cameraTarg - cameraPos);
direction *= 0.2; // 移动0.2个单位向量
cameraPos += direction;
}
else if (nKey == GLFW_KEY_S)
{
glm::vec3 direction = glm::normalize(cameraTarg - cameraPos);
direction *= 0.2;
cameraPos -= direction;
}
else if (nKey == GLFW_KEY_A)
{
// 物体到相机的单位向量
glm::vec3 direction = glm::normalize(cameraTarg - cameraPos);
// 物体到相机的单位向量 与 相机的向上向量相乘,得到垂直向量,即平移向量
glm::vec3 vertical = glm::normalize(glm::cross(direction, glm::vec3(0.0f, 1.0f, 0.0f)));
vertical *= 0.2;
cameraPos += vertical; // 移动相机位置
cameraTarg += vertical; //相机的指向位置也一起平衡(不平移则以原来的目标转圈)
}
else if (nKey == GLFW_KEY_D)
{
glm::vec3 direction = glm::normalize(cameraTarg - cameraPos);
glm::vec3 vertical = glm::normalize(glm::cross(direction, glm::vec3(0.0f, 1.0f, 0.0f)));
vertical *= 0.2;
cameraPos -= vertical;
cameraTarg -= vertical;
}
else if (nKey == GLFW_KEY_Q)
{
GLfloat radius = glm::distance(cameraPos, cameraTarg);
fRotateAngle += 0.2;
GLfloat camX = sin(fRotateAngle) * radius + cameraTarg.x;
GLfloat camZ = cos(fRotateAngle) * radius + cameraTarg.z;
cameraPos = glm::vec3(camX, 0.0, camZ);
}
else if (nKey == GLFW_KEY_E)
{
GLfloat radius = glm::distance(cameraPos, cameraTarg);
fRotateAngle -= 0.2;
GLfloat camX = sin(fRotateAngle) * radius + cameraTarg.x;
GLfloat camZ = cos(fRotateAngle) * radius + cameraTarg.z;
cameraPos = glm::vec3(camX, 0.0, camZ);
}
else if (nKey == GLFW_KEY_X) // 还原视图
{
cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
cameraTarg = glm::vec3(0.0f, 0.0f, 0.0f);
}
}
}