OpenGL入门07.实现摄像机的旋转和移动
Posted stq_wyy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL入门07.实现摄像机的旋转和移动相关的知识,希望对你有一定的参考价值。
这篇文章记录的是如何在OpenGL中实现一个摄像机的旋转移动操作,首先我们需要添加监听事件,我们的旋转通过按下鼠标右键触发,W,A,S,D则控制前后左右的移动。
这里放一个完整版的Main代码:
#include "ggl.h"
#include "scene.h"
#include "texture.h"
#include "Utils.h"
#include "objmodel.h"
#include "camera.h"
Camera camera;
#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"glu32.lib")
#pragma comment(lib,"winmm.lib")
POINT originalPos;
bool bRotateView = false;
LRESULT CALLBACK GLWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
switch (msg)
case WM_RBUTTONDOWN:
originalPos.x = LOWORD(lParam);
originalPos.y = HIWORD(lParam);
ClientToScreen(hwnd, &originalPos);
SetCapture(hwnd);
ShowCursor(false);
bRotateView = true;
break;
case WM_RBUTTONUP:
SetCursorPos(originalPos.x, originalPos.y);
ReleaseCapture();
ShowCursor(true);
bRotateView = false;
break;
case WM_MOUSEMOVE:
if (bRotateView)
POINT currentPos;
currentPos.x = LOWORD(lParam);
currentPos.y = HIWORD(lParam);
ClientToScreen(hwnd, ¤tPos);
int deltaX = currentPos.x - originalPos.x;
int deltaY = currentPos.y - originalPos.y;
float angleRotatedByRight = (float)deltaY / 1000.0f;
float angleRotatedByUp = (float)deltaX / 1000.0f;
camera.Yaw(-angleRotatedByUp);
camera.Pitch(-angleRotatedByRight);
SetCursorPos(originalPos.x, originalPos.y);
break;
case WM_KEYDOWN:
switch (wParam)
case 'A':
camera.mbMoveLeft = true;
break;
case'D':
camera.mbMoveRight = true;
break;
case'W':
camera.mbMoveForward = true;
break;
case'S':
camera.mbMoveBack = true;
break;
break;
case WM_KEYUP:
switch (wParam)
case 'A':
camera.mbMoveLeft = false;
break;
case'D':
camera.mbMoveRight = false;
break;
case'W':
camera.mbMoveForward = false;
break;
case'S':
camera.mbMoveBack = false;
break;
break;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
return DefWindowProc(hwnd, msg, wParam, lParam);
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
//注册
WNDCLASSEX wndclass;
wndclass.cbClsExtra = 0;
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.cbWndExtra = 0;
wndclass.hbrBackground = NULL;
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hIcon = NULL;
wndclass.hIconSm = NULL;
wndclass.hInstance = hInstance;
wndclass.lpfnWndProc = GLWindowProc;
wndclass.lpszClassName = L"GLWindow";
wndclass.lpszMenuName = NULL;
wndclass.style = CS_VREDRAW | CS_HREDRAW;
ATOM atom = RegisterClassEx(&wndclass);
if (!atom)
MessageBox(NULL, L"Register Fail", L"Error", MB_OK);
return 0;
//设置窗口的视口大小
RECT rect;
rect.left = 0;
rect.right = 800;
rect.top = 0;
rect.bottom = 600;
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, NULL);
int windowWidth = rect.right - rect.left;
int windiwHeight = rect.bottom - rect.top;
//创建窗口
HWND hwnd = CreateWindowEx(NULL, L"GLWindow", L"OpenGL Window", WS_OVERLAPPEDWINDOW,
100, 100, windowWidth, windiwHeight,
NULL, NULL, hInstance, NULL);
//搭建OpenGL渲染环境---------------------------
HDC dc = GetDC(hwnd);
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nVersion = 1;
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
int pixelFormat = ChoosePixelFormat(dc, &pfd);
SetPixelFormat(dc, pixelFormat, &pfd);
HGLRC rc = wglCreateContext(dc);
wglMakeCurrent(dc, rc);
//搭建OpenGL渲染环境-----------------------------
//选中投影矩阵
glMatrixMode(GL_PROJECTION);
//给投影矩阵赋值
gluPerspective(50.0f, (float)windowWidth / (float)windiwHeight, 0.1f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Texture texture;
texture.Init("res/earth.bmp");
ObjModel model;
model.Init("res/Sphere.obj");
glClearColor(0.1, 0.4, 0.6, 1.0);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
//初始化灯光
float whiteColor[] = 1.0f,1.0f,1.0f,1.0f ;
//灯源位置
float lightPos[] = 0.0f,1.0f,0.0f,0.0f ;
//环境光
glLightfv(GL_LIGHT0, GL_AMBIENT, whiteColor);
//漫反射光
glLightfv(GL_LIGHT0, GL_DIFFUSE, whiteColor);
//镜面反射光
glLightfv(GL_LIGHT0, GL_SPECULAR, whiteColor);
//设置光源类型
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
//设置材质颜色
float blackMat[] = 0.0f,0.0f,0.0f,1.0f ;
float ambientMat[] = 0.1f,0.1f,0.1f,1.0f ;
float diffuseMat[] = 0.4f,0.4f,0.4f,1.0f ;
float specularMat[] = 0.9f,0.9f,0.9f,1.0f ;
glMaterialfv(GL_FRONT, GL_AMBIENT, ambientMat);
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuseMat);
//glMaterialfv(GL_FRONT, GL_SPECULAR, specularMat);
//设置镜面反射
//glMaterialf(GL_FRONT, GL_SHININESS, 30.0f);
//开启光照
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
//让窗口一直存在
MSG msg;
static float sTimeSinceStartUp = timeGetTime() / 1000.0f;
while (true)
if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
glLoadIdentity();
float currentTime = timeGetTime() / 1000.0f;
float timeElapse = currentTime - sTimeSinceStartUp;
sTimeSinceStartUp = currentTime;
//设置camera
camera.Update(timeElapse);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//开启纹理
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture.mTextureID);
model.Draw();
SwapBuffers(dc);
return 0;
在vector3f里重载了运算符,vector3f.h:
#pragma once
#include <math.h>
class Vector3f
public:
union
struct
float x, y, z;
;
float v[3];
;
Vector3f(float x, float y, float z);
Vector3f();
Vector3f operator*(float scaler);
float operator*(const Vector3f& r);
Vector3f operator^(const Vector3f& r);
Vector3f operator+(const Vector3f& r);
Vector3f operator-(const Vector3f& r);
void operator=(const Vector3f& r);
void Normalize();
float Magnitude();
;
vector3f.cpp:
#include "vector3f.h"
Vector3f::Vector3f(float x, float y, float z)
this->x = x;
this->y = y;
this->z = z;
Vector3f::Vector3f()
this->x = 0;
this->y = 0;
this->z = 0;
Vector3f Vector3f::operator*(float scaler)
return Vector3f(x * scaler, y * scaler, z * scaler);
float Vector3f::operator *(const Vector3f& r)
return x * r.x + y * r.y + z * r.z;
Vector3f Vector3f::operator^(const Vector3f& r)
return Vector3f(y * r.z - z * r.y, x * r.z - z * r.z, x * r.y - y * r.x);
Vector3f Vector3f::operator+(const Vector3f& r)
return Vector3f(x + r.x, y + r.y, z + r.z);
Vector3f Vector3f::operator-(const Vector3f& r)
return Vector3f(x - r.x, y - r.y, z - r.z);
void Vector3f::operator=(const Vector3f& r)
x = r.x;
y = r.y;
z = r.z;
void Vector3f::Normalize()
float len = Magnitude();
x /= len;
y /= len;
z /= len;
float Vector3f::Magnitude()
return sqrtf(x * x + y * y + z * z);
接下来是camera.h:
#pragma once
#include <windows.h>
#include <gl/GL.h>
#include "vector3f.h"
class Camera
protected:
void RotateView(float angle, float x, float y, float z);
public:
Camera();
Vector3f mPos, mViewCenter, mUp;
bool mbMoveLeft, mbMoveRight,mbMoveForward,mbMoveBack;
void Pitch(float angle);
void Yaw(float angle);
void Update(float deltaTime);
;
camera.cpp:
#include "camera.h"
#include <windows.h>
#include <gl/GL.h>
#include <gl/GLU.h>
#include "vector3f.h"
#include <stdio.h>
Camera::Camera() :mPos(0.0f, 0.0f, 0.0f), mViewCenter(0.0f, 0.0f, -1.0f),
mUp(0.0f, 1.0f, 0.0f), mbMoveLeft(false), mbMoveRight(false), mbMoveForward(false), mbMoveBack(false)
void Camera::RotateView(float angle, float x, float y, float z)
Vector3f viewDirection = mViewCenter - mPos;
Vector3f newDirection;
float C = cosf(angle);
float S = sinf(angle);
Vector3f tempX(C + x * x * (1 - C), x * y * (1 - C) - z * S, x * z * (1 - C) + y * S);
newDirection.x = tempX * viewDirection;
Vector3f tempY(x * y * (1 - C) + z * S, C + y * y * (1 - C), y * z * (1 - C) + x * S);
newDirection.y = tempY * viewDirection;
Vector3f tempZ(x * z * (1 - C) - y * S, y * z * (1 - C) + x * S, C + z * z * (1 - C));
newDirection.z = tempZ * viewDirection;
mViewCenter = mPos + newDirection;
void Camera::Pitch(float angle)
Vector3f viewDirection = mViewCenter - mPos;
viewDirection.Normalize();
Vector3f rightDirection = viewDirection ^ mUp;
rightDirection.Normalize();
RotateView(angle, rightDirection.x, rightDirection.y, rightDirection.z);
void Camera::Yaw(float angle)
RotateView(angle, mUp.x, mUp.y, mUp.z);
void Camera::Update(float deltaTime)
//update everything
float moveSpeed = 5.0f;
float rotateSpeed = 1.0f;
if (mbMoveLeft)
Vector3f viewDirection = mViewCenter - mPos;
viewDirection.Normalize();
Vector3f rightDirection = viewDirection ^ mUp;
rightDirection.Normalize();
mPos = mPos + rightDirection * moveSpeed * deltaTime * -1.0f;
mViewCenter = mViewCenter + rightDirection * moveSpeed * deltaTime * -1.0f;
if (mbMoveRight)
Vector3f viewDirection = mViewCenter - mPos;
viewDirection.Normalize();
Vector3f rightDirection = viewDirection ^ mUp;
rightDirection.Normalize();
mPos = mPos + rightDirection * moveSpeed * deltaTime;
mViewCenter = mViewCenter + rightDirection * moveSpeed * deltaTime;
if (mbMoveForward)
Vector3f forwardDirection = mViewCenter - mPos;
forwardDirection.Normalize();
mPos = mPos + forwardDirection * moveSpeed * deltaTime;
mViewCenter = mViewCenter + forwardDirection * moveSpeed * deltaTime;
if (mbMoveBack)
Vector3f backDirection = mPos - mViewCenter;
backDirection.Normalize();
mPos = mPos + backDirection * moveSpeed * deltaTime;
mViewCenter = mViewCenter + backDirection * moveSpeed * deltaTime;
//set model veiw matrix
gluLookAt(mPos.x, mPos.y, mPos.z,
mViewCenter.x, mViewCenter.y, mViewCenter.z,
mUp.x, mUp.y, mUp.z);
来个效果图:
以上是关于OpenGL入门07.实现摄像机的旋转和移动的主要内容,如果未能解决你的问题,请参考以下文章