Unity学习(九)Bresenham快速画直线算法
2016-04-18 10:28
573 查看
在游戏中求直线,一般情况会想到通过斜率计算,但是这会涉及到大量的浮点运算,一旦玩家过多,还是会有比较大的消耗。
通常在电脑中画直线,圆形等各种形状并不是真正的直线,因为屏幕的像素非常小,所以肉眼看起来很像直线,其实都是由格子组成的。底层的算法比较多,这里就先学习Bresenham算法,它是光栅化的画直线算法。直线光栅化是指用像素点来模拟直线,如下图:
以上图为例,进行推导模拟:
1.起点为x1,y1时:y轴误差量为e1,e1+m=0.7>0.5,那么e2=e1+m-1=-0.3,y=y1+1=y2。
2.起点为x2,y2时:y轴误差量为e2,e2+m=-0.3+0.7=0.4,那么e3=e2+m=0.4,y=y2。
3.起点为x3,y2时:y轴误差量为e3,e3+m=0.4+0.7=1.1>0.5,那么e4=e3-1=0.1,y=y2+1=y3。
4.起点为x4,y3时:以此类推...知道x轴到达终点。
其中e+m>0.5,可以表示为2*(e+m) > 1
根据起点和终点可以得出x轴增量:dx。将上面的公式都乘以dx。
可以得到:
e= e*dx+m*dx = eps + dy
e= e+m-1 = eps+dy-dx
实现流程:
1.首先判断x,y的增量,谁大就累加谁。(上面是坐标系的左上方向)
2.循环累加x,累加误差量eps+dy
3.判断eps+dy是否大于dx,如果小于不做处理,如果大于等于dx,那么新的y=y+1,新的eps=eps-dx。
为了兼容xy坐标系的各个方向,我们可以先算出增量的方向,比如上面如果是坐标系的左下方向,y=y-1。
代码如下:
public bool LinePath(int x1, int y1, int x2, int y2, ref List mpaths)
{
int dx = x2 - x1;
int dy = y2 - y1;
int ux = (dx > 0) ? 1 : -1;
int uy = (dy > 0) ? 1 : -1;
int x = x1, y = y1, eps;
x2 += ux; y2 += uy;
eps = 0; dx = Mathf.Abs(dx); dy = Mathf.Abs(dy);
if (dx > dy)
{
for (x = x1; x != x2; x += ux)
{
mpaths.Add(new Vector2(x, y));
eps += dy;
if ((eps << 1) >= dx)
{
y += uy;
eps -= dx;
}
}
}
else
{
for (y = y1; y != y2; y += uy)
{
mpaths.Add(new Vector2(x, y));
eps += dx;
if ((eps << 1) >= dy)
{
x += ux; eps -= dy;
}
}
}
return true;
}
通常在电脑中画直线,圆形等各种形状并不是真正的直线,因为屏幕的像素非常小,所以肉眼看起来很像直线,其实都是由格子组成的。底层的算法比较多,这里就先学习Bresenham算法,它是光栅化的画直线算法。直线光栅化是指用像素点来模拟直线,如下图:
以上图为例,进行推导模拟:
1.起点为x1,y1时:y轴误差量为e1,e1+m=0.7>0.5,那么e2=e1+m-1=-0.3,y=y1+1=y2。
2.起点为x2,y2时:y轴误差量为e2,e2+m=-0.3+0.7=0.4,那么e3=e2+m=0.4,y=y2。
3.起点为x3,y2时:y轴误差量为e3,e3+m=0.4+0.7=1.1>0.5,那么e4=e3-1=0.1,y=y2+1=y3。
4.起点为x4,y3时:以此类推...知道x轴到达终点。
其中e+m>0.5,可以表示为2*(e+m) > 1
根据起点和终点可以得出x轴增量:dx。将上面的公式都乘以dx。
可以得到:
e= e*dx+m*dx = eps + dy
e= e+m-1 = eps+dy-dx
实现流程:
1.首先判断x,y的增量,谁大就累加谁。(上面是坐标系的左上方向)
2.循环累加x,累加误差量eps+dy
3.判断eps+dy是否大于dx,如果小于不做处理,如果大于等于dx,那么新的y=y+1,新的eps=eps-dx。
为了兼容xy坐标系的各个方向,我们可以先算出增量的方向,比如上面如果是坐标系的左下方向,y=y-1。
代码如下:
public bool LinePath(int x1, int y1, int x2, int y2, ref List mpaths)
{
int dx = x2 - x1;
int dy = y2 - y1;
int ux = (dx > 0) ? 1 : -1;
int uy = (dy > 0) ? 1 : -1;
int x = x1, y = y1, eps;
x2 += ux; y2 += uy;
eps = 0; dx = Mathf.Abs(dx); dy = Mathf.Abs(dy);
if (dx > dy)
{
for (x = x1; x != x2; x += ux)
{
mpaths.Add(new Vector2(x, y));
eps += dy;
if ((eps << 1) >= dx)
{
y += uy;
eps -= dx;
}
}
}
else
{
for (y = y1; y != y2; y += uy)
{
mpaths.Add(new Vector2(x, y));
eps += dx;
if ((eps << 1) >= dy)
{
x += ux; eps -= dy;
}
}
}
return true;
}
相关文章推荐
- Unity之将Texture保存成png
- Unity3D内存管理
- Unity3D脚本(MonoBehaviour)生命周期
- Unity Manual 笔记01 第一章 使用Unity工作——资源工作流
- unity3d面试2
- 【转】[unity3d]easytouch的使用
- Unity Shader 二 发光Shader
- 关于部分Unity发布IOS报错的解决办法
- Unity Panel open & close
- Unity3d-Application设备读写目录
- Unity monodev环境搭建
- Unity-破解-Disunity、Unity Studio提取资源
- Unity.击球游戏
- Unity3D中的Coroutine详解
- Unity 使用 Stripping Level == Use micro mscorlib 导致 MD5.Create() 返回NULL
- Unity3D学习笔记(7)—— 击球游戏
- UNITY发布安卓APK的整体流程
- 安装UNITY4.3.6,提示SSL ERROR解决方法
- Unity iOS 互相调用
- Unity3D开发者快速上手Unreal Engine 4指南