原文:从零实现3D图像引擎:(2)画2D直线不简单

1. 数学分析

1) 画直线的问题

本来我以为画直线会很容易,随便拿个直线公式,遍历X求Y画出来不就完了么,但事实并非如此。以2D直线为例,因为3D直线也只是多引入了个Z坐标而已。关键的问题:我们在数学中所学的直线是基于实数域的,而在计算机屏幕上,所画的直线是基于正整数域的,可以想象这么一个情形,在直线的某一点X=1,Y=0.01时,在屏幕上如何画呢?下图对比了实数域的直线,与基于正整数域的直线:

为什么直线在正整数域是不连续的呢,还记得斜率的的定义么:斜率m = dy / dx = (y1 - y0) / (x1 - x0)

这意味着当X坐标增加1,则Y坐标就增加m。这就是会出现上述情况的根本原因。

2) Bresenham算法

该算法由Bresenham在1965年发明,它到底做了什么事呢?其实想法很简单,就是每X移动一个像素,则考虑Y应该是如何移动。为什么我们要关注Bresenham算法呢,我们发现,这种算法实际只做了加减法,是非常适合计算机运算的,这种算法的速度是相当快的。

该算法把直线分为两种:一种是斜率<1的线,即近X轴线。另一种是斜率>1的线,即近Y轴线。

我们以近X轴直线为例,如图:

Bresenham算法的核心就是,当X加1后,如何决定Y的移动。显然可见,近X轴直线的dy<dx。所以一个直观的想法是,保存一个误差累计变量,每当X加1,误差变量便累计增加一个dy。当累计误差小于等于dx时,Y不动,当累计的误差大于dx时,Y加1,同时把累计误差减掉一个dx。这样,算法将不停的将光栅线与实际线之间的误差减到最小。

2. 函数实现

这里给出一个例子,实现了上面的算法,但只限近X轴并且是从左上往右下画的,可以很清楚的看到实现的逻辑。通用的画线在源码中已实现,可以下载获取。

int dx = x1 - x0;
int dy = y1 - y0;
int error = 0;
if (dx > dy) // 近X轴
{
for (int x = x0, y = y0; x<= x1; ++x)
{
DrawPixel(x, y, color);
error += dy; // 累计误差 if (error > dx)
{
error -= dx;
++y;
}
}
}

  针对所有情况的完整代码如下,其中在误差的计算方面进行了一些优化,起始值更居中,而不是写死的0。

int _CPPYIN_3DLib::DrawLine(int x0, int y0, int x1, int y1, DWORD color)
{
int x, y, dx, dy, dx2, dy2, xstep, ystep, error, index;
x = x0;
y = y0;
dx = x1 - x0;
dy = y1 - y0; if (dx >= 0) // 从左往右画
{
xstep = 1; // x步进正1
}
else // 从右往左画
{
xstep = -1; // x步进负1
dx = -dx; // 取绝对值
} if (dy >= 0) // 从上往下画
{
ystep = 1; // y步进正1
}
else // 从下往上画
{
ystep = -1; // y步进负1
dy = -dy; // 取绝对值
} dx2 = dx << 1; // 2 * dx
dy2 = dy << 1; // 2 * dy if (dx > dy) // 近X轴直线
{
error = dy2 - dx;
for (index = 0; index <= dx; ++index)
{
DrawPixel(x, y, color);
if (error >= 0)
{
error -= dx2;
y += ystep;
}
error += dy2;
x += xstep;
}
}
else // 近Y轴直线
{
error = dx2 - dy;
for (index = 0; index <= dy; ++index)
{
DrawPixel(x, y, color);
if (error >= 0)
{
error -= dy2;
x += xstep;
}
error += dx2;
y += ystep;
}
} return 1;
}

  

3. 源码下载

这个示例使用该函数,每帧在窗口中画500条随机颜色的直线,截图如下:

项目源代码下载:>>点击进入下载页<<

4. 补充更新

画直线还有一些算法,速度有的更快,如:

Run-Slicing

Symmetric Double Step

Quadruple Step

如果有时间我会一一实现,如果读者已经实现,请留言分享,谢谢。

【转载】从零实现3D图像引擎:(2)画2D直线不简单的更多相关文章

  1. 【转载】从零实现3D图像引擎:(1)环境配置与项目框架

    原文:从零实现3D图像引擎:(1)环境配置与项目框架 0. 要学懂3D程序设计,必然要精通3D相关的线性代数.3D几何.复分析等相关知识,我也因为如此才开始这个博客系列的写作,不自己实现,就不是自己的 ...

  2. 转载:[转]如何学好3D游戏引擎编程

      [转]如何学好3D游戏引擎编程 Albert 本帖被 gamengines 从 游戏引擎(Game Engine) 此文为转载,但是值得一看. 此篇文章献给那些为了游戏编程不怕困难的热血青年,它的 ...

  3. 棒!使用.NET Core构建3D游戏引擎

    原文地址:https://mellinoe.wordpress.com/2017/01/18/net-core-game-engine/ 作者:ERIC MELLINO 翻译:杨晓东(Savorboa ...

  4. achartengine andorid图像引擎入门

    最近在帮机械学院开发一个app 用了第三方的图像引擎——achartengine功能还算强大(虽然相比于Html那些第三方图像引擎还是差点不过也够用了) 入门: 参考http://blog.csdn. ...

  5. 排名前10的H5、Js 3D游戏引擎和框架

    由于很多人都在用JavaScript.HTML5和WebGL技术创建基于浏览器的3D游戏,所有JavaScript 3D游戏引擎是一个人们主题.基于浏览器的游戏最棒的地方是平台独立,它们能在iOS.A ...

  6. 全息眼镜HoloLens可快速捕捉真人3D图像

    http://www.d9soft.com/zixun/62287.html 北京时间3月28日午间消息,微软研发部门开发出一种新的3D视频捕捉系统“Holoportation”,可以实现将某人3D图 ...

  7. C++ 3D物理引擎库BulletPhysics基本使用

    前言:最近在接触OpenGl和DX11的时候,顺便学习了Bullet这个3D物理引擎的基本使用,记录一下. |BulletPhysics介绍 BulletPhysics是一个跨平台的开源物理引擎,也是 ...

  8. Python 画3D图像

    绘制一副3D图像 draw3D(X,Y,Z, angle) import numpy as np from matplotlib import pyplot as plt from mpl_toolk ...

  9. 纯CSS实现3D图像轮转

    CSS演武场今天继续,今天看一个纯css实现的3D图像轮转效果,请大家猛戳研究效果先,也可下载收藏先. 首先看html文件,div.billboard为效果的容器,利用10个div.poster分割图 ...

随机推荐

  1. 纯css3跑马灯demo

    我们写跑马灯一般都是用js控制定时器不断循环产生,但是定时器消耗比较大,特别是程序中很多用到定时器的时候,感觉有的时候比较卡.但是css3样式一般不会.这里主要的思路就是用css3代替js定时器实现一 ...

  2. 2018-2019-2 网络对抗技术 20165322 Exp2 后门原理与实践

    2018-2019-2 网络对抗技术 20165322 Exp2 后门原理与实践 目录 实验准备 后门概念 常用后门工具 实验内容与步骤 使用netcat获取主机操作Shell,cron启动 使用so ...

  3. 复习静态页面polo-360

    1.ps快捷键 ctrl+1 恢复到100% ctrl+0 适应屏幕大小 ctrl+r 显示标尺 辅助线的利用 矩形框--图像--裁剪:文件存储为web所用格式,注意选格式. 1个像素的平铺 雪碧图的 ...

  4. Yum 下载安装包及对应依赖包

    Yum 下载安装包及对应依赖包: 安装该软件:yum install -y yum-plugin-downloadonly 以下载 openssh-server 为例 yum install -y o ...

  5. nRF5 SDK for Mesh(六) BLE MESH 的 基础概念

    Basic Bluetooth Mesh concepts The Bluetooth Mesh is a profile specification developed and published ...

  6. tortoisegit 学习

    注:陈刚在Ubuntu虚拟机架设了git的服务器,用于管理公司的代码工程: tortoisegit是TortoiseSVN的Git版本,tortoisegit用于迁移TortoiseSVN到Torto ...

  7. Linux下gdb调试(tui)

    1 处于TUI模式的GDB 为了以TUI模式运行GDB,可以在调用GDB时在命令行上指定-tui选项,或者处于非TUI模式时在GDB中使用Ctrl+X+A组合键.如果当前处于TUI模式,后一种命令方式 ...

  8. Font Awesome图标字体

    1.unicode unicode是字体在网页端最原始的应用方式,特点是: 兼容性最好,支持ie6+,及所有现代浏览器. 支持按字体的方式去动态调整图标大小,颜色等等. 但是因为是字体,所以不支持多色 ...

  9. HCNP - Server

    Server DHCP配置 DHCP服务器配置: 第一种方法:自动配置 路由上面配置网关,开启dhcp服务 [R1]dhcp enable [R1-GigabitEthernet0/0/0]dhcp ...

  10. helloworld模块

    环境: HelperA64开发板 Linux3.10内核 时间:2019.01.11 目标:编译helloword模块 ​ 1.当出先下面错误时候,查找问题 ​ 问题为Make的时候默认为PC-X86 ...