现在,我知道一种抗锯齿的方法是简单地想象存在一个矩形,该矩形包含线条和将被打开或填充有RGB值的触摸的任何像素。
现在,如果我知道被矩形切除的像素部分的面积(假设像素为圆形),我将如何使用该部分的面积来计算像素的密度是0-1的颜色(0是非常浅而1是最暗)?
#1 楼
您有背景色和线条的颜色,反走样的线条在第一个线条的两侧绘制了其他线条,这些线条只是原始线条和背景的颜色和亮度之间的一部分。如果线条如果您画的是水平或垂直的,则其他的抗锯齿线(但是,取决于预期的最终线条粗细)应该在颜色和亮度上更接近于预期的颜色-此类线的抗锯齿性绝对最小,只有极少量这是由于在某些矩阵上而不是全部矩阵上具有偏移量的子像素渲染所致。
这说明了难题:
当线条不是水平或垂直时,它会变得更加复杂...
如果在线条的两侧绘制了其他线条:
,其颜色和亮度与背景颜色更接近,那么线条将保持清晰,线条附近的背景模糊。
或
颜色和亮度与行的颜色更紧密匹配,则行变得更加模糊(更宽),并且行附近的背景颜色保持清晰。
>这意味着,如果您打算绘制一条细线,一条像素宽的线,则将使用第一个选项。 (使结果皮包骨头)。
如果要使用两像素宽的线,则可以选择第二个选项,但要权衡背景的颜色,使其更接近背景的颜色和亮度。 (使结果不像单行那样紧,两行额外的行几乎占总宽度的50%。)
如果要三像素宽的行您仍然使用第二个选项,但是会更加权衡背景的颜色和线条的颜色和亮度。 (使结果明显比单行更胖)。
对于四像素宽的线,请返回第一种方法,在该方法中,您可以使用第二种方法绘制两条具有预期颜色和亮度的线,并用两条线将其包围。 (将第一种和第二种方法混合排序)
对于五像素宽的线,中心恰好是您想要的颜色,最接近的两条周围的线与颜色和亮度非常接近中心线的颜色,外部两个线非常接近中心线的颜色(但小于紧邻中心线的颜色)
对于六像素宽的线是两条要绘制的颜色和亮度的中心线,被两条非常相似的线包围,被另外两条不太相似的中心线的颜色和亮度包围;但与背景颜色相比(较亮或较暗)仍然有很大差异。
上面的5或6后面有七个像素线或更大。
将其他线条的权重更趋向于预期的颜色时,线条会更清晰,如果从侧面类比的角度来看,它会是高顶礼帽状的。如果您对其他颜色的线更偏重于背景色,则(不可能的)侧视图类推就是2D线的轮廓将为圆形或三角形。如果要绘制2D形状,则需要权衡预期的颜色。如果要在2D屏幕上渲染3D形状,则倾向于将背景颜色融合到具有不同Z深度的后续线条中。
吴晓琳是对Bresenham线条绘制算法的改进,它是一种简单而有效的算法,具有良好的速度抗锯齿。
// Pascal
function plot(x, y, c) is
plot the pixel at (x, y) with brightness c (where 0 ≤ c ≤ 1)
// integer part of x
function ipart(x) is
return floor(x)
function round(x) is
return ipart(x + 0.5)
// fractional part of x
function fpart(x) is
return x - floor(x)
function rfpart(x) is
return 1 - fpart(x)
function drawLine(x0,y0,x1,y1) is
boolean steep := abs(y1 - y0) > abs(x1 - x0)
if steep then
swap(x0, y0)
swap(x1, y1)
end if
if x0 > x1 then
swap(x0, x1)
swap(y0, y1)
end if
dx := x1 - x0
dy := y1 - y0
gradient := dy / dx
if dx == 0.0 then
gradient := 1.0
end if
// handle first endpoint
xend := round(x0)
yend := y0 + gradient * (xend - x0)
xgap := rfpart(x0 + 0.5)
xpxl1 := xend // this will be used in the main loop
ypxl1 := ipart(yend)
if steep then
plot(ypxl1, xpxl1, rfpart(yend) * xgap)
plot(ypxl1+1, xpxl1, fpart(yend) * xgap)
else
plot(xpxl1, ypxl1 , rfpart(yend) * xgap)
plot(xpxl1, ypxl1+1, fpart(yend) * xgap)
end if
intery := yend + gradient // first y-intersection for the main loop
// handle second endpoint
xend := round(x1)
yend := y1 + gradient * (xend - x1)
xgap := fpart(x1 + 0.5)
xpxl2 := xend //this will be used in the main loop
ypxl2 := ipart(yend)
if steep then
plot(ypxl2 , xpxl2, rfpart(yend) * xgap)
plot(ypxl2+1, xpxl2, fpart(yend) * xgap)
else
plot(xpxl2, ypxl2, rfpart(yend) * xgap)
plot(xpxl2, ypxl2+1, fpart(yend) * xgap)
end if
// main loop
if steep then
for x from xpxl1 + 1 to xpxl2 - 1 do
begin
plot(ipart(intery) , x, rfpart(intery))
plot(ipart(intery)+1, x, fpart(intery))
intery := intery + gradient
end
else
for x from xpxl1 + 1 to xpxl2 - 1 do
begin
plot(x, ipart(intery), rfpart(intery))
plot(x, ipart(intery)+1, fpart(intery))
intery := intery + gradient
end
end if
end function
评论
网上有很多关于行初始化的文章,例如http.developer.nvidia.com/GPUGems2/gpugems2_chapter22.html。在80年代,这是一个非常受欢迎的话题,因此您可能会在Graphics Gem之类的书中找到不错的文章。完全由Google来搜索和阅读自己的问题。但这是一个很好的文档主题。@ user18490是一个非常有据可查的话题,只有其中许多文件包含系统的缺陷和假设。因此,它有很多文档,但是很多只是误导。
@jooja,我尊重您的意见,但是,如果有一个主题包含很多信息,那么它就是关于行抗锯齿的主题。这是CG中研究过的第一个主题,您会发现70年代/ 80年代开发的专门用于CG的算法。我将OP指向Graphics Gems书籍,他/她将在其中找到信息。关于此类基本问题,您必须鼓励操作人员先在Google上进行搜索,然后再在此处提出此类问题(并表明他们在来此之前已研究了该主题)。也许您也可以写一个答案)
@ user18490的要点是,许多计算机图形学论文都忽略了定义其假设的范围和限制。因此,例如许多基于覆盖率的计算都忘记提及1。您不能假设盒式过滤器是最好的过滤器。 2.仅当您画一条线/曲线但它们不能正确堆叠时,算法才是正确的(导致许多矢量引擎出现合并问题,甚至自1980年代以来我们就不知道原因),3.您的输出帧缓冲区为不是线性的。等