网站首页 > 技术文章 正文
显示器是由一个个像素组成的,这种离散量导致绘制出的直线会出现下图所示的锯齿现象,这种由离散量来表示连续量而引起的失真称为走样(Aliasing)。走样问题只能减轻,无法消除,用于减轻走样现象的技术称为反走样(Anti-Aliasing),游戏中也叫抗锯齿。
Wu反走样算法
1991年,Wu Xiaolin在An efficient antialiasing technique论文中提出了一种反走样算法,称为Wu反走样算法。
相对于Bresenham画线算法,Wu反走样算法使用两个相邻像素来表示一个点,它通过计算相邻像素与理想直线的偏差来调节像素亮度。如上图所示,e表示扫描线上方像素与理想直线的距离,则1-e则表示下方相邻像素与理想直线的距离,两个数之和为1。e越小表示越接近理想直线,该像素的颜色应越接近直线的颜色,反之1-e就越大,就应接近背景颜色,因此可以通过e和1-e来调节颜色的亮度,达到模糊锯齿边界的效果,最终画出的直线看起来效果仍然和一个像素差不多。
类似于Bresenham算法,Wu反走样算法也是一种增量算法,e显然可以通过累加dy/dx(斜率)进行计算,当e大于1时,两个像素坐标增加或减少1,偏差e也减去1。
代码示例
以下为JavaScript语言实现的Wu反走样画线算法示例,支持任意斜率的直线。为避免干扰,其他辅助代码未给出,这里稍作说明:
- p0、p1为Point类对象,包含坐标x、y以及颜色属性color;
- color为Color类对象,tostr()方法将颜色转换为字符串"rgba(r,g,b,a)"的形式传给html canvas的绘图方法,setOpacity方法设置通道a的值,1表示完全不透明,0表示完全透明;
- linearInterp为线性颜色插值,可以实现绘制颜色渐变的直线;
function draw_line(p0, p1) {
let x0 = p0.x;
let y0 = p0.y;
let xEnd = p1.x;
let yEnd = p1.y;
let e = 0;
let color, c0 = p0.color, c1 = p1.color;
x0 = Math.round(x0);
y0 = Math.round(y0);
xEnd = Math.round(xEnd);
yEnd = Math.round(yEnd);
// x变化快于y,则x作为主位移
if (Math.abs(xEnd - x0) >= Math.abs(yEnd - y0)) {
let x, y;
if (x0 > xEnd) {
// 交换起点
x = xEnd;
y = yEnd;
xEnd = x0;
yEnd = y0;
x0 = x;
y0 = y;
c0 = p1.color;
c1 = p0.color;
} else {
x = x0;
y = y0;
}
let dx = xEnd - x;
let dy = yEnd - y;
let m = dy / dx;
let signX;
// 正斜率
if ((yEnd - y) * (xEnd - x) >= 0) {
signX = 1;
} else {
// 负斜率
signX = -1;
}
while (x < xEnd) {
// 计算颜色插值
color = linearInterp(x, x0, xEnd, c0, c1);
// 绘制两个相邻像素
color.setOpacity(e);
setPixel(x, y + signX, color.tostr());
color.setOpacity(1 - e);
setPixel(x, y, color.tostr());
x += 1;
e += signX * m;
if (e >= 1.0) {
e -= 1;
y += signX;
}
}
} else {
// y变化快于x,则y为主位移
let x, y;
if (y0 > yEnd) {
// 交换起点
x = xEnd;
y = yEnd;
xEnd = x0;
yEnd = y0;
x0 = x;
y0 = y;
c0 = p1.color;
c1 = p0.color;
} else {
x = x0;
y = y0;
}
let dx = xEnd - x;
let dy = yEnd - y;
let m = dx / dy;
let signY;
// 正斜率
if ((yEnd - y) * (xEnd - x) >= 0) {
signY = 1;
} else {
// 负斜率
signY = -1;
}
while (y < yEnd) {
color = linearInterp(y, y0, yEnd, c0, c1);
color.setOpacity(e);
setPixel(x + signY, y, color.tostr());
color.setOpacity(1 - e);
setPixel(x, y, color.tostr());
y += 1;
e = e + signY * m;
if (e >= 1.0) {
e -= 1;
x += signY;
}
}
}
}
利用上面的画线方法绘制了反走样时钟和金刚石图案,绘制的直线已没有明显的锯齿感了。
参考文献
[1] - Wu, Xiaolin (July 1991). "An efficient antialiasing technique". [Computer Graphics](https://en.wikipedia.org/wiki/Computer_Graphics(newsletter) "Computer Graphics (newsletter)"). 25 (4): 143–152. [doi](https://en.wikipedia.org/wiki/Doi(identifier) "Doi (identifier)"):10.1145/127719.122734. ISBN 0-89791-436-8.
[2] -《计算机图形学--理论与实践项目化教程》孔令德著,第33页;
猜你喜欢
- 2024-10-31 如何实现鼠标绘制三角形? 鼠标三角形显示怎样才能增大
- 2024-10-31 CADCAM软件应用试题 cadcam题库
- 2024-10-31 Python pyecharts v1.x 绘制图形 python怎么绘制图形
- 2024-10-31 视觉SLAM中闭环检测算法的研究 什么是闭环测试
- 2024-10-31 |期刊分享|SLAM|不到200行C代码的CoreSLAM
- 2024-10-31 纹理贴图原理与实践【Texture Mapping】
- 2024-10-31 算力平台跑出200FPS!已知最快最精确的视觉SLAM!吊打ORB+VINS!
- 2024-10-31 利用html canvas实践三角形光栅化
- 2024-10-31 OpenGL绘制城堡报告加源码计算机图形学 城堡
- 2024-10-31 圆生成算法 圆的生成方式有哪三种
你 发表评论:
欢迎- 最近发表
-
- 在 Spring Boot 项目中使用 activiti
- 开箱即用-activiti流程引擎(active 流程引擎)
- 在springBoot项目中整合使用activiti
- activiti中的网关是干什么的?(activiti包含网关)
- SpringBoot集成工作流Activiti(完整源码和配套文档)
- Activiti工作流介绍及使用(activiti工作流会签)
- SpringBoot集成工作流Activiti(实际项目演示)
- activiti工作流引擎(activiti工作流引擎怎么用)
- 工作流Activiti初体验及在数据库中生成的表
- Activiti工作流浅析(activiti6.0工作流引擎深度解析)
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)