Bresenham 算法

文章目录

说明

在阅读此博客前,请访问2018级山东大学计算机学院图形学实验汇总

原笔记通过latex编写,csdn只支持latex部分功能,所以下面主要是将pdf截屏上传。

Bresenham

课本上的讲解十分清晰,这里不再赘述,需要注意,使用避免浮点数的方法是将 0.5 替换为 dx。

需要注意的是,课本上的算法部分只能够画 x 正方向逆时针旋转 0-45 度的场景,其余情况需要将代码稍作修改。

修改的方式可以采用矩阵乘法实现旋转功能,但是我没有实现,希望大家可以尝试一下。我只采用了一种普通的方式。

代码

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "shader.h"
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

const unsigned int MAXN=600*800*2;
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
const char* vertexShaderPath="/Users/longzhengtian/Desktop/代码/C++代码/ComputerGraphics/shader.vs";
const char* fragmentShaderPath="/Users/longzhengtian/Desktop/代码/C++代码/ComputerGraphics/shader.fs";

unsigned int VBO, VAO, theSize;
int clickwho=-1;
bool DrawLine=false,DrawLineEnd=false;

struct Point{//像素点
    int x,y;
}Line[2];
vector<float> DrawTheLine;

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
void Bresenham(int x0,int y0,int x1,int y1);//画线算法
void CoordinateTransformation(int x0,int y0,int x1,int y1);//坐标变换函数
void drawpixei(int x,int y,int y0);
float transX(int x){return (float)((float)(2*x)-SCR_WIDTH)/(SCR_WIDTH*1.0f);}
float transY(int y){return (float)(SCR_HEIGHT-2*(float)y)/(SCR_HEIGHT*1.0f);}
bool distant(Point p1,Point p2){return (pow(fabs(p1.x-p2.x),2)+pow(fabs(p1.y-p2.y),2)<=25);}

int main(){
    //实例化glfw函数
    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);
#endif

    //创建glfw窗口
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Breseham", nullptr, nullptr);
    if (window == nullptr){
        cout << "Failed to create GLFW window" << endl;
        glfwTerminate();
        return -1;
    }

    glfwMakeContextCurrent(window);//将window设置为接下来操作的主窗口
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    glfwSetKeyCallback(window, key_callback);
    glfwSetMouseButtonCallback(window, mouse_button_callback);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){//使用glad加载glfw的所有函数指针
        cout << "Failed to initialize GLAD" << endl;
        return -1;
    }

    Shader ourShader(vertexShaderPath,fragmentShaderPath);//创建着色器程序

    float verticesLine[MAXN];

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(verticesLine), verticesLine, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    while (!glfwWindowShouldClose(window)){
        //输入
        processInput(window);

        //渲染命令
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        //作图
        ourShader.setVec4("ourColor",1.0f,0.0f,0.0f,1.0f);
        ourShader.use();
        glBindVertexArray(VAO);
        glDrawArrays(GL_POINTS, 0, theSize/3);

        //检查并调用事件,交换缓冲
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

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

    glfwTerminate();
    return 0;
}
void drawpixei(int x,int y){
    DrawTheLine.push_back(transX(x));
    DrawTheLine.push_back(transY(y));
    DrawTheLine.push_back(1.0f);
}
void Bresenham(int x0,int y0,int x1,int y1){
    int dx=x1-x0,dy=y1-y0;
    int ux=(dx>0)?1:-1;//x增加的方向,是加还是减
    int uy=(dy>0)?1:-1;//y增加的方向,是加还是减
    int x=x0,y=y0;
    dx=abs(dx); dy=abs(dy);
    if(dx>dy){
        int e=-dx;
        for (x=x0; x!=x1; x+=ux){
            drawpixei(x,y);
            e+=2*dy;
            if(e>=0){
                y+=uy; e-=2*dx;
            }
        }
    }
    else {
        int e=-dy;
        for (y=y0; y!=y1; y+=uy){
            drawpixei(x,y);
            e+=2*dx;
            if(e>=0){
                x+=ux; e-=2*dy;
            }
        }

    }

}
/*
void Bresenham(int x0,int y0,int x1,int y1){
    int dx=x1-x0,dy=y1-y0,e=-dx,x=x0,y=y0;
    for (int i=0; i<=dx; i++){
        drawpixei(x,y);
        x++; e+=2*dy;
        if(e>=0) {
            y++; e-=2*dx;
        }
    }
}
*/
void processInput(GLFWwindow *window){
    if(clickwho!=-1){//处在移动状态
        double xpos,ypos;
        glfwGetCursorPos(window,&xpos,&ypos);
        Line[clickwho].x=(int)xpos; Line[clickwho].y=(int)ypos;
        DrawTheLine.clear();

        Bresenham(Line[0].x,Line[0].y,Line[1].x,Line[1].y);

        GLfloat* tempvec=DrawTheLine.data();
        theSize=DrawTheLine.size();
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferSubData(GL_ARRAY_BUFFER,0,theSize*sizeof(GLfloat), tempvec);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height){
    glViewport(0, 0, width, height);
}
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods){
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
    else if (key == GLFW_KEY_L && action == GLFW_PRESS) {//如果按下"L",画直线
        if(!DrawLine){//开始画直线
            double xpos,ypos;
            glfwGetCursorPos(window,&xpos,&ypos);
            Line[0].x=(int)xpos; Line[0].y=(int)ypos;
            clickwho=1; DrawLine=true;//此时状态和点击了第二个点是一样点,都是第二个点在移动
        }
        else {//结束画直线
            clickwho=-1; DrawLine=false; DrawLineEnd=true;
        }
    }
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods){
    if(button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS && !DrawLine){//此时没有画直线
        double xpos,ypos;
        glfwGetCursorPos(window,&xpos,&ypos);
        if(clickwho!=-1) clickwho=-1;//移动中点击了鼠标,肯定是要结束了
        else if(distant(Line[0],{(int)xpos,(int)ypos})) clickwho=0;//点击直线的第一个点
        else if(distant(Line[1],{(int)xpos,(int)ypos})) clickwho=1;//点击直线的第二个点
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值