opengl鼠標鍵盤控制相機漫游


 

鍵盤wsad控制相機位移,鼠標左鍵按下控制相機旋轉
效果如下
代碼如下
#include <stdio.h>
#include <string.h> 
#include <iostream>
#include <fstream> 
#include <sstream>
#include <GL/glew.h>  
#include <GL/freeglut.h>   
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> 

using namespace std;
using namespace glm;
 
const char* vsShaderName = "shader.vs";//頂點着色器
const char* fsShaderName = "shader.fs";//片元着色器

GLuint VBO;//頂點緩沖對象
GLuint IBO;//索引緩沖對象 
static  GLfloat *vertices;//頂點數組
static unsigned int *indices; //索引數組
GLuint ShaderProgram;
GLuint MatrixID;
int windowWidth = 800;
int windowHeight = 800;
//相機參數
glm::mat4 ViewMatrix;//視圖矩陣
glm::mat4 ProjectionMatrix; //投影矩陣
glm::mat4 MVP;//模型視圖矩陣
glm::mat4 ModelMatrix;//模型矩陣
glm::vec3 position = glm::vec3(5, 5, 5); //相機位置
float horizontalAngle = 3.14f;
float verticalAngle = 0.0f;
float initialFoV = 45.0f; //相機視場角
float speed = 0.05f; //平移速度
float mouseSpeed = 0.005f;
int mouseX, mouseY;//鼠標位置 窗口坐標
bool mouseLeftDown=false;//鼠標左鍵按下 

 // 傳遞鍵盤事件
static void SpecialKeyboardCB(unsigned char Key, int x, int y)
{ 
	glm::vec3 direction(
		cos(verticalAngle) * sin(horizontalAngle),
		sin(verticalAngle),
		cos(verticalAngle) * cos(horizontalAngle)
	);
	glm::vec3 right = glm::vec3(
		sin(horizontalAngle - 3.14f / 2.0f),
		0,
		cos(horizontalAngle - 3.14f / 2.0f)
	);
	glm::vec3 up = glm::cross(right, direction);

	switch (Key) {  
	case 'w':
		position += direction  * speed;
		//fprintf(stderr, "up \n");
		break; 
	case 'd':
		position += right  * speed;
		//fprintf(stderr, "right \n");
		break; 
	case 's':
		position -= direction  * speed;
		//fprintf(stderr, "down \n");
		break; 
	case 'a':
		position -= right  * speed;
		//fprintf(stderr, "left \n");
		break;
	case 27:
		exit(1);
		break;
	default:
		break;
		//fprintf(stderr, "Unimplemented GLUT key\n");
		//exit(1); 
	}

	float FoV = initialFoV;
	ProjectionMatrix = glm::perspective(glm::radians(FoV), (float)windowWidth /(float) windowHeight, 0.1f, 100.0f);
	ViewMatrix = glm::lookAt(
		position,
		position + direction,
		up
	);
	ModelMatrix = glm::mat4(1.0);
	MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
	glutPostRedisplay();//設置窗口重繪
}

//傳遞鼠標事件
void mouseCB(int button, int state, int x, int y)
{ 
	if (button == GLUT_LEFT_BUTTON)
	{
		if (state == GLUT_DOWN)
		{
			mouseLeftDown = true;
			mouseX = x;
			mouseY = y; 
		} 
		else if (state == GLUT_UP)
		{
			mouseLeftDown = false;
		}
	}  
}

//傳遞鼠標位置
static void mouseMotionCB(int x, int y)
{
	if (mouseLeftDown == true)
	{
		horizontalAngle += mouseSpeed * float(x - mouseX);
		verticalAngle += mouseSpeed * float(y - mouseY);
		mouseX = x;
		mouseY = y;
		SpecialKeyboardCB(0, 0, 0);
	}
}


//渲染回調函數 
void RenderScenceCB() {
	// 清空顏色緩存 
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
	glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); 
	glEnableVertexAttribArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); 
	glDrawArrays(GL_LINES, 0, 40*4);
	glDisableVertexAttribArray(0);
	//交換前后緩存
	glutSwapBuffers();
}

//創建頂點
static void CreateVertexBuffer()
{ 
	vertices = new GLfloat[40*3];
	for (size_t i = 0; i < 10; i++)
	{  
		vertices[i * 12] = 0;
		vertices[i * 12 + 1] = 0;
		vertices[i * 12 + 2] = i;

		vertices[i * 12 + 3] = 9;
		vertices[i * 12 + 4] = 0;
		vertices[i * 12 + 5] = i;

		vertices[i * 12 + 6] = i;
		vertices[i * 12 + 7] = 0;
		vertices[i * 12 + 8] = 0;

		vertices[i * 12 + 9] = i;
		vertices[i * 12 + 10] = 0;
		vertices[i * 12 + 11] = 9;
	}
	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);  
	glBufferData(GL_ARRAY_BUFFER, 40*3* sizeof(GLfloat), vertices, GL_STATIC_DRAW); 
} 
 
static void AddShader(GLuint ShaderProgram, const char* pShaderText, GLenum ShaderType)
{
	// 根據shader類型參數定義兩個shader對象
	GLuint ShaderObj = glCreateShader(ShaderType);
	// 檢查是否定義成功
	if (ShaderObj == 0) {
		fprintf(stderr, "Error creating shader type %d\n", ShaderType);
		exit(0);
	}
	// 定義shader的代碼源
	const GLchar* p[1];
	p[0] = pShaderText;
	GLint Lengths[1];
	Lengths[0] = strlen(pShaderText);
	glShaderSource(ShaderObj, 1, p, Lengths);
	glCompileShader(ShaderObj);// 編譯shader對象 
							   // 檢查和shader相關的錯誤
	GLint success;
	glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &success);
	if (!success) {
		GLchar InfoLog[1024];
		glGetShaderInfoLog(ShaderObj, 1024, NULL, InfoLog);
		fprintf(stderr, "Error compiling shader type %d: '%s'\n", ShaderType, InfoLog);
		exit(1);
	}
	// 將編譯好的shader對象綁定到program object程序對象上
	glAttachShader(ShaderProgram, ShaderObj);
}

// 編譯着色器函數
static void CompileShaders()
{
	// 創建着色器程序
	ShaderProgram = glCreateProgram();
	// 檢查是否創建成功
	if (ShaderProgram == 0) {
		fprintf(stderr, "Error creating shader program\n");
		exit(1);
	}
	// 存儲着色器文本的字符串
	string vs, fs;
	// 分別讀取着色器文件中的文本到字符串
	std::ifstream VertexShaderStream(vsShaderName, std::ios::in);
	if (VertexShaderStream.is_open()) {
		std::stringstream sstr;
		sstr << VertexShaderStream.rdbuf();
		vs = sstr.str();
		VertexShaderStream.close();
	}
	else {
		printf("Error to open %s\n", vsShaderName);
		getchar();
		exit(0);
	}
	std::ifstream FragmentShaderStream(fsShaderName, std::ios::in);
	if (FragmentShaderStream.is_open()) {
		std::stringstream sstr;
		sstr << FragmentShaderStream.rdbuf();
		fs = sstr.str();
		FragmentShaderStream.close();
	}

	// 添加頂點着色器和片段着色器
	AddShader(ShaderProgram, vs.c_str(), GL_VERTEX_SHADER);
	AddShader(ShaderProgram, fs.c_str(), GL_FRAGMENT_SHADER);
	// 鏈接shader着色器程序,並檢查程序相關錯誤
	GLint Success = 0;
	GLchar ErrorLog[1024] = { 0 };
	glLinkProgram(ShaderProgram);
	glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &Success);
	if (Success == 0) {
		glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog);
		fprintf(stderr, "Error linking shader program: '%s'\n", ErrorLog);
		exit(1);
	}
	// 檢查驗證在當前的管線狀態程序是否可以被執行
	glValidateProgram(ShaderProgram);
	glGetProgramiv(ShaderProgram, GL_VALIDATE_STATUS, &Success);
	if (!Success) {
		glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog);
		fprintf(stderr, "Invalid shader program: '%s'\n", ErrorLog);
		exit(1);
	}
	// 設置到管線聲明中來使用上面成功建立的shader程序
	glUseProgram(ShaderProgram);
	MatrixID = glGetUniformLocation(ShaderProgram, "gWVP");
}

int main(int argc, char ** argv) {
	// 初始化GLUT
	glutInit(&argc, argv);
	// 顯示模式:雙緩沖、RGBA
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowSize(windowWidth, windowHeight);
	glutInitWindowPosition(100, 100);
	glutCreateWindow("CameraTest");
	GLenum res = glewInit();
	if (res != GLEW_OK) {
		fprintf(stderr, "Error: '%s'\n", glewGetErrorString(res));
		return 1;
	}
	// 開始渲染
	glutDisplayFunc(RenderScenceCB);
	// 注冊鍵盤事件 
	glutKeyboardFunc(SpecialKeyboardCB);
	//注冊鼠標事件
	glutMouseFunc(mouseCB);
	glutMotionFunc(mouseMotionCB);
	mouseX = windowWidth / 2;
	mouseY = windowHeight / 2;
	// 緩存清空后的顏色值
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	//創建頂點
	CreateVertexBuffer(); 
	// 編譯着色器
	CompileShaders();
	//開啟深度測試
	glEnable(GL_DEPTH_TEST);
	// 通知開始GLUT的內部循環
	glutMainLoop();
	delete vertices;
	return 0;
}

 

#version 330 
layout (location = 0) in vec3 Position;  
uniform mat4 gWVP;  
out vec3 Color; 
void main()
{
    gl_Position = gWVP * vec4(Position, 1.0); 
	Color = Position/10;
}

 

#version 330 
out vec3 FragColor;   
in vec3 Color; 
void main()
{
    FragColor = Color;
}

 

本文鏈接https://www.cnblogs.com/gucheng/p/10139299.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM