[More Mathematics] Sprite Displacement

Started by Calin Leafshade, Tue 22/06/2010 14:57:41

Previous topic - Next topic

Calin Leafshade

So I've been thinking about reflections on uneven surfaces and how to model them and I can't quite get my head around it.

Now I know this has been discussed before and it was decided it would be very slow.. but that was modelling distortion on a whole background.. what if it's just a characters reflection that's modelled?

Basically I see it like this:

1, You have a greyscale reflection/height map for your surface,
2, you project a reflection onto that surface,
3, then you somehow 'transpose' that greyscale reflection map onto the position values of the sprites pixels
4, draw the sprite

I can handle steps 1,2 and 4 but step 3 is puzzling me a little :P

It doesnt have to be very accurate since we are talking about a 2D plane with a static camera, but it has to look convincing.

any help?

SteveMcCrea, GarageGothic, Khris, I'm looking at you.

GarageGothic

(Doesn't Wintermute support that kind of thing through shaders, Calin? ;))

Well, it doesn't make sense to talk about height maps unless you have some sort of 3D projection algorithm implemented (even just an approximated one), since a surface facing the player straight-on wouldn't show any distortion. You don't say whether this is for vertical or horizontal reflections but in either case a per-pixel displacement of an image would be similar to rendering a voxel landscape. I actually did this in an unfinished MAGS game, so it's possible but quite slow, mainly due to the GetPixel function.

It would help if you go into a bit more detail on what you're trying to achieve. If you could settle for displacement in vertical or horizontal strips (or both at once even) rather than per-pixel it would improve performance a lot, and even more so if the distortion could be math-based rather than using an image heightmap.

Wyz

#2
.
Life is like an adventure without the pixel hunts.

Calin Leafshade

Quote from: GarageGothic on Tue 22/06/2010 15:32:20
(Doesn't Wintermute support that kind of thing through shaders, Calin? ;))

Don't judge me.. I want those damn alpha channels :D

Anyway, back to the task at hand!

basically i want to create a similar effect to this:



so pixels are shifted based on the luminance of the displacement map (in this case you can see the map used but that doesnt always have to be the case)

is it just that simple? Sample the colour value of the dis-map pixel and shift the character pixel depending on that? i.e 128 grey = no shift, 0 = full shift left and 255 = full shift right.

..im confused again..



Monsieur OUXX

Quote from: GarageGothic on Tue 22/06/2010 15:32:20
It would help if you go into a bit more detail on what you're trying to achieve.

Yes, describe exactly what kind of processing you plan to apply onto the pixels, depending on the displacement map (I shall call it that way because, as mentionned, it's not really a height map) :
- Are you moving whole rows of pixels horizontally to create some sort of "lake reflection"? (by the way, there's already a module doing that
- Are you moving each single pixel arbitrarily, based on the displacement map, to acheive some sort of distorted relection?
- Are you moving every pixel following a certain direction (angle) to achieve a fake 3D efect, voxel-style? (in that case it'd make sense to talk about a height map)

Let us know.
 

Calin Leafshade

Quote from: Monsieur OUXX on Tue 22/06/2010 16:55:36

- Are you moving each single pixel arbitrarily, based on the displacement map, to acheive some sort of distorted relection?


That one.

Monsieur OUXX

#6
Quote from: Calin Leafshade on Tue 22/06/2010 16:55:00
basically i want to create a similar effect to this:
so pixels are shifted based on the luminance of the displacement map

OK, so You're indeed in the second case I described.
Well, it sounds like your solution works (128 grey = no shift, 0 = full shift left and 255 = full shift right). Yes, I'd say it works.

Also, I believe that it will work better if you move the pixels in the same direction (horizontally, diagonally, vertically...) as the direction you chose to generate the kind-of light source when you created the displacement map. Otherwise the effect will work but will look awkward. But I might be wrong.

What do you think, people?


EDIT:  I believe that, to achieve the full effect, you might have to proceed as follow:
You might have to evaluate the "flatness" of each displacement map's pixel. It would NOT be ONLY about "how high" it is, but about "is this pixel facing the viewer?".
For example:
- if a pixel on the displacement map has 2 neighbours of the same color, it means you're in a area of the map that perfectly faces the viewer.
- However, if the pixel on the left is darker, and the pixel on the right is lighter, then it means that this area is not flat, and faces left. Similarly, if the pixel on the left is lighter and the pixel on the right is darker, then this area of the displacement map faces right.

This is equivalent to evaluating the direction of the NORMAL of each pixel of the displacement map.
You might have to do that in order to REALLY know of what amount you should displace the pixel up or down.

then again, I'm not sure if it's really necessary in your case, even though it is interesting to achieve cool effects.
 

GarageGothic

#7
I think you could build on the code you already used for the puddle reflections in McCarthy, or possibly Steve's underwater module, but instead of random/sinal distortion simply get the displacement values from the image map. If you're happy with displacement along a single axis (of any angle) that should be enough to achieve the effect. You may have to settle for a lower resolution on the reflection than in your example image though (e.g. displacing blocks of 4 pixels at a time), as long as things are the character is moving I doubt anyone would notice the difference.

Edit: I agree with Monsieur OUXX' edit, both on the technical part as well as his assumption that normal-based displacement would be overkill. The true art of game programming isn't simulating reality but creating an illusion of it with a fraction of the resources, which is something that took me a many overly complicated effect modules to learn :).

Jim Reed

It seems simple.
To bad it's hard to explain. =)
Catch me on irc, it's easier there.

Calin Leafshade

#9
ok so, this is what I have so far

http://www.thethoughtradar.com/AGS/Distortion.zip (AGS 3.2 Final 5)

(edit: actually you can see the effect better with this slightly modified version http://www.thethoughtradar.com/AGS/Distortion2.zip)

It actually distorts pretty well and looks fairly cool except for the whole pixellyness of it.

so how could I fix that? some kind of bilinear filter?

...

...how do i do that?


EDIT: also how does the AGS colour system work? is there a function to convert it to RGB values?

GarageGothic

#10
No built-in function to get RGB values, but here's my script for it:

Code: ags

enum eRGBComponent {
  eRed, 
  eGreen,
  eBlue,
  };

function GetRGBComponent(int color, eRGBComponent component) {
  if (component == eRed) return 8*(color/2048);
  if (component == eGreen) return 8*((color%2048)/64);
  int b = (8*((color%2048)%64));
  if (b > 255) return (8*(((color%2048)%64)-31))-1;
  return b;
  }


The test looks good to me. I don't think the reflection appears much more pixelly than the character itself, but you could always draw the final reflection multiple times slightly offset and at different transparencies to smooth out the edges a bit.

Edit: Cleaned up unnecessary "if else" statements in code.

Calin Leafshade

#11
thanks GG, mind if i add that to the Util module? Seems like a good candidate.

and here is my latest effort with some kind of filtering.. It looks very cool but I feel it could be better.

http://www.thethoughtradar.com/AGS/Distortion3.zip

edit: some reports of frame rate would be nice - Compiled version for the curious http://www.thethoughtradar.com/AGS/Distortionbin.zip

GarageGothic

Sure thing, Calin. I can't promise it's flawless, because it's a really bare-bones version of an earlier script that had many more conditionals (to map the first 32 palette slots correctly), but it has worked for my own purposes.

Love the effect in the new build, but the framerate is struggling between 24 and 33 in windowed mode on my 2.4GHz centrino. Though I do have several other applications open.

Calin Leafshade

#13
struggling? Direct Draw or D3D mode?

it should be easy to refine and improve upon.. i use getpixel an awful lot.. i should probably just dump the values into an array.

DoorKnobHandle

No framerate problems here but my computer is pretty decent at 2x3.14Ghz intel in window mode while rendering a video too. :D

Looking very nice.

GarageGothic

#15
DirectDraw mode - I didn't think it would make much difference since all the DrawingSurface stuff happens in the CPU in either mode, but Direct3D gives me 35-36FPS. Probably full screen would bring it closer to 40, but my Nvidia drivers prevent me from testing that without shutting down Firefox, so it'll have to wait.

And yeah, GetPixel is the most likely culprit in terms of performance. Reducing the sampling resolution should help loads. For my per-pixel lighting module the performance/quality sweet spot seemed to be around 4 pixels, but that was a hi-res game so even sampling every second pixel would probably boost your game well above 40FPS.

Calin Leafshade

the way i've done the whole thing is really really messy but the actual calcs are really not that intensive so i'm pretty sure I can get 40fps on most modern systems

Crimson Wizard

#17
Omg, freaking cool!
Can I use this in my game? Pleeese?  ;D

Okay, technical stuff.
Run on laptop with AMD Turion 2.0 Ghz, video ATI Mobility Radeon X1300 (128mb)

DirectDraw 5
Windowed mode, scaled x3 (960x720), FPS 37-41
FullScreen mode, scaled x2 (640x480)*, FPS 38-41

Direct3D
Windowed mode, scaled x3 (960x720), FPS 40 (stable)
FullScreen mode, scaled x2 (640x480)*, FPS 40 (stable)

* for some reason graphics driver could not run fullscreen with 960x720 resolution

Jim Reed

Quote from: Crimson Wizard on Tue 22/06/2010 19:16:24
freaking cool!
Ditto that. Heck, if you placed the distortion map precisely, and paint the distorted sprite black, but semi-transparent, you can have a real time shadow!

Calin, you da man!

GarageGothic

Quote from: Jim Reed on Tue 22/06/2010 20:48:31Heck, if you placed the distortion map precisely, and paint the distorted sprite black, but semi-transparent, you can have a real time shadow!

Not one of the more efficient nor flexible ways to do realtime shadows, but if you wanted a shadow on, say, a rough cave wall, the displacement map technique could definitely be added on top of a straightforward shadow renderer.

SMF spam blocked by CleanTalk