I have this code on python that I use as a Bloom effect on my game, but I've noticed that it has this weird black shadow around the particles
The effect looks like this ^
as you can see, there is some shadows on the particles, on white background it's obvious, while in grey is subtle
I would like to know if there is a way to remove/reduce this weird effect
This is the code for the bloom (where the shadows are coming from):
def Bloom(canvas: pygame.Surface):
size = canvas.get_size()
canvas_color = pygame.surfarray.array2d(canvas)
canvas_rgba = canvas_color.view(dtype=np.uint8).reshape((*canvas_color.shape, 4))
newCanvas = pygame.Surface(size, pygame.SRCALPHA)
cv2.blur(canvas_rgba, ksize=(9, 9), dst=canvas_rgba)
pygame.surfarray.blit_array(newCanvas, canvas_color)
return newCanvas
Any help would be great :3
Edit: Removed the image with black background (no reason to be there)
CodePudding user response:
The problem isn't with the "bloom" algorithm, but with the way you blit
the surface to the target.
Not just the alpha channel is blurred, also the color channels are blurred. Therefore you have to
left: Bloom
; center: Bloom
BLEND_PREMULTIPLIED
; right: BloomNoPremultipliedAlpha
import pygame, cv2
import numpy as np
def Bloom(canvas: pygame.Surface):
size = canvas.get_size()
canvas_color = pygame.surfarray.array2d(canvas)
canvas_rgba = canvas_color.view(dtype=np.uint8).reshape((*canvas_color.shape, 4))
newCanvas = pygame.Surface(size, pygame.SRCALPHA)
cv2.blur(canvas_rgba, ksize=(25, 25), dst=canvas_rgba)
pygame.surfarray.blit_array(newCanvas, canvas_color)
return newCanvas
def BloomNoPremultipliedAlpha(canvas: pygame.Surface):
size = canvas.get_size()
canvas_color = pygame.surfarray.array2d(canvas)
canvas_rgba = canvas_color.view(dtype=np.uint8).reshape((*canvas_color.shape, 4))
newCanvas = pygame.Surface(size, pygame.SRCALPHA)
cv2.blur(canvas_rgba, ksize=(25, 25), dst=canvas_rgba)
canvas_rgba[:,:,0:3] = canvas_rgba[:,:,0:3] * 255.0 / canvas_rgba[:,:,[3,3,3]]
pygame.surfarray.blit_array(newCanvas, canvas_color)
return newCanvas
pygame.init()
window = pygame.display.set_mode((800, 300))
clock = pygame.time.Clock()
background = pygame.Surface(window.get_size())
ts, w, h, c1, c2 = 100, *window.get_size(), (160, 160, 160), (96, 96, 96)
tiles = [((x*ts, y*ts, ts, ts), c1 if (x y) % 2 == 0 else c2) for x in range((w ts-1)//ts) for y in range((h ts-1)//ts)]
[pygame.draw.rect(background, color, rect) for rect, color in tiles]
surface = pygame.Surface((250, 250), pygame.SRCALPHA)
pygame.draw.circle(surface, (255, 255, 255), surface.get_rect().center, 100)
surface1 = Bloom(surface)
surface2 = Bloom(surface)
surface3 = BloomNoPremultipliedAlpha(surface)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
window.blit(background, (0, 0))
window.blit(surface1, surface1.get_rect(center = (150, 150)))
window.blit(surface2, surface2.get_rect(center = (400, 150)), special_flags = pygame.BLEND_PREMULTIPLIED)
window.blit(surface3, surface1.get_rect(center = (650, 150)))
pygame.display.flip()
clock.tick(60)
pygame.quit()
exit()