Main Menu

Object Echoes / Object Motion Blur

Started by kevin, November 14, 2021, 06:07:43 AM

Previous topic - Next topic

kevin

 Object Echoes / Object Motion Blur

  Today we'll take a look a one approach for creation echo or motion blur styled effect using nothing more than some variable addition alpha blending.


PlayBASIC Code: [Select]
; PROJECT : Echo or Motion Effect
; AUTHOR : Kev Picone - http://playbasic.com
; CREATED : 14/11/2021
; EDITED : 14/11/2021
; ---------------------------------------------------------------------



// -------------------------------------------------------
// ---------------------- MAIN LOOP ----------------------
// -------------------------------------------------------



type tobject
X#(10)
Y#(10)

SpeedX#
SpeedY#
Colour
endtype

Dim Objects(35) as tobject

for lp=1 to getarrayelements(Objects())
Objects(lp)= new tobject
x#=rnd(800)
y#=rnd(600)


for poslp=0 to 10
Objects(lp).x#(poslp) = x#
Objects(lp).y#(poslp)= y#
next

Speed#=rndrange#(10,20)
Angle#=Rnd(360)
Objects(lp).speedx#=cos(Angle#)*Speed#
Objects(lp).speedy#=sin(Angle#)*Speed#
Objects(lp).Colour =rndrgb()
next




Screen=Newfximage(GetScreenWidth(),GetScreenheight())


// -------------------------------------------------------
do // -------------------- MAIN LOOP ---------------------
// -------------------------------------------------------



for lp=1 to getarrayelements(Objects())
x#=Objects(lp).x#(0)
y#=Objects(lp).y#(0)

x#+=Objects(lp).speedx#
y#+=Objects(lp).speedy#

// scroll old positions down
for oldpos=10 to 1 step -1
Objects(lp).x#(oldpos)=Objects(lp).x#(oldpos-1)
Objects(lp).y#(oldpos)=Objects(lp).y#(oldpos-1)
next

if x#<0 then x#=0 : Objects(lp).speedx#*= -1
if x#>800 then x#=800 : Objects(lp).speedx#*= -1
if y#<0 then y#=0 : Objects(lp).speedy#*= -1
if y#>600 then y#=600 : Objects(lp).speedy#*= -1

Objects(lp).x#(0)=x#
Objects(lp).y#(0)=y#

next



rendertoimage Screen
cls 0
// render
lockbuffer
; set ink pen drawing mode to Alpha Addition / Alpha ADD
inkmode 1+64

; step through the objects and the draw the oldest ones first
; looping to the last down to first.
for pass=10 to 0 step -1
blendlevel#=cliprange#(pass/10.0,0,1)

BlendColour =255-(255*BlendLevel#)
BlendColour=Rgb(BlendColour,BlendColour,BlendColour)


// Draw all the objects from this pass in one group
for lp=1 to getarrayelements(Objects())
x#=Objects(lp).x#(pass)
y#=Objects(lp).y#(pass)

// Compute the objects colour with the fade level
ThisRGB = rgbAlphamult (Objects(lp).Colour, BlendColour)

// draw it as a circle
circlec x#,y#,32,true,ThisRGB
next
next

unlockbuffer

; set inkmode back to normal
inkmode 1
rendertoscreen
drawimage screen,0,0,false


sync
wait 10
loop spacekey()





PlayBASIC LIVE - Overview of Object Echo / Motion Blur Example - (2021-11-16)

 



Script

 
[Music]

hi welcome back play basic coders uh

just posted a small example before i

thought it was worth going over this is

i've called this object echoes or object

motion blur and it's kind of an old

effect

but we'll jump over to play basic uh

we'll run the effect first and then

we'll have a bit of a talk about how

it's done

you can probably guess how it's done

actually i would say

so we've got really a bunch of balls

just bouncing around a bunch of circles

actually just bouncing around the screen

they're all just given random velocities

moving in whatever direction they want

to move in

and each one has an echo or

a blur kind of effect there's a few ways

of doing the same same effect you can

have what's called video feedback

which is where you

each frame you draw the objects in the

new positions and

over the top of the previous frame which

has been dimmed down a little bit

that works really well for lots of

objects

generally i prefer that method but it

does

mean you're never clearing the screen

and you can it can kind of get messy in

what you're looking at

this method here what we're doing is

we're drawing the object

and in we're keeping track of where it

was for the last 10 frames and going

back and drawing

10 frames ago

nine frames ago and then with each

time we step through there we're drawing

it

with uh

with more intensity so

uh objects that have been

they're 10 frames old they are they are

still visible but they have a much lower

amount of blending uh they're all

blended with additives so anything that

overlaps will make it look sort of white

or

brighter than what it might actually be

normally

let's look at the code in this section

here we have a declaration of our type

so each character on screen

we need its coordinates and we need a

way of storing where it was this frame

last frame

a frame before that all the way up to 10

frames so we're using two arrays here

within the type

for its actual speed and direction we're

using just

a pair of uh very floating point fields

called speed x and speed y

and the color is just stored randomly

inside the object as well

inside the character structure actually

so this is the fields each object

cares about contains and uses

and we have

our object array

i've set it to 35 you can just change

the size if you want you know

let's just write with five for example

a bit easier to see what's going on with

five characters on screen

hit space to exit

so before the program starts when it

when it's running it's not actually

creating any new objects like you would

in a game so here i've just run through

and filled up

their objects array with

some randomized data so each object's

created with

given a randomized position

so here i'm looping through

all of the available indexes within this

object's array

from one to however many objects are in

this array

allocating a type structure

the t object type type for this

position within the array

coming up with a random space that's on

screen

positioning

setting all the positions on this object

so

it's current position it's previous etc

all start off that same location when we

start which means they're all being

rendered over the top of each other

we

randomly compute a speed

and an angle so i can we can come up

with a vector

for its kind of direction

we're just going using constant sign for

that

so the angle we're using so we're using

polar coordinates then computing the

speed vector from that

the last one is our color

just using the random rgb function

building to play basic to give us give

us an rgb color now we could just do you

know rgb

we could this is like shortcut for

this we could go rgb

random 255

comma

random 255

random

255.

that's the equivalent

this

does this

so save yourself a bit of typing and use

the shorthand version

so that's it set up our data

uh beyond that is just the update of the

screen so

if we put a break in here

which is one of the debug modes

just have to pull that across because

the debugger's been moved to some other

point

for a different program

go up to variables

select main

go through and click on the objects

all right it will show us all of the

the five characters or the five objects

in our object array

and the contents of each one so

our x arrays are full of the same data

our y arrays are for the same data and

our speed and

have been assigned for this character

this

first object

second object has different data because

it's randomized

so it's handy

if you need to know what's in it arrays

can be handy to look at use the debugger

to check out what's what's going on

something sometimes you can pick up

little

little inaccuracies in your own code

where you might be

looping too far too few that kind of

stuff

just by stopping the program and

checking out what's in in the debug view

let's go back to the program or remove

the break statement we don't need that

so this first section here is all just

set up

this first page really to set up

nothing special

then we're creating our what's called an

effects screen which is really just a

screen

an image that's stored in system memory

uh in normal system every not not in gpu

memory

and we're going to use that for

rendering too all the time so

our main loop starts with the do loop so

at the bottom we actually have a

loop statement down here and we've added

we've added a

a statement after that which is a

conditional statement so this is a

conditional do loop

it acts basically like a repeat

until that's the same so i could swap

out the um

the do

uh inhale

and

loop for a repeat until it's the same

thing but it's just handy sometimes you

might want to use you might prefer to

use the do loop syntax

for that same thing but all the basics

tended to have

a while loop and a repeat until for that

kind of special thing the nice thing

about dual in particular is you can put

conditions on

the start of the expression at the end

one thing to remember

so that loop keeps our program running

until we press the space key and that

will just fall through and since there's

no code beyond this we

hit an end statement which is added at

the end of every program that pb builds

to exit execution

let's have a look at the main loop so

the main loop's broken up into two

things what we're going to do

we're going to move the characters first

and then we're going to render them

so that's what we're doing here we're

running through every object

so i think we've got it set to five

characters at the moment we could change

that until we like

we're grabbing

the x and y coordinate off of the

the bottom of the array

of the fields of the x-coordinates and

the y-coordinates for each object

just to refresh our memories up here

we've used an array for our x's and our

array for our y's

so these have not just one value they

actually have a range of values up to

that one but the upper limit

and here we're going to consider the low

value to be the current position and

then

index 1 will be where it was last frame

index two will be where it was the frame

before that three is the frame for that

up to ten frames ago so its positions

are held over time over ten frames

once we grab its current position we

add speed

i've and i'm running through here i'm

copying

its existing positions

uh down one uh it's old current position

becomes the previous frame and so forth

so they have all been called down one

this is for the x and y

for each object

doing a quick clip to see are we have we

hit the bounds of the screen if we have

let's flip the speed

on that axis so if we hit the

the side of the screen it will flip the

x-axis and we hit the

the top of the screen or the bottom will

hit the y-axis

and we'll force it to be on the screen

bounds as well

just in case we split past something

uh

and then we

said it's

as new as

this new position after it's moved but

we haven't drawn it yet

so we run through and we update the

what have we got five characters

five characters at the moment once we've

updated them all we move on to rendering

so we redirect rendering to our

effects screen

we clear the screen out

if we don't clean the screen we just end

up with a eventually it's like painting

itself over the screen well look at that

as you can see

it's kind of a nice looking effect i

guess if you

worked out

a collection of balls you could use that

as like a transition effect perhaps you

know

but something a bit different

let's reinsert the

if you're wondering what the zero is

here

as

rgb colors are stored in

a 32-bit format

uh it's just just a number actually just

a 32-bit number so if i if i insert here

rgb

i want 0 red i want 0 green and zero

blue which is what black is

that will give me a value of zero

now i know that off the top of my head

but you may not now if i recompile this

play basically we'll see this is is a

constant expression and it will solve it

at compile time

so

if you're more comfortable using rgb

like that then do that

if you like me and you can remember a

bunch of stuff off the top of your head

then okay whatever

other weird ones too if you want you've

got white

a quick way of getting white is just

negative one

and i'll let you work at that by

yourself

give you a hint if you go

uh and

see what negative one hexadecimal is

you'll see that it's has all the bits

set

which would mean that the rgbs of

values of those the red channel would be

255 which is the upper limit

the green one would be 255 and the blue

would be 255 so that won't give us our

white

pressing on all right so we've got our

we're rendering to our screen

we're going to lock our buffer because

we're drawing a bunch of circles

we're going to change the pen drawing

which is

this one here is set to alpha edition

uh nodes the color draw what color we

select for the draw command

not all things respond to alpha edition

or this pen mode

but things like you know drawing a line

a dot

a box a circle they do

things like text don't

it's not really supported

i guess it's possible if you did

something like

with serif fonts and that has limited

support for something as well because

you have blend modes with serif fonts

but

it gets complicated it's different

we're drawing using different methods

and different apis

and some things are possible and some

things are not

unfortunately we can't do a blend of

everything to everything which is not

possible so we're seeing the info here

we're drawing to an effects screen and

we know which

we know we can draw circles with

this kind of effect applied which is

taking the pixels in the circle and

we're adding them together to the to the

pixels that are in the screen that we're

rendering over

then we loop through

all the characters

and we do 10 passes we

look at the

for each object we draw the object that

was

where we where this character was 10

frames ago and we work out

how much blend level we want for it in

other words how bright would this thing

is going to be

so characters that have been the

uh positions that have been

uh rendered 10 that are 10 frames old

should be

duller than the the current one that's

been rendered and it's cut it's its

highest brightness

it's most luminous i guess

so here we just we're just using

a bit of a division and doing a clip to

cut this this range into zero to one

so we're starting from the oldest frame

from 10 and looping backward up to zero

up to the most current position

uh for the actual blending itself we

turn our blend level into

basically a grayscale color

so we compute

uh

we take the our

value our sorry blend level which is the

value between 9 and 1 a floating point

value multiplied by 255 so it's a scalar

we invert it we actually want the

inversion of the color

and then make a color out of it

using the rgb statement we do this

outside of the drawing loop so we just

compute that once

and we start drawing so because all of

the objects yeah at this um

during this pass will have the same

blend level that they'll all be not the

same color but the amount of they've

faded this much over time

let me head up and do a do a loop and we

draw the

circles from this frame

uh we grow its position

we grab its

we grab the object and then we grab its

position

from this pass so

when pass is equal to 10 we're grabbing

where it was 10 frames ago

computing its color

with that with its level of brightness

that it would need

since it's 10 frames old and then

drawing a circle we're just drawing the

same in a basic 32 pixel circle

and that

really is it

to recap we have we do the movement

first

we move them all first

once they're all been moved

and their

their coordinates have been

uh stored in their their own personal

arrays

of

their their current coordinates their

old their previous coordinates from

previous frames

if we go through and we draw them

uh back to front so we draw the oldest

we draw it from the from where it was 10

frames ago then we draw them all those

at a low level of brightness and we draw

them

the ones where it was nine frames ago

then eight then seven etc that's how you

get the trials going behind it

hope that makes some sense hope that's

kind of useful for you i'm not quite

sure what people find useful

you know

if you've got some feedback about what

kind of programming you want to see us

doing what kind of things

you're interested in

how you can use this kind of effect i

don't know

uh hit us up in the comments below

or jump on the forum and and just ask

until then thanks for watching and we

hope you enjoy programming and just keep

learning just keep staying at it keep going

thanks so much and see you bye

 



Related Articles

       * YAAC (Yet Another Asteroids Clone)
        * Blur-O-Vision