原文:从零实现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. 使用zepto实现QQ消息左滑删除效果

    有这样一个需求: 1. 有一个列表,将每一个列表项左滑动出现删除按钮: 2. 右滑动隐藏删除按钮: 3. 点击这个删除按钮删除该列表项. 完成以后的效果: 这是微信网页端的页面,使用的是 zepto ...

  2. canvas图形库

    总结了一些canvas绘制2d图形的方法,记录在博客中,以便需要的同学参考,也便于日后加深记忆. 1. 圆角矩形: 如上图:w表示矩形的宽,h表示矩形的高,r表示矩形圆角的半径.整个矩形在画布中,(0 ...

  3. 离散对数&&大步小步算法及扩展

    bsgs algorithm ax≡b(mod n) 大步小步算法,这个算法有一定的局限性,只有当gcd(a,m)=1时才可以用 原理 此处讨论n为素数的时候. ax≡b(mod n)(n为素数) 由 ...

  4. 108.UIView关于布局和约束的方法(AutoLayout)

    http://blog.csdn.net/wangyanchang21/article/details/52270136 关于布局(UIViewHierarchy) 1.layoutSubviews ...

  5. BZOJ2780:[SPOJ8093]Sevenk Love Oimaster(广义SAM)

    Description Oimaster and sevenk love each other. But recently,sevenk heard that a girl named ChuYuXu ...

  6. 「bzoj 4184: shallot」

    权限题 线段树分治加线性基 首先这个题要求删除线性基肯定是没法处理的 于是我们套上一个线段树分治 线段树分治就是一种能够避免删除的神仙操作 我们发现询问是对一个时间的单点询问,而每一个数存在的时间却是 ...

  7. list详解

    #include <iostream> #include <vector> #include <list> std::list<std::string> ...

  8. mark DOwm

    https://github.com/summerscar/live2dDemo {% cq %} 人生乃是一面镜子, 从镜子里认识自己, 我要称之为头等大事, 也只是我们追求的目的! {% endc ...

  9. 【Dubbo源码阅读系列】之远程服务调用(上)

    今天打算来讲一讲 Dubbo 服务远程调用.笔者在开始看 Dubbo 远程服务相关源码的时候,看的有点迷糊.后来慢慢明白 Dubbo 远程服务的调用的本质就是动态代理模式的一种实现.本地消费者无须知道 ...

  10. 精准测试白皮书v3.0-2019最新版

    现代社会是建立在各种以计算机为基石的软件技术基础之上的.随着日新月异的需求变化,软件系统越来越复杂.很多人觉得软件开发才是重要环节,但实际上,无法对大型软件进行有效的质量把控,就无法真正构建与维护大型 ...