Gaussian blur in real time?
Gaussian blur in real time?
Hey,
I'd like to know if there's a library somewhere that makes it possible to blur a part of a (2D) screen in real time. The goal would be to have a GUI over the game world, and have this game world blurred as a GUI background. I think the best way would be to capture an area of the screen, then turn it into a blurred sprite.
I saw two libraries that blur images, but they are extremely slow (500ms for 3 passes on a 512x512 image). I fear the answer contains the word "shader", and I know nothing about them
(the effect is pretty cool in 3D)
I'd like to know if there's a library somewhere that makes it possible to blur a part of a (2D) screen in real time. The goal would be to have a GUI over the game world, and have this game world blurred as a GUI background. I think the best way would be to capture an area of the screen, then turn it into a blurred sprite.
I saw two libraries that blur images, but they are extremely slow (500ms for 3 passes on a 512x512 image). I fear the answer contains the word "shader", and I know nothing about them
(the effect is pretty cool in 3D)
Re: Gaussian blur in real time?
Most 2D games, unless very old school, use 3D too.
Glow effect can be achieved in PureBasic's Ogre3D using CreateCompositorEffect().
See this one: http://wiki.ogre3d.org/Glow
You need the scripts and a suitable material to go with it.
Do a search for 'compositor' here and that should lead you to relevant and nice examples.
Glow effect can be achieved in PureBasic's Ogre3D using CreateCompositorEffect().
See this one: http://wiki.ogre3d.org/Glow
You need the scripts and a suitable material to go with it.
Do a search for 'compositor' here and that should lead you to relevant and nice examples.
Current configurations:
Ubuntu 20.04/64 bit - Window 10 64 bit
Intel 6800K, GeForce Gtx 1060, 32 gb ram.
Amd Ryzen 9 5950X, GeForce 3070, 128 gb ram.
Ubuntu 20.04/64 bit - Window 10 64 bit
Intel 6800K, GeForce Gtx 1060, 32 gb ram.
Amd Ryzen 9 5950X, GeForce 3070, 128 gb ram.
Re: Gaussian blur in real time?
I don't know how to do it with shaders unfortunately.
I tried with direct DrawingBuffer() access what it could do but I don't know how to make it fast enough (and good). You can change the test case with number keys 1-8. The mouse moves the sprite and it should blur in some way in the center of the screen in case 3,4,6,7,8.
Please disable the debugger.
Here are the times the drawing block takes on my Linux machine. On my windows machine the times are way to long, over a second in some cases, but I do not have a real graphics card in there at the moment, maybe that's why.
It doesn't blur very much (would be more expensive) and it blurs only 1/4 of a 800x600 screen, so not sure it could ever be done fast enough for a whole large screen, so FWIW
I tried with direct DrawingBuffer() access what it could do but I don't know how to make it fast enough (and good). You can change the test case with number keys 1-8. The mouse moves the sprite and it should blur in some way in the center of the screen in case 3,4,6,7,8.
Please disable the debugger.
Here are the times the drawing block takes on my Linux machine. On my windows machine the times are way to long, over a second in some cases, but I do not have a real graphics card in there at the moment, maybe that's why.
Code: Select all
mode 1: empty drawing block time: 11ms
mode 2: base time: 11ms
mode 3: 4 direct neighbors time: 15ms
mode 4: 8 neighbors with greater distance time: 16ms
mode 5: test only CopyMemory() time: 12ms
mode 6: CopyMemory() and more neighbors time: 110ms
mode 7: CopyMemory() and weighted neighbors time: 175ms
mode 8: 4 neighbors with multiple distances time: 25ms
Code: Select all
CompilerIf #PB_Compiler_Debugger
If MessageRequester("debugger?", "the debugger is enabled. run anyway?", #PB_MessageRequester_YesNo) = #PB_MessageRequester_No
End
EndIf
CompilerEndIf
EnableExplicit
#ScreenWidth = 800
#ScreenHeight = 600
InitSprite()
InitKeyboard()
InitMouse()
ElapsedMilliseconds()
Structure Pixel
r.a
g.a
b.a
EndStructure
Define win, quit, mode, mode$
Define spr, i
Define sprFR, FR, FRt, FR$
Define time, timeTmp
win = OpenWindow(#PB_Any, 0, 0, #ScreenWidth, #ScreenHeight, "window")
OpenWindowedScreen(WindowID(win), 0, 0, #ScreenWidth, #ScreenHeight)
UsePNGImageDecoder()
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Define spr = LoadSprite(#PB_Any, #PB_Compiler_Home + "examples/3D/Data/PureBasic3DLogo.png") ; windows
CompilerElse
Define spr = LoadSprite(#PB_Any, #PB_Compiler_Home + "examples/3d/Data/PureBasic3DLogo.png") ; linux
CompilerEndIf
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Define font = LoadFont(#PB_Any, "courier new", 10)
CompilerElse
Define font = LoadFont(#PB_Any, "monospace", 10)
CompilerEndIf
sprFR = CreateSprite(#PB_Any, 400, 60)
mode = 6
Procedure mode3(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize)
Protected x, y
Protected *pixel1.Pixel
Protected *pixel2lef.Pixel
Protected *pixel2rig.Pixel
Protected *pixel2top.Pixel
Protected *pixel2bot.Pixel
For y = yStart To yEnd
For x = xStart To xEnd
*pixel1 = buffer + ((y ) * pitch) + ((x ) * pixelSize)
*pixel2lef = buffer + ((y ) * pitch) + ((x-1) * pixelSize)
*pixel2rig = buffer + ((y ) * pitch) + ((x+1) * pixelSize)
*pixel2top = buffer + ((y-1) * pitch) + ((x ) * pixelSize)
*pixel2bot = buffer + ((y+1) * pitch) + ((x ) * pixelSize)
*pixel1\r = (*pixel1\r + *pixel2lef\r + *pixel2rig\r + *pixel2top\r + *pixel2bot\r) / 5.0
*pixel1\g = (*pixel1\g + *pixel2lef\g + *pixel2rig\g + *pixel2top\g + *pixel2bot\g) / 5.0
*pixel1\b = (*pixel1\b + *pixel2lef\b + *pixel2rig\b + *pixel2top\b + *pixel2bot\b) / 5.0
Next
Next
EndProcedure
Procedure mode4(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize)
Protected x, y
Protected *pixel1.Pixel
Protected *pixel2_1.Pixel
Protected *pixel2_2.Pixel
Protected *pixel2_3.Pixel
Protected *pixel2_4.Pixel
Protected *pixel2_5.Pixel
Protected *pixel2_6.Pixel
Protected *pixel2_7.Pixel
Protected *pixel2_8.Pixel
For y = yStart To yEnd
For x = xStart To xEnd
*pixel1 = buffer + ((y ) * pitch) + ((x ) * pixelSize)
*pixel2_1 = buffer + ((y-3) * pitch) + ((x+1) * pixelSize)
*pixel2_2 = buffer + ((y-1) * pitch) + ((x+3) * pixelSize)
*pixel2_3 = buffer + ((y+1) * pitch) + ((x+3) * pixelSize)
*pixel2_4 = buffer + ((y+3) * pitch) + ((x+1) * pixelSize)
*pixel2_5 = buffer + ((y+3) * pitch) + ((x-1) * pixelSize)
*pixel2_6 = buffer + ((y+1) * pitch) + ((x-3) * pixelSize)
*pixel2_7 = buffer + ((y-1) * pitch) + ((x-3) * pixelSize)
*pixel2_8 = buffer + ((y-3) * pitch) + ((x-1) * pixelSize)
*pixel1\r = (*pixel2_1\r + *pixel2_2\r + *pixel2_3\r + *pixel2_4\r + *pixel2_5\r + *pixel2_6\r + *pixel2_7\r + *pixel2_8\r) / 8.0
*pixel1\g = (*pixel2_1\g + *pixel2_2\g + *pixel2_3\g + *pixel2_4\g + *pixel2_5\g + *pixel2_6\g + *pixel2_7\g + *pixel2_8\g) / 8.0
*pixel1\b = (*pixel2_1\b + *pixel2_2\b + *pixel2_3\b + *pixel2_4\b + *pixel2_5\b + *pixel2_6\b + *pixel2_7\b + *pixel2_8\b) / 8.0
Next
Next
EndProcedure
Procedure mode5(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize, buffer2)
Protected x, y
CopyMemory(buffer, buffer2, OutputHeight() * pitch)
EndProcedure
Procedure mode6(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize, buffer2)
Protected x, y, i, k
Protected r, g, b, cnt
Protected *pixelTmp.Pixel
Protected *pixel1.Pixel
CopyMemory(buffer, buffer2, OutputHeight() * pitch)
For y = yStart To yEnd
For x = xStart To xEnd
r = 0
g = 0
b = 0
cnt = 0
For k=-4 To 4
For i=-4 To 4
*pixelTmp = buffer2 + ((y+k) * pitch) + ((x+i) * pixelSize)
r + *pixelTmp\r
g + *pixelTmp\g
b + *pixelTmp\b
cnt + 1
Next
Next
*pixel1 = buffer + (y * pitch) + (x * pixelSize)
*pixel1\r = r / cnt
*pixel1\g = g / cnt
*pixel1\b = b / cnt
Next
Next
EndProcedure
Procedure mode7(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize, buffer2)
Protected x, y, i, k
Protected r.f, g.f, b.f, cnt.f
Protected *pixelTmp.Pixel
Protected *pixel1.Pixel
CopyMemory(buffer, buffer2, OutputHeight() * pitch)
#d = 3
Protected initWeights
Protected Dim weights.f(1, 1) ; use .d ?
Protected rMax.f
If Not initWeights
initWeights = #True
Dim weights( (2 * #d + 1), (2 * #d + 1) )
rMax = Sqr((#d * #d) + (#d * #d))
For k=-#d To #d
For i=-#d To #d
weights(#d + k, #d + i) = 1.0 - Sqr((i * i) + (k * k)) / rMax
Debug "" + i + " " + k + " " + weights(#d + k, #d + i)
Next
Next
;End
EndIf
; test weights()
; DrawingMode(#PB_2DDrawing_AllChannels)
; Box(10-2, 10-2, 90+4, 90+4, $ff006600)
; For k=-4 To 4
; For i=-4 To 4
; Circle(10+5+(4+k)*10, 10+5+(4+i)*10, 3, RGBA(255.0 * weights(4+k, 4+i), 0, 0, 255))
; Next
; Next
For y = yStart To yEnd
For x = xStart To xEnd
r = 0
g = 0
b = 0
cnt = 0
For k=-#d To #d
For i=-#d To #d
*pixelTmp = buffer2 + ((y+k) * pitch) + ((x+i) * pixelSize)
r + *pixelTmp\r * weights(#d+k, #d+i)
g + *pixelTmp\g * weights(#d+k, #d+i)
b + *pixelTmp\b * weights(#d+k, #d+i)
cnt + weights(#d+k, #d+i)
Next
Next
*pixel1 = buffer + (y * pitch) + (x * pixelSize)
*pixel1\r = r / cnt
*pixel1\g = g / cnt
*pixel1\b = b / cnt
Next
Next
EndProcedure
Procedure mode8(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize, buffer2)
Protected x, y
Protected *pixel1.Pixel
Protected *pixel2lef.Pixel
Protected *pixel2rig.Pixel
Protected *pixel2top.Pixel
Protected *pixel2bot.Pixel
CopyMemory(buffer, buffer2, OutputHeight() * pitch)
Define n
For n = 1 To 4
For y = yStart To yEnd
For x = xStart To xEnd
*pixel1 = buffer + ((y ) * pitch) + ((x ) * pixelSize)
*pixel2lef = buffer2 + ((y ) * pitch) + ((x-n) * pixelSize)
*pixel2rig = buffer2 + ((y ) * pitch) + ((x+n) * pixelSize)
*pixel2top = buffer2 + ((y-n) * pitch) + ((x ) * pixelSize)
*pixel2bot = buffer2 + ((y+n) * pitch) + ((x ) * pixelSize)
*pixel1\r = (*pixel2lef\r + *pixel2rig\r + *pixel2top\r + *pixel2bot\r) / 4.0
*pixel1\g = (*pixel2lef\g + *pixel2rig\g + *pixel2top\g + *pixel2bot\g) / 4.0
*pixel1\b = (*pixel2lef\b + *pixel2rig\b + *pixel2top\b + *pixel2bot\b) / 4.0
Next
Next
Next
EndProcedure
Repeat
ExamineMouse()
ExamineKeyboard()
If KeyboardPushed(#PB_Key_Escape) : quit = #True : EndIf
If KeyboardPushed(#PB_Key_1) : mode = 1 : EndIf
If KeyboardPushed(#PB_Key_2) : mode = 2 : EndIf
If KeyboardPushed(#PB_Key_3) : mode = 3 : EndIf
If KeyboardPushed(#PB_Key_4) : mode = 4 : EndIf
If KeyboardPushed(#PB_Key_5) : mode = 5 : EndIf
If KeyboardPushed(#PB_Key_6) : mode = 6 : EndIf
If KeyboardPushed(#PB_Key_7) : mode = 7 : EndIf
If KeyboardPushed(#PB_Key_8) : mode = 8 : EndIf
While WindowEvent()
Select Event()
Case #PB_Event_CloseWindow
quit = #True
EndSelect
Wend
FR + 1
If ElapsedMilliseconds() > FRt
time / FR
Select mode
Case 1 : mode$ = "empty drawing block"
Case 2 : mode$ = "base"
Case 3 : mode$ = "4 direct neighbors"
Case 4 : mode$ = "8 neighbors with greater distance"
Case 5 : mode$ = "test only CopyMemory()"
Case 6 : mode$ = "CopyMemory() and more neighbors"
Case 7 : mode$ = "CopyMemory() and weighted neighbors"
Case 8 : mode$ = "4 neighbors with multiple distances"
EndSelect
FRt = ElapsedMilliseconds() + 500
FR$ = "fps:" + Str(FR * 2)
FR = 0
StartDrawing(SpriteOutput(sprFR))
DrawingMode(#PB_2DDrawing_Transparent)
Box(0, 0, OutputWidth(), OutputHeight(), $0)
DrawingFont(FontID(font))
DrawText(0, 0, FR$)
DrawText(0, 20, "mode: " + mode + " (" + mode$ + ")")
DrawText(0, 40, "time: " + time + "ms")
StopDrawing()
EndIf
ClearScreen($333333)
DisplayTransparentSprite(spr, MouseX(), MouseY())
timeTmp = ElapsedMilliseconds()
If StartDrawing(ScreenOutput())
If mode >= 2
Define buffer = DrawingBuffer()
Define pitch = DrawingBufferPitch()
Define pixelFormat = DrawingBufferPixelFormat()
Define pixelSize
; Debug pixelFormat
; Debug pixelFormat!#PB_PixelFormat_ReversedY
; Debug #PB_PixelFormat_24Bits_RGB
; Debug #PB_PixelFormat_32Bits_BGR
; End
If pixelFormat & (#PB_PixelFormat_24Bits_BGR | #PB_PixelFormat_24Bits_RGB)
pixelSize = 3
ElseIf pixelFormat & (#PB_PixelFormat_32Bits_BGR | #PB_PixelFormat_32Bits_RGB)
pixelSize = 4
Else
CloseScreen()
CloseWindow(win)
MessageRequester("error", "pixel format not supported")
End
EndIf
If pixelSize
Define yStart = #ScreenHeight * 0.25
Define yEnd = #ScreenHeight * 0.75
Define xStart = #ScreenWidth * 0.25
Define xEnd = #ScreenWidth * 0.75
DrawingMode(#PB_2DDrawing_Outlined)
Box(xStart - 20, yStart - 20, xEnd - xStart + 40, yEnd - yStart + 40, $ff00ff00)
Define buffer2
If Not buffer2
buffer2 = AllocateMemory(pitch * OutputHeight())
EndIf
If mode >= 3
Select mode
Case 3 : mode3(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize)
Case 4 : mode4(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize)
Case 5 : mode5(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize, buffer2)
Case 6 : mode6(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize, buffer2)
Case 7 : mode7(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize, buffer2)
Case 8 : mode8(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize, buffer2)
EndSelect
EndIf
EndIf
EndIf
StopDrawing()
EndIf
time = time + (ElapsedMilliseconds() - timeTmp)
DisplaySprite(sprFR, MouseX(), MouseY() + 80)
FlipBuffers()
Until quit
Re: Gaussian blur in real time?
Hello,
you may be able to try the following:
Take the sprite for the background and copy it to a number of SpriteID . For example, 4 sprites.
You change the transparency and output the sprites slightly (randomly) offset and overlapping on the screen.
It is possible that this will achieve the desired effect.
download:
https://www.dropbox.com/s/fjizfurnprr70 ... O.zip?dl=0
you may be able to try the following:
Take the sprite for the background and copy it to a number of SpriteID . For example, 4 sprites.
You change the transparency and output the sprites slightly (randomly) offset and overlapping on the screen.
It is possible that this will achieve the desired effect.
download:
https://www.dropbox.com/s/fjizfurnprr70 ... O.zip?dl=0
Code: Select all
;small and dirty example for "blur"
InitKeyboard()
InitSprite()
InitMouse()
InitSound()
UsePNGImageDecoder()
EnableExplicit
Structure _gfx
id.i
x.f
y.f
t.l
EndStructure
Global NewList _gfx._gfx()
Global _gfx_work_id.i=0
Global _key_id.l=0
Global _ok.l=0
Global _win_id.i=0
Global _x.f=0
Global _y.f=0
Global _w.f=1024
Global _h.f=512
Global _win_id.i=0
Global _screen_id.i=0
Global _event.i=0
Global _i.b=0
Global _bx.b=0
Global _by.b=6
;load the gfx:
_win_id.i=OpenWindow(#PB_Any,_x.f,_y.f,_w.f,_h.f," *BLUR* ?")
_screen_id.i=OpenWindowedScreen(WindowID(_win_id.i),0,0,_w.f,_h.f)
_gfx_work_id.i=LoadSprite(#PB_Any,GetCurrentDirectory()+"blur.png",#PB_Sprite_AlphaBlending )
If IsSprite(_gfx_work_id.i)
ResetList(_gfx())
For _i.b=0 To 3
If AddElement(_gfx())
CopySprite(_gfx_work_id,_gfx()\id)
_bx.b+1
_by.b-1
_gfx()\x=_bx.b
_gfx()\y=_by.b
EndIf
Next
If ListSize(_gfx())>0
Repeat
_event.i=WaitWindowEvent(1)
ResetList(_gfx())
While NextElement(_gfx())
; _gfx()\x=Random(4)
; _gfx()\y=Random(-4)
DisplayTransparentSprite(_gfx()\id,_gfx()\x,_gfx()\y,50)
Wend
FlipBuffers()
Until _event.i=#PB_Event_CloseWindow
EndIf
Else
_ok.l=MessageRequester("ERROR","Can not load gfx",#PB_MessageRequester_Ok )
EndIf
End
Last edited by darius676 on Mon Oct 14, 2019 8:59 pm, edited 4 times in total.
Re: Gaussian blur in real time?
Thank you for your answers! Those pieces of code will be useful!
- Michael Vogel
- Addict
- Posts: 2680
- Joined: Thu Feb 09, 2006 11:27 pm
- Contact:
Re: Gaussian blur in real time?
Not sure if the following routines are from Wilbert or someone else, but they are quite fast - do quick check by loading an image of your preference...
Code: Select all
Procedure Gaussian1D(*PixelBuf32,NumPixels,NextPixelOffset=4)
!mov ecx, [p.v_NumPixels]
!sub ecx, 3
!js gaussian1d_exit
!mov eax, [p.v_NextPixelOffset]
CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
!mov rdx, [p.p_PixelBuf32]
!movd mm1, [rdx]
!movd mm4, [rdx + rax]
CompilerElse
!mov edx, [p.p_PixelBuf32]
!movd mm1, [edx]
!movd mm4, [edx + eax]
CompilerEndIf
!punpcklbw mm1, mm1
!punpcklbw mm4, mm4
!psrlw mm1, 4
!psrlw mm4, 4
!movq mm2, mm1
!movq mm3, mm1
; loop
!gaussian1d_loop0:
CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
!movd mm5, [rdx + rax * 2]
CompilerElse
!movd mm5, [edx + eax * 2]
CompilerEndIf
!punpcklbw mm5, mm5
!psrlw mm5, 4
!gaussian1d_loop1:
!movq mm0, mm2
!paddw mm0, mm3
!paddw mm0, mm4
!psllw mm0, 2
!paddw mm0, mm1
!paddw mm0, mm3
!paddw mm0, mm3
!paddw mm0, mm5
!psrlw mm0, 8
!packuswb mm0, mm0
CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
!movd [rdx], mm0
!add rdx, rax
CompilerElse
!movd [edx], mm0
!add edx, eax
CompilerEndIf
!movq mm1, mm2
!movq mm2, mm3
!movq mm3, mm4
!movq mm4, mm5
!dec ecx
!jns gaussian1d_loop0
!cmp ecx, -3
!jne gaussian1d_loop1
!gaussian1d_exit:
!emms
EndProcedure
Procedure Gaussian2D(*PixelBuf32,Width,Height,BufferPitch=0)
If BufferPitch=0
BufferPitch=Width<<2
EndIf
Protected i.i=0
While i<Height
Gaussian1D(*PixelBuf32 + BufferPitch * i, Width)
i+1
Wend
i=0
While i<Width
Gaussian1D(*PixelBuf32+i<<2,Height,BufferPitch)
i+1
Wend
EndProcedure
Procedure GaussianBlur(Image,Strength=2)
Protected.i i,w,h,x,y,max_x,max_y
;If CheckCompilerInformation()
If StartDrawing(ImageOutput(image))
w=OutputWidth()
h=OutputHeight()
If DrawingBufferPixelFormat() & $60
For i=0 To Strength
Gaussian2D(DrawingBuffer(),w,h,DrawingBufferPitch())
Next
Else
max_x=w-1
max_y=h-1
Dim Buffer.l(max_y, max_x)
DrawingMode(#PB_2DDrawing_AllChannels)
For y=0 To max_y
For x=0 To max_x
Buffer(y,x)=Point(x,y)
Next
Next
For i=0 To Strength
Gaussian2D(@Buffer(),w,h)
Next
For y=0 To max_y
For x=0 To max_x
Plot(x,y,Buffer(y,x))
Next
Next
EndIf
StopDrawing()
EndIf
;EndIf
EndProcedure
#ScreenWidth = 400
#ScreenHeight = 400
win = OpenWindow(0, 0, 0, #ScreenWidth, #ScreenHeight, "window")
ImageGadget(0,0,0,#ScreenWidth, #ScreenHeight,0)
UsePNGImageDecoder()
LoadImage(1,"c:\...\....png")
AddWindowTimer(0,0,100)
strength=200
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
quit = #True
EndSelect
t=ElapsedMilliseconds()
CopyImage(1,0)
GaussianBlur(0,strength)
t=ElapsedMilliseconds()-t
SetGadgetState(0,ImageID(0))
SetWindowTitle(0,Str(t)+" @"+Str(strength))
If strength
strength-2
EndIf
Until quit
Re: Gaussian blur in real time?
Yeah that one I know. Not fast enough in my opinion
Re: Gaussian blur in real time?
It can blur an 800x600 screen with 3 passes in ~40ms on my system.
Code: Select all
CompilerIf #PB_Compiler_Debugger
If MessageRequester("debugger?", "the debugger is enabled. run anyway?", #PB_MessageRequester_YesNo) = #PB_MessageRequester_No
End
EndIf
CompilerEndIf
EnableExplicit
#ScreenWidth = 800
#ScreenHeight = 600
;#ScreenWidth = 1680
;#ScreenHeight = 1050
InitSprite()
InitKeyboard()
InitMouse()
ElapsedMilliseconds()
Structure Pixel
r.a
g.a
b.a
EndStructure
Define win, quit, mode, mode$
Define spr, i
Define sprFR, FR, FRt, FR$
Define time, timeTmp
win = OpenWindow(#PB_Any, 0, 0, #ScreenWidth, #ScreenHeight, "window")
OpenWindowedScreen(WindowID(win), 0, 0, #ScreenWidth, #ScreenHeight)
UsePNGImageDecoder()
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Define spr = LoadSprite(#PB_Any, #PB_Compiler_Home + "examples/3D/Data/PureBasic3DLogo.png") ; windows
CompilerElse
Define spr = LoadSprite(#PB_Any, #PB_Compiler_Home + "examples/3d/Data/PureBasic3DLogo.png") ; linux
CompilerEndIf
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Define font = LoadFont(#PB_Any, "courier new", 10)
CompilerElse
Define font = LoadFont(#PB_Any, "monospace", 10)
CompilerEndIf
sprFR = CreateSprite(#PB_Any, 400, 60)
mode = 3
Procedure Gaussian1D(*PixelBuf32,NumPixels,NextPixelOffset=4)
!mov ecx, [p.v_NumPixels]
!sub ecx, 3
!js gaussian1d_exit
!mov eax, [p.v_NextPixelOffset]
CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
!mov rdx, [p.p_PixelBuf32]
!movd mm1, [rdx]
!movd mm4, [rdx + rax]
CompilerElse
!mov edx, [p.p_PixelBuf32]
!movd mm1, [edx]
!movd mm4, [edx + eax]
CompilerEndIf
!punpcklbw mm1, mm1
!punpcklbw mm4, mm4
!psrlw mm1, 4
!psrlw mm4, 4
!movq mm2, mm1
!movq mm3, mm1
; loop
!gaussian1d_loop0:
CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
!movd mm5, [rdx + rax * 2]
CompilerElse
!movd mm5, [edx + eax * 2]
CompilerEndIf
!punpcklbw mm5, mm5
!psrlw mm5, 4
!gaussian1d_loop1:
!movq mm0, mm2
!paddw mm0, mm3
!paddw mm0, mm4
!psllw mm0, 2
!paddw mm0, mm1
!paddw mm0, mm3
!paddw mm0, mm3
!paddw mm0, mm5
!psrlw mm0, 8
!packuswb mm0, mm0
CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
!movd [rdx], mm0
!add rdx, rax
CompilerElse
!movd [edx], mm0
!add edx, eax
CompilerEndIf
!movq mm1, mm2
!movq mm2, mm3
!movq mm3, mm4
!movq mm4, mm5
!dec ecx
!jns gaussian1d_loop0
!cmp ecx, -3
!jne gaussian1d_loop1
!gaussian1d_exit:
!emms
EndProcedure
Procedure Gaussian2D(*PixelBuf32,Width,Height,BufferPitch=0)
If BufferPitch=0
BufferPitch=Width<<2
EndIf
Protected i.i=0
While i<Height
Gaussian1D(*PixelBuf32 + BufferPitch * i, Width)
i+1
Wend
i=0
While i<Width
Gaussian1D(*PixelBuf32+i<<2,Height,BufferPitch)
i+1
Wend
EndProcedure
Procedure GaussianBlur(Image,Strength=2)
Protected.i i,w,h,x,y,max_x,max_y
;If CheckCompilerInformation()
;If StartDrawing(ImageOutput(image))
w=OutputWidth()
h=OutputHeight()
If DrawingBufferPixelFormat() & $60
For i=0 To Strength
Gaussian2D(DrawingBuffer(),w,h,DrawingBufferPitch())
Next
Else
max_x=w-1
max_y=h-1
Dim Buffer.l(max_y, max_x)
DrawingMode(#PB_2DDrawing_AllChannels)
For y=0 To max_y
For x=0 To max_x
Buffer(y,x)=Point(x,y)
Next
Next
For i=0 To Strength
Gaussian2D(@Buffer(),w,h)
Next
For y=0 To max_y
For x=0 To max_x
Plot(x,y,Buffer(y,x))
Next
Next
EndIf
;StopDrawing()
;EndIf
;EndIf
EndProcedure
Repeat
ExamineMouse()
ExamineKeyboard()
If KeyboardPushed(#PB_Key_Escape) : quit = #True : EndIf
If KeyboardPushed(#PB_Key_1) : mode = 1 : EndIf
If KeyboardPushed(#PB_Key_2) : mode = 2 : EndIf
If KeyboardPushed(#PB_Key_3) : mode = 3 : EndIf
While WindowEvent()
Select Event()
Case #PB_Event_CloseWindow
quit = #True
EndSelect
Wend
FR + 1
If ElapsedMilliseconds() > FRt
time / FR
Select mode
Case 1 : mode$ = "empty drawing block"
Case 2 : mode$ = "base"
Case 3 : mode$ = "asm gauss"
EndSelect
FRt = ElapsedMilliseconds() + 500
FR$ = "fps:" + Str(FR * 2)
FR = 0
StartDrawing(SpriteOutput(sprFR))
DrawingMode(#PB_2DDrawing_Transparent)
Box(0, 0, OutputWidth(), OutputHeight(), $0)
DrawingFont(FontID(font))
DrawText(0, 0, FR$)
DrawText(0, 20, "mode: " + mode + " (" + mode$ + ")")
DrawText(0, 40, "time: " + time + "ms")
StopDrawing()
EndIf
ClearScreen($333333)
DisplayTransparentSprite(spr, MouseX(), MouseY())
timeTmp = ElapsedMilliseconds()
If StartDrawing(ScreenOutput())
If mode >= 2
Define buffer = DrawingBuffer()
Define pitch = DrawingBufferPitch()
Define pixelFormat = DrawingBufferPixelFormat()
Define pixelSize
; Debug pixelFormat
; Debug pixelFormat!#PB_PixelFormat_ReversedY
; Debug #PB_PixelFormat_24Bits_RGB
; Debug #PB_PixelFormat_32Bits_BGR
; End
If pixelFormat & (#PB_PixelFormat_24Bits_BGR | #PB_PixelFormat_24Bits_RGB)
pixelSize = 3
ElseIf pixelFormat & (#PB_PixelFormat_32Bits_BGR | #PB_PixelFormat_32Bits_RGB)
pixelSize = 4
Else
CloseScreen()
CloseWindow(win)
MessageRequester("error", "pixel format not supported")
End
EndIf
If pixelSize
Define yStart = #ScreenHeight * 0.25
Define yEnd = #ScreenHeight * 0.75
Define xStart = #ScreenWidth * 0.25
Define xEnd = #ScreenWidth * 0.75
DrawingMode(#PB_2DDrawing_Outlined)
Box(xStart - 20, yStart - 20, xEnd - xStart + 40, yEnd - yStart + 40, $ff00ff00)
Define buffer2
If Not buffer2
buffer2 = AllocateMemory(pitch * OutputHeight())
EndIf
If mode >= 3
Select mode
Case 3
Define strength = 3
GaussianBlur(1, strength)
EndSelect
EndIf
EndIf
EndIf
StopDrawing()
EndIf
time = time + (ElapsedMilliseconds() - timeTmp)
DisplaySprite(sprFR, MouseX(), MouseY() + 80)
FlipBuffers()
Until quit
Re: Gaussian blur in real time?
How much faster do you need it to be ?Joubarbe wrote:Yeah that one I know. Not fast enough in my opinion
You can also think the other way around. First decide how much time the blur is allowed to take and then see what you can accomplish in that time.
A one directional blur (only horizontal or vertical) would be faster and if you have an example image of how much blur you want, it might also be possible to blur more in one pass so you don't need 3 passes.
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: Gaussian blur in real time?
The look I'd like to obtain is in my first post, the link to Everspace 2. That's pretty blurry. 40ms in a real time game is out of the question, but I'm trying some stuff right now, "pre-blurring" the elements that have a chance to go behind the UI. I don't have a choice anyway, that's either that, or shaders (or give up on this idea).
"blur more in one pass" you said, how so? (I know nothing about ASM)
(and thanks for your code anyway wilbert, it's been useful to me in the past )
"blur more in one pass" you said, how so? (I know nothing about ASM)
(and thanks for your code anyway wilbert, it's been useful to me in the past )
Re: Gaussian blur in real time?
The link you posted seems to freeze the background image when the menu appears.Joubarbe wrote:The look I'd like to obtain is in my first post, the link to Everspace 2. That's pretty blurry. 40ms in a real time game is out of the question, but I'm trying some stuff right now, "pre-blurring" the elements that have a chance to go behind the UI. I don't have a choice anyway, that's either that, or shaders (or give up on this idea).
In that case you only have to blur it once.
If you take another approach (like a low pass filter), you can make the strength of the blur independent of the running time of the procedure.Joubarbe wrote:"blur more in one pass" you said, how so? (I know nothing about ASM)
It would require different code but you would be able to create a highly blurred image without a lot of extra time.
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: Gaussian blur in real time?
Is there such code in PB somewhere?
Re: Gaussian blur in real time?
You can try our UB2D - 2D Physically Based Rendering Engine.
In this video you can actually see the blurred scene behind the GUI: https://youtu.be/_luehiIpetU?t=182
In this video you can actually see the blurred scene behind the GUI: https://youtu.be/_luehiIpetU?t=182
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Re: Gaussian blur in real time?
Wow I forgot about this one. Seeing that it's still pre-alpha, is it safe to use?
A shame this seems... discontinued? It's by far the most promising 2D engine I've seen on PB.
(32bits only, hmm... No way to have the source code of the blur part I suppose? - really don't feel good using a whole alpha engine for just one library)
(I'm also of the opinion of Artus about Godot. Would have been easier to play with predefined shaders)
EDIT: Could you explain briefly what is the method you used for this blur behind the GUI?
A shame this seems... discontinued? It's by far the most promising 2D engine I've seen on PB.
(32bits only, hmm... No way to have the source code of the blur part I suppose? - really don't feel good using a whole alpha engine for just one library)
(I'm also of the opinion of Artus about Godot. Would have been easier to play with predefined shaders)
EDIT: Could you explain briefly what is the method you used for this blur behind the GUI?
Last edited by Joubarbe on Mon Oct 14, 2019 7:24 am, edited 2 times in total.
Re: Gaussian blur in real time?
I could try to create it if you wish; it might benefit others as well.Joubarbe wrote:Is there such code in PB somewhere?
I believe I can make it have a strong blur and at the same time be faster as my gaussian blur procedure at its lowest strength.
The only thing is that the code will be longer and a bit more complicated for me to code so it might take a few days to get it right.
You could also check out thenOpenCV examples by JHPJHP.
OpenCV is also capable of blurring.
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)