For the background i want to have an animated door, that is opening and closing then door should be animated.
Right now it is pretty simple, the door is a texture painted on a quad, so i tried to seperate the parts of the door and paint them on other quads to move them arround.
While this works, it looks ugly because of z-fighting when the parts overlap. Also it is not a small feat to have a simple triggerable animation that just moves arround some geometries, at least i found no easy way, so i thought this is a good start to dig into shaders.
The door looks something like this:
[java]
// ==========
// |########|
// |######++|
// |###+++++|
// |++++++++|
[/java]
The = and | parts are the frame that should stay where it is and allways be on top.
The # part should move upwards.
The + part should move downwards.
I started reading through https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:jme3_shadernodes and while i understand the general concept this page talks about a .j3sn file without any clue how to use it. The IDE offers no template for this filetype and i have found no refference to that filetype anywhere in assetmanager or other articles. It might be an idea to give an example here on how to actualy use those kind of files. But leaving that aside i thought if can just edit a material definition to do what i want.
For this i took the Lighting.j3md because i want to have the nice light effects included in this. I copied the file into my project together with the Lighting.frag and Lighting.vert so i can create my own version (and renaming them).
To create this animation i thought i put in a few textures, one for the base frame of the door and a few for the parts that can be moved. Also i needed a trigger to start the animation, so i added texture attributes and a boolean to the definition file:
[java]
MaterialParameters {
// Trigger to open door
Boolean Open : false
// Texture that is static door base
Texture2D BaseFrame
// Texture to slide upwards
Texture2D SlideUp
// Texture to slide downwards
Texture2D SlideDown
// Texture to slide left
Texture2D SlideLeft
// Texture to slide right
Texture2D SlideRight
.....
[/java]
Thinking the best way for this to work would be to just put together the drawn image from those textures the best place to do this is the fragment shader, so i put the new attributes in the define of the technique and added them to the .frag file:
Definition file:
[java]
Technique {
LightMode MultiPass
VertexShader GLSL100: MatDefs/LightingDoor.vert
FragmentShader GLSL100: MatDefs/LightingDoor.frag
WorldParameters {
WorldViewProjectionMatrix
NormalMatrix
WorldViewMatrix
ViewMatrix
CameraPosition
WorldMatrix
}
Defines {
...
// added these
OPEN : Open
BASE_FRAME : BaseFrame
SLIDE_UP : SlideUp
SLIDE_DOWN : SlideDown
SLIDE_LEFT : SlideLeft
SLIDE_RIGHT : SlideRight
...
}
}
[/java]
Fragment shader:
[java]
#ifdef BASE_FRAME
uniform sampler2D m_BaseFrame;
#endif
#ifdef SLIDE_UP
uniform sampler2D m_SlideUp;
#endif
#ifdef SLIDE_DOWN
uniform sampler2D m_SlideDown;
#endif
#ifdef SLIDE_LEFT
uniform sampler2D m_SlideLeft;
#endif
#ifdef SLIDE_RIGHT
uniform sampler2D m_SlideRight;
#endif
[/java]
So at this point i should have the textured passed to the fragment shader and con work with them.
Looking at the code of the Lighting.frag file i choosed this place to be the best spot, because when i want to compose the drawn texture out of the other textures i don’t need a diffuse map, and i don’t need the stuff done with normal maps etc in front of this block.
Original:
[java]
#ifdef DIFFUSEMAP
vec4 diffuseColor = texture2D(m_DiffuseMap, newTexCoord);
#else
vec4 diffuseColor = vec4(1.0);
#endif
[/java]
And edited it so i compose the pixel stored in diffuseColor from my textures.
The problem right now is that nothing happens. I created a material file to test it and added the textures for base frame, part that moves up and part that moves down.
In the small preview window in the IDE nothing is shown and i don’t get an error in the output window, so i dont have a clue what is wrong right now.
[java]
#ifdef DIFFUSEMAP
vec4 diffuseColor = texture2D(m_DiffuseMap, newTexCoord);
#else
vec4 diffuseColor = vec4(1.0);
#ifdef SLIDE_UP
newTexCoord = texCoord;
diffuseColor.rgb += texture2D(m_SlideUp, newTexCoord).rgb * texture2D(m_SlideUp, newTexCoord).a;
#endif
#ifdef SLIDE_DOWN
newTexCoord = texCoord;
diffuseColor.rgb += texture2D(m_SlideDown, newTexCoord).rgb * texture2D(m_SlideDown, newTexCoord).a;
#endif
#ifdef SLIDE_LEFT
newTexCoord = texCoord;
diffuseColor.rgb += texture2D(m_SlideLeft, newTexCoord).rgb * texture2D(m_SlideLeft, newTexCoord).a;
#endif
#ifdef SLIDE_RIGHT
newTexCoord = texCoord;
diffuseColor.rgb += texture2D(m_SlideRight, newTexCoord).rgb * texture2D(m_SlideRight, newTexCoord).a;
#endif
#ifdef BASE_FRAME
diffuseColor.rgb += texture2D(m_BaseFrame, texCoord).rgb * texture2D(m_BaseFrame, texCoord).a;
#endif
#endif
[/java]
Also i am at a loss how to actualy do the animation.
My current thoughts are that at some point in the game when the player opens the door i get the material from the geometry and just set the Open attribute to true.
At that point in the fragment shader i start moving the defined parts according to the passed time until the part is completely outside of the base texture.
So do i still need to define the Open attribute inside the fragment shader like i did with the textures, or can i just use something like if (Open) ?
Also i think need to check if the parts are allready outside of the base frame so i don’t need to get a pixel from it any more.
For this i thought i can use an internal variable that stores when the animation started and a boolean that it has started, then i could calculate the time that has passed since the animation was triggered and move the coordinated to get the pixel from the part textures accordingly.
Question there is can i define a variable inside the vertex shader that stores this ?
I think i have to add Time to world parameters and can access that with g_Time then. So if i do that can i define the parameters in the vertex shader and so something like this ?
[java]
// at top of file
uniform float startTime;
uniform bool animationStarted;
// inside main
if ((m_Open && !animationStarted) || (!m_Open && !animationStarted))
animationStarted = true;
startTime = g_Time;
float passedTime = g_Time - AnimationStarted;
[/java]
Then i just have to move the coordinates for getting the pixels out of the part trextures accordingly.
There i have my next problem, maybe i am too much used to code explicit and strict, but don’t i have to check if the given coorsinates are actualy inside the texture i am getting the pixel from ? What happens if i try to get (20, 80) from a texture that is actualy only 26x26 big ?
And can i get the height and width somehow from a uniform sampler2D so i can determine when to stop the animation ?
I hope someone can give me some clues on how to solve this.
Or maybe you say this is total to try it this way and can point me in a better direction
Also i have googled arround but don’t find a good reference to glsl functions and objects. I find tit-bits of information here and there but nothing put together like a javadoc where you can browse all attributes a uniform sampler2D has for example. Anyone knows a good address to look something like this up ?
Edit: Sorry for strange formating of the text, but it seems somehow after a code tag the forum ignores empty lines and line breaks.