HLSL - Animated texture shader

I would like to try to make some form of simple texture animation for a shader, e.g. sliding UVs or something. But so far I haven’t been able to find anything that can get me started. Can anyone help me out here or point me to a tutorial on the subject? I would like to make a river water shader, with a sliding texture simulating the ripples due to current and the flow of the water - you know, like in computer games :):

I’m mainly writing my shaders for the 3ds max viewport and I would like to write a shader with an animation “connected” to the 3ds max timeline, so that I can preview the animation in max.

By the way, is there some online database over HLSL commands, like php.net for PHP scripting you can search for every function and read about it what it does and how it works?

[QUOTE=Nanne;3078]
By the way, is there some online database over HLSL commands, like php.net for PHP scripting you can search for every function and read about it what it does and how it works?[/QUOTE]

Intrinsic Functions

Keywords, Directives, etc

There are probably better ones though…

You might find some of what you are looking for here, basic commands and syntax and such:
http://msdn.microsoft.com/en-us/library/bb509638(VS.85).aspx

As for the shader, you could use the TIME semantic and then offset you uv coordinates with that. There is an example of the shader you want to do in the ShaderFX examples.


WIKI VAPORIZER

Your best bet is to download shaderFX (www.lumonix.net), build a simple test shader, export to .fx, and look at what they do. It is an extremely effective way to learn.

There is even a tutorial on how to do an UV-waterfall with ShaderFX by me :slight_smile:

http://www.lumonix.net/Blog.php

If you wanted to do it in HLSL, here are some quicky examples.

Simple V Scroll:


// +----------------------------------------+
//    Semantics
// +----------------------------------------+
float4x4 WorldViewProj : WorldViewProjection < string UIWidget="None"; >;
float Time             : Time                < string UIWidget="None"; >;

// +----------------------------------------+
//    Parameters
// +----------------------------------------+

float Speed <
	string UIName = "Speed";
> = 1.0f;

texture Tex  <
	  string ResourceName = "scroll.tga";
	  string UIName =  "Texture";
	  string ResourceType = "2D";
>;

sampler2D TexSampler = sampler_state {
	  Texture = <Tex>;
	  MinFilter = Linear;
	  MagFilter = Linear;
	  MipFilter = Linear;
	  AddressU = Wrap;
	  AddressV = Wrap;
};
	
// +----------------------------------------+
//    Stage Interop
// +----------------------------------------+

struct AppData
{
	float3 Position : POSITION;
	float4 UV       : TEXCOORD0;
};

struct VertData
{
	float4 HPos     : POSITION;
	float2 UV       : TEXCOORD0;
};

// +----------------------------------------+
//    Vertex Shader
// +----------------------------------------+

VertData mainVS( AppData IN )
{
	VertData OUT;
	OUT.HPos = mul(float4(IN.Position.xyz, 1.0), WorldViewProj);
	OUT.UV = float2( IN.UV.x, IN.UV.y + Time * Speed );
	return OUT;
}

// +----------------------------------------+
//    Pixel Shader
// +----------------------------------------+
float4 mainPS( VertData IN ) : COLOR
{
	return tex2D(TexSampler, IN.UV);
}

technique technique0 {
	pass p0 {
		CullMode = None;
		VertexShader = compile vs_3_0 mainVS();
		PixelShader = compile ps_3_0 mainPS();
	}
}

Atlas Walk:


// +----------------------------------------+
//    Semantics
// +----------------------------------------+
float4x4 WorldViewProj : WorldViewProjection < string UIWidget="None"; >;
float Time             : Time                < string UIWidget="None"; >;

// +----------------------------------------+
//    Parameters
// +----------------------------------------+

float Speed <
	string UIName = "Speed";
> = 1.0f;

float XDim <
	string UIName = "X Tiles (Multiple of 2)";
> = 2.0f;

float YDim <
	string UIName = "Y Tiles (Multiple of 2)";
> = 2.0f;

texture Tex  <
	  string ResourceName = "atlas.tga"
	  string UIName =  "Texture";
	  string ResourceType = "2D";
>;

sampler2D TexSampler = sampler_state {
	  Texture = <Tex>;
	  MinFilter = Linear;
	  MagFilter = Linear;
	  MipFilter = Linear;
	  AddressU = Wrap;
	  AddressV = Wrap;
};
	
// +----------------------------------------+
//    Stage Interop
// +----------------------------------------+

struct AppData
{
	float3 Position : POSITION;
	float4 UV       : TEXCOORD0;
};

struct VertData
{
	float4 HPos     : POSITION;
	float2 UV       : TEXCOORD0;
};
// +----------------------------------------+
//    Vertex Shader
// +----------------------------------------+

VertData mainVS( AppData IN )
{
	VertData OUT;
	OUT.HPos = mul(float4(IN.Position.xyz, 1.0), WorldViewProj);
	
	// Atlas properties
	float2 scale = 1 / float2( XDim, YDim );	// How much to scale the UVs to fit a tile
	float index = floor(Time * Speed);			// Which Item in the Atlas to pick (INT)
	
	// NOTE:
	// We traverse the atlas without manually wrapping U:
	//  12
	//  --34
	//  ----56
	//  ------78
	//  --------9......
	// would otherwise need: float2( index % XDim, floor( index / YDim ) );
	
	OUT.UV = IN.UV + float2( index, floor(index / YDim) );
	OUT.UV *= scale;
	return OUT;
}

// +----------------------------------------+
//    Pixel Shader
// +----------------------------------------+
float4 mainPS( VertData IN ) : COLOR
{
	return tex2D(TexSampler, IN.UV);
}

technique technique0 {
	pass p0 {
		CullMode = None;
		VertexShader = compile vs_3_0 mainVS();
		PixelShader = compile ps_3_0 mainPS();
	}
}

They don’t do much of anything except put the verts in the right place and then scroll the UVs.

I’ve attached some Textures that should read as sentences when scrolling, so you know what you should be expecting.

Good luck on your actual shader! -Lith

I also endorse the use of ShaderFX for learning (although my opinion might be biased. :wink:)

The most important part of Lithium’s posted code is:

float Time : Time < string UIWidget=“None”; >;

With that line in the header of your shader, you’re bringing in the current time from Max’s time slider. Then you’d just add that value to your U coord or V coord with perhaps a speed multiplier.

Wow! Thanks Lithium, that’s amazing of you. I’ll dig into that code tomorrow - thank you!
By the way, what is “Atlas Walk”? I never heard that term before.

ShaderFX looks very cool and I think it is very noble of you to offer it for free for individuals whom are learning :): But I really like the extra “geekiness” you get from actually writing the shader from scratch - I’m a nerd and damn proud of it :D: Plus it really impresses my teacher that I know a little programming :cool:

We’re not suggesting that you use ShaderFX to write the shaders - just that you use it for code reference. So in this case, you’d make a shader that animates the UV coords in ShaderFX and then spit out the code and look at it. It’s a way to learn. Then you can apply the same ideas to your own code.

Atlasing is combining several textures into a grid - so multiple textures become one big texture.

Yes, that sound like a good idea. But I don’t feel comfortable with the syntax and semantics of HLSL yet, so I going to stick with newbie tutorial for a little while. Then I give ShaderFX a go. We have it in school and my teacher knows the basics of it.

An “atlas walk” is the act of traversing through an atlas. An atlas, as ben said, is a collection of images. In this particular example, the atlas is a sequence, like an animated gif. You can use it to do something like animate an explosion, or flash the words “hot damn an atlas” to the screen one after another.

If you’d like the animation to play corresponding to the timeline, you can also animate DirectX shader parameters through the material editor interface, as with any other material. Just add a UV offset to your water, expose it as a parameter in the shader, and key it.

As an aside, you can also add new controllers to any shader parameter. Wire controllers can be especially useful for doing things like blending wrinkle normal maps in a character’s shader based on bone orientations, or creating look-at targets for projected/parameterized UVs. If you didn’t want to key anything, so that if you extend your timeline the water will just keep flowing, you could use an expression controller that references time.

Of course, any of that stuff will be max-only (and specific to your one material instance), so if you try to take the shader to another app, you’ll have to find a different way of driving the animation. But if you’re primarily prototyping in Max to prove out ideas, animating your parameters can save you a lot of time.

Lithiums example is good

The basics of scrolling the UVs is that you want to add a value to the texture coordiantes.

UV.x + 0.5
would shift all your uvs in the x direction by 0.5

But it would be static, not moving

So if you send a value that changes every frame instead of 0.5
you will get moving UVs that change every frame.
This time can be a value as Bronwen says, that you can animate in Max
UV.y + time

UV.xy+time would scroll the UVs diagonal

if you want to adjust the speed you need to multiply time by speed
(time * speed)

Just mess around with shaders that work,changing code, thats the best way to learn

nicholasjosephandrewmatthewjoshua