[WIP] Vertex 3-axis deformation shader (Incorporated JME’s Lighting.frag)

Heyas…



I’m working on a vertex shader for handling some standard deformations. Basically (when complete) it will allow for selecting a deformation type and then setting speed, size and depth to achieve the effect your looking for. The vertex shader can be coupled with any fragment shader you like, however, it will require you know a bit about creating material definition files and making sure you pass in the appropriate MaterialParameters, WorldParameters and Defines to accompidate both the vertex deform .vert and whatever .frag you choose to use it with.



The final deformation types will consist of:



Wave

Ripple

Pinch

Swell



Well… and I guess any others that people would like to have included (just post your idea here).



Here is a sample of the Ripple and Wave deformations. Oh… I also need to allow for reversing the direction of the effect as well.



http://youtu.be/oUjdic5VG5k



Anyways... let me know what you think or pass along any ideas for deforms you'd like to see added.

Forgot to mention the TODOs...

I'm finishing up recalculating normals and adding a few more standard deformations.

Oh man...

I totally failed to mention the coolest part. This isn't a single axis deformation... you can turn on and off the X, Y and Z axis deformations individually. Here is a sphere with a Wave deform against all 3 axis:

http://youtu.be/TkhHUOsppfA


Normals recalculation:
http://youtu.be/LFhW2d6miNg


With Common/MatDefs/Light/Lighting.frag
http://youtu.be/k0JQ7i066DU
12 Likes

Cool stuff, great to see so many people fearlessly jumping into “shader world” ^^

this is really cool!

I’ve done a bit more work on this.



For each axis, you can now set:



Deform axis on/off

Deformation Type

Direction

Speed

Size

Depth



Here is a sphere with Ripple along the Y axis, and Wave along the X and Z axis with different setting for each.



http://youtu.be/yeZjfd2P1Pk



Some of the cooler applications this can be used for (off the top of my head) would be:

Animating a snakes movement... without having to animate.
Animating just about any underwater creature... without having to animate.
Animating a land animals tail... without having to animate.
Animating liquid in any shape... would work really well for zero-g liquid.

Are you getting the "without having to animate" part yet? ;)

Anyways.... once this a little further along and I start using it with fragment shaders, I'll throw together an example of a snake or some such thing.
5 Likes

Really awesome stuff man! :slight_smile:

@t0neg0d , you are killing me again! Will you contribute this shader to the shader library?

very nice stuff!

oh snap :slight_smile: very nice, how did u learn to use shaders?

@mifth Absolutely… As soon as it is finished up, I’ll post the code here. As for getting you that GPU-based version of the other one, I’ll have time to get that out here tonight. Just to clarify, you can switch directions in the GPU-based version, it just jumps the textures oddly when you update the float. @pspeed was nice enough to explain why it was happening to me and patient enough to let me babble about how I could fix it… knowing full well it wasn’t possible lol :wink:



@wezrule Asking a TON of really silly questions and a bunch of reading. People here are really patient (even when my questions made no sense). There isn’t a lot to it… it’s mostly getting the fundamental understand of how they work (which didn’t click with me for quite a while).



EDIT: I should also mention, info on the fundamental workings of shaders is NOT readily available on the web. Trying to find an answer to simple concepts like what texture coordinates actually are (0-1??! Makes sense now… but…), is next to impossible to find… so ask here. Also, I’m still lost on a TON of of these… but trial and error/asking those who know has been a good thing.

3 Likes

ok cool thx :), i’ve been meaning to learn them for a while, but always get stuck at the first hurdle

@t0neg0d said:
@wezrule Asking a TON of really silly questions and a bunch of reading. People here are really patient (even when my questions made no sense).

Well according to your recent achievements, helping you wasn't a waste at all ;)

How difficult is calculating normals for a solid surface going to be?

@Sploreg Well… I thought I had a good understanding of how to do this… but it is proving a bit more difficult than I originally thought. All the examples I can find for recalculating normals are based off of changes to a single axis, so I am getting stuck on how to determine the normal once a deformation is applied to more than one axis. I’ll post the code I was working with soon and see if someone smarter than me can figure it out.

You essentially need the neighbour vertices, and for that you will need a geometry shader. Or, if your mesh is symetrical (like a sphere or plane) with evenly spaced points, I suppose you could still do this in the vertex shader and just interpolate one unit length in each direction of the neighbouring vertices, run the calculation on them, then take the normals and average them (say 4 samples to 4 neighbours to get 4 normals, and then average those to get your new normal).



How do the examples suggest to recalculate the normals after the deformation?

If your formula for generating the position is based on standard curves then it should be possible to find the normal for that position on the curves. I don’t know the math you are using, though. I also don’t know what vertex-specific info your shader uses to figure out where on the curves…



This will be more accurate in general than sampling surrounding points, though. If you can get away with it.

@Sploreg @pspeed I’m trying to figure out how to use an inverse Jaconian Matrix to determine the normal (basically what pspeed just said). The big problem is… I’m totally lost hahahahaha. Here is a sample of one of the deforms (to show how they are being calculated… but it is based on a curve over time.



[java]

vec4 displaceWave(vec4 pos, int axis, float speed, float size, float depth, int dir) {

vec4 new_pos;

new_pos.x = pos.x;

new_pos.y = pos.y;

new_pos.z = pos.z;

new_pos.w = pos.w;

float dist1;

float dist2;

if (dir == 0) speed = -speed;



if (axis == 0) {

dist1 = sqrt(pos.ypos.y);

dist2 = sqrt(pos.z
pos.z);

new_pos.x = pos.x+(depthsin((sizedist1)+speed));

new_pos.x += pos.x-(depthcos((sizedist2)+speed));

} else if (axis == 1) {

dist1 = sqrt(pos.xpos.x);

dist2 = sqrt(pos.z
pos.z);

new_pos.y = pos.y+(depthsin((sizedist1)+speed));

new_pos.y += pos.y-(depthcos((sizedist2)+speed));

} else if (axis == 2) {

dist1 = sqrt(pos.xpos.x);

dist2 = sqrt(pos.y
pos.y);

new_pos.z = pos.z+(depthsin((sizedist1)+speed));

new_pos.z += pos.z-(depthcos((sizedist2)+speed));

}

return new_pos;

}



vec4 displaceRipple(vec4 pos, int axis, float speed, float size, float depth, int dir) {

vec4 new_pos;

new_pos.x = pos.x;

new_pos.y = pos.y;

new_pos.z = pos.z;

new_pos.w = pos.w;

float dist;

if (dir == 0) speed = -speed;



if (axis == 0) {

dist = sqrt((pos.ypos.y)+(pos.zpos.z));

new_pos.x = pos.x+(depthsin((sizedist)+speed));

} else if (axis == 1) {

dist = sqrt((pos.xpos.x)+(pos.zpos.z));

new_pos.y = pos.y+(depthsin((sizedist)+speed));

} else if (axis == 2) {

dist = sqrt((pos.xpos.x)+(pos.ypos.y));

new_pos.z = pos.z+(depthsin((sizedist)+speed));

}

return new_pos;

}

[/java]



And as far as determining the normals… I know I need a tangent and binormal, which should look something like (for the Y axis and assuming no other deformations have been performed):



[java]

var3 norm = inNormal;

vec3 tangent;

vec3 binormal;



vec3 c1 = cross(norm, vec3(0.0, 0.0, 1.0));

vec3 c2 = cross(norm, vec3(0.0, 1.0, 0.0));



if(length(c1)>length(c2)) tangent = normalize(c1);

else tangent = normalize(c2);



binormal = normalize(cross(norm, tangent));

[/java]



And I think the matrix should look something like (for the Y axis/wave deformation):



[java]

float dist = sqrt((pos.xpos.x)+(pos.zpos.z));

float coef = cos(speed*dist+depth);//(dist+0.00001);

J[0][0] = 1.0;

J[0][1] = coef * pos.x;

J[0][2] = 0.0;



J[1][0] = 0.0;

J[1][1] = 1.0;

J[1][2] = 0.0;



J[2][0] = 0.0;

J[2][1] = coef * pos.z;

J[2][2] = 1.0;

[/java]



But something is wrong with the above normal calculation and I’m not really feeling like I have a solid grasp of how to implement it correctly.



Oh… Out of curiosity… can you use switch statements in the glsl shader language?

There is a function in the water shader that determines the TBN space matrix of a point according to its position, normal and UVs . (computeTangentFrame)



Also in the water shader the normal is computed by fetching 4 surrounding points in the height map, maybe you could do the same math exactly but computing arbitrary surrounding points with your deformation function.

1 Like

@nehon I’m definitely going to look at this. I think my feeble brain will be able to follow this much easier than what I was looking in to. I read an article on this method (using neighboring vertex positions to calculate the normal), but most of what I read said using the Jacobian method was they way “we all” do it.



What kills me about the articles I have found on the web thus far, is example code is given for most everything you would want to attempt… UNTIL it comes to this one subject and then even though “we all do it this way”… I find nothing useful on how “we all do it” :wink:

@Sploreg @pspeed @nehon @anyoneelsewhomayknow Could someone please take a look at this and tell me what might be wrong with it. I’m sure this is the proper way to recalc the normals, but I am getting a shader link failure.



For info’s sake:

norm is inNormal if only one deform is performed.

pos I have tried as the original inPosition to see if I can just recalc the original normal & the deformed vertex position.



If you just return norm, it works fine of course… but with a useless return like shader link filure, I’m not sure what the problem is. Anyways, here is the routine for calculating the normals for a ripple deformation.



[java]

vec3 displaceNormalRipple(vec3 pos, vec3 norm, int axis, float speed, float size, float depth, int dir) {

mat3 J = mat3(1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0);

float dist;

float coef;

if (dir == 0) speed = -speed;



vec3 tangent;

vec3 binormal;



if (axis == 0) {

dist = sqrt((pos.ypos.y)+(pos.zpos.z));

coef = cos((speeddist)+depth)/(dist+0.00001);

J[1][1] = coef * pos.y;

J[2][1] = coef * pos.z;

} else if (axis == 1) {

dist = sqrt((pos.x
pos.x)+(pos.zpos.z));

coef = cos((speed
dist)+depth)/(dist+0.00001);

J[0][1] = coef * pos.x;

J[2][1] = coef * pos.z;

} else if (axis == 2) {

dist = sqrt((pos.xpos.x)+(pos.ypos.y));

coef = cos(speeddist+depth)/(dist+0.00001);

J[0][1] = coef * pos.x;

J[1][1] = coef * pos.y;

}



vec3 c1 = cross(norm, vec3(0.0, 0.0, 1.0));

vec3 c2 = cross(norm, vec3(0.0, 1.0, 0.0));



if(length(c1)>length(c2)) tangent = c1;

else tangent = c2;

tangent = normalize(tangent);



binormal = cross(norm, tangent);

binormal = normalize(binormal);



vec3 u1 = J
tangent;

vec3 v1 = J*binormal;



vec3 n1 = cross(v1, u1);

return normalize(n1);

}

[/java]

That was the only information in the error? Let me guess, ATI card?



How do you know this function is the one causing the link error?