[bb] Simple Motion Blur by GIB3D [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:39

Previous topic - Next topic

BlitzBot

Title : Simple Motion Blur
Author : GIB3D
Posted : 1+ years ago

Description : It uses an overlay+texture to create motion blur. It grabs what you see on screen and puts it on the texture. The down side is that the screen or cameraviewport must be to the power of 2 (meaning it must be 2x2,4x4,512x512,1024x1024).

Change the overlay position/alpha/other changeable stuff to make oher interesting effects. You can also add on more overlays and move then around too.


Code :
Code (blitzbasic) Select
InitGraphics(1024,1024)

Global Light = CreateLight()

Global Camera = CreateCamera()
PositionEntity Camera,0,1,-5
CameraRange Camera,.001,100


CreatePlane()

Local Cube = CreateCube()
PositionEntity Cube,0,1,0
RotateEntity Cube,30,40,0

Local Overlay = CreateQuad(1,1,-1,Camera)
PositionEntity Overlay,0,0,.5
EntityAlpha Overlay,.8

Local Texture = CreateTexture(1024,1024,1+16+32)
EntityTexture Overlay,Texture

LockBuffer TextureBuffer(Texture)
For y = 0 To TextureHeight(Texture)-1
For x = 0 To TextureWidth(Texture)-1
WritePixelFast x,y,0,TextureBuffer(Texture)
Next
Next
UnlockBuffer TextureBuffer(Texture)

RenderTexture(Texture)

While Not KeyDown(1)

TurnEntity Cube,.5,1,.5

If KeyDown(200) TranslateEntity Camera,0,0,.1
If KeyDown(208) TranslateEntity Camera,0,0,-.1
If KeyDown(203) TranslateEntity Camera,-.1,0,0
If KeyDown(205) TranslateEntity Camera,.1,0,0

UpdateWorld

RenderTexture(Texture)

Flip
Wend
End

Function RenderTexture(texture)
RenderWorld
CopyRect 0,0,1024,1024,0,0,FrontBuffer(),TextureBuffer(texture)
End Function

Function InitGraphics(w = 1024, h = 768,title$="Blitz3D Program",exit_message$="")
Graphics3D w, h, 32, 2
SetBuffer BackBuffer()
SeedRnd MilliSecs()

If exit_message <> ""
AppTitle title,exit_message
Else
AppTitle title
EndIf
End Function

Function CreateQuad(width#,height#,order%=-1,parent%=False)
Local v0,v1,v2,v3
Local Point,Surface

If Not parent = False
Point = CreateMesh(parent)
Else
Point = CreateMesh()
EndIf

If order <> 0
EntityOrder Point,order
EndIf

EntityFX Point,1

Surface = CreateSurface(Point)

v0=AddVertex(Surface,-(width*.5),(height*.5),0 ,0,0)
v1=AddVertex(Surface,(width*.5),(height*.5),0 ,1,0)
v2=AddVertex(Surface,-(width*.5),-(height*.5),0 ,0,1)
v3=AddVertex(Surface,(width*.5),-(height*.5),0 ,1,1)

AddTriangle(Surface,v0,v1,v2)
AddTriangle(Surface,v1,v3,v2)

Return Point
End Function


Comments :


Nate the Great(Posted 1+ years ago)

 thanks! this is great


Knight #51(Posted 1+ years ago)

 Awsome!


laytonkinyon(Posted 8 months ago)

 Is there a way to get around the power of two problem? I'd really like to play with accumulation blur for a horror game I'm making (not really too inspired by the SCP games btw)


RustyKristi(Posted 8 months ago)

 @laytonkinyonUse OpenB3D and Blitzmax instead so you can actually do some shader stuff. Check out the examples here:<a href="https://github.com/markcwm/openb3d.mod/search?utf8=%E2%9C%93&q=blur" target="_blank">https://github.com/markcwm/openb3d.mod/search?utf8=%E2%9C%93&q=blur</a>There's already a DOF shader where you can get started.Don't do any workaround post effects with Blitz3D, it will just cripple the fps of your game. I know this because I tried some of it not on a demo but on a demo I'm trying to make.<div class="quote"> for a horror game I'm making (not really too inspired by the SCP games btw)  </div>lol no one asked you about that SCP thing, but hey good luck and welcome! :)


Kryzon(Posted 8 months ago)

 That texture will always have a power of two size, but the camera viewport doesn't have to be the same.You can change the UV coordinates of the quad being created in that "CreateQuad" function so the UV coordinates only capture the section of that power-of-two texture that has the non-power-of-two viewport content.This is done in this example:<a href="../Community/posts7c85.html?topic=95702#1104688" target="_blank">http://www.blitzbasic.com/Community/posts.php?topic=95702#1104688</a>


Bobysait(Posted 8 months ago)

 There is an error in the code (not dramatic as the texture size is square, but could lead to a MAV if you modify the texture size)For y = 0 To TextureWidth-1For x = 0 To TextureHeight-1it must be swapped ! x -> texturewidth, y -> textureheight.Then, here is a "non power of 2" viewport (the texture will always be power of 2 ... but it's not a big deal)For the example I used 600*400 arbitrarily, to let you know the texture will be 1024*512but actually, there is no other restriction than the video memory of the graphics card (ex: a 1920*1080 will create a 2048*2048 texture which use a lot of memory and is slower to "copyrect")
Function CreateOverlay(order%=-1,parent%=False)
Local Point = CreateMesh(parent), Surface

If order <> 0 Then EntityOrder Point,order

EntityFX Point,1

Surface = CreateSurface(Point)

Local depth# = 0.2
Local ratio# = depth * Float(GraphicsHeight())/GraphicsWidth()
AddVertex(Surface, -depth,  ratio, depth, 0,0)
AddVertex(Surface,  depth,  ratio, depth, 1,0)
AddVertex(Surface,  depth, -ratio, depth, 1,1)
AddVertex(Surface, -depth, -ratio, depth, 0,1)
AddTriangle(Surface,0,1,2)
AddTriangle(Surface,0,2,3)

Return Point
End Function

Function SetOverlay(Overlay, Texture, pCameraWidth, pCameraHeight)
; ratio of the texture area
Local i# = Float(pCameraWidth) / TextureWidth(Texture)
Local j# = Float(pCameraHeight) / TextureHeight(Texture)
; apply new UVs
Local s = GetSurface(Overlay,1)
VertexTexCoords s,0, 0,0
VertexTexCoords s,1, i,0
VertexTexCoords s,2, i,j
VertexTexCoords s,3, 0,j
EntityTexture Overlay,Texture
End Function

Function RenderTexture(texture, pCameraWidth, pCameraHeight)
RenderWorld
; copy only the camera viewport
CopyRect 0,0,pCameraWidth, pCameraHeight,0,0,FrontBuffer(),TextureBuffer(texture)
End Function

Function InitGraphics(w = 1024, h = 768,title$="Blitz3D Program",exit_message$="")
Graphics3D w, h, 32, 2
SetBuffer BackBuffer()
SeedRnd MilliSecs()

If exit_message <> ""
AppTitle title,exit_message
Else
AppTitle title
EndIf
End Function





; -------------------------------------------------------
; - Init graphics context -
; -------------------------------------------------------
;  ( -> a 600*400 resolution will round to a "1024 * 512" texture size )
;  ( you can use any resolution, it will work ... but keep in mind :
;    anything bigger than 1024 will create a 2048*XXXX texture
;    it can eat a lot of memory and cpu for the copyrect)
; -------------------------------------------------------

InitGraphics(600,400)

; -------------------------------------------------------
; - The Camera -
; -------------------------------------------------------

;---> add thoose variable to control the camera viewport
Local CamViewW% = GraphicsWidth()
Local CamViewH% = GraphicsHeight()
;<----

Global Camera = CreateCamera ( )
PositionEntity ( Camera, 0,1,-5 )
CameraRange ( Camera,.1,10000 )
CameraViewport ( Camera, 0,0, CamViewW, CamViewH )

; -------------------------------------------------------
; - The Blur Overlay -
; -------------------------------------------------------

; use directly the viewport size to create the texture -> it will fit to the nearest power of 2
Local Texture = CreateTexture ( CamViewW, CamViewH, 1+16+32 )

Local Overlay = CreateOverlay ( -1, Camera )
EntityAlpha ( Overlay, .8 )
;---> Adapt overlay UVs to viewport and set the overlay texture
SetOverlay ( Overlay, Texture, CamViewW, CamViewH )
;<---

; clear pixels of the texture (a bit useless -> texture are cleared at creation)
LockBuffer TextureBuffer(Texture)
; no need to clear "all" pixels, the viewport is enough.
; (and by the way -> the original is wrong here :)
; * y is in range [0, TextureHEIGHT-1]
;   x is in range [0, textureWIDTH-1]
For y = 0 To CamViewH-1;TextureWidth(Texture)-1
For x = 0 To CamViewW-1;TextureHeight(Texture)-1
WritePixelFast x,y,0,TextureBuffer(Texture)
Next
Next
UnlockBuffer TextureBuffer(Texture)

; -------------------------------------------------------
; - The scene -
; -------------------------------------------------------

; a simple type to store entities (just to turn them in the loop)
Type TObj
Field ent
End Type

; light, plane (and a mirror) and some entities
Local light = CreateLight ( )
PositionEntity ( light, 200,200,-150 )
LightRange ( light, 500 )

Local Plane = CreatePlane ( )
EntityColor ( Plane, 20,50,10 )
EntityAlpha ( Plane, .7 )
PositionEntity ( Plane, 0,-1.5,0 )
CreateMirror ( Plane )

Local o.TObj
Local Obj, i
For i = 0 To 20
Select Rand(0,2)
Case 0: Obj = CreateCube ( )
Case 1: Obj = CreateSphere ( 24 )
Case 2: Obj = CreateCylinder ( 32, 1 )
End Select
PositionEntity ( Obj, Rnd(-5,5),Rnd(0,1),Rnd(2,8) )
RotateEntity ( Obj, Rnd(90),Rnd(360),Rnd(90) )
EntityColor ( Obj, Rand(100,255),Rand(100,255),Rand(100,255) )
EntityShininess ( Obj, Rnd(0.1,0.4) )
o = New TObj
oent = Obj
Next

; -------------------------------------------------------
; - Init Overlay Texture - (fill the front buffer)
; -------------------------------------------------------

RenderTexture ( Texture, CamViewW, CamViewH )

; -------------------------------------------------------
; - Loop -
; -------------------------------------------------------

While Not KeyDown(1)

For o = Each TObj
TurnEntity oent, .5,1,.5
Next

TranslateEntity Camera, Float(KeyDown(205)-KeyDown(203))*.1,0,Float(KeyDown(200)-KeyDown(208))*.1

RenderTexture(Texture, CamViewW, CamViewH)

Flip
Wend
End




BlitzSupport(Posted 8 months ago)

 Well spotted! I don't normally do it, but I've edited GIB3D's code to fix this, as it would be really hard to notice.


jfk EO-11110(Posted 7 months ago)

 When I recently run some code that didn't do a boundary check and wrotepixelfast to some way offscreen coords, it drew me pixels right onto the Desktops tray bar. So, be careful.Anyhow, speaking of delay and motion-blur: one real cheap method is to disable the cameras cls and instead render a black plane with like 80% opacy ontop of the last scene render, so there will be a very fast, easily adjustable trail of fading past frames.


xlsior(Posted 7 months ago)

 <div class="quote"> Anyhow, speaking of delay and motion-blur: one real cheap method is to disable the cameras cls and instead render a black plane with like 80% opacy ontop of the last scene render, so there will be a very fast, easily adjustable trail of fading past frames.  </div>It's also very unreliable, since the state of the backbuffer is undetermined after a flip. Depending on the videocard and the drivers, you COULD see the previous frame, or random memory noise, OR some cards use 2,3,4 or 5 backbuffers, meaning that your background could go back in time 2,3, or 4 frames which can lead to really annoying flickering.So... while it may work perfectly fine when you test it on your own PC, it WILL give odd results on a lot of computers in the wild, and isn't recommended.(My previous videocard cycled through 3 backbuffers, and it lead to really annoying visuals when you assumed the frame was left in place unaltered.)Only way to ensure that you see what you expect is to do a screengrab and redraw it first.


jfk EO-11110(Posted 7 months ago)

 I didn't know that. So what is CameraClsMode good for at all?


xlsior(Posted 7 months ago)

 If you explicitly redraw the entire screen yourself there is no need to clear it out first,so I suppose you can forego that.Apparently the multiple backbuffers things is called a 'swap chain', and is there to help prevent tearing and such:  <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb206356(v=vs.85).aspx" target="_blank">https://msdn.microsoft.com/en-us/library/windows/desktop/bb206356(v=vs.85).aspx</a>


Kryzon(Posted 7 months ago)

 CameraClsMode is useful if you want to layer different render passes (i.e call RenderWorld more than once in the same frame).You can use it to combine different camera positions in the same shot, like the game below (Radiata Stories) does it by showing a scene in the background and the character speaking on the foreground, they are two different passes:


jfk EO-11110(Posted 7 months ago)

 Ok I see. But you still could use copyrect from backbuffer to frontbuffer, instead of a flip, which is what windows does anyway in windowed mode, afaik.So theoreticly the speed loss wouldn't be so bad. [/i]