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, &currentPos);
			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.实现摄像机的旋转和移动的主要内容,如果未能解决你的问题,请参考以下文章

✠OpenGL-7-光照

OpenGL入门8:摄像机

OpenGL入门04.光照

如何避免 OpenGL 中的光旋转?

OpenGL相机旋转怪异

过多的镜面光opengl