这篇着重光栅化2D直线的算法实现

一、数据结构设置

//************************基本数据结构*******************
typedef struct { float x, y; } vector_t;
typedef vector_t point_t;//顶点

typedef struct { float r, g, b,a; } color_t;//颜色

目前还是2d,也不需要3d变换,暂时只需要x,y2个坐标数据

二、DDA画线算法

void DrawLineDDA2d(point_t v1, point_t v2,color_t c)//DDA画线算法
{

    glColor4d(c.r, c.g, c.b,c.a);
    float x1 = v1.x;
    float y1 = v1.y;
    float x2 =v2.x;
    float y2 = v2.y;
    float length = __max(abs(x1 - x2), abs(y1 - y2));
    float dx = (x2 - x1) / length;
    float dy = (y2 - y1) / length;
    float x = x1 + 0.5;
    float y = y1 + 0.5;
    int i = 0;
    while (i <= length)
    {
        glVertex2i((int)x, (int)y);
        x += dx;
        y += dy;
        i++;
    }

}

此算法参考《计算机图形学的算法基础》

光栅渲染器(二)画线_游戏引擎开发

利用光栅渲染器(二)画线_游戏引擎开发_02公式完成绘制

三、中点画线算法

void DrawLineMid(point_t v1, point_t v2,color_t c)//中点画线算法
{

    glColor4d(c.r, c.g, c.b, c.a);
    float x1 = v1.x;
    float y1 = v1.y;
    float x2 = v2.x;
    float y2 = v2.y;
    float dx = x2 - x1;
    float dy = y2 - y1;
    float d = dy - dx;
    int x = x1+0.5;
    int y = y1+0.5;
    glVertex2i((int)x1, (int)y1);
    while (x < x2)
    {
        if (d >= 0)
        {
            glVertex2i(x++, y);
            d -= dy;
        }
        else if (d < 0)
        {
            glVertex2i(x++, y++);
            d += dy - dx;
        }
    }
}

这个算法仅限第一象限
希望扩展到全坐标系,参考无幻博客

http://blog.csdn.net/akof1314/article/details/5447652

四、Bresenham算法

void DrawLineBre(point_t v1, point_t v2, color_t c)//Bresenham算法
{
    glColor4d(c.r, c.g, c.b, c.a);
    float x1 = v1.x;
    float y1 = v1.y;
    float x2 = v2.x;
    float y2 = v2.y;
    int x = x1;
    int y = y1;
    float dx =abs(x1-x2);
    float dy = abs(y2 - y1);
    int s1 = Sgn(x2 - x1);
    int s2 = Sgn(y2 - y1);
    bool IntChange = false;
    if (dy > dx)
    {
        swap(dy, dx);
        IntChange = true;
    }
    float e = 2 * dy - dx;
    for (int i = 0; i < dx; i++)
    {
        glVertex2i(x, y);
        if(e>0)
        {
            if (IntChange)x += s1;
            else x += s2;
            e =e- 2*dx;
        }
        if (IntChange) y += s2;
        else y += s1;
        e += 2 * dy;
    }
}

五、测试画线案例

完整代码如下:

#include "pch.h"

#include <iostream>
#include <string>
using namespace std;

const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
const char* SCREEN_TITLE = "光栅渲染器";


//************************基本数据结构*******************
typedef struct { float x, y; } vector_t;
typedef vector_t point_t;//顶点

typedef struct { float r, g, b, a; } color_t;//颜色

int Sgn(float d)//符号判断
{
	if (d < 0) return -1;
	else if (d == 0) return 0;
	else return 1;
}

void DrawLineDDA2d(point_t v1, point_t v2, color_t c)//DDA画线算法
{

	glColor4d(c.r, c.g, c.b, c.a);
	float x1 = v1.x;
	float y1 = v1.y;
	float x2 = v2.x;
	float y2 = v2.y;
	float length = __max(abs(x1 - x2), abs(y1 - y2));
	float dx = (x2 - x1) / length;
	float dy = (y2 - y1) / length;
	float x = x1 + 0.5;
	float y = y1 + 0.5;
	int i = 0;
	while (i <= length)
	{
		glVertex2i((int)x, (int)y);
		x += dx;
		y += dy;
		i++;
	}

}

void DrawLineMid(point_t v1, point_t v2, color_t c)//中点画线算法
{

	glColor4d(c.r, c.g, c.b, c.a);
	float x1 = v1.x;
	float y1 = v1.y;
	float x2 = v2.x;
	float y2 = v2.y;
	float dx = x2 - x1;
	float dy = y2 - y1;
	float d = dy - dx;
	int x = x1 + 0.5;
	int y = y1 + 0.5;
	glVertex2i((int)x1, (int)y1);
	while (x < x2)
	{
		if (d >= 0)
		{
			glVertex2i(x++, y);
			d -= dy;
		}
		else if (d < 0)
		{
			glVertex2i(x++, y++);
			d += dy - dx;
		}
	}
}

void DrawLineBre(point_t v1, point_t v2, color_t c)//Bresenham算法
{
	glColor4d(c.r, c.g, c.b, c.a);
	float x1 = v1.x;
	float y1 = v1.y;
	float x2 = v2.x;
	float y2 = v2.y;
	int x = x1;
	int y = y1;
	float dx = abs(x1 - x2);
	float dy = abs(y2 - y1);
	int s1 = Sgn(x2 - x1);
	int s2 = Sgn(y2 - y1);
	bool IntChange = false;
	if (dy > dx)
	{
		swap(dy, dx);
		IntChange = true;
	}
	float e = 2 * dy - dx;
	for (int i = 0; i < dx; i++)
	{
		glVertex2i(x, y);
		if (e > 0)
		{
			if (IntChange)x += s1;
			else x += s2;
			e = e - 2 * dx;
		}
		if (IntChange) y += s2;
		else y += s1;
		e += 2 * dy;
	}
}


//<<<<<<<<<<<<<<<<<<<<<<< myInit >>>>>>>>>>>>>>>>>>>>
void myInit(void)
{
	glClearColor(0.0, 0.0, 0.0, 0.0);      // 设置背景颜色为亮白
	glColor3f(1.0f, 1.0f, 1.0f);           // 设置绘制颜色为黑
	glPointSize(4.0);                    //设置点的大小为4*4像素
	glMatrixMode(GL_PROJECTION);// 设置合适的投影矩阵-以后解释 
	glLoadIdentity();
	gluOrtho2D(0.0, 640.0, 0.0, 480.0);
}

//<<<<<<<<<<<<<<<<<<<<<<<< myDisplay >>>>>>>>>>>>>>>>>
// 重绘函数
void myDisplay(void)
{


	glClear(GL_COLOR_BUFFER_BIT);     // 清屏幕 
	glPointSize(1);
	glBegin(GL_POINTS);
	point_t v1{ 10,15 };
	point_t v2{ 400,200 };
	point_t v3{ 10,15 };
	point_t v4{ 400,300 };
	color_t c{ 1.0,1.0,0,1.0 };//黄色
	color_t c2{ 1.0,0.0,0,1.0 };//黄色
	DrawLineDDA2d(v1, v2, c);
	DrawLineMid(v3, v4, c2);
	DrawLineBre(v2, v4, c2);
	glEnd();
	glFlush();                         // 将所有输出到显示屏上 

}

//<<<<<<<<<<<<<<<<<<<<<<<< main >>>>>>>>>>>>>>>>>>>>>>
int main(int argc, char **argv)
{
	glutInit(&argc, argv);          // 初始化工具包
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 设置显式模式
	glutInitWindowSize(SCREEN_WIDTH, SCREEN_HEIGHT);     // 设置窗口大小
	glutInitWindowPosition(100, 150); // 设置窗口位置
	glutCreateWindow(SCREEN_TITLE); // 打开屏幕窗口
	glutDisplayFunc(myDisplay);     // 注册绘制函数
	myInit();
	glutMainLoop();              // 进入主循环

	return 0;
}



光栅渲染器(二)画线_光栅渲染器_03