环境配置
系统:Windows 10
OpenGL配置:参照https://learnopengl-cn.readthedocs.io/zh/latest/这系列的教程配置的GLEW和GLFW库
根据鼠标点击画点
鼠标回调函数
int num = 0; //记录当前存储的坐标个数
GLfloat pos[4][3]; //记录每个顶点的x,y, z坐标
GLfloat mouseX, mouseY; //鼠标点击时的鼠标位置
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_move_callback(GLFWwindow* window, double xpos, double ypos) {
mouseX = xpos;
mouseY = ypos;
}
显示点的函数
void display(void) {
glBegin(GL_POINTS);
for (int i = 0; i < Points.size(); i++) {
glColor3f(1.0f, 1.0f, 1.0f);//绘点的颜色
glVertex3f(Points[i][0], Points[i][1], Points[i][2]);
}
glEnd();
}
完整代码
#include <iostream>
#include <vector>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
using std::vector;
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void mouse_move_callback(GLFWwindow* window, double xpos, double ypos);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
void display(void);
const GLuint WIDTH = 800, HEIGHT = 600;
vector<vector<GLfloat>> Points; //记录每个顶点的x,y, z坐标
GLfloat mouseX, mouseY; //鼠标点击时的鼠标位置
int main()
{
glfwInit();
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, key_callback);
glfwSetCursorPosCallback(window, mouse_move_callback);//鼠标移动回调函数
glfwSetMouseButtonCallback(window, mouse_button_callback);//鼠标点击回调函数
glewInit();
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
display();
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
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_move_callback(GLFWwindow* window, double xpos, double ypos) {
mouseX = xpos;
mouseY = ypos;
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
float rotateAngle = 0.0f;
if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
vector<GLfloat> pos(3);
pos[0] = mouseX / 400 - 1;
pos[1] = (mouseY / 300 - 1)*-1;
pos[2] = 0.0f;
Points.push_back(pos);
}
}
void display(void) {
glBegin(GL_POINTS);
for (int i = 0; i < Points.size(); i++) {
glColor3f(1.0f, 1.0f, 1.0f);//绘点的颜色
glVertex3f(Points[i][0], Points[i][1], Points[i][2]);
}
glEnd();
}
PS:我一直在学习LearnOpenGL这个教程,在教程中作者让我们通过以下几个语句设置OpenGL的版本和模式。但我发现如果这样设置之后,无法利用glXXX()这些函数(比如画点用的glVertex3f()),不知原因。
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);
利用鼠标选择4个点绘制Bezier曲线
描绘Bezier曲线函数
void Bezier(int n) {
float f1, f2, f3, f4;
float deltaT = 1.0 / n;
float T;
glBegin(GL_LINE_STRIP);
glColor3f(0.8f, 0.2f, 0.5f);
for (int i = 0; i <= n; i++) {
T = i * deltaT;
f1 = (1 - T) * (1 - T) * (1 - T);
f2 = 3 * T * (1 - T) * (1 - T);
f3 = 3 * T * T * (1 - T);
f4 = T * T * T;
float x = f1 * Points[0][0] + f2 * Points[1][0] + f3 * Points[2][0] + f4 * Points[3][0];
float y = f1 * Points[0][1] + f2 * Points[1][1] + f3 * Points[2][1] + f4 * Points[3][1];
float z = f1 * Points[0][2] + f2 * Points[1][2] + f3 * Points[2][2] + f4 * Points[3][2];
glVertex3f(x, y, z);
}
glEnd();
}
完整代码
#include <iostream>
#include <vector>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
using std::vector;
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void mouse_move_callback(GLFWwindow* window, double xpos, double ypos);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
void display(void);
void Bezier(int n);
const GLuint WIDTH = 800, HEIGHT = 600;
vector<vector<GLfloat>> Points(4,vector<GLfloat>(3)); //记录每个顶点的x,y, z坐标
GLfloat mouseX, mouseY; //鼠标点击时的鼠标位置
int count = 0;
int main()
{
glfwInit();
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, key_callback);
glfwSetCursorPosCallback(window, mouse_move_callback);//鼠标移动回调函数
glfwSetMouseButtonCallback(window, mouse_button_callback);//鼠标点击回调函数
glewInit();
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
display();
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
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_move_callback(GLFWwindow* window, double xpos, double ypos) {
mouseX = xpos;
mouseY = ypos;
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
count %= 4;
Points[count][0] = mouseX / 400 - 1;
Points[count][1] = (mouseY / 300 - 1)*-1;
Points[count][2] = 0.0f;
count++;
}
}
void display(void) {
if (count == 4) {
glBegin(GL_LINE_STRIP);
for (int i = 0; i < count; i++) {
glColor3f(1.0f, 1.0f, 1.0f);//绘点的颜色
glVertex3f(Points[i][0], Points[i][1], Points[i][2]);
}
glEnd();
Bezier(20);
}
else {
glBegin(GL_POINTS);
for (int i = 0; i < count; i++) {
glColor3f(1.0f, 1.0f, 1.0f);//绘点的颜色
glVertex3f(Points[i][0], Points[i][1], Points[i][2]);
}
glEnd();
}
}
void Bezier(int n) {
float f1, f2, f3, f4;
float deltaT = 1.0 / n;
float T;
glBegin(GL_LINE_STRIP);
glColor3f(0.8f, 0.2f, 0.5f);
for (int i = 0; i <= n; i++) {
T = i * deltaT;
f1 = (1 - T) * (1 - T) * (1 - T);
f2 = 3 * T * (1 - T) * (1 - T);
f3 = 3 * T * T * (1 - T);
f4 = T * T * T;
float x = f1 * Points[0][0] + f2 * Points[1][0] + f3 * Points[2][0] + f4 * Points[3][0];
float y = f1 * Points[0][1] + f2 * Points[1][1] + f3 * Points[2][1] + f4 * Points[3][1];
float z = f1 * Points[0][2] + f2 * Points[1][2] + f3 * Points[2][2] + f4 * Points[3][2];
glVertex3f(x, y, z);
}
glEnd();
}
当鼠标点出了4个点之前,只显示点,而当4个点选完之后,描绘出曲线。
三次贝塞尔曲线参数方程如下:
在离散的时候,我们可以让t=i/n,其中i为绘制的第i个点,n为绘制的总的点数。(这里我选择的是20个点)