Dark Bit Factory & Gravity

GENERAL => Projects => Topic started by: ninogenio on December 09, 2008

Title: comp scene test.
Post by: ninogenio on December 09, 2008
hi guys i was wondering if you had any advice on improving the look of my led scene and also i want too make sure it runs on your system ok.

this is an unfinished scene ripped from my comp entry.
Title: Re: comp scene test.
Post by: bikerboy on December 09, 2008
just tested it both fullscreen and windoed mode and runs smoothly :)

nice effect both background and scroller :D
Title: Re: comp scene test.
Post by: Shockwave on December 09, 2008
Runs perfectly here Nino..

Looking really smooth and nice too!

XPSP2 P4 3.0 Ghz, ATI X1650
Title: Re: comp scene test.
Post by: Hezad on December 09, 2008
Ran fine :)  (in fact the animation was a bit jerky, but my computer has some serious problems these days lol so please just assume it ran right :) )


It looks pretty cool  ;D


Quoteany advice on improving the look of my led scene

hum not really, just a subjective thought : The space between the rectangular leds make them look like some ascii art (imho), that's beautiful :) But I don't see it as leds.
However, all those cool scrolling and rotating stuff are drawn in a way which make me think about stadiums gigantic screens, and so reinforce the fact it looks like leds.

Anyway, I already like it a lot  :D
Title: Re: comp scene test.
Post by: hellfire on December 09, 2008
Quoteany advice on improving the look of my led scene
How about a bit of glow?
Title: Re: comp scene test.
Post by: Clyde on December 09, 2008
One area I would suggest you look into is the colourings used.
Also instead of a line for you LEDS's perhaps use a small filled circle; like the graphic used for bullet points in word processing.
Title: Re: comp scene test.
Post by: ninogenio on December 09, 2008
cheers everyone for testing this, really good comments.

@hellfire: wow how did you do that? how would i go about that in my engine, additive blending on the final buffer before being passed through for rendering maybe?.

@Clyde i totaly agree i have been playing around with the coloring for a few days, i just cant seem to get it any better than this. i also tryed circles but i liked the feel of squares better.
Title: Re: comp scene test.
Post by: hellfire on December 10, 2008
Quotehow did you do that?
i took a screencapture, applied pretty much of gaussian blur (radius of ~30 pixels), subtracted some intensity (so that darker areas don't contribute to the glow), scaled the brightness up (blurring made it rather dark) and added the result to the original picture.
i also hue-shifted by ~180 degree (because blue is preceived as darkest colour and doesn't work so well for shiny things) and fiddled a bit with the intensity of the initial picture.
Title: Re: comp scene test.
Post by: ninogenio on December 10, 2008
well its a really nice effect! ive just been messing around with a gaussian blur but i cant get it quite right ill keep going and see what if i can get close to your image. cheers.
Title: Re: comp scene test.
Post by: ninogenio on December 10, 2008
finaly i got quite a nice glow.

this version is really really slow due to all the extra calcs i wonder now if i can optimize this enough to get it going at a fast speed.also the edges of the grid are a bit messed up i know how to fix this though its just the way my blur routine works.
Title: Re: comp scene test.
Post by: benny! on December 10, 2008
@hellfire:
K++ for explaining how you made the image glow.
Always love the glowing filter.


@nino:
Nice work - runs a bit slower now - but glow FX is very
nice!
Title: Re: comp scene test.
Post by: Hezad on December 10, 2008
Idem :) A bit slower, but really cool  :clap:
Title: Re: comp scene test.
Post by: Shockwave on December 10, 2008
Really nice looking glow effect, I think it would be even more effective if you changed the colours to red / orange like Hellfire suggested.

Speed wise, I am guessing that it has dropped from full framerate to about 8fps here but the glow is so nice that it must be worth optimising.
Title: Re: comp scene test.
Post by: hellfire on December 10, 2008
Nice!
The glow seems to be a bit off to the upper left, though - make sure to use an odd-sized filter-matrix so that the center element is actually in center.

Quotethis version is really really slow due to all the extra calcs i wonder now if i can optimize this
Are you using a 2d filter matrix? Since the gaussian is completely symetrical, you can separate it into two consecutive passes, one doing horizontal, another one doing vertical blur (you're using the center row and center coloumn as 1d filters).
A good approximation of the gaussian weights for a radius "r" is f(x)= e ^ -(x^2*4/r^2) (with x=-r..+r, x=0 being the center element).
You should prescale the weights so that their sum is some power of two, so you can replace the final divide by a shift.
Another approach is to use a triangular filter-shape (a somewhat poor approximation of a gaussian) so that for every new pixel only one input sample comes in (and another one falls out), the existing sum can be scaled by a constant.
Generally you don't need to apply gaussian to the full resolution of the image (you are blurring anyways), just reduce the image size by a simple 2x2 box-filter beforehand.
Alternatively you can approximate the gaussian by a series of box-filters of different radii (look up "summed area tables").
For filters of reasonable size (means <50) you're usually faster with a well optimized 2x1d approach.
Title: Re: comp scene test.
Post by: Clyde on December 10, 2008
Maybe applying a copper list of colours, would make it more funky.
Title: Re: comp scene test.
Post by: ninogenio on December 10, 2008
thanks everyone for sharing your thoughts/comments i will really consider them!

@hellfire theres loads of room for improvement right now im trying to approximate a gaussian by doing a box filter on the whole screen buffer 8 times with a radius of 12 then correcting and adding the result to the original image. which is slow.

infact here is my glow function, it was botched together very quickly last night.


Dim Shared TBuf(800*600) As integer
Sub Smooth( TempBuffer As Integer Ptr , ByVal ScrWidth As Integer , ByVal ScrHeight As Integer )
   
    Dim MaxPixel As Integer
    Dim OffSet As Integer
    Dim Pixel As UInteger
    Dim R As UInteger
    Dim G As UInteger
    Dim B As UInteger
    Dim Nr As UInteger
    Dim Ng As UInteger
    Dim Nb As UInteger
    Dim As Integer Radius = 12
   
    Dim X As integer
   
    For X=0 to 600*800
        TBuf(x) = 0
        Tbuf(x) = TempBuffer[x]
    Next
    For X = 0 to 4
        MaxPixel = ScrWidth*ScrHeight
        For OffSet = ScrWidth*Radius To ( MaxPixel - ( ScrWidth * Radius ) )
            Pixel = TBuf( OffSet - ( Radius - 1 ) )
            B = Pixel
            Nb = B Shr 2
       
            Pixel = TBuf( OffSet + ( Radius - 1 ) )
            B = Pixel
            Nb = Nb + ( B Shr 2 )

            Pixel = Tbuf( offset + ( ScrWidth * ( radius - 1 ) ) )
            B = Pixel
            Nb = Nb + ( B Shr 2 )

            Pixel = Tbuf( offset - ( ScrWidth * ( radius - 1 ) ) )
            B = pixel
            Nb = Nb + ( B Shr 2 )
       
            TBuf( OffSet ) = Nb
     
        Next
    next
       
    For X=0 to 600*800
        TempBuffer[ x  ] += Tbuf(x)*3
        If TempBuffer[ x ] > 255 Then TempBuffer[ x ] = 255
    Next
End Sub
Title: Re: comp scene test.
Post by: ninogenio on December 11, 2008
ive managed to roughly double the speed to 15fps with these changes.


Sub Smooth( TempBuffer As Integer Ptr , ByVal ScrWidth As Integer , ByVal ScrHeight As Integer )
   
    Dim X As Integer
    Dim TBuf As Integer Ptr
    Dim TB As Integer Ptr
   
    Dim OffSet As Integer
    Dim Nb As Integer
    Dim As UByte Radius = 11
    Dim As Integer MaxPixel = ( ScrWidth * ScrHeight ) - ( ScrWidth * Radius )
    Dim As Integer O1 = ( Radius - 1 )
    Dim As Integer O2 = ( ScrWidth * ( radius - 1 ) )

    TBuf = Callocate( 800 * 600 * Sizeof( Integer ) )
    memcpy( @Tbuf[ 0 ] , @TempBuffer[ 0 ] , 800 * 600 * SizeOf( Integer ) )

    For X = 0 to 4
        TB = TBuf+ScrWidth*Radius
        For OffSet = ScrWidth*Radius To MaxPixel

            Nb = TBuf[ OffSet - o1 ]
            Nb = Nb + ( TBuf[ OffSet + o1 ] )
            Nb = Nb + ( Tbuf[ offset + o2 ] )
            Nb = Nb + ( Tbuf[ offset - o2 ] )
       
            *TB = Nb Shr 2
            TB += 1
        Next
    next
       
    For X = 0 To 600 * 800
       
        TempBuffer[ X ] += Tbuf[ X ]*3
        If TempBuffer[ X ] > 255 Then TempBuffer[ X ] = 255
    Next
   
    DeAllocate( TBuf )
   
End Sub


but now im stumped, there is a few bottlenecks the memcpy being one and a four array acesses in the tightest part of my main for loop structure. i cant see any way of getting more speed out can any of you guys?
Title: Re: comp scene test.
Post by: Shockwave on December 11, 2008
memcpy is a fast function so I don't think that's going to be much of a bottleneck.

To get more speed I'd consider using pointers more in this part of the code;

            Nb = TBuf[ OffSet - o1 ]
            Nb = Nb + ( TBuf[ OffSet + o1 ] )
            Nb = Nb + ( Tbuf[ offset + o2 ] )
            Nb = Nb + ( Tbuf[ offset - o2 ] )


That could be simplified quite a lot and probably contained in a #define statement.. There must be other stuff too, it's still not as fast as it should be :)
Title: Re: comp scene test.
Post by: ninogenio on December 11, 2008
cheers shockwave ill have a go at making that part additive pointers.

i meant there was a bottleneck coming from the fact i had to memcpy the framebuffer to a temprary buffer not from the memcpy function itself.
Title: Re: comp scene test.
Post by: ninogenio on December 11, 2008
cheers nick 20fps now!


Sub Smooth( TempBuffer As Integer Ptr , ByVal ScrWidth As Integer , ByVal ScrHeight As Integer )
   
    Dim X As Integer
    Dim TBuf As Integer Ptr
    Dim TB As Integer Ptr
    Dim TB1 As Integer Ptr
    Dim TB2 As Integer Ptr
    Dim TB3 As Integer Ptr
    Dim TB4 As Integer Ptr
   
    Dim OffSet As Integer
    Dim Nb As Integer
    Dim As UByte Radius = 11
    Dim As Integer MaxPixel = ( ScrWidth * ScrHeight ) - ( ScrWidth * Radius )
    Dim As Integer O1 = ( Radius - 1 )
    Dim As Integer O2 = ( ScrWidth * ( radius - 1 ) )
    Dim As Integer o3 = ( ScrWidth * Radius )
   
    TBuf = Callocate( 800 * 600 * Sizeof( Integer ) )
    memcpy( @Tbuf[ 0 ] , @TempBuffer[ 0 ] , 800 * 600 * SizeOf( Integer ) )

    For X = 0 to 4
        TB = TBuf+o3
        TB1 = TBuf+( o3 - o1 )
        TB2 = TBuf+( o3 + o1 )
        TB3 = Tbuf+( o3 + o2 )
        TB4 = Tbuf+( o3 - o2 )
        For OffSet = o3 To MaxPixel

            *TB = ( *TB1 + *TB2 + *TB3 + *TB4 ) Shr 2
            TB += 1
            TB1 += 1
            TB2 += 1
            TB3 += 1
            TB4 += 1
           
        Next
    next
       
    For X = 0 To 600 * 800
       
        TempBuffer[ X ] += Tbuf[ X ]*3
        If TempBuffer[ X ] > 255 Then TempBuffer[ X ] = 255
    Next
   
    DeAllocate( TBuf )
   
End Sub

any more? also ive attached this version in red which i think looks really cool.
Title: Re: comp scene test.
Post by: Shockwave on December 11, 2008
Maybe change the integer definitions to uintegers.. That should yield a few more fps..

Do you have to allocate and deallocate the buffer each time you call the sub?
Maybe you could allocate it on startup and then deallocate it on exit..
That pointer stuff and the rgb conversion would definately benefit from being #defined :)

Looking good mate, there's still a good bit of fps to come from this though I am thinking.. It should go around 50 - 70 with ultra optimisation.

You could create an indexed colour palette too with a huge overflow area, you could get rid of 480,000 if, then checks then...

and also the rgb conversion...

The mind boggles ;)
Title: Re: comp scene test.
Post by: ninogenio on December 12, 2008
using uints and moving the alloc dealloc stuff out of the sub has me up another 5fps, i must be really rusty as this is stuff i just couldnt see.

also using a pallet buffer with more ellements than 255 is a great idea im going to try it.

one thing i dont get though is about the pointer stuff being #defined i just cant see how it would work/go any quicker with that. also what do you mean about rgb conversions? each int only holds a single byte worth of data on the bottom bits so no conversion is neccessary.
Title: Re: comp scene test.
Post by: Shockwave on December 12, 2008
Glad to see that your fps is creeping up :)

The biggie here is going to be having a colour table to index and dispensing with all those if then checks.

About the rgb conversion, sorry about that. You have provided a sub, not your whole program (heaven knows why!), I have to guess what you do with the data later on.

That can be disregarded though because you'll be using an indexed palette instead, full framerate awaits you...

About #define..

I don't know why it speeds things up.
It seems to help though.
Title: Re: comp scene test.
Post by: hellfire on December 12, 2008
I find it rather strange to discard the center-element in an averaging-filter.
Running a filter multiple times is less efficient than using a bigger filter-kernel once; you can't expect a 800x600-image to stay in the cache.
As pointed out earlier, you're cheaper off by performing separate horizontal/vertical passes.
Title: Re: comp scene test.
Post by: ninogenio on December 12, 2008
@hellfire i would like to be able to do this in one pass as your right doing multiple passes is killing the performance but i dont know how.when you say a bigger filter-kernel what is meant by this? to use a bigger buffer?

also when you say that id be cheaper to do separate horizontal/verical passes does that mean just seperate them into diffrent loops?
Title: Re: comp scene test.
Post by: hellfire on December 12, 2008
Quotewhen you say that id be cheaper to do separate horizontal/verical passes does that mean just seperate them into diffrent loops?
A digital filter is nothing else than a matrix applied to an input-vector (in this case a piece of your image).
Let's assume two simple 1d matrices.

A horizontal one:
1 4 13 28 36 28 13 4 1

And a vertical one:
1
4
13
28
36
28
13
4
1


Both do the same except that one takes a vertical piece of your image as input vector and the other one a horizontal piece.
You can multiply both matrices (just expanding both to 2d-layout by adding zeros) which results in a perfect 2d averaging matrix:
00 00 00 01 01 01 00 00 00
00 01 02 03 04 03 02 01 00
00 02 07 10 13 10 07 02 00
01 03 10 19 28 19 10 03 01
01 04 13 28 36 28 13 04 01
01 03 10 19 28 19 10 03 01
00 02 07 10 13 10 07 02 00
00 01 02 03 04 03 02 01 00
00 00 00 01 01 01 00 00 00


The 2d matrix, however, has 9*9= 81 coefficients while the 1d matrices just have a total of 18 coefficients.
So applying both 1d-filters sequentially is obviously faster and yields the same result.
Title: Re: comp scene test.
Post by: ninogenio on December 12, 2008
ahh i get it  :inspired: cheers hellfire.

thats simple and brilliant, i will try to get it going in practise.
Title: Re: comp scene test.
Post by: ninogenio on December 14, 2008
something like this maybe hellfire.


Dim Shared As Integer sz = 50
Dim Shared As Integer kernelSize
KernelSize = 1 + sz * 2
Dim Shared As Integer kernel( KernelSize )
Dim Shared As Integer i

For I = 1 To Sz
    Dim As Integer szi = sz - i
    kernel( sz + i ) = (Szi) * (Szi)
    kernel( szi ) = (Szi) * (Szi)
Next
kernel( Sz ) = Sz * Sz

Dim Shared As Integer Ptr B2
B2 = CAllocate( 800*600 * SizeOf( Integer ) )

Sub Smooth2( TempBuffer As Integer Ptr , ByVal ScrWidth As Integer , ByVal ScrHeight As Integer )
   

    Dim As Integer sum,cr,cg,cb,k
    Dim As Integer pixel,re,ri,x,y,ym,riw
    Dim As Integer iw = 800

    Dim As Integer wh = 800*600

    Dim As Integer b( wh )
    sum = 0

    memcpy( @b( 0 ) , @TempBuffer[ 0 ] , 800 * 600 * SizeOf( Integer ) )
    Dim As Integer Ptr Temp
   
    For y = 0 To 599
        Temp = B2 + y*800
        For x = 0 To 799
            cb = 0
            sum = 0
            ri = x - Sz
            For i = 0 To kernelSize
                re = ri + i
                If ( re >= 0 And re < 800 ) Then
                    re += y*800
                    cb += b( re ) * Kernel( i )
                    sum += kernel( i )
                EndIf
            Next
            *Temp = ( cb / sum )
            Temp += 1
        Next
    Next
   
    Dim FCol As Integer
    Dim Temp2 As Integer Ptr
    Dim Temp3 As Integer Ptr
    For y = 0 To 599
      ym = y - sz
      riw = ym * iw
      Temp = B2 + riw
      Temp3 = TempBuffer + y*800
      For X = 0 To 799
        cb = 0
        sum = 0
        ri = ym
        Temp2 = Temp + X
        For i = 0 To kernelSize
            If ( ri < 600 And ri >= 0 ) Then
                cb += *Temp2 * kernel( i )
                sum += kernel( i )
            EndIf
            ri += 1
            Temp2 += iw
        Next
        FCol = *Temp3+( cb / sum )*3
        If FCol > 255 Then FCol = 255
        If FCol <0 Then FCol =0
       *Temp3 = FCol shl 16
        Temp3 += 1
      Next
  Next

End Sub


this produces an excellent and correct glow but its very slow(about 1-2 fps).
Title: Re: comp scene test.
Post by: hellfire on December 14, 2008
Quoteits very slow (about 1-2 fps)
For i = 0 To kernelSize
  re = ri + i
  If ( re >= 0 And re < 800 ) Then
    re += y*800
    cb += b( re ) * Kernel( i )
    sum += kernel( i )
  EndIf
Next
*Temp = ( cb / sum )


For large filter-radii I wouldn't apply a gaussian at full resolution.
Downsample the image with a simple 2x2 box-filter to half the resolution, apply the gaussian (with half the radius) and upsample with a bilinear filter (which is very simple since only the "middle" colours are missing).

About the gaussian itself you shouldn't test each input-sample if it's inside the image boundaries.
Split each scanline into three sections: left, center and right.
On the left side (which is as wide as your filter-radius), samples can only be outside on the left side.
On the right side, samples can only be outside on the right side.
In the center region, all samples are inside the image boundaries, there's no need to test anything and "sum" stays constant!
You can now prescale your filter-kernel so that "sum" is a power of two (or accordingly bigger/smaller if you have intensity-scaling to do anyways) and the division can be replaced by a shift.

If you don't skip outside-samples (which changes "sum") but map these to the "boundary" sample (clamping), you can use the shifting-approach for the left/right-sections, too.
Let's assume your filter has a radius "r" and "kernel" ranges from 0 .. 2*r (inclusive) and kernel[r] corresponds to the center element.
When processing the left section, the number of outside samples decreases with each iteration:
For the first output-pixel, samples [0..r-1] are outside (access b(0) instead), sample [r..r*2] access b(0..r).
For the second output-pixel, samples [0..r-2] are outside, sample [r-1..r*2] access b(0..r+1) - and so on.
So you just have to keep track of the weight for b(0) which starts with sum(kernel[0..r]) (since you know the sum of the complete kernel this is for free, too) and decreases by kernel(x).
The right side works just the other way round. Use the same approach for the vertical pass with top/center/bottom.
Depending on the required precision you can process multiple samples at once (integers are 32bits wide).

Notice that you kernel function (pink) approximates a gaussian (green) rather well, but overestimates the center significantly:
(http://img2.abload.de/img/kernelvqk8.gif)
(more of the unprocessed signal passes, less lowpass, more ringing).
Title: Re: comp scene test.
Post by: ninogenio on December 14, 2008
wow thanks hellfire there is a lot too go through there but ill give it all a go k+
Title: Re: comp scene test.
Post by: ninogenio on December 14, 2008
i never noticed that it was so off at the centre! looks like i have a bit more work todo :) iv attached the exe with this new function.

i may have some questions about splitting the scanlines into three sections as im not too sure about that i will have a go at it tomorrow though.
Title: Re: comp scene test.
Post by: ninogenio on December 16, 2008
right i have spent the last few days trying loads of stuff out,

i managed to get the full gaussian blur up to about 10 fps, so what i ended up doing was coding a new box filter with a simple kernel that blurrs the image in two passes one vertical and one horizontal, im now getting 45 fps because i now draw everything in a 400*300 buffer. blurr that and then upsample to a 800*600.

the box filter doesnt look as nice as the gaussian but really i couldnt see the gaussian running at full frame rates. i must thank you though hellfire as iv learned loads from trying out all this stuff, i might even have a go at gaussian in shaders after the comp. 
Title: Re: comp scene test.
Post by: hellfire on December 16, 2008
Well done, ninogenio! Looks great and runs in full framerate here.
Sometimes one of the triangles goes black.
Title: Re: comp scene test.
Post by: ninogenio on December 16, 2008
cheers mate im glad you like it so far.

yeah there is a bug in my normals that needs fixing ill get on with developing it for the comp now :D.
Title: Re: comp scene test.
Post by: Shockwave on December 16, 2008
It's a pleasure to see this running at a good framerate :)

Nice work Nino and fair play to Hellfire for the great information.
Title: Re: comp scene test.
Post by: ninogenio on December 16, 2008
QuoteIt's a pleasure to see this running at a good framerate

your telling me mate, i was really starting to stress about the deadline coming and not having even half of the demo done lol.

it was really just last night it all came together.
Title: Re: comp scene test.
Post by: Clyde on December 20, 2008
Great Job Nino :)
It runs reasonably well on my system.
Btw, it is still a little bit too one colour. Or maybe thats the way its mean to be, in that case, I'll get my coat... :D

Cheers,
Clyde.
Title: Re: comp scene test.
Post by: ninogenio on December 20, 2008
yeah i would have loved to be able to change the leds color at anytime but in keeping with the rules i stuck to a byte range of red for each led.