Gamestudio Links
Zorro Links
Newest Posts
Change chart colours
by 7th_zorro. 05/11/24 09:25
Data from CSV not parsed correctly
by dr_panther. 05/06/24 18:50
AUM Magazine
Latest Screens
The Bible Game
A psychological thriller game
SHADOW (2014)
DEAD TASTE
Who's Online Now
3 registered members (AndrewAMD, alibaba, TipmyPip), 1,144 guests, and 4 spiders.
Key: Admin, Global Mod, Mod
Newest Members
Hanky27, firatv, wandaluciaia, Mega_Rod, EternallyCurious
19051 Registered Users
Previous Thread
Next Thread
Print Thread
Rate Thread
Page 1 of 2 1 2
[Tut] How a toon shader works (PART 1) #39967
01/23/05 06:12
01/23/05 06:12
Joined: Mar 2001
Posts: 3,298
Beverly, Massachusetts
Rhuarc Offline OP
Expert
Rhuarc  Offline OP
Expert

Joined: Mar 2001
Posts: 3,298
Beverly, Massachusetts
Alright, there's posts flying everywhere about toon shaders, so here's a run down on how one works .

To begin with, in a shader you need to declare what variables you are going to use, this is done at the top of your shader:
Code:
float4x4 matWorldViewProj;
float4x4 matWorld;
float4 vecSunDir;

Texture entSkin1;
Texture mtlSkin1;



Here you see 3 different variable types, float4x4, float4 and Texture. There are a few others, including float3x3 float3, float2, and float.
Float variables are simply a number or an array of numbers.
Float would be a single number. Float2 would be a 2d coordinate. Float3 would be 3d. And float4 is a 4d coordinate (x,y,z,w). 4D coordinates are used in vector multiplication and other operations. W will equal 0 if it is a vector (direction), and 1 if it is a position when using float4.

We declare the float4, vecSunDir. This is the directional vector of our sun.

float4x4 and float3x3 are matrices. These are used to transform, rotate, and scale vectors and postions. These will usually consist of various predefined ones:
matView
matWorld
matProj (projected)
matWorldView (this is matView*matWorld)
matWorldViewProj (matView*matWorld*matProj)


In our declarations we use matWorldViewProj, when you multiply a position in a vertex shader by this, it is tranformed into clip space. This is something that is a good rule of thumb to always do. We will get to this later.

Last, we have Textures. These are simple, they simply define what you are going to use for textures.
The textures can be mtlSkin1..4 and entSkin1..4 for material and entity skins 1-4, respectively.

Now that we have our variables declared, we can go on to create our tecnique.

Code:
technique lightMapping
{
pass SingleLight
{
//globals
zwriteenable= true;
zenable = true;



In a technique, which is the code that tells the shader what it is supposed to do, you can have multiple passes. A pass is simply one time rendering the model. In this part we are only going to do the lighting pass, for a toon shader you can add a second pass that will render the model slightly larger, flip its normals, and make it black- this creates a ink outline. Everything inside this technique is considered the Fixed Function Pipeline, or FFP. You can call vertex and pixel shaders from inside of this.

Our global variables, zwriteenable and zenable, simply enable Z buffering for our render and disallow the shader from rendering new depth values.

Each pass is made up of stages. Stages are individual layers of texture that are blended together in different ways to create the texture appearence of the model. In our first stage we will render our model without any lighting, and in the second we will multiply the lighting over it (lighting of 1 keeps the texture fullbright, where 0 makes it black).

Code:
	//Stage variables
Texture[0]=<mtlSkin1>;
ColorOp[0]=Modulate;
ColorArg1[0]=Texture;
ColorArg2[0]=Texture;
AddressU[0]=Clamp;
AddressV[0]=Clamp;
AddressW[0]=Clamp;



We are setting several stage variables here. Stage variables (such as Texture) are followed by brackets [] that enclose the stage number you are setting the variable for. We are going to use the material skin for the first pass, which will contain an image holding lighting values from black to white going from left to right in the image. To do this, we enclose the texture in angular brackets <mtlSkin1>. This is how we reference declared variables in the FFP. Next, ColorOp defines how the texture should be rendered atop other stages. Modulate makes it multiply it over whatever is already there. When doing it in the first stage, it simply sets the texture as what you are giving it. Our two colorArg variables determine how the texture itself is rendered. You can use Texture and Diffuse for example to get simple diffuse lighting. Here we want a fullbright (no shadows/lighting) texture, so we give it Texture and Texture. Lastly, we want to clamp the texture at the edges so it doesnt tile. We do this by clamping the AddressU..W variables.

Next we need to render our model texture. We will render this in the second stage, multiplied over the lighting stage to achieve the final effect.

Code:
	Texture[1]=<entSkin1>;
ColorOp[1]=Modulate;
ColorArg1[1]=Texture;
ColorArg2[1]=Current;



The only thing new here is that we use Current for the second colorArg. This just takes what was previously defined. This isn't required, but good for conisistencey.

Lastly, we need to call our vertex shader (that we will define). This is done by setting VertexShader. When using HLSL, we don't put the code in the FFP, but rather define functions for it. So we compile for vs_1_0 (vertexshader 1.0), our function VS_Main().

Code:
	//shaders
VertexShader = compile vs_1_0 VS_Main();
}
}



Now, we are ready to code our vertex shader. Let's go inbetween our declarations and our technique to declare this.

Before we start, we need to do something similar to our declarations- and that is to define our input and output structures for the vertex shader.

Code:
struct VS_INPUT
{
float4 position : POSITION;
float2 TexCoords: TEXCOORD0;
float3 normal : NORMAL;
};

struct VS_OUTPUT
{
float4 position : POSITION;
float2 uvCoords: TEXCOORD0;
float2 TexCoords: TEXCOORD1;
float4 diffuse : COLOR;
};



I'm not going to go into the syntax too heavily, just notice the format:
Code:
struct STRUCT_NAME
{
varType varName : VARIABLE;
};//don't forget the ';' !!



We want the engine to give us the vertex position, first texture coordinate, and the lighting normal, so we use POSITION, TEXCOOD0, and NORMAL. We cannot change those, but we can change what we call them in our code: position, TexCoords, and normal (note that these are case sensitive). We are required to take the POSITION and return it. So, in our output, we return out the POSITION along with two texture coordinates, corresponding to the first two texture stages in our FFP. Also, we want to return the diffuse color for lighting. Some cards have defaults set in the diffuse, which causes artifacts- so we will set diffuse to be a static value in our shader.

Now lets code the shader!

Code:
VS_OUTPUT VS_Main(VS_INPUT input)
{
//zero out the struct members
VS_OUTPUT output = (VS_OUTPUT)0;

//our code will go in here

return output;
}



Notice the structure again being:
Code:
OUTPUT_STRUCT Function_Name( INPUT_STRUCT inputName ) //structName is what we will call it in our code
{
OUTPUT_STRUCT outputName = (OUTPUT_STRUCT)0; //this defines our output variable, using our own variable type (just like we would define with float for eample). We also have to "zero it out", done with "= (OUTPUT_STRUCT)0".

return outputName; //return our output structure variable to the shader- this will either be passed directly to the FFP, or to a pixel shader if one is used.
}

//note: no ';' here, only on structs.

Now that we have the structure, the first thing we will do is, as I mentioned earlier, transform our vertex position into clip space.

Code:
	//transform vertex pos to clip space
output.position = mul(input.position, matWorldViewProj );


We reference variables inside of our structures like skills in C-Script: struct.var. Here we are working with a float3, but we don't need any fancy vec_set or anything here. HLSL will assume what it is supposed to do. the mul function will multiply the first argument by the second. So here, we are multiplying the position "into" the clip space by using matWorldViewProj. This takes a bit of 3d math theory, so look it up if you don't quite understand it.

Next, we need to work with our texture coordinates. The second set (TexCoords) we aren't going to do anything with, so lets do those first just copy the texture coordinates that we already have back into it to be returned:
Code:
	output.TexCoords= input.TexCoords;



Next, we need to calculate our light direction:
Code:
	float4 LightDir = mul(matWorld,-vecSunDir);


Here we are multiplying the world matrix by the sun direction (inverted). This gives us something to work with when we calculate where the texture coordinate to use for our lighting should be (remember it is reading the lighting values from a bmap, we need to know where they should be read from).

Now, we can calculate that position:
Code:
	float diffuse = max(0,dot(LightDir,input.normal ));


diffuse is where we will store the light intensity. We make sure it doesn't go below zero- if this happens the lighting will wrap around to the other side of the object. We use a simple max() instruction to do this (takes larger value, so if the second argument is below 0, 0 will be used.) We use another new function here, dot. This computes the dot product of two vectors. By calculating the light direction to to normal, we get the light intensity (look at some light thoery tutorials if you need more explanation).

Now, we are ready to set those lightingmap texture coordinates!
Code:
	output.uvCoords.x = diffuse;
output.uvCoords.y = 0.0f;


We are reading it horizontally, so we set the X coordinate based on the light intensity, and the Y coordinate to 0. The Y coordinate doesn't matter very much because we will use a single pixel height image.

And now? We're done! The next line of code we should have after this is the "return output;" that we put in our structure.

Here is an example image to use for the lighting image: TGA Image

This shader requires VS1.0 and NO PS!
If you use the code put in here, a note of credit would be nice.

-Rhuarc


I no longer post on these forums, keep in touch with me via:
Linkedin.com
My MSDN blog
Re: [Tut] How a toon shader works (PART 1) [Re: Rhuarc] #39968
01/23/05 06:28
01/23/05 06:28
Joined: Jul 2001
Posts: 1,269
Hopewell Jct, NY
Yulor Offline
Senior Developer
Yulor  Offline
Senior Developer

Joined: Jul 2001
Posts: 1,269
Hopewell Jct, NY
Very Informative! Nice Contribution Dan!

Re: [Tut] How a toon shader works (PART 1) [Re: Rhuarc] #39969
01/23/05 07:01
01/23/05 07:01
Joined: Apr 2004
Posts: 324
downunder
sixfeetunder Offline
Senior Member
sixfeetunder  Offline
Senior Member

Joined: Apr 2004
Posts: 324
downunder
Thanks broŽ - this will help me very much to make my game!

Re: [Tut] How a toon shader works (PART 1) [Re: sixfeetunder] #39970
01/23/05 11:54
01/23/05 11:54
Joined: Nov 2004
Posts: 832
United States, Utah
Braxton Offline
Developer
Braxton  Offline
Developer

Joined: Nov 2004
Posts: 832
United States, Utah
5 STARS!!! I think I have a new hero. This has made everything for me much easier.

-Braxton

*EDIT* - I am very, very confused. How would this look in a cpmlete code? As you can tell I am very new and have learned enought that you have to say:

skin1 = ts3tone;

and above that add a bmap called ts3tone, but that is it.

Can someone help me figure out how this would work/look in a code?

Thanks,
Braxton

Last edited by Braxton; 01/23/05 13:12.

"The GREAT LAW: Life is and always will be justly ordered, and that all past experiences, good and bad, were the equitable out working of our evolving, yet unevolved selves" - As A Man Thinketh
Re: [Tut] How a toon shader works (PART 1) [Re: Rhuarc] #39971
01/23/05 20:50
01/23/05 20:50
Joined: Jul 2004
Posts: 328
The Netherlands
JvsJGameDesign Offline
Senior Member - banned
JvsJGameDesign  Offline
Senior Member - banned

Joined: Jul 2004
Posts: 328
The Netherlands
WOW!
This realy help me to understand shader coding. Thnx buddy!


Re: [Tut] How a toon shader works (PART 1) [Re: JvsJGameDesign] #39972
01/25/05 07:05
01/25/05 07:05
Joined: Jun 2002
Posts: 724
atlantic canada
pocorev Offline
Developer
pocorev  Offline
Developer

Joined: Jun 2002
Posts: 724
atlantic canada
your contribution is already very generous, and i hesitate to ask for even more from you
but being the complete shader noob that i am, i feel the need to ask anyways.

would you (please) consider putting up a small demo that uses this method?

i think that between the demo and the explanations found here i may actually be able to
put the pieces together... and there are probably many others like me.

either way, thank you for this help.

Last edited by pocorev; 01/25/05 07:07.
Re: [Tut] How a toon shader works (PART 1) [Re: pocorev] #39973
01/25/05 07:19
01/25/05 07:19
Joined: Mar 2001
Posts: 3,298
Beverly, Massachusetts
Rhuarc Offline OP
Expert
Rhuarc  Offline OP
Expert

Joined: Mar 2001
Posts: 3,298
Beverly, Massachusetts
I'll try to throw something up this week.

-Rhuarc


I no longer post on these forums, keep in touch with me via:
Linkedin.com
My MSDN blog
Re: [Tut] How a toon shader works (PART 1) [Re: Rhuarc] #39974
01/25/05 07:21
01/25/05 07:21
Joined: Nov 2004
Posts: 832
United States, Utah
Braxton Offline
Developer
Braxton  Offline
Developer

Joined: Nov 2004
Posts: 832
United States, Utah
Please include a full working .wdl of the shader.


"The GREAT LAW: Life is and always will be justly ordered, and that all past experiences, good and bad, were the equitable out working of our evolving, yet unevolved selves" - As A Man Thinketh
Re: [Tut] How a toon shader works (PART 1) [Re: Braxton] #39975
01/25/05 07:31
01/25/05 07:31
Joined: Jun 2002
Posts: 724
atlantic canada
pocorev Offline
Developer
pocorev  Offline
Developer

Joined: Jun 2002
Posts: 724
atlantic canada
greatly appreciated

Re: [Tut] How a toon shader works (PART 1) [Re: pocorev] #39976
03/05/05 17:55
03/05/05 17:55
Joined: Aug 2000
Posts: 7,490
O
Orange Brat Offline

Senior Expert
Orange Brat  Offline

Senior Expert
O

Joined: Aug 2000
Posts: 7,490
I went digging. I put this thing together but it returns an error on startup. It says "ErrorX3004: Undeclared identifier in 'VS_Main'"

Code:

bmap tstonemap = <ts3tone.tga>;
material toon
{
skin1 = tstonemap;
effect
"
float4x4 matWorldViewProj;
float4x4 matWorld;
float4 vecSunDir;
Texture entSkin1;
Texture mtlSkin1;

struct VS_INPUT
{
float4 position : POSITION;
float2 TexCoords: TEXCOORD0;
float3 normal : NORMAL;
};

struct VS_OUTPUT
{
float4 position : POSITION;
float2 uvCoords: TEXCOORD0;
float2 TexCoords: TEXCOORD1;
float4 diffuse : COLOR;
};

VS_OUTPUT VS_Main(VS_INPUT input)
{
//zero out the struct members
VS_OUTPUT output = (VS_OUTPUT)0;

//transform vertex pos to clip space
output.position = mul(input.position, matWorldViewProj );
output.TexCoords= input.TexCoords;
float4 LightDir = mul(matWorld,-vecSunDir);
float diffuse = max(0,dot(LightDir,input.normal ));
output.uvCoords.x = diffuse;
output.uvCoords.y = 0.0f;
return output;
}

technique lightMapping
{
pass SingleLight
{
//globals
zwriteenable= true;
zenable = true;
//Stage variables
Texture[0]=<mtlSkin1>;
ColorOp[0]=Modulate;
ColorArg1[0]=Texture;
ColorArg2[0]=Texture;
AddressU[0]=Clamp;
AddressV[0]=Clamp;
AddressW[0]=Clamp;
Texture[1]=<entSkin1>;
ColorOp[1]=Modulate;
ColorArg1[1]=Texture;
ColorArg2[1]=Current;
//shaders
VertexShader = compile vs_1_0 VS_Main();
}
}

technique fallback // empty fallback causes normal rendering
{
pass p0 { }
}
"; // end of effect
}




My User Contributions master list - my initial post links are down but scroll down page to find list to active links
Page 1 of 2 1 2

Moderated by  Blink, Hummel, Superku 

Gamestudio download | chip programmers | Zorro platform | shop | Data Protection Policy

oP group Germany GmbH | Birkenstr. 25-27 | 63549 Ronneburg / Germany | info (at) opgroup.de

Powered by UBB.threads™ PHP Forum Software 7.7.1