作者热门文章
- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在努力实现“快速抗锯齿圆圈生成器”例程,吴晓林在他的论文“一种有效的抗锯齿技术”中描述了 Siggraph '91。
这是我使用 Python 3 和 PySDL2 编写的代码:
def draw_antialiased_circle(renderer, position, radius):
def _draw_point(renderer, offset, x, y):
sdl2.SDL_RenderDrawPoint(renderer, offset.x - x, offset.y + y)
sdl2.SDL_RenderDrawPoint(renderer, offset.x + x, offset.y + y)
sdl2.SDL_RenderDrawPoint(renderer, offset.x - x, offset.y - y)
sdl2.SDL_RenderDrawPoint(renderer, offset.x + x, offset.y - y)
i = 0
j = radius
d = 0
T = 0
sdl2.SDL_SetRenderDrawColor(renderer, 255, 255, 255, sdl2.SDL_ALPHA_OPAQUE)
_draw_point(renderer, position, i, j)
while i < j + 1:
i += 1
s = math.sqrt(max(radius * radius - i * i, 0.0))
d = math.floor(sdl2.SDL_ALPHA_OPAQUE * (math.ceil(s) - s) + 0.5)
if d < T:
j -= 1
T = d
if d > 0:
alpha = d
sdl2.SDL_SetRenderDrawColor(renderer, 255, 255, 255, alpha)
_draw_point(renderer, position, i, j)
if i != j:
_draw_point(renderer, position, j, i)
if (sdl2.SDL_ALPHA_OPAQUE - d) > 0:
alpha = sdl2.SDL_ALPHA_OPAQUE - d
sdl2.SDL_SetRenderDrawColor(renderer, 255, 255, 255, alpha)
_draw_point(renderer, position, i, j + 1)
if i != j + 1:
_draw_point(renderer, position, j + 1, i)
j
而不是
i
因为要么我误解了什么,要么他的论文有错误。事实上,他初始化了
i
与半径值,
j
与
0
,然后定义循环条件
i <= j
仅当半径为
0
时才为真.此更改使我对所描述的内容进行了其他一些小的修改,并且我还更改了
if d > T
至
if d < T
只是因为它看起来很破。
(sqrt(2) / 2, sqrt(2) / 2)
区域),也出现了严重的错误。我设法通过更改
if d < T
使最后一个问题消失了。条件到
if d <= T
,但同样的问题随后出现在每个八分圆的开头。
最佳答案
让我们解构您的实现以找出您犯了哪些错误:
def draw_antialiased_circle(renderer, position, radius):
radius
意思?画圆是不可能的,你只能画一个圆环(一个圆环/甜甜圈),因为除非你有一定的厚度你是看不到它的。因此半径不明确,是内半径,中点半径还是外半径?如果你没有在变量名中指定,它会变得困惑。或许我们可以一探究竟。
def _draw_point(renderer, offset, x, y):
sdl2.SDL_RenderDrawPoint(renderer, offset.x - x, offset.y + y)
sdl2.SDL_RenderDrawPoint(renderer, offset.x + x, offset.y + y)
sdl2.SDL_RenderDrawPoint(renderer, offset.x - x, offset.y - y)
sdl2.SDL_RenderDrawPoint(renderer, offset.x + x, offset.y - y)
i = 0
j = radius
d = 0
T = 0
i
到 0 和
j
到半径,这些必须是
x
和
y
坐标。什么是
d
和
T
?非描述性的变量名称无济于事。复制科学家的算法以使用您知道的更长的变量名称使它们真正可以理解时,这是可以的!
sdl2.SDL_SetRenderDrawColor(renderer, 255, 255, 255, sdl2.SDL_ALPHA_OPAQUE)
_draw_point(renderer, position, i, j)
(0, radius)
中的正方形完全不透明。所以现在我们知道了什么
radius
即,它是环的外半径,环的宽度显然是一个像素。或者至少,这就是这个特殊情况告诉我们的……让我们看看这是否适用于通用代码。
while i < j + 1:
i > j
,然后停止。 IE。我们正在绘制一个八分圆。
i += 1
i = 0
处绘制了我们关心的所有像素。位置,让我们进入下一个。
s = math.sqrt(max(radius * radius - i * i, 0.0))
s
是一个浮点数,它是点
i
处八分圆的 y 分量在 x 轴上。 IE。 x 轴上方的高度。出于某种原因,我们有一个
max
在那里,也许我们担心非常小的圆圈……但这并不能告诉我们该点是否在外半径/内半径上。
d = math.floor(sdl2.SDL_ALPHA_OPAQUE * (math.ceil(s) - s) + 0.5)
(math.ceil(s) - s)
给我们一个 0 到 1.0 之间的数字。此数字将增加为
s
减少,所以
i
增加,然后一旦达到 1.0 将重置为 0.0,因此呈锯齿状。
sdl2.SDL_ALPHA_OPAQUE * (math.ceil(s) - s)
提示我们使用锯齿输入来生成一定程度的不透明,即消除圆圈的锯齿。 0.5 常数添加似乎没有必要。
floor()
表明我们只对整数值感兴趣——可能 API 只接受整数值。这一切表明
d
最终是介于 0 和
SDL_ALPHA_OPAQUE
之间的整数级别,从 0 开始,然后逐渐增加为
i
增加,那么当
ceil(s) - s
从 1 回到 0,它也再次回落到低点。
s
差不多
radius
自
i
是 1,(假设一个非平凡大小的圆)所以假设我们有一个整数半径(第一个特殊情况代码显然是假设的)
ceil(s) - s
是 0
if d < T:
j -= 1
d = T
d
已经从高变低,我们向下移动屏幕,这样我们的
j
位置保持在理论上应该靠近戒指的位置。
d
是 100.9。然后在下一次迭代中它下降了,但仅下降到 100.1。因为
d
和
T
相等,因为地板消除了它们的差异,我们不递减
j
在这种情况下,这是至关重要的。我想可能解释了八分圆末端的奇怪曲线。
if d < 0:
alpha = d
sdl2.SDL_SetRenderDrawColor(renderer, 255, 255, 255, alpha)
_draw_point(renderer, position, i, j)
d
低,所以这很吸引
(1, radius)
一个几乎完全透明的元素。但是开始的特殊情况为
(0, radius)
绘制了一个完全不透明的元素。 ,很明显这里会出现图形故障。这就是你所看到的。
if i != j:
_draw_point(renderer, position, j, i)
_draw_point()
中只画了 4 个点。 ,因为你在这里做了另一个对称。它会简化您的代码,而不是。
if (sdl2.SDL_ALPHA_OPAQUE - d) > 0:
alpha = sdl2.SDL_ALPHA_OPAQUE - d
sdl2.SDL_SetRenderDrawColor(renderer, 255, 255, 255, alpha)
_draw_point(renderer, position, i, j + 1)
import math
def draw_antialiased_circle(outer_radius):
def _draw_point(x, y, alpha):
# draw the 8 symmetries.
print('%d:%d @ %f' % (x, y, alpha))
i = 0
j = outer_radius
last_fade_amount = 0
fade_amount = 0
MAX_OPAQUE = 100.0
while i < j:
height = math.sqrt(max(outer_radius * outer_radius - i * i, 0))
fade_amount = MAX_OPAQUE * (math.ceil(height) - height)
if fade_amount < last_fade_amount:
# Opaqueness reset so drop down a row.
j -= 1
last_fade_amount = fade_amount
# The API needs integers, so convert here now we've checked if
# it dropped.
fade_amount_i = int(fade_amount)
# We're fading out the current j row, and fading in the next one down.
_draw_point(i, j, MAX_OPAQUE - fade_amount_i)
_draw_point(i, j - 1, fade_amount_i)
i += 1
outer_radius
,算法在
(0, outer_radius - 1)
处绘制一个 100% 不透明的正方形地点。但是,如果您想转换为
(0, 0.5)
位置,您可能希望圆在
(0, outer_radius - 1)
处平滑地混叠至 50% 的不透明度。和
(0, outer_radius)
位置,这个算法没有给你,因为它忽略了原点。因此,如果您想准确地使用此算法,则必须在传入原点之前对其进行四舍五入,因此使用浮点数没有任何好处。
关于python - 绘制一个由 Xaolin Wu 描述的抗锯齿圆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37589165/
我正在努力实现“快速抗锯齿圆圈生成器”例程,吴晓林在他的论文“一种有效的抗锯齿技术”中描述了 Siggraph '91。 这是我使用 Python 3 和 PySDL2 编写的代码: def draw
我是一名优秀的程序员,十分优秀!