OpenGL:中点直线算法

理论部分

中点直线算法是通过在像素中确定与理想直线最靠近的像素来进行扫描转换的。

image.png

在上图中,假设直线的斜率 0 ≤ m ≤ 1 0\le m \le 1 0m1。假设当前最近的像素已经确认为 P ( x k , y k ) P(x_k, y_k) P(xk,yk),由于 x x x位最大的位移方向,因此直线在 x x x方向上每次增加一个像素单位,而在 y y y方向上是否增加一个像素单位,即 P P P点的下一个点是选 P 1 ( x k + 1 , y k ) P_1(x_{k+1},y_k) P1(xk+1,yk)还是 P 2 ( x k + 1 , y k + 1 ) P_2(x_{k+1},y_k+1) P2(xk+1,yk+1),取决于两个备选像素哪一个离理想像素最近
M ( x k + 1 , y k + 0.5 ) M(x_k+1, y_k+0.5) M(xk+1,yk+0.5) P 1 P 2 P_1P_2 P1P2的中点, Q Q Q是理想直线与直线 x = x k + 1 x=x_k+1 x=xk+1的交点。在图中可以看出, P 2 P_2 P2离理想像素 Q Q Q更近,所以应该选择 P 2 P_2 P2作为下一个像素。
像素选择的方法:理想像素 Q Q Q在中点 M M M上方,则选取 P 2 P_2 P2,否则选取 P 1 P_1 P1。如果 Q = M Q=M Q=M,规定选取 P 1 P_1 P1

假设直线的起点为 ( x 1 , y 1 ) (x_1,y_1) (x1,y1),终点为 ( x 2 , y 2 ) (x_2,y_2) (x2,y2),则直线方程为: F ( x , y ) = a x + b y + c = 0 F(x,y)=ax+by+c=0 F(x,y)=ax+by+c=0
其中, a = y 1 − y 2 a=y_1-y_2 a=y1y2 b = x 2 − x 1 b=x_2-x_1 b=x2x1 c = x 1 y 2 − x 2 y 1 c=x_1y_2-x_2y_1 c=x1y2x2y1
如果点 ( x , y ) (x,y) (x,y)在直线上,则 F ( x , y ) = 0 F(x,y)=0 F(x,y)=0
如果点 ( x , y ) (x,y) (x,y)在直线的上方,则 F ( x , y ) > 0 F(x,y)>0 F(x,y)>0
如果点 ( x , y ) (x,y) (x,y)在直线的下方,则 F ( x , y ) < 0 F(x,y)<0 F(x,y)<0
因此要判断中点 M M M在理想点 Q Q Q上方还是下方,只需要奖 M ( x k + 1 , y k + 0.5 ) M(x_k+1,y_k+0.5) M(xk+1,yk+0.5)代入方程,得
d = F ( x k + 1 , y k + 0.5 ) = a ( x k + 1 ) + b ( y k + 0.5 ) + c d=F(x_k+1,y_k+0.5)=a(x_k+1)+b(y_k+0.5)+c d=F(xk+1,yk+0.5)=a(xk+1)+b(yk+0.5)+c
d ≥ 0 d\ge 0 d0时,取 P 1 P_1 P1像素后,此时下一个候选像素的判别式为:
d 1 = F ( x k + 2 , y k + 0.5 ) = a ( x k + 2 ) + b ( y k + 0.5 ) + c = d + a d_1=F(x_k+2,y_k+0.5)=a(x_k+2)+b(y_k+0.5)+c=d+a d1=F(xk+2,yk+0.5)=a(xk+2)+b(yk+0.5)+c=d+a
d < 0 d \lt 0 d<0时,取 P 2 P_2 P2像素后,此时下一个候选像素的判别式为:
d 2 = F ( x k + 2 , y k + 1.5 ) = a ( x k + 2 ) + b ( y k + 1.5 ) + c = d + ( a + b ) d_2=F(x_k+2,y_k+1.5)=a(x_k+2)+b(y_k+1.5)+c=d+(a+b) d2=F(xk+2,yk+1.5)=a(xk+2)+b(yk+1.5)+c=d+(a+b)
d d d的初始值 d 0 d_0 d0 d 0 = F ( x 1 + 1 , y 1 + 0.5 ) = a ( x 1 + 1 ) + b ( y k + 0.5 ) + c = F ( x 1 , y 1 ) + a + 0.5 b d_0=F(x_1+1,y_1+0.5)=a(x_1+1)+b(y_k+0.5)+c=F(x_1,y_1)+a+0.5b d0=F(x1+1,y1+0.5)=a(x1+1)+b(yk+0.5)+c=F(x1,y1)+a+0.5b,其中 F ( x 1 , y 1 ) F(x_1,y_1) F(x1,y1)是起点,必然在直线上,所以 d 0 = a + 0.5 b d_0=a+0.5b d0=a+0.5b

OpenGL代码

#pragma once
#include "Object.h"

class MLA : public Object
{
public:
    MLA(glm::vec2 startPoint, glm::vec2 endPoint);
    MLA(float x1, float y1, float x2, float y2);
    ~MLA();

    void Draw(Shader* shader);
    void Draw(Shader* shader, Texture2D tex);

private:
    glm::vec2 startPoint;
    glm::vec2 endPoint;

    void CalculatePoints();

};
#include "MLA.h"

MLA::MLA(glm::vec2 startPoint, glm::vec2 endPoint)
    : Object(), startPoint(startPoint), endPoint(endPoint)
{
    CalculatePoints();
    SetData();
}

MLA::MLA(float x1, float y1, float x2, float y2)
    : Object(), startPoint(x1, y1), endPoint(x2, y2)
{
    CalculatePoints();
    SetData();
}

MLA::~MLA()
{
}

void MLA::Draw(Shader* shader)
{
    glBindVertexArray(VAO);
    glDrawArrays(GL_POINTS, 0, vertices.size());
    glBindVertexArray(0);
}

void MLA::Draw(Shader* shader, Texture2D tex)
{
}

void MLA::CalculatePoints()
{
    float a = endPoint.x - startPoint.x;
    float b = endPoint.y - startPoint.y;

    float d = (2 * a + b) * 0.01f;
    float d1 = 2 * a * 0.01f;
    float d2 = 2 * (a + b) * 0.01f;

    float x = startPoint.x;
    float y = startPoint.y;

    while (x < endPoint.x)
    {
        if (d < 0)
        {
            x += 0.01f;
            y += 0.01f;
            d += d2;
        }
        else
        {
            x += 0.01f;
            d += d1;
        }
        vertices.push_back(Vertex(x, y, 0.0f));
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ht巷子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值