gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > motion blur,[NEW]Possible 1 bank "HDR"+bloom+dof

#138189 - omaremad - Mon Aug 20, 2007 11:11 pm

I cant seem to get single bank mtion blur working with the newest libnds (both my code and the demo made by deku64 http://forum.gbadev.org/viewtopic.php?t=7983&highlight=motion+blur)

I am using the following code:
3D is running on the main screen, main screen video mode is FB1; so i can render the contents of Bank B LCD.
I place the regcapture code before drawing anything (first thing in my main loop).

i flush at the end and also vblank.

setup code (before loop)
Code:

videoSetMode(MODE_FB1);
 vramSetBankB(VRAM_B_LCD);



glInit();

   // enable antialiasing
   glEnable(GL_ANTIALIAS);

   // setup the rear plane
   glClearColor(0,0,0,31); // BG must be opaque for AA to work
   glClearPolyID(63); // BG must have a unique polygon ID for AA to work
   glClearDepth(0x7FFF);

   //this should work the same as the normal gl call
   glViewPort(0,0,255,191);

   //any floating point gl call is being converted to fixed prior to being implemented
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(35, 256.0 / 192.0, 0.1, 40);

   gluLookAt(   0.0, 0.0, 1.0,      //camera possition
            0.0, 0.0, 0.0,      //look at
            0.0, 1.0, 0.0);      //up



regcapture setup

Code:


    while (1)
    {

 REG_DISPCAPCNT= DCAP_ENABLE |
    DCAP_MODE(2) |   // Capture Source    (0=Source A, 1=Source B, 2/3=Sources A+B blended)
    DCAP_DST(0) |   // VRAM Write Offset (0=00000h, 0=08000h, 0=10000h, 0=18000h)
    DCAP_SRC(0) |   // Source A          (0=Graphics Screen BG+3D+OBJ, 1=3D Screen)
    DCAP_SIZE(3) |   // Capture Size      (0=128x128, 1=256x64, 2=256x128, 3=256x192 dots)
    DCAP_OFFSET(0)|   // VRAM Read Offset  (0=00000h, 0=08000h, 0=10000h, 0=18000h)
    DCAP_BANK(1) |   // VRAM Write Block  (0..3 = VRAM A..D) (VRAM must be allocated to LCDC)
    DCAP_B(6) |   // EVB (0..16, or 0..31 ?) Blending Factor for Source A (or B ?)
    DCAP_A(14);   // EVA (0..16, or 0..31 ?) Blending Factor for Source B (or A ?)


im using blending mode 2 or 3 (both give black screens)

I remeber dekus code working fine on old versions of devkitpro but i dont have the setup to test it on.

Update:
Messing around with the regcapture hardware i have devised (there is actual code but ill say why i need help) a method for 1 bank "HDR"+bloom+dof+motion blur.

The diffrence between the DCAP_B factor and the DCAP_A one defines how long lasting the motion blur lasts (the decay). The magnitude of DCAP_B seems to be useful for exposure control (defines how strong the additive blend is ). a DCAP_B value of 16 seems to have a permenant burn in effect normatter what DCAP_A is (further testing required).

So now we got our hardware acclerated blur and exposure control, we can start doing some effects.

For Bloom simply jiggle your camera position every frame, diffrent jiggles positions / speeds can simulate diffrent blur kernels.

For Dof jiggle your camera target this will make far away objects more blurred.

Now for HDR:

Im going to represent our colour data as it is captured, RGBA.

We will use RGB components to define the LDR colour range and A to describe the magnitude of the irradiance. Why alpha for irradiance? well thats because we get a free multiply with alpha if we use the capture hardware.

Quote:

from gbatek
Capture A+B (blending):
Dest_Intensity = ( (SrcA_Intensitity * SrcA_Alpha * EVA)
+ (SrcB_Intensitity * SrcB_Alpha * EVB) ) / 16
Dest_Alpha = (SrcA_Alpha AND (EVA>0)) OR (SrcB_Alpha AND EVB>0))


So by using a combination of alpha values and exposure control we can define more than colour; we can also define brightness.

Simply changing the exposure seems to automatically interpolate nicely depending on motion blur decay.

Getting the average scene brightness is just averaging several pixels from the LCD mapped v bank (my case its bank b).

So whats my problem? i cant seem to find a way to define those alpha values, i tried using glPolyFmt(POLY_ALPHA(31)| POLY_CULL_NONE); for maximum brightness and glPolyFmt(POLY_ALPHA(1)| POLY_CULL_NONE); for minimum brightness but it seems poly alpha is only useful for polygon to polygon blending? Is there a way to define the alpha value of a fragment that will be stored much like the colours when the screen is captured.

If anyone is experienced with ds tranparency and alpha storage please help :).


Last edited by omaremad on Tue Aug 21, 2007 9:52 pm; edited 2 times in total

#138210 - Cydrak - Tue Aug 21, 2007 5:16 am

I can't speak to the old code, as the link in that thread is broken... however I've done a blur on dual screens and it works fine.

But, about DCAP_SRC(0). This selects VRAM + the final *2D* output, with 3D mixed in, and sprites and layers accounted for. Of course, they respect the BGn_ACTIVE bits. Apparently this is true even for framebuffer mode (!).

The problem with that would be, videoSetMode() rewrites DISPLAY_CR, so if you pass only MODE_FB1 (I think) you're implicitly disabling all the layers...

Does it work with MODE_FB1 | ENABLE_3D | DISPLAY_BG0_ACTIVE ?

#138216 - omaremad - Tue Aug 21, 2007 8:16 am

Thanks, that fixed it :)

Seems the old FB1 didnt disable the 3d cores.
Now it works; i can see blur inside polygons and also colour banding (because low percision math?).

#138256 - omaremad - Tue Aug 21, 2007 9:53 pm

See updated OP.

#138275 - Cydrak - Wed Aug 22, 2007 2:32 am

Heh, the HDR thing sounds nifty! Unfortunately, capture alpha is only 1 bit (DS 16bpp format). :( So I don't see how to do it...

Specifically it gives you 1 alpha bit + 15 bits BGR, which explains the banding, yeah... Although internally the depth is higher (I'd guess 6-6-6-6), the blending reuses that 16bpp. If you draw a scene and mirror to the subscreen, the difference is obvious.

I haven't tested exhaustively, but here's my experience with this stuff:

- Poly alpha overrides AA and fog, so you would give up those effects. (If anyone manages to avoid this I'd love to hear it!)
- B factors above 7/16 (namely the useful ones :P) will produce some burn-in, maybe due to rounding; otherwise 8/16 would just be a >>1 which always hits 0. So you might have to avoid the darkest "burnable" colors in your scene. 16/16 won't decay as it's just 1.0, you're simply adding each frame to the last.

- If you choose the 2D source, output will be opaque, since the backdrop is always solid.
- If you capture 3D (DCAP_SRC(1)), you should get one bit of alpha (assuming your backplane is transparent). This is what BG0 displays by default.
- If you set a BLEND_CR on BG0, it blends with the full, 5/6 bpp alpha. Unfortunately, it doesn't seem possible to capture that. :(

If you really want alpha or Z (maybe for some software effect...) there are a couple desparate things you could try (in a second pass, with colors and lighting off etc):

- Draw white geometry over black, to yield alpha values.
- Draw with a linear fog table, giving a rough Z. The fog seems to follow this formula (corrections appreciated, note W-buffering should be off, it seems to work differently):

// For a full ramp over zNear..zFar, use fogOffset = fogShift = 0.
// I.fog is 7 bits, range 0..1.0. Zbuf is 15 bits.
I.fog = fogTable[ clamp(0..31, (Zbuf - fogOffset) >> (10-fogShift)) ];
A.out = A.in + I.fog*(A.fog - A.in)
C.out = C.in + I.fog*(C.fog - C.in) // GL_FOG
C.out = C.in // GL_FOG | GL_FOG_ONLY_ALPHA


Last edited by Cydrak on Thu Aug 23, 2007 1:26 am; edited 2 times in total

#138283 - omaremad - Wed Aug 22, 2007 8:35 am

Well i thought there was some kind of alpha storage because gbatek says 3d is rendered in 18 bit and is then converted to 15 bits (after or before the blending i dont know)


Anyway 1 bit isnt bad since i can use PWM to get a diffrent brightness levels, but poly alpha zero also turns on wireframe mode, ill look around to see how i can make the alpha bit zero while keeping my polygons filled.

#138295 - omaremad - Wed Aug 22, 2007 2:09 pm

I`ll just use a diffrent part of the hardware to do the multiply, ill use the material settings and darken/brighten the scene depending on a ratio between the actual brightness(old alpha values) and the exposure value.

That way i dont have to modify each vertex colour in software.

#138325 - silent_code - Wed Aug 22, 2007 11:27 pm

you might want to play a bit with the material's ambient colour for a nice overexposure effect and of course, it would be nice to see a demo of what you've done, some day. :)

#138362 - Dood77 - Thu Aug 23, 2007 8:16 am

I would love a demo too!
_________________
If I use a term wrong or something then feel free to correct, I?m not much of a programmer.

Original DS Phat obtained on day of release + flashme v7
Supercard: miniSD, Kingston 1GB, Kingston 2GB
Ralink chipset PCI NIC

#138500 - omaremad - Fri Aug 24, 2007 7:32 pm

Im currently short on time so i cant make a polished demo let alone continue my current project. However ill put some code here with explainations which is better since it would be like a tutorial.

The setup for our main screen is as follows
Code:
videoSetMode(MODE_FB1 | ENABLE_3D | DISPLAY_BG0_ACTIVE);

vramSetBankB(VRAM_B_LCD);

glInit();

   // enable antialiasing
   glEnable(GL_ANTIALIAS);

   // setup the rear plane
   glClearColor(0,0,0,31); // BG must be opaque for AA to work
   glClearPolyID(63); // BG must have a unique polygon ID for AA to work
   glClearDepth(0x7FFF);

   //this should work the same as the normal gl call
   glViewPort(0,0,255,191);

   //any floating point gl call is being converted to fixed prior to being implemented
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(35, 256.0 / 192.0, 0.1, 40);

   gluLookAt(   0.0, 0.0, 1.0,      //camera possition
            0.0, 0.0, 0.0,      //look at
            0.0, 1.0, 0.0);      //up

We activate the 3d core and enable Frame buffer mode 1(which reads from Vram Bank 1 which is B). I reccomend using banks A,B or D over C since you will need C if you plan on using lots of data for the sub screen.

Antialiasing also helps give Bloom a more natural effect.

For our bloom filter we will use the following code, it gives a moderate amount of motion blur too. The filter works by taking 5 weighted samples, the un jittered image has the most weight (DCAP_B value 16) while jittered images have a lower weight.

The bloom size is controlled using a constant value + random value. Frame is a frame counter integer, it is used as a random number seed and also to select the scene transformation during diffrent samplings.

Code:
s32 random(signed int min, signed int max,int seed)
      {
         seed *= 69069;
         if(seed == 0) {seed++;}
         return min + ((((max - min + 1) * (seed >> 16))) >> 16);
      }


Code:
Float rand = inttof32(random(-10,10,frame));
rand = rand/200.0f;

Float is a struct around f32 with some operator overloads.

These values are then used to translate the scene by tiny amounts.
Code:

switch (frame%5)
        {
        case 0:
            REG_DISPCAPCNT= DCAP_ENABLE |
                            DCAP_MODE(2) |   // Capture Source    (0=Source A, 1=Source B, 2/3=Sources A+B blended)
                            DCAP_DST(0) |   // VRAM Write Offset (0=00000h, 0=08000h, 0=10000h, 0=18000h)
                            DCAP_SRC(1) |   // Source A          (0=Graphics Screen BG+3D+OBJ, 1=3D Screen)
                            DCAP_SIZE(3) |   // Capture Size      (0=128x128, 1=256x64, 2=256x128, 3=256x192 dots)
                            DCAP_OFFSET(0)|   // VRAM Read Offset  (0=00000h, 0=08000h, 0=10000h, 0=18000h)
                            DCAP_BANK(1) |   // VRAM Write Block  (0..3 = VRAM A..D) (VRAM must be allocated to LCDC)
                            DCAP_B(14) |   // EVB (0..16, or 0..31 ?) Blending Factor for Source A (or B ?)
                            DCAP_A(2);   // EVA (0..16, or 0..31 ?) Blending Factor for Source B (or A ?)
            glTranslate3f32(floattof32(0.04f)+rand.val, floattof32(0.0f)+rand.val, floattof32(0.0f));
            break;

        case 1:
            REG_DISPCAPCNT= DCAP_ENABLE |
                            DCAP_MODE(2) |   // Capture Source    (0=Source A, 1=Source B, 2/3=Sources A+B blended)
                            DCAP_DST(0) |   // VRAM Write Offset (0=00000h, 0=08000h, 0=10000h, 0=18000h)
                            DCAP_SRC(1) |   // Source A          (0=Graphics Screen BG+3D+OBJ, 1=3D Screen)
                            DCAP_SIZE(3) |   // Capture Size      (0=128x128, 1=256x64, 2=256x128, 3=256x192 dots)
                            DCAP_OFFSET(0)|   // VRAM Read Offset  (0=00000h, 0=08000h, 0=10000h, 0=18000h)
                            DCAP_BANK(1) |   // VRAM Write Block  (0..3 = VRAM A..D) (VRAM must be allocated to LCDC)
                            DCAP_B(14) |   // EVB (0..16, or 0..31 ?) Blending Factor for Source A (or B ?)
                            DCAP_A(2);   // EVA (0..16, or 0..31 ?) Blending Factor for Source B (or A ?)
            glTranslate3f32(floattof32(0.0f)+rand.val, floattof32(-0.04f)-rand.val, floattof32(0.0f));
            break;

        case 2:
            REG_DISPCAPCNT= DCAP_ENABLE |
                            DCAP_MODE(2) |   // Capture Source    (0=Source A, 1=Source B, 2/3=Sources A+B blended)
                            DCAP_DST(0) |   // VRAM Write Offset (0=00000h, 0=08000h, 0=10000h, 0=18000h)
                            DCAP_SRC(1) |   // Source A          (0=Graphics Screen BG+3D+OBJ, 1=3D Screen)
                            DCAP_SIZE(3) |   // Capture Size      (0=128x128, 1=256x64, 2=256x128, 3=256x192 dots)
                            DCAP_OFFSET(0)|   // VRAM Read Offset  (0=00000h, 0=08000h, 0=10000h, 0=18000h)
                            DCAP_BANK(1) |   // VRAM Write Block  (0..3 = VRAM A..D) (VRAM must be allocated to LCDC)
                            DCAP_B(14) |   // EVB (0..16, or 0..31 ?) Blending Factor for Source A (or B ?)
                            DCAP_A(2);   // EVA (0..16, or 0..31 ?) Blending Factor for Source B (or A ?)
            glTranslate3f32(floattof32(0.00f)-rand.val, floattof32(0.04f)+rand.val, floattof32(0));
            break;

        case 3:
            REG_DISPCAPCNT= DCAP_ENABLE |
                            DCAP_MODE(2) |   // Capture Source    (0=Source A, 1=Source B, 2/3=Sources A+B blended)
                            DCAP_DST(0) |   // VRAM Write Offset (0=00000h, 0=08000h, 0=10000h, 0=18000h)
                            DCAP_SRC(1) |   // Source A          (0=Graphics Screen BG+3D+OBJ, 1=3D Screen)
                            DCAP_SIZE(3) |   // Capture Size      (0=128x128, 1=256x64, 2=256x128, 3=256x192 dots)
                            DCAP_OFFSET(0)|   // VRAM Read Offset  (0=00000h, 0=08000h, 0=10000h, 0=18000h)
                            DCAP_BANK(1) |   // VRAM Write Block  (0..3 = VRAM A..D) (VRAM must be allocated to LCDC)
                            DCAP_B(14) |   // EVB (0..16, or 0..31 ?) Blending Factor for Source A (or B ?)
                            DCAP_A(2);   // EVA (0..16, or 0..31 ?) Blending Factor for Source B (or A ?)
            glTranslate3f32(floattof32(-0.04f)-rand.val, floattof32(0.00f)+rand.val, floattof32(0.0f));
            break;
        case 4:
            REG_DISPCAPCNT= DCAP_ENABLE |
                            DCAP_MODE(2) |   // Capture Source    (0=Source A, 1=Source B, 2/3=Sources A+B blended)
                            DCAP_DST(0) |   // VRAM Write Offset (0=00000h, 0=08000h, 0=10000h, 0=18000h)
                            DCAP_SRC(1) |   // Source A          (0=Graphics Screen BG+3D+OBJ, 1=3D Screen)
                            DCAP_SIZE(3) |   // Capture Size      (0=128x128, 1=256x64, 2=256x128, 3=256x192 dots)
                            DCAP_OFFSET(0)|   // VRAM Read Offset  (0=00000h, 0=08000h, 0=10000h, 0=18000h)
                            DCAP_BANK(1) |   // VRAM Write Block  (0..3 = VRAM A..D) (VRAM must be allocated to LCDC)
                            DCAP_B(16) |   // EVB (0..16, or 0..31 ?) Blending Factor for Source A (or B ?)
                            DCAP_A(2);   // EVA (0..16, or 0..31 ?) Blending Factor for Source B (or A ?)
         
            break;

        }


You can take more samples for bloom at the cost of flicker, lower frame rates also induce flicker so try to use packed geometry rather than glBegin() etc...

For the HDR effectyou will need two inputs and a object based rendering approach.

Paramaters:

-Average scene brightness,get this by averaging the brightness of onscreen objects or by taking random samples from memory range of the LCD bank (in my case i read it using VRAMB[pixel]).

-Brightness of current object, this can be either a user defined constant or calculated in real time; treat the whole object as if its a single vertex and do software lighting on that.

we take these two paramters and then we compute the apparent brightness (brightness will affect bloom power see gbatek blending equation).

finalvalue = (objectBrightness/sceneBrightness);

we then take the final value and multiply it by our ambient value which we set using

Code:
glMaterialf(GL_DIFFUSE, RGB15(16,16,16));


Ill have to revise the Rnd number generator since i think my seeding method is biasisng (bloom starts to look good after 1/2 minutes of runtime)

#141613 - silent_code - Thu Sep 27, 2007 3:19 pm

hi!
it works fine (after adjusting those values), thank you very much! :^)
although i still have to find a good blending ratio, as the current settings blur the image too much and too low settings make the whole thing obsolete, as the effect is barely noticable.
what i didn't get is the bloom. it's more of a depth of field effect than a bloom, because the latter would brighten stuff instead just blending over. it's a pitty you can't change the blending mode on the nds. :^C

#141623 - Noda - Thu Sep 27, 2007 6:57 pm

can you post some screenshots of your results? ^^

#141893 - silent_code - Mon Oct 01, 2007 10:25 am

it will take a while (i don't have inet@home (TM), so i'm rarely online), but i might release a new version of my shadow volume demo (still with gbfs - NODA, please help me with efs!), so everyone can see for themselves. but i guess it would be cool to have some screens online, too. :^D

ps: can i use the code for that demo and can i make it public? (i guess the answer is yes, though i prefer asking beforehand. ;^) ) whom should i credit for it (means, by what name)?

#142963 - silent_code - Mon Oct 15, 2007 5:47 pm

just a "short" throw-in:

blending factors are 0..15 (4bit)! to get an even amount of colors from both "sources" ("live render" and capture) you set the ratios to sum up to 16. lower total will result in a darker image, higher will result in "over-blending", thus claming color components.

the formular is roughly (per component):
Code:
(factorA * colorA + factorB * colorB) / 16
again with clamping the result. (check out gbatek for the full thing!)

i don't know with which bit depth the clamping works. all colors are 15/16bit, rendering/lighting is 24bit, displays are 18bit and capturing seems to be 15bit (less colorfull than "live render").

if one would like to make a true bloom effect, one had to render the scene twice, first time capturing for bloom processing. that isn't very fast though. but otherwise there's colors bleeding from the previous frame(s) and that ruins the whole image (aka "burned-in colors").

any ideas?

btw: the depth of field effect works (with flickering that may be caused by bad blending ratios), but also suffers from color burning and over the top motion blur... or better motion *smudge*. :^C


Last edited by silent_code on Mon Oct 15, 2007 6:47 pm; edited 2 times in total

#142966 - Lick - Mon Oct 15, 2007 6:13 pm

Pictures or it didn't happen. ;)
_________________
http://licklick.wordpress.com

#142968 - silent_code - Mon Oct 15, 2007 6:24 pm

what pictures do you like? you better not want to see the depth of field, because i canned it in favour of a lovely motion blur effect! ;^p (might be able to restore a build with the dof, though...)

<offtopic>
man, gbatek has expanded quite a *BIT*! it's nice to see that the (still unreleased) volume shadow mini-tutorial is finally obsolete.
</offtopic>

#143008 - Noda - Tue Oct 16, 2007 1:21 am

Still, I'm very interested into that shadow volume mini tutorial, as I didn't get the thing even with the new gbatek info :/ I'm probably missing something...

#143063 - silent_code - Tue Oct 16, 2007 2:04 pm

"you wish - i serve" ;^D
tutorial will be up very soon (here on the forum first, then i'll eventually make a html page for my website).

EDIT: there you go: http://forum.gbadev.org/viewtopic.php?p=143065