ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

从零开始写一个opengl渲染器——基础设施搭建篇

2022-07-13 19:34:37  阅读:185  来源: 互联网

标签:Camera 渲染器 glm opengl 0.0 void 从零开始 GLFW vec3


基于OpenGL书《计算机图形学编程(使用OpenGL和C++)》中的描述,已经可以在屏幕上输出物体了。但是代码复用的比较多,所以要把复用的代码封装成类,方便后期的维护。先从原始代码中抽象出3个类:窗口类,相机类和控制器类。

窗口类

最开始的窗口代码

GLFWwindow* window = glfwCreateWindow(600, 600, "TEST", nullptr, nullptr);//创建GLFW窗口

glfwMakeContextCurrent(window);//将创建的GLFW窗口与opengl的上下文关联起来

这里的窗口需要指定长度和宽度。写在main函数中,不方便别的地方调用。

为了便于其他方法调用,封装窗口管理类,类中使用单例模式,因为整个程序中只会出现一个窗口。单例出来的实例可以在任意类中调用。

封装代码

//
// Filename: WindowManager.h
// Created by W. Mysterio on 2022-07-04 02:01:39.
// Description:
// Mail: woden3702@gmail.com
//

#ifndef __WINDOWMANAGER_H__
#define __WINDOWMANAGER_H__
#include "GLFW/glfw3.h"

struct WindowSize
{
	unsigned int w;//width
	unsigned int h;//height
};

class WindowManager
{
private:
	static WindowManager* ins_;
	WindowManager();
	WindowSize wSize_;
	GLFWwindow* window_;
public:
	~WindowManager();
	static WindowManager* instance();
	void createMainWindow(unsigned int w, unsigned int h, const char* title, bool fullScreen);
	WindowSize getWindowSize() const;
	GLFWwindow* getWindow() const;
};

#endif //__WINDOWMANAGER_H__
//
// Filename: WindowManager.cpp
// Created by W. Mysterio on 2022-07-04 02:01:39.
// Description:
// Mail: woden3702@gmail.com
//

#include "WindowManager.h"

WindowManager* WindowManager::ins_ = nullptr;

WindowManager::WindowManager() = default;


WindowManager::~WindowManager()
{
	delete ins_;
	ins_ = nullptr;
}

WindowManager* WindowManager::instance()
{
	if (ins_ == nullptr)
		ins_ = new WindowManager();
	return ins_;
}

void WindowManager::createMainWindow(unsigned w, unsigned h, const char* title, bool fullScreen)
{
	wSize_.w = w;
	wSize_.h = h;
	if (fullScreen)
		window_ = glfwCreateWindow(static_cast<int>(wSize_.w), static_cast<int>(wSize_.h), title, glfwGetPrimaryMonitor(), nullptr);
	else
		window_ = glfwCreateWindow(static_cast<int>(wSize_.w), static_cast<int>(wSize_.h), title, nullptr, nullptr);

	glfwSetWindowAttrib(window_, GLFW_RESIZABLE, GLFW_FALSE);//控制是否缩放
	glfwMakeContextCurrent(window_);
	glViewport(0, 0, static_cast<GLsizei>(wSize_.w), static_cast<GLsizei>(wSize_.h));
}

WindowSize WindowManager::getWindowSize() const
{
	return wSize_;
}

GLFWwindow* WindowManager::getWindow() const
{
	return window_;
}

封装好窗口管理类后,修改原来main函数中的代码,先调用createMainWindow方法初始化窗口,后面就可以通过单例方法直接调用窗口。

代码如下:

WindowManager::instance()->createMainWindow(1920, 1080, "test_1", false);
//调用窗口
WindowManager::instance()->getWindow())

相机类

第二个需要的是相机类,有了相机类可以方便后序实现相机移动。原本的代码需要先定义相机的位置坐标、投影矩阵和视图矩阵等信息,现在封装到一个类里,调用的时候会全部初始化。

原来的代码

封装好的相机类

//
// Filename: Camera.h
// Created by W. Mysterio on 2022-07-04 03:22:45.
// Description:
// Mail: woden3702@gmail.com
//

#ifndef __CAMERA_H__
#define __CAMERA_H__
#include <glm\glm.hpp>
#include <glm\gtc\type_ptr.hpp> // glm::value_ptr
#include <glm\gtc\matrix_transform.hpp>
#include "WindowManager.h"

class Camera
{
private:
	glm::vec3 position_; // 相机位置
	glm::vec3 cameraTarget_; //相机朝向
	glm::vec3 cameraDirection_; //相机的方向
	glm::vec3 cameraUp_; //相机的上方
	glm::vec3 cameraRight_; //相机的右轴

	float fov_; //度
	float farClip_;
	float nearClip_;

	float inWidth_;
	float inHeight_;
	float aspect_;
	glm::mat4 projectionMatrix_;
	glm::mat4 viewMatrix_;
	glm::mat4 modelMatrix_;
	glm::mat4 modelViewMatrix_;


public:

	Camera();
	~Camera();
	void SetPerspectiveCamera(float iFov, float iNearClip, float iFarClip);	void SetNearClip(float iNearClip);
	void setPosition(glm::vec3 ipos);
	void setDirection(glm::vec3 idir);
	float GetNearClip() const;
	void SetFarClip(float iFarClip);
	float GetFarClip() const;
	void SetFov(float iFov);
	float GetFov() const;
	void updateProjectionMatrix();
	void updateViewMatrix();
	void updateModelMatrix();
	void updateModelViewMatrix();
	glm::mat4 getModelViewMatrix() const;
	glm::mat4 getProjectionMatrix() const;
	glm::mat4 getViewMatrix() const;
	glm::vec3 getPosition() const;
	glm::vec3 getRight() const;
	glm::vec3 getDirection() const;
	glm::vec3 getUp() const;
};

#endif //__CAMERA_H__
//
// Filename: Camera.cpp
// Created by W. Mysterio on 2022-07-04 03:22:45.
// Description:
// Mail: woden3702@gmail.com
//

#include "Camera.h"
float toRadians(float degrees) { return (degrees * 2.0f * 3.14159f) / 360.0f; }
glm::vec3 up= glm::vec3(0.0, 1.0f, 0.0f);
glm::vec3 front = glm::vec3(0.0, 0.0f, -1.0f);

Camera::Camera()
{
	position_ = glm::vec3(0.0f, 0.0f, 8.0f);
	cameraTarget_ = glm::vec3(0.0f, 0.0f, 0.0f);
	cameraDirection_ = glm::vec3(0.0, 0.0f, -1.0f);
	cameraUp_ = glm::vec3(0.0, 1.0f, 0.0f);
	cameraRight_ = glm::normalize(glm::cross(cameraDirection_, cameraUp_));

	fov_ = 60.0f; //度
	farClip_ = 1000.0f;
	nearClip_ = 0.1f;
	inWidth_ = WindowManager::instance()->getWindowSize().w;
	inHeight_ = WindowManager::instance()->getWindowSize().h;
	aspect_ = inWidth_ / inHeight_;
	updateProjectionMatrix();
	updateViewMatrix();
}

Camera::~Camera() = default;

void Camera::updateProjectionMatrix()
{
	projectionMatrix_= glm::perspective(toRadians(fov_), aspect_, nearClip_, farClip_);
}

void Camera::SetNearClip(float iNearClip)
{
	nearClip_ = iNearClip;
}

void Camera::setPosition(glm::vec3 ipos)
{
	position_ = ipos;
}

void Camera::setDirection(glm::vec3 idir)
{
	cameraDirection_ = idir;
}

float Camera::GetNearClip() const
{
	return nearClip_;
}

void Camera::SetFarClip(float iFarClip)
{
	farClip_ = iFarClip;
}

float Camera::GetFarClip() const
{
	return farClip_;
}

void Camera::SetFov(float iFov)
{
	fov_ = iFov;
}

float Camera::GetFov() const
{
	return fov_;
}

void Camera::updateViewMatrix()
{

	viewMatrix_= glm::lookAt(position_,position_+cameraDirection_,cameraUp_);
}

void Camera::updateModelMatrix()
{
	modelMatrix_ = glm::translate(glm::mat4(1.0f),cameraTarget_);
}

void Camera::updateModelViewMatrix()
{
	modelViewMatrix_ = viewMatrix_ * modelMatrix_;
}

glm::mat4 Camera::getModelViewMatrix() const
{
	return modelViewMatrix_;
}

glm::mat4 Camera::getProjectionMatrix() const
{
	return projectionMatrix_;
}

glm::mat4 Camera::getViewMatrix() const
{
	return viewMatrix_;
}

glm::vec3 Camera::getPosition() const
{
	return position_;
}

glm::vec3 Camera::getRight() const
{
	return glm::normalize(glm::cross(cameraDirection_, cameraUp_));
}

glm::vec3 Camera::getDirection() const
{
	return cameraDirection_;
}

glm::vec3 Camera::getUp() const
{
	return cameraUp_;
}

目前相机类仍然是比较复杂,后期需要重构,可能还要抽象出一个物体类,封装坐标等信息

如果想要在别的函数中直接获取已有的相机对象,则需要一个相机管理类,管理创建删除等操作。

//
// Filename: CameraManager.h
// Created by W. Mysterio on 2022-07-07 03:20:01.
// Description:
// Mail: woden3702@gmail.com
//

#ifndef __CAMERAMANAGER_H__
#define __CAMERAMANAGER_H__
#include <stack>
#include <memory>

#include "Camera.h"

class CameraManager
{
private:
	CameraManager();
	static CameraManager* ins_;
	std::stack<std::shared_ptr<Camera>> cams_;
public:

	~CameraManager();
	static CameraManager* instance();
	std::shared_ptr<Camera> push();
	void pop();
	std::shared_ptr<Camera> getCurCamera();
};

#endif //__CAMERAMANAGER_H__
//
// Filename: CameraManager.cpp
// Created by W. Mysterio on 2022-07-07 03:20:01.
// Description:
// Mail: woden3702@gmail.com
//

#include "CameraManager.h"

CameraManager* CameraManager::ins_ = nullptr;

CameraManager::CameraManager() = default;

CameraManager::~CameraManager()
{
	ins_ = nullptr;
}

CameraManager* CameraManager::instance()
{
	if (ins_ == nullptr)
		ins_ = new CameraManager();
	return ins_;
}

std::shared_ptr<Camera> CameraManager::push()
{
	std::shared_ptr<Camera> newCam = std::make_shared<Camera>();
	cams_.push(newCam);
	return newCam;
}

void CameraManager::pop()
{
	cams_.pop();
}

std::shared_ptr<Camera> CameraManager::getCurCamera()
{
	return cams_.top();
}

管理类都长一个样子,后面的管理类大概都是这个模式。

控制类

创建好相机后,要实现移动相机,需要绑定一些回调函数。为了方便管理,把这些操作封装成一个控制类。

//
// Filename: Controller.h
// Created by W. Mysterio on 2022-07-07 03:58:35.
// Description:
// Mail: woden3702@gmail.com
//

#ifndef __CONTROLLER_H__
#define __CONTROLLER_H__
#include <glm/vec3.hpp>
#include <glm\gtc\type_ptr.hpp> // glm::value_ptr
#include <glm\gtc\matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale, glm::perspective

#include "WindowManager.h"
#define FIXEDUPDATE_TIME 0.01f//In seconds

class Controller
{
private:
	double lastMousePos[2];
	int curMouseButton;
	float moveSpeed=3.0f;
	glm::vec3 moveVec;
	float rotSensitivity[2];
	float mouseMovSensitivity[3];
	float offsetX, offsetY;
	float yaw, pitch;//两种欧拉角  俯仰角(Pitch)、偏航角(Yaw)
public:
	Controller();
	void init();
	void update();
	void MouseMotionCallback(GLFWwindow* window, double x, double y);
	void MouseKeyCallback(GLFWwindow* window, int button, int state, int mods);
	void KeyInputCallback(GLFWwindow* window, int key, int scanCode, int action, int mods);
};

#endif //__CONTROLLER_H__
//
// Filename: Controller.cpp
// Created by W. Mysterio on 2022-07-07 03:58:35.
// Description:
// Mail: woden3702@gmail.com
//

#include "Controller.h"

#include "CameraManager.h"

Controller::Controller()
{
	init();
}

void Controller::init()
{
	rotSensitivity[0] = 0.05f;
	rotSensitivity[1] = 0.03f;
	mouseMovSensitivity[0] = 0.02f;
	mouseMovSensitivity[1] = 0.01f;
	mouseMovSensitivity[2] = 0.1f;
	moveVec = glm::vec3(0.0f, 0.0f, 0.0f);
	yaw = -90.0f;
	pitch = 0.0f;
}

void Controller::update()
{
	if (curMouseButton == GLFW_MOUSE_BUTTON_RIGHT)
	{
		glm::vec3 curPos = CameraManager::instance()->getCurCamera()->getPosition();
		// printf("按下右键 position: ");
		// printf("(%f,%f,%f)\n", curPos.x, curPos.y, curPos.z);
		// printf("sasd%f\n", moveVec.x);
		curPos = curPos + (normalize(CameraManager::instance()->getCurCamera()->getDirection()) * moveSpeed * moveVec.x +
			normalize(CameraManager::instance()->getCurCamera()->getRight()) * moveSpeed * moveVec.y +
			normalize(CameraManager::instance()->getCurCamera()->getUp()) * moveSpeed * moveVec.z) * FIXEDUPDATE_TIME;
		// printf("______处理完后: ");
		// printf("(%f,%f,%f)\n", curPos.x, curPos.y, curPos.z);
		CameraManager::instance()->getCurCamera()->setPosition(curPos);
	}
}

void Controller::MouseMotionCallback(GLFWwindow* window, double x, double y)
{
	switch (curMouseButton)
	{
	case GLFW_MOUSE_BUTTON_RIGHT:
	{
			//参考https://learnopengl-cn.github.io/01%20Getting%20started/09%20Camera/#_6
		offsetX = x - lastMousePos[0];
		offsetY = lastMousePos[1] - y;
		// printf("(%f,%f)\n", x, y);
		// printf("(%f,%f)\n", offsetX, offsetY);
		offsetX *= rotSensitivity[0];
		offsetY *= rotSensitivity[1];
		yaw += offsetX;
		pitch += offsetY;

		if (pitch > 89.0f)
			pitch = 89.0f;
		if (pitch < -89.0f)
			pitch = -89.0f;

		glm::vec3 front;
		front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
		front.y = sin(glm::radians(pitch));
		front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
		CameraManager::instance()->getCurCamera()->setDirection(normalize(front));
	}
	break;
	}
	//记录鼠标松开的位置
	lastMousePos[0] = x;
	lastMousePos[1] = y;
}

void Controller::MouseKeyCallback(GLFWwindow* window, int button, int state, int mods)
{
	switch (state)
	{
	case GLFW_PRESS:
	{
		curMouseButton = button;
	}
	break;
	case GLFW_RELEASE:
	{
		curMouseButton = -1;
	}
	break;
	}

	glfwGetCursorPos(window, &lastMousePos[0], &lastMousePos[1]);
}

void Controller::KeyInputCallback(GLFWwindow* window, int key, int scanCode, int action, int mods)
{
	switch (key)
	{
	default:
		break;
	case GLFW_KEY_W:
		moveVec.x = (action == GLFW_PRESS || action == GLFW_REPEAT) ? 1.0f : 0.0f;
		break;
	case GLFW_KEY_S:
		moveVec.x = (action == GLFW_PRESS || action == GLFW_REPEAT) ? -1.0f : 0.0f;
		break;
	case GLFW_KEY_A:
		moveVec.y = (action == GLFW_PRESS || action == GLFW_REPEAT) ? -1.0f : 0.0f;
		break;
	case GLFW_KEY_D:
		moveVec.y = (action == GLFW_PRESS || action == GLFW_REPEAT) ? 1.0f : 0.0f;
		break;
	case GLFW_KEY_E:
		moveVec.z = (action == GLFW_PRESS || action == GLFW_REPEAT) ? 1.0f : 0.0f;
		break;
	case GLFW_KEY_Q:
		moveVec.z = (action == GLFW_PRESS || action == GLFW_REPEAT) ? -1.0f : 0.0f;
		break;
	}


	switch (key)
	{
	default:
		break;
	case GLFW_KEY_W:
		if (action == GLFW_RELEASE)
		{
			moveVec.x = 0.0f;
		}
		break;
	case GLFW_KEY_S:
		if (action == GLFW_RELEASE)
		{
			moveVec.x = 0.0f;
		}
		break;
	case GLFW_KEY_A:
		if (action == GLFW_RELEASE)
		{
			moveVec.y = 0.0f;
		}
		break;
	case GLFW_KEY_D:
		if (action == GLFW_RELEASE)
		{
			moveVec.y = 0.0f;
		}
		break;
	case GLFW_KEY_E:
		if (action == GLFW_RELEASE)
		{
			moveVec.z = 0.0f;
		}
		break;
	case GLFW_KEY_Q:
		if (action == GLFW_RELEASE)
		{
			moveVec.z = 0.0f;
		}
		break;
	case GLFW_KEY_SPACE:
		if (action == GLFW_PRESS)
		{
			//回到原位
			CameraManager::instance()->getCurCamera()->setPosition(glm::vec3(0.0f, 0.0f, 8.0f));
			CameraManager::instance()->getCurCamera()->setDirection(glm::vec3(0.0f, 0.0f, -1.0f));
			CameraManager::instance()->getCurCamera()->updateViewMatrix();
		}
	}
}

在该类中,实现了按住鼠标右键的同时按住wasdqe方向键实现相机的前后左右上下移动,操作方式和unity中的一致。

主要逻辑是在主循环中调用控制类中的update方法,该方法实现的功能是按住鼠标右键获取当前相机的位置坐标,通过回调函数监听各个坐标的改变情况,再实现位置坐标的改变,目前相机类缺少旋转坐标,后期要想办法加上去。

后期可能还有别的种类的控制类,还需要创建一个控制类的父类,绑定鼠标按键等重复操作。

实现控制管理类:

//
// Filename: ControllerManager.h
// Created by W. Mysterio on 2022-07-07 04:20:43.
// Description:
// Mail: woden3702@gmail.com
//

#ifndef __CONTROLLERMANAGER_H__
#define __CONTROLLERMANAGER_H__
#include <stack>
#include <memory>
#include "Controller.h"

class ControllerManager
{
private:
	ControllerManager();
	static ControllerManager* ins_;
	std::stack<std::shared_ptr<Controller>> ctrls_;
public:
	~ControllerManager();
	static ControllerManager* instance();
	void push();
	void push(std::shared_ptr<Controller>);
	void pop();
	std::shared_ptr<Controller> getCurController();
};

#endif //__CONTROLLERMANAGER_H__
//
// Filename: ControllerManager.cpp
// Created by W. Mysterio on 2022-07-07 04:20:43.
// Description:
// Mail: woden3702@gmail.com
//

#include "ControllerManager.h"
ControllerManager* ControllerManager::ins_ = nullptr;

ControllerManager::ControllerManager()= default;

ControllerManager::~ControllerManager()
{
	ins_ = nullptr;
}

ControllerManager* ControllerManager::instance()
{
	if (ins_ == nullptr)
		ins_ = new ControllerManager();
	return ins_;
}

void ControllerManager::push()
{
	auto newCtrl = std::make_shared<Controller>();
	ctrls_.push(newCtrl);
}

void ControllerManager::push(std::shared_ptr<Controller> controller)
{
	ctrls_.push(controller);
}

void ControllerManager::pop()
{
	ctrls_.pop();
}

std::shared_ptr<Controller> ControllerManager::getCurController()
{
	return ctrls_.top();
}

代码参考haha2345/myTinyOpenglRender (github.com)

标签:Camera,渲染器,glm,opengl,0.0,void,从零开始,GLFW,vec3
来源: https://www.cnblogs.com/woden3702/p/16475276.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有