代码中把画直线算法(Bresenham 直线算法)封装为一个函数,把画直线算法生成的像素点覆盖vertices[]数组中的点,并通过glDrawArrays(GL_POINTS, 0, counts)画出来,counts为直线上像素点的个数。
具体要求为程序中用户给定直线两个端点的坐标(斜率在0到1之间),然后在窗口中画出直线
存档一下主要代码
// Bresenham直线算法
void drawLineBresenham(int x0, int y0, int x1, int y1, std::vector<float>& vertices) {
int dx = abs(x1 - x0);
int dy = abs(y1 - y0);
int sx = (x0 < x1) ? 1 : -1;
int sy = (y0 < y1) ? 1 : -1;
int err = dx - dy;
while (true) {
// 添加当前点到vertices数组
vertices.push_back(x0);
vertices.push_back(y0);
vertices.push_back(1.0f); // red color
vertices.push_back(0.0f);
vertices.push_back(0.0f);
if (x0 == x1 && y0 == y1) break;
int e2 = err * 2;
if (e2 > -dy) {
err -= dy;
x0 += sx;
}
if (e2 < dx) {
err += dx;
y0 += sy;
}
}
}
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
#endif
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);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
Shader ourShader("3.3.shader.vert", "3.3.shader.frag"); // you can name your shader files however you like
std::vector<float> vertices;
// 用户给定的直线端点
int x0 = 50, y0 = 50;
int x1 = 750, y1 = 550;
// 使用Bresenham算法计算直线上的像素点
drawLineBresenham(x0, y0, x1, y1, vertices);
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
int t = sizeof(vertices);
t = t * sizeof(float);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)* vertices.size(), &vertices[0], GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(2 * sizeof(float)));
glEnableVertexAttribArray(1);
glm::mat4 proj = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f);
glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view = glm::mat4(1.0f);
while (!glfwWindowShouldClose(window))
{
processInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ourShader.use();
glm::mat4 proj = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f);
glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(0.0, 0.0, -10.0));
glm::mat4 view = glm::mat4(1.0f);
unsigned int modelLoc = glGetUniformLocation(ourShader.ID, "model");
unsigned int viewLoc = glGetUniformLocation(ourShader.ID, "view");
unsigned int projectLoc = glGetUniformLocation(ourShader.ID, "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]);
glUniformMatrix4fv(projectLoc, 1, GL_FALSE, glm::value_ptr(proj));
glBindVertexArray(VAO);
glDrawArrays(GL_POINTS, 0, vertices.size() / 5); // count = number of points in vertices
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 framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
{
double* x_pos = new double;
double* y_pos = new double;
glfwGetCursorPos(window, x_pos, y_pos);
double x = *x_pos;
double y = *y_pos;
}
}
程序中用户给定直线两个端点的坐标(需要处理所有斜率),然后在窗口中画出直线。
// 计算直线的像素点并更新 vertices 数组
void bresenhamLine(int x1, int y1, int x2, int y2, std::vector<float>& vertices) {
int dx = x2 - x1;
int dy = y2 - y1;
int dx1 = 2 * abs(dx);
int dy1 = 2 * abs(dy);
int twody1 = 2 * dy1;
int twodx1 = 2 * dx1;
int x = x1;
int y = y1;
int xEnd, yEnd;
if (dx >= dy) { // 处理水平或者接近水平的情况
if (x1 > x2) {
std::swap(x1, x2);
std::swap(y1, y2);
}
x = x1;
y = y1;
xEnd = x2;
if (dy < 0) {
dy1 = -dy1;
}
int slope1 = dy1 - dx1;
for (; x <= xEnd; x++) {
vertices.push_back(x);
vertices.push_back(y);
vertices.push_back(1.0f); // 红色
vertices.push_back(0.0f); // 绿色
vertices.push_back(0.0f); // 蓝色
if (slope1 >= 0) {
y += (y2 > y1) ? 1 : -1;
slope1 -= twodx1;
}
slope1 += dy1;
}
}
else { // 处理竖直或者接近竖直的情况
if (y1 > y2) {
std::swap(x1, x2);
std::swap(y1, y2);
}
x = x1;
y = y1;
yEnd = y2;
if (dx < 0) {
dx1 = -dx1;
}
int slope2 = dx1 - dy1;
for (; y <= yEnd; y++) {
vertices.push_back(x);
vertices.push_back(y);
vertices.push_back(1.0f); // 红色
vertices.push_back(0.0f); // 绿色
vertices.push_back(0.0f); // 蓝色
if (slope2 >= 0) {
x += (x2 > x1) ? 1 : -1;
slope2 -= twodx1;
}
slope2 += dy1;
}
}
}
// 主程序
int main()
{
if (!glfwInit()) {
std::cout << "Failed to initialize GLFW" << std::endl;
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
GLFWwindow* window = glfwCreateWindow(800, 600, "Bresenham Line", NULL, NULL);
if (!window) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// 设置视口
glViewport(0, 0, 800, 600);
// 设置着色器
const char* vertexShaderSource = R"(
#version 330 core
layout(location = 0) in vec2 aPos;
layout(location = 1) in vec3 aColor;
out vec3 vertexColor;
uniform mat4 projection;
void main()
{
gl_Position = projection * vec4(aPos, 0.0, 1.0);
vertexColor = aColor;
})";
const char* fragmentShaderSource = R"(
#version 330 core
in vec3 vertexColor;
out vec4 FragColor;
void main()
{
FragColor = vec4(vertexColor, 1.0f);
})";
// 编译着色器
unsigned int vertexShader, fragmentShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// 创建顶点数据
std::vector<float> vertices;
// 初始直线端点(可以设置一个默认值)
int x0 = 100, y0 = 100;
int x1 = 700, y1 = 500;
// 使用Bresenham算法计算直线上的像素点
bresenhamLine(x0, y0, x1, y1, vertices);
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW);
// 设置顶点属性指针
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(2 * sizeof(float)));
glEnableVertexAttribArray(1);
// 投影矩阵
glm::mat4 projection = glm::ortho(0.0f, 800.0f, 600.0f, 0.0f, -1.0f, 1.0f);
unsigned int projLoc = glGetUniformLocation(shaderProgram, "projection");
glUniformMatrix4fv(projLoc, 1, GL_FALSE, &projection[0][0]);
// 渲染循环
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT);
// 检查用户输入,更新直线端点
int new_x0, new_y0, new_x1, new_y1;
std::cout << "Enter first point (x0, y0): ";
std::cin >> new_x0 >> new_y0;
std::cout << "Enter second point (x1, y1): ";
std::cin >> new_x1 >> new_y1;
// 更新直线端点并重新计算 Bresenham 直线
vertices.clear();
bresenhamLine(new_x0, new_y0, new_x1, new_y1, vertices);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW);
glDrawArrays(GL_POINTS, 0, vertices.size() / 5); // 每个顶点包含5个浮点数:坐标+颜色
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 framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
{
x_pos = new double;
y_pos = new double;
glfwGetCursorPos(window, x_pos, y_pos);
double x = *x_pos;
double y = *y_pos;
}
}


6213

被折叠的 条评论
为什么被折叠?



