OpenGl实现一个简单的随手画功能

环境:Windows、VS2012。  

简介:一个用OpenGL实现的2D(所有点的Z坐标设为0.0f)随手画,刚开始学opengl的时候,只是按照教程写了一遍代码,对其理解还不是很深刻,本功能把各功能分开,让其看上去更像一个工程。这个随手画其实效率很低,实现的方法是画点,由n个点组成一条线,每个点我定义成一个正n边形(因为点小,近似圆)。


结构图如下:

       效果(鼠标点击时画线,鼠标释放线消失):



关键代码在Line.h  Point.h  源.cpp中:

//Line.h
#include <string >
#include <iostream>
#include <vector>
#include <GL/glew.h>
#include <cmath>
#include "Point.h"

using namespace std;

class Line{

public :
	Line();
	Line(GLfloat);
	void add(Point,int);
	int getLength();
	void clear();
	//void createBuffer(GLuint&,GLuint&);
	void createBuffer();
	void deleteBuffer();
	GLuint getVAO();
private :
	GLfloat radius;
	vector<Point> clickPoint;
	vector<GLfloat> allPoint;
	GLfloat num[999999];
	GLuint VAO;
	GLuint VBO;
	int edges;
};

//设置每个点的大小(类似圆的半径),边的数量
Line::Line(GLfloat radius = 0.1f,int edges = 4){
	this->radius = radius;
}

//添加新的点,每个点都是由n个正三角形组成的正n六边形
void Line::add(Point p){
	clickPoint.push_back(p);

	const GLfloat PI = 3.141592653;

	Point pointTemp[16]={p};
	for(int i=1;i<=edges;++i){
		pointTemp[i].x = p.x + radius * cos(PI*(360/edges * i)/180.0);
		pointTemp[i].y = p.y + radius * sin(PI*(360/edges * i)/180.0);
	}
	for(int i = 1;i <= edges - 1;++i){
		allPoint.push_back(pointTemp[0].x);
		allPoint.push_back(pointTemp[0].y);
		allPoint.push_back(0.0f);

		allPoint.push_back(pointTemp[i].x);
		allPoint.push_back(pointTemp[i].y);
		allPoint.push_back(0.0f);

		allPoint.push_back(pointTemp[i+1].x);
		allPoint.push_back(pointTemp[i+1].y);
		allPoint.push_back(0.0f);
	}
	allPoint.push_back(pointTemp[0].x);
	allPoint.push_back(pointTemp[0].y);
	allPoint.push_back(0.0f);

	allPoint.push_back(pointTemp[edges].x);
	allPoint.push_back(pointTemp[edges].y);
	allPoint.push_back(0.0f);

	allPoint.push_back(pointTemp[1].x);
	allPoint.push_back(pointTemp[1].y);
	allPoint.push_back(0.0f);

	for(int i=0;i<allPoint.size();++i){
		num[i] = allPoint[i];
	}
}

int Line::getLength(){return allPoint.size();}


GLuint Line::getVAO(){return VAO;}

//创建VAO
void Line::createBuffer(){
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	glBindVertexArray(VAO);

	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(num),num, GL_STATIC_DRAW);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
	glEnableVertexAttribArray(0);

	glBindBuffer(GL_ARRAY_BUFFER, 0); 

	glBindVertexArray(0); 
}

void Line::clear(){
	clickPoint.clear();
	allPoint.clear();
	memset(num,0,sizeof(num));
}    

void Line::deleteBuffer(){
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);
}


//Point.h
#ifndef __POINT_HH__
#define __POINT_HH__

struct Point{
	GLfloat x,y;
	Point() {};
	Point(GLfloat x,GLfloat y) {
		this->x=x;
		this->y=y;
	}
};

#endif

//Shader.h
#ifndef SHADER_H
#define SHADER_H

#include <string >
#include <fstream>
#include <sstream>
#include <iostream>

#include <GL/glew.h>

class Shader{
public : 
	 // 程序ID
    GLuint Program;
    // 构造器读取并构建着色器
    Shader(const GLchar* vertexPath, const GLchar* fragmentPath){
		//1.从文件路径中获取着色器
		std::string vertexCode,fragmentCode; 
		std::ifstream vShaderFile,fShaderFile;
		//保证ifstream异常能抛出
		vShaderFile.exceptions(std::ifstream::badbit);
		fShaderFile.exceptions(std::ifstream::badbit);
		try{
			vShaderFile.open(vertexPath);
			fShaderFile.open(fragmentPath);
			//读取文件的缓冲内容到流中			
			std::stringstream vShaderStream,fShaderStream;
			vShaderStream << vShaderFile.rdbuf();
			fShaderStream << fShaderFile.rdbuf();

			vShaderFile.close();
			fShaderFile.close();
			//转换为GLchar数组
			vertexCode = vShaderStream.str();
			fragmentCode = fShaderStream.str();
		}catch(std::ifstream::failure e){
			std::cout<<"ERROR::SHADER::FILEW_NOT_SUCCESS_READ"<<std::endl;
		}
		const GLchar *vShaderCode = vertexCode.c_str();
		const GLchar *fShaderCode = fragmentCode.c_str();

		//2.compile shader
		GLuint vertex,fragment;
		GLint success;
		GLchar infoLog[512];

		//vertex shader
		vertex = glCreateShader(GL_VERTEX_SHADER);
		glShaderSource(vertex,1,&vShaderCode,NULL);
		glCompileShader(vertex);
		glGetShaderiv(vertex,GL_COMPILE_STATUS,&success);
		if(!success){
			glGetShaderInfoLog(vertex,512,NULL,infoLog);
			std::cout<<"ERROR::SHADER_VERTEX_COMPILE_FAILED\n"<<infoLog<<std::endl;
		}
		//fragment shader
		fragment = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(fragment,1,&fShaderCode,NULL);
		glCompileShader(fragment);
		glGetShaderiv(fragment,GL_COMPILE_STATUS,&success);
		if(!success){
			glGetShaderInfoLog(fragment,512,NULL,infoLog);
			std::cout<<"ERROR::SHADER_FRAGMENT_COMPILE_FAILED\n"<<infoLog<<std::endl;
		}

		//shader program
		this->Program = glCreateProgram();
		glAttachShader(this->Program,vertex);
		glAttachShader(this->Program,fragment);
		glLinkProgram(this->Program);
		glGetShaderiv(this->Program,GL_LINK_STATUS,&success);
		if(!success){
			glGetShaderInfoLog(this->Program,512,NULL,infoLog);
			std::cout<<"ERROR::SHADER_PROGRAM_LINKING_FAILED\n" << infoLog<<std::endl;
		}
		glDeleteShader(vertex);
		glDeleteShader(fragment);
	}
    // 使用程序
	void Use(){
		glUseProgram(this->Program);
	}
};

#endif

//源.cpp
#include <iostream>

// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "Shader.h"
#include "Point.h"
#include "Line.h"


void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void mouse_callback(GLFWwindow *window,double xpos,double ypos);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) ;

// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;

Line line(0.01f);

// The MAIN function, from here we start the application and run the game loop
int main()
{
	GLfloat num;
	std::cout<<sizeof(num);
    // Init GLFW
    glfwInit();
    // Set all the required options for GLFW
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); 

    // Create a GLFWwindow object that we can use for GLFW's functions
    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
    glfwMakeContextCurrent(window);

    // Set the required callback functions
    glfwSetKeyCallback(window, key_callback);
	glfwSetMouseButtonCallback(window,mouse_button_callback);
	glfwSetCursorPosCallback(window, mouse_callback);  //鼠标输入回调函数
	

    // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
    glewExperimental = GL_TRUE;
    // Initialize GLEW to setup the OpenGL Function pointers
    glewInit();

    // Define the viewport dimensions
    int width, height;
    glfwGetFramebufferSize(window, &width, &height);  
    glViewport(0, 0, width, height);

	Shader ourShader("vertexShader.txt","fragmentShader.txt");

    // Game loop
    while (!glfwWindowShouldClose(window))
    {
		line.createBuffer();    
        glfwPollEvents();

        // Render
        // Clear the colorbuffer
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Draw our first triangle
		ourShader.Use();

		glBindVertexArray(line.getVAO());
		glDrawArrays(GL_TRIANGLES, 0, line.getLength());
        glBindVertexArray(0);

        // Swap the screen buffers
        glfwSwapBuffers(window);
		line.deleteBuffer();
	}
    // Terminate GLFW, clearing any resources allocated by GLFW.
	glfwTerminate();
    return 0;
}

// Is called whenever a key is pressed/released via GLFW

bool mouseLeftIsClick ;
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode){
    
	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}

void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
	
	if (action == GLFW_PRESS && button == GLFW_MOUSE_BUTTON_LEFT){
		mouseLeftIsClick = true;
	}
	if (action == GLFW_RELEASE && button == GLFW_MOUSE_BUTTON_LEFT){
		mouseLeftIsClick = false;
		line.clear();
	}
}

//鼠标移动回调函数
void mouse_callback(GLFWwindow *window,double xpos,double ypos){
	if(mouseLeftIsClick){
		//屏幕坐标和着色器坐标变换
		Point p(2.0*xpos/(GLfloat)WIDTH - 1.0f,1.0f - 2.0*ypos/(GLfloat)HEIGHT);
		line.add(p);
		std::cout<<xpos<<","<<ypos<<","<<line.getLength()<<std::endl;
	}
}


//vertexShader.txt
#version 330 core
layout (location = 0) in vec3 position;

void main()
{
    gl_Position = vec4(position, 1.0f);
}

//fragmentShader.txt
#version 330 core
out vec4 color;

void main()
{
    color =  vec4(1.0f,0.5f,0.0f,1.0f);
}










  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenGL是一种图形库,它提供了一套用于绘制2D和3D图形的API。利用OpenGL,我们可以实现简单功能。 首先,我们需要创建一个OpenGL窗口来容纳我们的绘图。可以使用外部库,如GLFW或SDL来创建窗口。然后,我们需要设置窗口的大小和绘制模式。 在OpenGL中,绘制是通过调用绘制函数来实现的。为了实现功能,我们可以使用鼠标和键盘事件来触发绘制函数。 当用户按下鼠标按钮时,我们可以将鼠标坐标与绘制区域坐标进行关联。然后,我们可以使用OpenGL的绘制函数来在相应的位置绘制图形。 例如,当用户按下鼠标左键并移动鼠标时,我们可以使用OpenGL的直线绘制函数来实时绘制线条。我们可以将当前鼠标位置与上一个鼠标位置进行连接,形成一条线。 类似地,当用户按下鼠标右键时,我们可以使用OpenGL的点绘制函数来在当前鼠标位置一个点。 另外,我们也可以使用OpenGL的矩形绘制函数来实现绘制矩形的功能。当用户按下键盘上的特定按键时,我们可以判断按键的类型,并调用相应的绘制函数来实现绘制矩形的功能。 最后,我们可以使用一个清除板的按钮,当用户点击该按钮时,我们可以通过调用OpenGL的清除函数来清除绘制区域,实现板的清空功能。 总的来说,通过使用OpenGL的绘制函数和鼠标键盘事件,以及相应的逻辑判断,我们可以实现一个简单功能

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值