пятница, 11 мая 2012 г.

Stage3D DisplacementMapFilter

Hi. Today I want to show how to achieve famous 'displacement map filter effect' using AGAL. This effect can be done as postprocess so there can be infinetely many sources of space distortions. Be careful - there's a huge number of word 'DISPLACEMENT' in the text.

First of all we need a map (not treasure, but displacement) that looks like this (found somewhere in the internet):

We are only intresting in two components - red that response for horizontal displacement and green that response for vertical displacement. I took 0.5 as point with no displacement, 0 to 0.5 - displacement to the left/up for red/green chanel and 0.5 to 1 - displacement to the right/down for red/green chanel. I made a quad with map and every update I draw it to special texture. This is the result (hover with mouse):


Notice that color of texture initialy is 0.5 for red and green chanels that means that there're no displacement in 'empty' places.

The steps quite simple:
- set projection matrix
- set vertex buffer for quad with map
- set texture where we will draw a map
- say to GPU that we will render to texture instead of back buffer
- clear texture to r = 0.5, g = 0.5
- set shaders
- draw triangles

The shaders are straightforward and no need in description:
var vertexShaderString:String =
    'm44 op va0 vc0\n' +
    'mov v0 va1';
var fragmentShaderString:String = 
    'tex oc, v0, fs0 <2d,linear,nomip>';
Now the most interesting part:
- set projection matrix
- set fragment constants as vector Vector( -0.5, -0.5, scale, 0). Here scale is strenght of displacement. 0 means no displacement and higher values means more displacement.
- set vertex buffer for geometry (quad with texture in my example)
- set texure for background
- set previously drawn map texture
- say to GPU that we will render to back buffer
- set shaders
- draw triangles

In the example vertex shader is the same - its purpose only to draw quad with background texture. And this is fragment shader:
var fragmentShaderString:String = 
    'tex ft0, v0, fs1 <2d,linear,nomip>\n' + //get color of displacement map - red and green chanels say us which direction we should displace
    'add ft1 fc0 ft0\n' + //add color to constant. Recal that 0.5 means no displacement, so ading it to constant (0.5) leads to zero.
    'mul ft1 ft1 fc0.zz\n' + //scale our displacement direction by strength. For example, if red, say, is 0, then we get -0.5 as basic displacement and we need to scale it to desired value.
    'add ft2 v0 ft1\n' + //result direction we should add to original texture coordinates that came as varing parameter frm vertex shader
    'tex oc, ft2, fs0 <2d,linear,nomip>'; //finaly sample texture with new texture coordinates
For pulse effect I choose scale as:
Math.abs(Math.sin(getTimer() * 0.001) * 0.1; //notice values range - they sould be small enougth for proper effect.
And finaly the result (hover with mouse):

12 комментариев:

  1. looks perfect - can you post the source code please?

  2. Hi. As I mention previously, I don't want to post long context3d setup code because it's the same and boring. Also I use my own math library and it will confuse. Instead, I try to cover the most challenging and interesting part - shaders. And I always post them with comments. So if you have some shader questions - feel free to ask.

  3. Is there a way to do displacement mapping for the whole scene?
    If there's multiple planes on the screens with different textures, this approach fill fail.
    Would work if we could do it in vertex shader, but vertex shader doesn't support textures =[

  4. Whole scene? Of course! You just render all your staff in single texture. And then apply displacement shader to it. It's simple postprocessing.

  5. Thanks! I'm very new to 3D so wasn't sure what's the right approach.

  6. Этот комментарий был удален автором.

  7. Everithing looks correct. And yes, passing textures back and forth (when you call setTextureAt) is very, very slow process. Especially on older hardware and mobile.

  8. Solved it
    createTexture(width:int,height:int,format:String,optimizeForRenderToTexture:Boolean,streamingLevels:int = 0)

    Hours of googling and I missed an argument in constructor.

    Но всеравно спасибо.

  9. Very interesting work !
    But is there a link where we can download the whole source code ? I still have some difficulties to implement the shader, and it would be very helpful to look at the entire code !
    Thanks for your help !

  10. Sad, but I have lost sources and I'm to lazy to write a new one. If you have difficulties, feel free to ask here.

  11. Thanks !
    After more research, I found what I was looking for, a Starling displacement map filter :