fastest HDR Filter

Blitz3D Forums/Blitz3D Programming/fastest HDR Filter

Sledge, thanks. There are no delta timing issues since I have no tween frames, the gloom texture is taken every frame. I have tested the method I described and it really works, althouh all in all about 4% slower than the current method.

sswift - not exactly sure if you are talking about the blitz window size - there's no way for me to use a square window size since the game is running in fullscreen and usually in a 4:3 ratio. I tried to find a blur function in your code archive entries, unfort. without success. EDIT: just found it, bluring a texture. I will have to try if this is faster. It could easily be faster, even with the overhead (or what's looking like it) because my current blur function takes 7ms for one pass on my machine (additional passes only take about 1ms since readpixel and writepixel is done only once, no matter how many passes).

Ok, here are the two methods that are head on head right now, concerning speed. If anybody can optimize the speed in a relevant amount, do it!

The first method works like this:
It's taking a small render with the Gloom Quad hidden, 128*96 Pixels. This is then blured and then copied to the texture that is used by the gloom quad. Then the Gloom Quad is unhidden and a full resolution game render is performed. Blendmode 3 of the gloom quad that is sticked to the camera, in front of everything else will now produce the gloom Effect.

In a Scene with 500 cubes onscreen I get about 9ms per frame with no gloom and about 24ms with the gloom turned on (hit space to toggle).
Graphics3D 1024,768,32,1
SetBuffer BackBuffer()

camera=CreateCamera()

light=CreateLight()
RotateEntity light,45,45,45
TranslateEntity camera,0,0,-45
CameraRange camera,.001,100

anz=500
Dim s(anz)
For i=0 To anz
 s(i)=CreateCube()
 PositionEntity s(i),Rnd(-20,20),Rnd(-20,20),Rnd(-20,20)
 EntityColor s(i),Rand(255),Rand(255),Rand(255)
Next

gloo_w#=128
gloo_h#=gloo_w#*(Float(GraphicsHeight())/Float(GraphicsWidth())); 0.75
Dim proc_array(gloo_w#,gloo_h#)
tex=CreateTexture(gloo_w#,gloo_w#,256); Or 16 Or 32)
quad=CreateQuad()
PositionEntity quad,EntityX(camera,1),EntityY(camera,1),EntityZ(camera,1),1
EntityTexture quad,tex
EntityFX quad,1
EntityBlend quad,3
TranslateEntity quad,-(1.0/1024.0),(1.0/1024.0),1.0
;EntityColor quad,0,255,0


gloo_wrel#=GraphicsWidth()/gloo_w
gloo_hrel#=GraphicsHeight()/gloo_h

; ************************************ MAIN ***********************************
While KeyDown(1)=0

 For i=0 To anz
  TurnEntity s(i),1,2,3
 Next


If KeyHit(57)
 do_gloom=do_gloom +1
 If do_gloom>1 Then do_gloom=0

  If do_gloom=0 Then 
   HideEntity quad
  EndIf

  If do_gloom=1 Then 
   ShowEntity quad
   EntityAlpha quad,0.95 ;1.0
  EndIf
 EndIf

 If do_gloom=1
  CameraViewport camera,0,0,gloo_w#,gloo_h#
  HideEntity quad
  RenderWorld()
  quick_blur(gloo_w#,gloo_h#,2)
  ShowEntity quad
  CopyRect 0,0,gloo_w#,gloo_h#,0,(gloo_w#-gloo_h#)/2,BackBuffer(),TextureBuffer(tex)
  CameraViewport camera,0,0,GraphicsWidth(),GraphicsHeight()
 EndIf


 RenderWorld()
 old_tt=tt
 tt=MilliSecs()
 Text 0,0,tt-old_tt
 Text 0,16,do_gloom
 Flip 0
Wend

End


Function quick_blur(w,h,passes=1)
 If passes<1 Then passes=1
 passes=passes-1
 SetBuffer BackBuffer()
 LockBuffer(BackBuffer())
 For j=0 To h-1
  For i=0 To w-1
   proc_array(i,j)=ReadPixelFast(i,j) ;And $FFFFFF
  Next
 Next
 For dbass=0 To passes
  For j=0 To h-1
   For i=1 To w-1
    proc_array(i,j)=((proc_array(i,j)And $FEFEFF)Shr 1)+((proc_array(i-1,j)And $FEFEFF)Shr 1)
   Next
   For i=w-2 To 0 Step -1
    proc_array(i,j)=((proc_array(i,j)And $FEFEFE)Shr 1)+((proc_array(i+1,j)And $FEFEFE)Shr 1)
   Next
  Next
  For i=0 To w-1
   For j=1 To h-1
    proc_array(i,j)=((proc_array(i,j)And $FEFEFF)Shr 1)+((proc_array(i,j-1)And $FEFEFF)Shr 1)
   Next
   For j=h-2 To 0 Step -1
    proc_array(i,j)=((proc_array(i,j)And $FEFEFE)Shr 1)+((proc_array(i,j+1)And $FEFEFE)Shr 1)
   Next
  Next
 Next
 
 For j=0 To h-1
  For i=0 To w-1
   WritePixelFast i,j,proc_array(i,j)
  Next
 Next
 UnlockBuffer(BackBuffer())
End Function


Function CreateQuad(parent=0)
  ; creates a quad, facing to the right side
  mesh=CreateMesh(parent)
  surf=CreateSurface(mesh)
  v0=AddVertex(surf, -1.0,   1.0,0, 0,0 )
  v1=AddVertex(surf,  1.0,   1.0,0, 1,0 )
  v2=AddVertex(surf,  1.0,  -1.0,0, 1,1 )
  v3=AddVertex(surf, -1.0,  -1.0,0, 0,1 )
  AddTriangle(surf,v0,v1,v2)
  AddTriangle(surf,v0,v2,v3)
  UpdateNormals mesh
  Return mesh
End Function



Now method 2 that I described eariler actually works like this:
Render the Scene in full game resolution, as usual. Then save a copy of the backbuffer in an imagebuffer. Then use a special trick to quickly scale the backbuffer to 128*96 Pixels. This trick is using Copyrect. It's fast, but not very accurate. However, after bluring the result is about the same as the method with the small extra render. Ok, then blur this 128*96 pixels on the backbuffer, then move them to a texture that is used by the gloom quad. Then restore the backbuffer that was saved in an imagebuffer before. Now hide the main game camera and unhide a special gloom camera that is located far away from any geometry of the scene. The gloom quad is also located there, adjusted to the gloom camera. The gloom camera is using a clsmode that won't clear the background. So we still have the last full render as background. The gloom cam will now render only one quad, with the old the background.

This method is slighty slower than the first one, but it has some potential, because one of the two renders has a very easy job (onyl one quad). At the other hand both renders are fullscreen renders, compared to the first method that is using a 128*96 pixels render for the second one.
My machine takes about 9ms without gloom and 25ms with gloom, as you can see, this is only one millisecond more than the other method.
Graphics3D 1024,768,32,1
SetBuffer BackBuffer()


gloomcam=CreateCamera()
CameraClsMode gloomcam,0,1
CameraRange gloomcam,1,10
PositionEntity gloomcam,30000,0,30000
HideEntity gloomcam

camera=CreateCamera()

light=CreateLight()
RotateEntity light,45,45,45
TranslateEntity camera,0,0,-45
CameraRange camera,.001,100


anz=500
Dim s(anz)
For i=0 To anz
 s(i)=CreateCube()
 PositionEntity s(i),Rnd(-20,20),Rnd(-20,20),Rnd(-20,20)
 EntityColor s(i),Rand(255),Rand(255),Rand(255)
Next




gloo_w#=128
gloo_h#=gloo_w#*(Float(GraphicsHeight())/Float(GraphicsWidth())); 0.75
Dim proc_array(gloo_w#,gloo_h#)
tex=CreateTexture(gloo_w#,gloo_w#,256); Or 16 Or 32)
quad=CreateQuad()
PositionEntity quad,EntityX(gloomcam,1),EntityY(gloomcam,1),EntityZ(gloomcam,1),1
EntityTexture quad,tex
EntityFX quad,1
EntityBlend quad,3
TranslateEntity quad,-(1.0/1024.0),(1.0/1024.0),1.0
EntityParent quad, gloomcam
;EntityColor quad,0,255,0


gloo_wrel#=GraphicsWidth()/gloo_w
gloo_hrel#=GraphicsHeight()/gloo_h

gloombuffer=CreateImage(GraphicsWidth(),GraphicsHeight())

; ************************************ MAIN ***********************************
While KeyDown(1)=0

 For i=0 To anz
  TurnEntity s(i),1,2,3
 Next


 If KeyHit(57)
  do_gloom=do_gloom +1
  If do_gloom>1 Then do_gloom=0

  If do_gloom=0 Then 
   HideEntity quad
   HideEntity gloomcam
  EndIf

  If do_gloom=1 Then 
   ShowEntity quad
   EntityAlpha quad,0.95 ;1.0
  EndIf
 EndIf


 RenderWorld()

 If do_gloom=1
  CopyRect 0,0,GraphicsWidth(),GraphicsHeight(),0,0,BackBuffer(),ImageBuffer(gloombuffer)
  i=0
  ifloat#=0
  For ifloat=0 To GraphicsWidth() Step 0.0001
   CopyRect ifloat,0,1,GraphicsHeight(),i,0,BackBuffer(),BackBuffer()
   ifloat=ifloat+gloo_wrel#
   i=i+1
  Next
  i=0
  ifloat#=0
  For ifloat=0 To GraphicsHeight() Step 0.0001
   CopyRect 0,ifloat,GraphicsWidth(),1,0,i,BackBuffer(),BackBuffer()
   ifloat=ifloat+gloo_hrel#
   i=i+1
  Next
  quick_blur(gloo_w#,gloo_h#,2)
  CopyRect 0,0,gloo_w#,gloo_h#,0,(gloo_w#-gloo_h#)/2,BackBuffer(),TextureBuffer(tex)
  CopyRect 0,0,GraphicsWidth(),GraphicsHeight(),0,0,ImageBuffer(gloombuffer),BackBuffer()

  HideEntity camera
  ShowEntity gloomcam
  RenderWorld()
  ShowEntity camera
  HideEntity gloomcam
 EndIf


 old_tt=tt
 tt=MilliSecs()
 Color 255,255,255
 Text 0,0,tt-old_tt
 Text 0,16,do_gloom
 Flip 0
Wend

End


Function quick_blur(w,h,passes=1,buffer=0)
 If passes<1 Then passes=1
 passes=passes-1
 If buffer=0 Then buffer = BackBuffer()
 SetBuffer Buffer
 LockBuffer(Buffer)
 For j=0 To h-1
  For i=0 To w-1
   proc_array(i,j)=ReadPixelFast(i,j) ;And $FFFFFF
  Next
 Next
 For dbass=0 To passes
  For j=0 To h-1
   For i=1 To w-1
    proc_array(i,j)=((proc_array(i,j)And $FEFEFF)Shr 1)+((proc_array(i-1,j)And $FEFEFF)Shr 1)
   Next
   For i=w-2 To 0 Step -1
    proc_array(i,j)=((proc_array(i,j)And $FEFEFE)Shr 1)+((proc_array(i+1,j)And $FEFEFE)Shr 1)
   Next
  Next
  For i=0 To w-1
   For j=1 To h-1
    proc_array(i,j)=((proc_array(i,j)And $FEFEFF)Shr 1)+((proc_array(i,j-1)And $FEFEFF)Shr 1)
   Next
   For j=h-2 To 0 Step -1
    proc_array(i,j)=((proc_array(i,j)And $FEFEFE)Shr 1)+((proc_array(i,j+1)And $FEFEFE)Shr 1)
   Next
  Next
 Next
 
 For j=0 To h-1
  For i=0 To w-1
   WritePixelFast i,j,proc_array(i,j)
  Next
 Next
 UnlockBuffer(Buffer)
End Function


Function CreateQuad(parent=0)
  ; creates a quad, facing to the right side
  mesh=CreateMesh(parent)
  surf=CreateSurface(mesh)
  v0=AddVertex(surf, -1.0,   1.0,0, 0,0 )
  v1=AddVertex(surf,  1.0,   1.0,0, 1,0 )
  v2=AddVertex(surf,  1.0,  -1.0,0, 1,1 )
  v3=AddVertex(surf, -1.0,  -1.0,0, 0,1 )
  AddTriangle(surf,v0,v1,v2)
  AddTriangle(surf,v0,v2,v3)
  UpdateNormals mesh
  Return mesh
End Function


You might think there is no reason to copy the backbuffer to an magebuffer, then scale the backbuffer, then restore it from the imagebuffer, instead of simply scaling the imagebuffer instead.

The reason why is, for some reason, doing the scaling in the backbuffer is much faster than in the imagebuffer. Even with the additional restoring of the full backbuffer it's still faster.

So how could I make this faster? Please note, using a smaller Screen resolution or gloom texture is no option. Also, when using only one blur pass instead of 2, you will see the flicker effect I mentioned.