OpenGL.Project 1.Changing color and Dragging Points

在美国接触到的第一个project是OpenGL。功能是要实现鼠标点击变色以及移动。第一次接触OpenGL,所以花了很多时间在学习上面,其实语法是和C++一样的,只不过用了很多库,因此在库函数上面花了很多精力。这是一个二维的界面,所以并不十分高级,很适合新手练级。
附上代码:
// Include standard headers
#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <sstream>

// Include GLEW
#include <GL/glew.h>

// Include GLFW
#include <glfw3.h>
GLFWwindow* window;

// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>
using namespace glm;
using namespace std;
// Include AntTweakBar
#include <AntTweakBar.h>

#include <common/shader.hpp>
#include <common/controls.hpp>
#include <common/objloader.hpp>
#include <common/vboindexer.hpp>

typedef struct {
	float XYZW[4];
	float RGBA[4];
} Vertex;

int main(void)
{
	// Initialise GLFW
	if (!glfwInit())
	{
		fprintf(stderr, "Failed to initialize GLFW\n");
		return -1;
	}

	glfwWindowHint(GLFW_SAMPLES, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	// Open a window and create its OpenGL context
	window = glfwCreateWindow(1024, 768, "Bohan_Liu_66127941", NULL, NULL);//定义一个窗口
	if (window == NULL) {
		fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n");
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);

	// Initialize GLEW
	glewExperimental = true; // Needed for core profile
	if (glewInit() != GLEW_OK) {
		fprintf(stderr, "Failed to initialize GLEW\n");
		return -1;
	}

	// Initialize the GUI
	TwInit(TW_OPENGL_CORE, NULL);
	TwWindowSize(1024, 768);
	TwBar * GUI = TwNewBar("Picking");
	TwSetParam(GUI, NULL, "refresh", TW_PARAM_CSTRING, 1, "0.1");
	std::string message;
	TwAddVarRW(GUI, "Last picked object", TW_TYPE_STDSTRING, &message, NULL);

	// Ensure we can capture the escape key being pressed below
	glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
	glfwSetCursorPos(window, 1024 / 2, 768 / 2);

	// 此处为背景颜色
	glClearColor(0.0f, 0.0f, 0.4f, 0.0f);

	// Enable depth test
	glEnable(GL_DEPTH_TEST);
	// Accept fragment if it closer to the camera than the former one
	glDepthFunc(GL_LESS);

	// Cull triangles which normal is not towards the camera
	glEnable(GL_CULL_FACE);

	// Projection matrix : 45° Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
	glm::mat4 ProjectionMatrix = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);
	// Or, for an ortho camera :
	//glm::mat4 ProjectionMatrix = glm::ortho(-3.0f, 3.0f, -3.0f, 3.0f, 0.0f, 100.0f); // In world coordinates

	// Camera matrix
	glm::mat4 ViewMatrix = glm::lookAt(
		glm::vec3(0, 0, -5), // Camera is at (4,3,3), in World Space
		glm::vec3(0, 0, 0), // and looks at the origin
		glm::vec3(0, 1, 0)  // Head is up (set to 0,-1,0 to look upside-down)
	);


	// 定义点的初始坐标
	Vertex Vertices[] =
	{
		{ { 1.0f, 0.0f, 0.0f, 1.0f },{ 1.0f, 0.0f, 0.0f, 1.0f } }, // 0
		{ { -1.0f, 0.0f, 0.0f, 1.0f },{ 0.0f, 1.0f, 0.0f, 1.0f } }, // 1
		{ { 0.0f, -1.0f, 0.0f, 1.0f },{ 0.0f, 0.0f, 1.0f, 1.0f } }, // 2
		{ { 0.0f, 1.0f, 0.0f, 1.0f },{ 1.0f, 0.0f, 1.0f, 1.0f } }, // 3
		{ { 0.7f, 0.7f, 0.0f, 1.0f },{ 0.0f, 1.0f, 1.0f, 1.0f } }, // 4
		{ { 0.7f, -0.7f, 0.0f, 1.0f },{ 1.0f, 1.0f, 0.0f, 1.0f } }, // 5
		{ { -0.7f, 0.7f, 0.0f, 1.0f },{ 1.0f, 1.0f, 1.0f, 1.0f } }, // 6
		{ { -0.7f, -0.7f, 0.0f, 1.0f },{ 0.0f, 0.0f, 0.0f, 1.0f } }, // 7


	};
	Vertex Vertices2[] =          //此处是为了改变颜色,这里的颜色改变颇为手动,位置坐标要跟随鼠标移动的结果
	{
	{ {Vertices[0].XYZW[0],Vertices[0].XYZW[1],0.0f,1.0f}, { 0.0f, 0.4f, 0.6f, 1.0f } }, // 0
	{ { Vertices[1].XYZW[0],Vertices[1].XYZW[1],0.0f,1.0f },{ 0.6f, 0.0f, 0.4f, 1.0f } }, // 1
	{ { Vertices[2].XYZW[0],Vertices[2].XYZW[1],0.0f,1.0f },{ 0.4f, 0.6f, 0.0f, 1.0f } }, // 2
	{ { Vertices[3].XYZW[0],Vertices[3].XYZW[1],0.0f,1.0f },{ 0.0f, 1.0f, 0.0f, 1.0f } }, // 3
	{ { Vertices[4].XYZW[0],Vertices[4].XYZW[1],0.0f,1.0f },{ 1.0f, 0.0f, 0.0f, 1.0f } }, // 4
	{ { Vertices[5].XYZW[0],Vertices[5].XYZW[1],0.0f,1.0f },{ 0.0f, 0.0f, 1.0f, 1.0f } }, // 5
	{ { Vertices[6].XYZW[0],Vertices[6].XYZW[1],0.0f,1.0f },{ 0.0f, 0.0f, 0.0f, 1.0f } }, // 6
	{ { Vertices[7].XYZW[0],Vertices[7].XYZW[1],0.0f,1.0f },{ 0.3f, 0.3f, 0.3f, 1.0f } }, // 7
	};


	unsigned short Indices[] = {
		0, 1, 2, 3, 4, 5, 6, 7
	};

	const size_t BufferSize = sizeof(Vertices);
	const size_t VertexSize = sizeof(Vertices[0]);
	const size_t RgbOffset = sizeof(Vertices[0].XYZW);
	const size_t IndexCount = sizeof(Indices) / sizeof(unsigned short);

	float pickingColor[IndexCount] = { 0 / 255.0f, 1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f, 5 / 255.0f, 6 / 255.0f, 7 / 255.0f };		// set this procedurally for greater number of points

																								// Create Vertex Array Object
	GLuint VertexArrayId;
	glGenVertexArrays(1, &VertexArrayId);
	glBindVertexArray(VertexArrayId);

	// Create and load Buffer for vertex data
	GLuint VertexBufferId;
	glGenBuffers(1, &VertexBufferId);
	glBindBuffer(GL_ARRAY_BUFFER, VertexBufferId);
	glBufferData(GL_ARRAY_BUFFER, BufferSize, Vertices, GL_STATIC_DRAW);

	// Create Buffer for indices
	GLuint IndexBufferId;
	glGenBuffers(1, &IndexBufferId);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferId);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);

	// Create and compile our GLSL program from the shaders
	GLuint programID = LoadShaders("StandardShading.vertexshader", "StandardShading.fragmentshader");
	GLuint pickingProgramID = LoadShaders("Picking.vertexshader", "Picking.fragmentshader");

	// Get a handle for our "MVP" uniform
	GLuint MatrixID = glGetUniformLocation(programID, "MVP");
	GLuint ViewMatrixID = glGetUniformLocation(programID, "V");
	GLuint ModelMatrixID = glGetUniformLocation(programID, "M");
	GLuint PickingMatrixID = glGetUniformLocation(pickingProgramID, "MVP");
	// Get a handle for our "pickingColorID" uniform
	GLuint pickingColorArrayID = glGetUniformLocation(pickingProgramID, "PickingColorArray");
	GLuint pickingColorID = glGetUniformLocation(pickingProgramID, "PickingColor");
	// Get a handle for our "LightPosition" uniform
	GLuint LightID = glGetUniformLocation(programID, "LightPosition_worldspace");

	// For speed computation
	double lastTime = glfwGetTime();
	int nbFrames = 0;
	bool LeftMouseButtonPressedLastFrame = GLFW_RELEASE;
	bool RightMouseBUttonPressedLastFrame = GLFW_RELEASE;
	int p = 0; double X, Y; glm::mat4 ModelMatrix2;
	do {
		// Measure speed
		double currentTime = glfwGetTime();
		nbFrames++;
		if (currentTime - lastTime >= 1.0) { // If last prinf() was more than 1sec ago
											 // printf and reset
			printf("%f ms/frame\n", 1000.0 / double(nbFrames));
			nbFrames = 0;
			lastTime += 1.0;
		}
		glBindBuffer(GL_ARRAY_BUFFER, VertexBufferId); //更新BUffer,用于改变颜色和拖拽
		glBufferSubData(GL_ARRAY_BUFFER, 0, BufferSize, Vertices);	// update buffer data
		if (LeftMouseButtonPressedLastFrame^glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT)) {
			LeftMouseButtonPressedLastFrame = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT); //检测鼠标左键是否离开
			glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			glUseProgram(pickingProgramID);
			{
				// Only the positions are needed (not the colors)
				glEnableVertexAttribArray(0);

				glm::mat4 ModelMatrix = glm::mat4(1.0); // TranslationMatrix * RotationMatrix;
				glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;

				// Send our transformation to the currently bound shader, in the "MVP" uniform
				glUniformMatrix4fv(PickingMatrixID, 1, GL_FALSE, &MVP[0][0]);

				glUniform1fv(pickingColorArrayID, IndexCount, pickingColor);
				glBindBuffer(GL_ARRAY_BUFFER, VertexBufferId);
				// Assign vertex attributes
				glVertexAttribPointer(
					0,                  // attribute
					8,                  // size
					GL_FLOAT,           // type
					GL_FALSE,           // normalized?
					VertexSize,         // stride
					(void*)0            // array buffer offset
				);

				// Index buffer
				glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferId);

				// Draw the ponts
				glEnable(GL_PROGRAM_POINT_SIZE);
				glDrawElements(
					GL_POINTS,      // mode
					IndexCount,    // count
					GL_UNSIGNED_SHORT,   // type
					(void*)0           // element array buffer offset
				);

				glDisableVertexAttribArray(0);

				// Wait until all the pending drawing commands are really done.
				// Ultra-mega-over slow ! 
				// There are usually a long time between glDrawElements() and
				// all the fragments completely rasterized.
				glFlush();
				glFinish();

				glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

				// Read the pixel at the center of the screen.
				// You can also use glfwGetMousePos().
				// Ultra-mega-over slow too, even for 1 pixel, 
				// because the framebuffer is on the GPU.
				double xpos, ypos;
				glfwGetCursorPos(window, &xpos, &ypos);
				unsigned char data[4];
				glReadPixels(xpos, 768 - ypos, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
				int pickedID = int(data[0]);//将颜色转化为点的ID

				if (pickedID >7 ) { // Full white, must be the background !
					message = "background";
				}
				else {
					std::ostringstream oss;
					oss << "point " << pickedID;
					message = oss.str();			
					Vertex tmp = {};
					swap(Vertices[pickedID].RGBA[0], Vertices2[pickedID].RGBA[0]); //变色
					swap(Vertices[pickedID].RGBA[1], Vertices2[pickedID].RGBA[1]);
					swap(Vertices[pickedID].RGBA[2], Vertices2[pickedID].RGBA[2]);
	
				}
			}
		}		
		if (RightMouseBUttonPressedLastFrame^glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT)) { //拖拽点 
			if (RightMouseBUttonPressedLastFrame = GLFW_PRESS&&glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_RELEASE) { 检测右键是否释放
				double xpos1, ypos1;
				glfwGetCursorPos(window, &xpos1, &ypos1);//记录右键释放时的鼠标坐标
				Vertex tmp = { { -(xpos1 - 516) / 133,(768 - ypos1 - 384) / 140,0.0f,1.0f },{Vertices[p].RGBA[0],Vertices[p].RGBA[1], Vertices[p].RGBA[2], 1.0f} };//将点移动到新的坐标
				Vertices[p] = tmp;
				RightMouseBUttonPressedLastFrame = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT);
			}
				RightMouseBUttonPressedLastFrame = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT);// Clear the screen in white
				glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
				glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
				glUseProgram(pickingProgramID);
				{
				// Only the positions are needed (not the colors)
				glEnableVertexAttribArray(0);

				ModelMatrix2 = glm::mat4(1.0); // TranslationMatrix * RotationMatrix;
				glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix2;

				// Send our transformation to the currently bound shader, in the "MVP" uniform
				glUniformMatrix4fv(PickingMatrixID, 1, GL_FALSE, &MVP[0][0]);

				glUniform1fv(pickingColorArrayID, IndexCount, pickingColor);	// here we pass in the picking marker array

																				// 1rst attribute buffer : vertices
				glBindBuffer(GL_ARRAY_BUFFER, VertexBufferId);
				// Assign vertex attributes
				glVertexAttribPointer(
					0,                  // attribute
					8,                  // size
					GL_FLOAT,           // type
					GL_FALSE,           // normalized?
					VertexSize,         // stride
					(void*)0            // array buffer offset
				);

				// Index buffer
				glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferId);

				// Draw the ponts
				glEnable(GL_PROGRAM_POINT_SIZE);
				glDrawElements(
					GL_POINTS,      // mode
					IndexCount,    // count
					GL_UNSIGNED_SHORT,   // type
					(void*)0           // element array buffer offset
				);

				glDisableVertexAttribArray(0);

				// Wait until all the pending drawing commands are really done.
				// Ultra-mega-over slow ! 
				// There are usually a long time between glDrawElements() and
				// all the fragments completely rasterized.
				glFlush();
				glFinish();

				glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

				// Read the pixel at the center of the screen.
				// You can also use glfwGetMousePos().
				// Ultra-mega-over slow too, even for 1 pixel, 
				// because the framebuffer is on the GPU.
				double xpos, ypos;
				glfwGetCursorPos(window, &xpos, &ypos);
				unsigned char data[4];
				glReadPixels(xpos, 768 - ypos, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data); // OpenGL renders with (0,0) on bottom, mouse reports with (0,0) on top
																					   // Convert the color back to an integer ID
				int pickedID = int(data[0]); 

				if (pickedID >7) { // Full white, must be the background !
					message = "background";
				}
				else {
					std::ostringstream oss;
					oss << "point " << pickedID;
					message = oss.str();
					p = pickedID;					
				}
			
			
			
			
				


				
			}
			// Uncomment these lines to see the picking shader in effect
			//glfwSwapBuffers(window);
			//continue; // skips the normal rendering
		}

		// Dark blue background
		glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
		// Re-clear the screen for real rendering
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


		// Use our shader
		glUseProgram(programID);
		{
			glEnableVertexAttribArray(0);
			glEnableVertexAttribArray(1);

			glm::mat4 ModelMatrix = glm::mat4(1.0); // TranslationMatrix * RotationMatrix;
			glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;

			// Send our transformation to the currently bound shader, 
			// in the "MVP" uniform
			glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
			glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
			glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);

			glm::vec3 lightPos = glm::vec3(4, 4, 4);
			glUniform3f(LightID, lightPos.x, lightPos.y, lightPos.z);


			// 1rst attribute buffer : vertices
			glBindBuffer(GL_ARRAY_BUFFER, VertexBufferId);
			glVertexAttribPointer(
				0,                  // attribute
				4,                  // size
				GL_FLOAT,           // type
				GL_FALSE,           // normalized?
				VertexSize,         // stride
				(void*)0            // array buffer offset
			);

			// 2nd attribute buffer : colors
			glVertexAttribPointer(
				1,                  // attribute
				4,                  // size
				GL_FLOAT,           // type
				GL_FALSE,           // normalized?
				VertexSize,         // stride
				(GLvoid*)RgbOffset  // array buffer offset
			);

			// Index buffer
			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferId);

			// Draw the triangles !
			glEnable(GL_PROGRAM_POINT_SIZE);
			glDrawElements(
				GL_POINTS,      // mode
				IndexCount,    // count
				GL_UNSIGNED_SHORT,   // type
				(void*)0           // element array buffer offset
			);

			glDisableVertexAttribArray(0);
			glDisableVertexAttribArray(1);
		}
		// Draw GUI
		TwDraw();

		// Swap buffers
		glfwSwapBuffers(window);
		glfwPollEvents();

	} // Check if the ESC key was pressed or the window was closed
	while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
		glfwWindowShouldClose(window) == 0);

	// Cleanup VBO and shader
	glDeleteBuffers(1, &VertexBufferId);
	glDeleteBuffers(1, &IndexBufferId);
	glDeleteProgram(programID);
	glDeleteProgram(pickingProgramID);
	glDeleteVertexArrays(1, &VertexArrayId);

	// Close OpenGL window and terminate GLFW
	glfwTerminate();

	return 0;
}

此处代码有一些值得注意的地方,Vertex变量只允许初始化时修改。也就是说,它不是左键值。所以需要修改的时候,我便用了swap函数。此处需要注意。
这里没有附上shader文件,因为shader文件的代码比较简单,没做出什么大的修改。
改变位置后的变色,使用swap时,应该只swap颜色,不要swap位置,很关键。
实现效果如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值