Cel shading OutLine question
by robo · in Torque Game Engine Advanced · 08/18/2008 (7:54 am) · 9 replies
I try to import Render Monkey Silhouette Shader.
this shader is 2Pass Shader.
How Can I use 2Pass Shader in torque?
Pass0
pass1
this shader is 2Pass Shader.
How Can I use 2Pass Shader in torque?
Pass0
float4x4 view_proj_matrix: register(c0);
struct VS_INPUT
{
float4 Pos : POSITION;
float2 TexCoord : TEXCOORD0;
};
struct VS_OUTPUT
{
float4 Pos : POSITION;
float2 TexCoord : TEXCOORD0;
};
VS_OUTPUT vs_main( VS_INPUT In )
{
VS_OUTPUT Out;
In.Pos.xy = sign(In.Pos.xy);
Out.Pos = float4(In.Pos.xy, 0.0, 1.0);
// Image-space
Out.TexCoord.x = 0.5 * (1 + In.Pos.x);
Out.TexCoord.y = 0.5 * (1 - In.Pos.y);
return Out;
}
sampler RT;
// One pixel offset
const float off = 1.0 / 512.0;
struct PS_INPUT
{
float2 TexCoord : TEXCOORD0;
};
struct PS_OUTPUT
{
float4 Color : COLOR0;
};
PS_OUTPUT ps_main( PS_INPUT In)
{
PS_OUTPUT Out;
// Sample neighbor pixels
float s00 = tex2D(RT, In.TexCoord + float2(-off, -off)).r;
float s01 = tex2D(RT, In.TexCoord + float2( 0, -off)).r;
float s02 = tex2D(RT, In.TexCoord + float2( off, -off)).r;
float s10 = tex2D(RT, In.TexCoord + float2(-off, 0)).r;
float s12 = tex2D(RT, In.TexCoord + float2( off, 0)).r;
float s20 = tex2D(RT, In.TexCoord + float2(-off, off)).r;
float s21 = tex2D(RT, In.TexCoord + float2( 0, off)).r;
float s22 = tex2D(RT, In.TexCoord + float2( off, off)).r;
// Sobel filter in X direction
float sobelX = s00 + 2 * s10 + s20 - s02 - 2 * s12 - s22;
// Sobel filter in Y direction
float sobelY = s00 + 2 * s01 + s02 - s20 - 2 * s21 - s22;
// Find edge, skip sqrt() to improve performance ...
float edgeSqr = (sobelX * sobelX + sobelY * sobelY);
// ... and threshold against a squared value instead.
Out.Color = 1.0-(edgeSqr > 0.07 * 0.07);
return Out;
}pass1
float4x4 view_proj_matrix: register(c0);
struct VS_INPUT
{
float4 Pos : POSITION;
float2 TexCoord : TEXCOORD0;
};
struct VS_OUTPUT
{
float4 Pos : POSITION;
float2 TexCoord : TEXCOORD0;
};
VS_OUTPUT vs_main( VS_INPUT In )
{
VS_OUTPUT Out;
In.Pos.xy = sign(In.Pos.xy);
Out.Pos = float4(In.Pos.xy, 0.0, 1.0);
// Image-space
Out.TexCoord.x = 0.5 * (1 + In.Pos.x);
Out.TexCoord.y = 0.5 * (1 - In.Pos.y);
return Out;
}
sampler RT;
// One pixel offset
const float off = 1.0 / 512.0;
struct PS_INPUT
{
float2 TexCoord : TEXCOORD0;
};
struct PS_OUTPUT
{
float4 Color : COLOR0;
};
PS_OUTPUT ps_main( PS_INPUT In)
{
PS_OUTPUT Out;
// Sample neighbor pixels
float s00 = tex2D(RT, In.TexCoord + float2(-off, -off)).r;
float s01 = tex2D(RT, In.TexCoord + float2( 0, -off)).r;
float s02 = tex2D(RT, In.TexCoord + float2( off, -off)).r;
float s10 = tex2D(RT, In.TexCoord + float2(-off, 0)).r;
float s12 = tex2D(RT, In.TexCoord + float2( off, 0)).r;
float s20 = tex2D(RT, In.TexCoord + float2(-off, off)).r;
float s21 = tex2D(RT, In.TexCoord + float2( 0, off)).r;
float s22 = tex2D(RT, In.TexCoord + float2( off, off)).r;
// Sobel filter in X direction
float sobelX = s00 + 2 * s10 + s20 - s02 - 2 * s12 - s22;
// Sobel filter in Y direction
float sobelY = s00 + 2 * s01 + s02 - s20 - 2 * s21 - s22;
// Find edge, skip sqrt() to improve performance ...
float edgeSqr = (sobelX * sobelX + sobelY * sobelY);
// ... and threshold against a squared value instead.
Out.Color = 1.0-(edgeSqr > 0.07 * 0.07);
return Out;
}About the author
Recent Threads
#2
pass modifier is not working.
I did like below
08/27/2008 (7:51 am)
Hi Picassopass modifier is not working.
I did like below
new ShaderData( textureShader )
{
DXVertexShaderFile = "shaders/myshader/textureV.hlsl";
DXPixelShaderFile = "shaders/myshader/textureP.hlsl";
pixVersion = 2.0;
};
new ShaderData( OutLineShader )
{
DXVertexShaderFile = "shaders/myshader/outLineV.hlsl";
DXPixelShaderFile = "shaders/myshader/outLineP.hlsl";
pixVersion = 2.0;
};
new CustomMaterial(HeroArmorOutLine) // v1.1
{
// mapTo = "c_armor_base_map01";
texture[1] = "./c_armor_base_map01";
shader = OutLineShader;
version = 2.0;
};
new CustomMaterial(HeroArmor) // v1.1
{
mapTo = "c_armor_base_map01";
texture[0] = "./c_armor_base_map01";
shader = textureShader;
pass[0] = HeroArmorOutLine;
version = 2.0;
};
#3
Specify your render targets and input semantics for 2nd pass.
08/27/2008 (11:45 am)
Why do you mess T0 and T1 registers?Specify your render targets and input semantics for 2nd pass.
#4
Can you tell me more detail about render targets, input semantic?
is it right?
input semantics => texture [0] ,texture[1]
render target => pass[0]
What do I need to fix below code?
08/27/2008 (11:59 am)
HI PicassoCan you tell me more detail about render targets, input semantic?
is it right?
input semantics => texture [0] ,texture[1]
render target => pass[0]
What do I need to fix below code?
new CustomMaterial(HeroArmorOutLine)
{
shader = OutLineShader;
version = 2.0;
};
new CustomMaterial(HeroArmor)
{
mapTo = "c_armor_base_map01";
texture[0] = "./c_armor_base_map01";
shader = textureShader;
pass[0] = HeroArmorOutLine;
version = 2.0;
};
#5
Your mapto parameter specifies the render target.
Each custom material is a single pass shader, that means it uses an input as an output from the previous pass.
That one is called a pipeline, a hardware implementation, that uses a blocks of modulation, connected withing a small pipe and a super fast cache memory, called 'fixator', That one is used to store a temporary data.
Try to watch your way, debug the shader.
Sometimes a small typo can cause a lot of problems.
08/30/2008 (11:01 am)
Input semantics is your V registers of the GPU.Your mapto parameter specifies the render target.
Each custom material is a single pass shader, that means it uses an input as an output from the previous pass.
That one is called a pipeline, a hardware implementation, that uses a blocks of modulation, connected withing a small pipe and a super fast cache memory, called 'fixator', That one is used to store a temporary data.
Try to watch your way, debug the shader.
Sometimes a small typo can cause a lot of problems.
#6
I did test below code
pass[0] parameter is not working.....
BlueV.hlsl
BlueP.hlsl
RedV.hlsl
RedP.hlsl
08/30/2008 (1:40 pm)
PicassoI did test below code
pass[0] parameter is not working.....
BlueV.hlsl
#define IN_HLSL
#include "../shdrConsts.h"
float4x4 view_proj_matrix: register(VC_WORLD_PROJ);
struct VS_INPUT
{
float4 Position : POSITION0;
};
struct VS_OUTPUT
{
float4 Position : POSITION0;
};
VS_OUTPUT main( in VS_INPUT Input )
{
VS_OUTPUT Output = (VS_OUTPUT) 0;
Output.Position = mul( view_proj_matrix, Input.Position );
return( Output );
}BlueP.hlsl
struct PS_INPUT //We define the vertex out structure again
{
float4 Position : POSITION0;
};
struct PS_OUTPUT //We define the pixel output
{
float4 Color : COLOR0;
};
//The heart of the shader
void main(in PS_INPUT IN, out PS_OUTPUT OUT)
{
OUT.Color = float4 (0.0f, 0.0f, 1.0f, 1.0f); //Output the color blue
}RedV.hlsl
#define IN_HLSL
#include "../shdrConsts.h"
float4x4 view_proj_matrix: register(VC_WORLD_PROJ);
struct VS_INPUT
{
float4 Position : POSITION0;
};
struct VS_OUTPUT
{
float4 Position : POSITION0;
};
VS_OUTPUT main( in VS_INPUT Input )
{
VS_OUTPUT Output = (VS_OUTPUT) 0;
Output.Position = mul( view_proj_matrix, Input.Position );
return( Output );
}RedP.hlsl
struct PS_INPUT //We define the vertex out structure again
{
float4 Position : POSITION0;
};
struct PS_OUTPUT //We define the pixel output
{
float4 Color : COLOR0;
};
//The heart of the shader
void main(in PS_INPUT IN, out PS_OUTPUT OUT)
{
OUT.Color = float4 (1.0f, 0.0f, 0.0f, 1.0f); //Output the color blue
}new ShaderData( BlueShader )
{
DXVertexShaderFile = "shaders/myshader/BlueV.hlsl";
DXPixelShaderFile = "shaders/myshader/BlueP.hlsl";
pixVersion = 2.0;
};
new ShaderData( RedShader )
{
DXVertexShaderFile = "shaders/myshader/RedV.hlsl";
DXPixelShaderFile = "shaders/myshader/RedP.hlsl";
pixVersion = 2.0;
};
new CustomMaterial(BlueMaterial)
{
shader = BlueShader;
version = 2.0;
};
new CustomMaterial(RedMaterial)
{
mapTo = "c_armor_base_map01";
texture[0] = "./c_armor_base_map01";
shader = RedShader;
pass[0] = BlueMaterial; //2 pass
version = 2.0;
};
#7
Is this approach wrong, or is it just my code? Can you do a model outline using shaders? Here is the shader I made from JHK's code of the first pass (the 2nd pass seems to be a clone of the first):
outlineV.hlsl
outlineP.hlsl
09/17/2008 (12:30 am)
Well, I kind of got it to work, but I don't think it does what you think it does. It drew a giant sobel filtered texture over my screen, so I had to modify the code to draw the model, but it really only sobel filtered the texture itself and not the model, there was no outline of the model's edges, but rather a model with a white texture with black lines drawn on the textures where there were edges of colors.Is this approach wrong, or is it just my code? Can you do a model outline using shaders? Here is the shader I made from JHK's code of the first pass (the 2nd pass seems to be a clone of the first):
outlineV.hlsl
// pixVersion = 2.0;
#define IN_HLSL
#include "shdrConsts.h"
float4x4 view_proj_matrix: register(VC_WORLD_PROJ);
struct AppData
{
float4 Pos : POSITION;
float2 TexCoord : TEXCOORD0;
};
struct VertexOut
{
float4 Pos : POSITION;
float2 TexCoord : TEXCOORD0;
};
VertexOut main(AppData In, uniform float4x4 modelview : register(VC_WORLD_PROJ))
{
VertexOut Out;
//In.Pos.xy = sign(In.Pos.xy); This didn't work either
//Out.Pos = mul(In.Pos, ModelViewProjMatrix); This didn't work
Out.Pos = mul(modelview, In.Pos);
//Out.Pos = float4(In.Pos.xy, 0.0, 1.0); this didnt work
Out.TexCoord = In.TexCoord; // this would do nothing I think
// Image-space stuff commented out, I couldn't get this to work
//Out.TexCoord.x = 0.5 * (1 + In.Pos.x);
//Out.TexCoord.y = 0.5 * (1 - In.Pos.y);
return Out;
}outlineP.hlsl
// pixVersion = 2.0;
#define IN_HLSL
#include "shdrConsts.h"
struct VertexIn
{
float4 Pos : POSITION;
float2 TexCoord : TEXCOORD0;
};
struct PixelOut
{
float4 Color : COLOR0;
};
PixelOut main(VertexIn In, uniform sampler2D tex : TEXUNIT0) // was TEXUNIT0
{
PixelOut Out;
// One pixel offset
const float off = 1.0 / 512.0;
// Sample neighbor pixels
float s00 = tex2D(tex, In.TexCoord + float2(-off, -off)).r;
float s01 = tex2D(tex, In.TexCoord + float2( 0, -off)).r;
float s02 = tex2D(tex, In.TexCoord + float2( off, -off)).r;
float s10 = tex2D(tex, In.TexCoord + float2(-off, 0)).r;
float s12 = tex2D(tex, In.TexCoord + float2( off, 0)).r;
float s20 = tex2D(tex, In.TexCoord + float2(-off, off)).r;
float s21 = tex2D(tex, In.TexCoord + float2( 0, off)).r;
float s22 = tex2D(tex, In.TexCoord + float2( off, off)).r;
// Sobel filter in X direction
float sobelX = s00 + 2 * s10 + s20 - s02 - 2 * s12 - s22;
// Sobel filter in Y direction
float sobelY = s00 + 2 * s01 + s02 - s20 - 2 * s21 - s22;
// Find edge, skip sqtexture() to improve performance ...
float edgeSqr = (sobelX * sobelX + sobelY * sobelY);
// ... and threshold against a squared value instead.
Out.Color = 1.0-(edgeSqr > 0.07 * 0.07);
return Out;
}
#8
It's easy if you think of it like this: A CustomMaterial's texture[n] can be thought of the input texture for that shader. The mapTo parameter can be thought of as the shader's output. Therefore, each CustomMaterial that is in the multipass sequence needs to have their texture/mapTo linked together properly.
So here is a corrected version of your code (Edited texture names to be more descriptive, change back to your original names for it to work in your project):
Hope this helps. Now let's see if we can get the outline code to work, :-)
09/25/2008 (2:38 am)
JHK: Aha! After reading this thread probably 100 times, I finally figured out what the heck was wrong with your red/blue shader.It's easy if you think of it like this: A CustomMaterial's texture[n] can be thought of the input texture for that shader. The mapTo parameter can be thought of as the shader's output. Therefore, each CustomMaterial that is in the multipass sequence needs to have their texture/mapTo linked together properly.
So here is a corrected version of your code (Edited texture names to be more descriptive, change back to your original names for it to work in your project):
new CustomMaterial(BlueMaterial)
{
texture[0] = "redArmor"; // this is our input, the redArmor from RedMaterial
shader = BlueShader;
version = 2.0;
mapTo = "finalArmor"; // this is the name of the texture that will be applied to the model
};
new CustomMaterial(RedMaterial)
{
version = 2.0;
texture[0] = "originalArmor"; // this is your input from wherever the input armor texture was located
shader = RedShader;
mapTo = "redArmor"; // we're going to output this to a temporary texture to make the pass to BlueMaterial
pass[0] = BlueMaterial; //2nd pass
};Hope this helps. Now let's see if we can get the outline code to work, :-)
#9
I'm not sure your sobel filter will give you an edge around the model because it's only filtering the stuff drawn on the texture itself. For instance, it will draw an outline of his belt, but it won't give you a silhouette of the entire model.
Render Monkey probably used that filter as a full screen filter, so that's why it worked, but in torque shaders apply to the model. I was playing around with a resource on here to do full screen shaders, so that's the route I'm investigating now, but then the problem is that you'd have to do some special stuff:
1. First render any model that you want to have an outline in some sort of solid color. Each model must be a different color for the filter to differentiate.
2. Run the filter to get the edges of all the stuff on the screen, then save that texture.
3. Now draw all your models normally, then add the filtered edge image on top, making sure that you draw the white as transparent, and the black as opaque.
Man, the more I think about this, this is pretty intense.
The other way of doing it is to first draw the backfaces of the model in a thick black wireframe, then draw the model as normal, but I have no idea how to do that, but it somehow seems easier.
09/30/2008 (11:58 pm)
JHK: have you given up on this? :-/I'm not sure your sobel filter will give you an edge around the model because it's only filtering the stuff drawn on the texture itself. For instance, it will draw an outline of his belt, but it won't give you a silhouette of the entire model.
Render Monkey probably used that filter as a full screen filter, so that's why it worked, but in torque shaders apply to the model. I was playing around with a resource on here to do full screen shaders, so that's the route I'm investigating now, but then the problem is that you'd have to do some special stuff:
1. First render any model that you want to have an outline in some sort of solid color. Each model must be a different color for the filter to differentiate.
2. Run the filter to get the edges of all the stuff on the screen, then save that texture.
3. Now draw all your models normally, then add the filtered edge image on top, making sure that you draw the white as transparent, and the black as opaque.
Man, the more I think about this, this is pretty intense.
The other way of doing it is to first draw the backfaces of the model in a thick black wireframe, then draw the model as normal, but I have no idea how to do that, but it somehow seems easier.
Torque Owner Ivan Mandzhukov
Liman
www.garagegames.com/docs/tgea/official/content/documentation/Materials%20and%20S...
Use the 'pass' modifier and define a second custom material.