TL; DR:使用(py)sdl2,我試圖繪製一個圓形輪廓,其內部是透明的,因此顯示在其後面繪製的對象。基本上我需要找到一種方法來擦除實心圓的內部像素(或將它們繪製/設置爲透明像素)。只要有可能,我想使用紋理而不是曲面。使用sdl2繪製輪廓圓
我想實現的東西看起來在概念上很簡單,但我不能讓它發生。
我想用python中的sdl2繪製圓形輪廓。當然,使用sdl2gfx函數circleRGBA()
可以非常簡單地實現,但它只允許您繪製線寬爲1px的輪廓線。畫輪廓更粗的圓看起來不太可能。
我一直在使用透明色鍵(inspired by this method)做這樣的事情之前pygame的面,我知道表面也可在SDL2,但告誡是,我想堅持到更快的紋理,它們不提供顏色鍵機制。
要更好一點視覺上解釋的事情:我想要實現的是:
圓(環)大於1px的寬其內部是透明的,從而得出項目在圓圈後面將在內部可見。
過去我用過的一個技巧就是畫出2個實心圓,第二個小圓與背景顏色相同。但是,這隱藏了圈內的所有東西(在這種情況下是白線)。下面是使用這種方法的函數的例子:
@to_texture
def draw_circle(self, x, y, r, color, opacity=1.0, fill=True, aa=False, penwidth=1):
# Make sure all spatial parameters are ints
x, y, r = int(x), int(y), int(r)
# convert color parameter to sdl2 understandable values
color = sdl2.ext.convert_to_color(color)
# convert possible opacity values to the right scale
opacity = self.opacity(opacity)
# Get background color set for this texture
bgcolor = self.__bgcolor
# Check for invalid penwidth values, and make sure the value is an int
if penwidth != 1:
if penwidth < 1:
raise ValueError("Penwidth cannot be smaller than 1")
if penwidth > 1:
penwidth = int(penwidth)
# if the circle needs to be filled, it's easy
if fill:
sdlgfx.filledCircleRGBA(self.sdl_renderer, x, y, r, color.r, color.g, color.b, opacity)
else:
# If penwidth is 1, simple use sdl2gfx own functions
if penwidth == 1:
if aa:
sdlgfx.aacircleRGBA(self.sdl_renderer, x, y, r, color.r, color.g, color.b, opacity)
else:
sdlgfx.circleRGBA(self.sdl_renderer, x, y, r, color.r, color.g, color.b, opacity)
else:
# If the penwidth is larger than 1, things become a bit more complex.
outer_r = int(r+penwidth*.5)
inner_r = int(r-penwidth*.5)
# Draw outer circle
sdlgfx.filledCircleRGBA(self.sdl_renderer, x, y,
outer_r, color.r, color.g, color.b, opacity)
# Draw inner circle
sdlgfx.filledCircleRGBA(self.sdl_renderer, x, y,
inner_r, bgcolor.r, bgcolor.g, bgcolor.b, 255)
return self
,導致:
我也試圖與不同的混合模式玩耍,這是我能得到最好的結果:
@to_texture
def draw_circle(self, x, y, r, color, opacity=1.0, fill=True, aa=False, penwidth=1):
# ... omitted for brevity
else:
# If the penwidth is larger than 1, things become a bit more complex.
# To ensure that the interior of the circle is transparent, we will
# have to work with multiple textures and blending.
outer_r = int(r+penwidth*.5)
inner_r = int(r-penwidth*.5)
# Calculate the required dimensions of the separate texture we are
# going to draw the circle on. Add 1 pixel to account for division
# inaccuracies (i.e. dividing an odd number of pixels)
(c_width, c_height) = (outer_r*2+1, outer_r*2+1)
# Create the circle texture, and make sure it can be a rendering
# target by setting the correct access flag.
circle_texture = self.environment.texture_factory.create_sprite(
size=(c_width, c_height),
access=sdl2.SDL_TEXTUREACCESS_TARGET
)
# Set renderer target to the circle texture
if sdl2.SDL_SetRenderTarget(self.sdl_renderer, circle_texture.texture) != 0:
raise Exception("Could not set circle texture as rendering"
" target: {}".format(sdl2.SDL_GetError()))
# Draw the annulus:
# as the reference point is the circle center, outer_r
# can be used for the circles x and y coordinates.
sdlgfx.filledCircleRGBA(self.sdl_renderer, outer_r, outer_r,
outer_r, color.r, color.g, color.b, opacity)
# Draw the hole
sdlgfx.filledCircleRGBA(self.sdl_renderer, outer_r, outer_r,
inner_r, 0, 0, 0, 255)
# Set renderer target back to the FrameBuffer texture
if sdl2.SDL_SetRenderTarget(self.sdl_renderer, self.surface.texture) != 0:
raise Exception("Could not unset circle texture as rendering"
" target: {}".format(sdl2.SDL_GetError()))
# Use additive blending when blitting the circle texture on the main texture
sdl2.SDL_SetTextureBlendMode(circle_texture.texture, sdl2.SDL_BLENDMODE_ADD)
# Perform the blitting operation
self.renderer.copy(circle_texture, dstrect=(x-int(c_width/2),
y-int(c_height/2), c_width, c_height))
return self
導致:
關閉,但沒有雪茄,作爲線路現在看來是在圓的前而不是它的身後,而據我瞭解添加劑/屏相融,這是預期的行爲。
我知道這裏也有函數SDL_SetRenderDrawBlendMode,但sdl2gfx繪圖函數似乎忽略了用這個函數設置的任何東西。
有沒有人比我有更多的經驗,他們之前做過這樣的事情,誰能指導我如何應對這一挑戰的正確方向?
謝謝!我認爲你是對的,因爲這是唯一的方法。你只是打敗了我:我也以類似的方式解決了這個問題,並且也會在這裏發佈我的解決方案。儘管如此,你還是有一個更完整和全面的例子,值得被接受的答案。 –