opengl可编程管线鼠标画线段

学习opengl可编程管线的基础知识的网站:learnOpengl

主要讲一下如何使用可编程管线实现鼠标交互的线段绘制。

首先声明两种回调函数以及将其设置给对应的函数:



MouseButtonCallback在鼠标按下时才会调用,CursorPosCallback则在每一帧都会附给width和height鼠标的实时坐标。

然后再看一下这两个函数的具体内容:


firstClick如果为true,代表线段的起点已经确定,再次点击会确定终点,并将firstClick设为false。

glfwGetCursorPos会将鼠标的实时位置附给两个参数tempX和tempY,该坐标为屏幕坐标,因此需要进行坐标转换,将其转换为窗口坐标。


当线段起点确定后,可以通过该函数在每一帧都以当前鼠标坐标为终点绘制出线段。

然后再看具体的绘制语句:


绑定对应的VAO,然后在glDrawArrays中选择GL_LINE_STRIP参数,注意不要使用GL_LINE,GL_LINE是用于固定管线的绘制。

#include <glad/glad.h>
#include <glfw3.h>
#include <iostream>
#include <shader_m.h>

void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
bool firstClick = true;
double startPointX,startPointY,endPointX,endPointY;
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";

unsigned int VBO, VAO;

int main()
{

	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
														 
	GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
	if (window == NULL)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
	glfwSetMouseButtonCallback(window, mouse_button_callback);
	glfwSetCursorPosCallback(window, mouse_callback);
	glfwSetScrollCallback(window, scroll_callback);

	
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}


	
	int vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);
	
	int success;
	char infoLog[512];
	glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
		std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
	}
	
	int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentShader);
	
	glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); 
		std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
	}

	int shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glLinkProgram(shaderProgram);

	glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
	if (!success) {
		glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
		std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
	}
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);
	
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);

	glBindVertexArray(VAO);

	glBindBuffer(GL_ARRAY_BUFFER, VBO);

	while (!glfwWindowShouldClose(window))
	{
		processInput(window);

		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		glUseProgram(shaderProgram);
		glBindVertexArray(VAO);
		glDrawArrays(GL_LINE_STRIP, 0, 2);

		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);

	glfwTerminate();
	return 0;
}
void processInput(GLFWwindow *window)
{
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		glfwSetWindowShouldClose(window, true);
}
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
	if (!firstClick)
	{
		double startVertices[] = { startPointX, startPointY, 0.0,
			(-1) + (xpos / SCR_WIDTH)*2,(-1) * ((-1) + (ypos / SCR_HEIGHT)*2),0.0 };
		glBindBuffer(GL_ARRAY_BUFFER, VBO);
		glBufferData(GL_ARRAY_BUFFER, sizeof(startVertices), startVertices, GL_STATIC_DRAW);
		glBindVertexArray(VAO);
		glVertexAttribPointer(0, 3, GL_DOUBLE, GL_FALSE, 3 * sizeof(double), (void*)0);
		glEnableVertexAttribArray(0);
	//解绑
		glBindBuffer(GL_ARRAY_BUFFER, 0);
		glBindVertexArray(0);
		
	}
	
}
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
	
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
	if (action == GLFW_PRESS) switch (button)
	{
	case GLFW_MOUSE_BUTTON_LEFT:
		if (firstClick)
		{
			glfwGetCursorPos(window, &startPointX, &startPointY);
			startPointX = (-1) + (startPointX / SCR_WIDTH)*2;
			startPointY = (-1)*((-1) + (startPointY / SCR_HEIGHT) * 2);
			firstClick = false;
			
		}
		else if (!firstClick)
		{
			double tempX = 0, tempY = 0;
			glfwGetCursorPos(window, &tempX, &tempY);
			//坐标转换
			tempX = (-1) + (tempX / SCR_WIDTH)*2;
			tempY = (-1)*((-1) + (tempY / SCR_HEIGHT) * 2);

			double startVertices[] = { startPointX, startPointY, 0.0,
				tempX, tempY, 0.0 };
			std::cout << startPointY <<" "<<startPointX<<" "<<tempX<<" "<<tempY<< std::endl;
			glBindBuffer(GL_ARRAY_BUFFER, VBO);
			glBufferData(GL_ARRAY_BUFFER, sizeof(startVertices), startVertices, GL_STATIC_DRAW);
			glBindVertexArray(VAO);
			glVertexAttribPointer(0, 3, GL_DOUBLE, GL_FALSE, 3 * sizeof(double), (void*)0);
			glEnableVertexAttribArray(0);
			//解绑
			glBindBuffer(GL_ARRAY_BUFFER, 0);
			glBindVertexArray(0);
			firstClick = true;

		}

			break;
	}
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
	glViewport(0, 0, width, height);
}

猜你喜欢

转载自blog.csdn.net/qq_17615227/article/details/80030082