Posted By: gnosh
ShaderFx plugin for 3ds Max - 07/24/09 16:58
I was wondering if anyone can tell me what to include or remove from the code that the ShaderFx for 3ds max spits out. I went through the shader workshop and although I found it informative I am a 3d artist and just beginning my long road in the world of programming. I find it easier to build a shader visually than by coding it at this time. I have included the code for a stock toon shader that comes with the plugin. I know you guys are very busy with your own project so any insights would be not only helpful but, very appreciated.Thank you.
// ---------------------------------------------
// Cartoon shader
// Two pass cartoon rendering technique featuring
// three-tone shading and silhouette detection
//
// Author: Bruno P. Evangelista
// www.brunoevangelista.com
// ---------------------------------------------
/**
* Execution script
*/
float Script : STANDARDSGLOBAL <
string UIWidget = "none";
string ScriptClass = "scene";
string ScriptOrder = "standard";
string ScriptOutput = "color";
string Script = "Technique=technique?depthMap:normalMap:laplacianEdge3tons:laplacian8Edge3tons:laplacianEdge3tonsHatching;";
> = 0.8; // version #
/**
* Projection, View and World matrix
*/
float4x4 matWVP : WorldViewProjection <string UIWidget = "none";>;
float4x4 matWV : WorldView <string UIWidget = "none";>;
float4x4 matV : View <string UIWidget = "none";>;
float4x4 matW : World <string UIWidget = "none";>;
/**
* Scene objects
*/
float near
<
string UIName = "Z Near Plane";
string UIWidget = "slider";
float UIMin = 1.0f;
float UIMax = 5.0f;
float UIStep = 0.5f;
> = {1.0f};
float far
<
string UIName = "Z Far Plane";
string UIWidget = "slider";
float UIMin = 10.0f;
float UIMax = 100.0f;
float UIStep = 1.0f;
> = {12.0f};
float3 pointLightPosition : position
<
string UIWidget = "none";
//string space = "World";
string object = "Pointlight";
//> = { -3.0, 5.0, -2.5 };
> = { 0.0, 1.0, -1.0 };
float ambientLight <
string UIName = "Ambient Light Intensity";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 1.0f;
float UIStep = 0.1f;
> = {0.3f};
float diffuseLight <
string UIName = "Diffuse Light Intensity";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 1.0f;
float UIStep = 0.1f;
> = {0.6f};
float specularLight <
string UIName = "Specular Light Intensity";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 1.0f;
float UIStep = 0.1f;
> = {0.4f};
float shininess <
string UIName = "Specular shininess";
string UIWidget = "slider";
float UIMin = 8.0f;
float UIMax = 128.0f;
float UIStep = 8.0f;
> = {24.0f};
float4 ClearColor <
string UIWidget = "color";
string UIName = "Scene Background";
> = {1.0, 1.0, 1.0, 1.0};
float depthTimesFactor <
string UIName = "Depth times factor";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 10.0f;
float UIStep = 1.0f;
> = {3.0f};
float normalTimesFactor <
string UIName = "Normal times factor";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 10.0f;
float UIStep = 1.0f;
> = {1.0f};
float borderDetectionFactor <
string UIName = "Border detection";
string UIWidget = "slider";
float UIMin = 0.2f;
float UIMax = 10.0f;
float UIStep = 0.2f;
> = {2.4f};
float edgeWidth <
string UIName = "Edge width";
string UIWidget = "slider";
float UIMin = 0.9f;
float UIMax = 4.0f;
float UIStep = 0.1f;
> = {1.0f};
float edgeColor <
string UIName = "Edge color";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 1.0f;
float UIStep = 0.1f;
> = {0.0f};
float ClearDepth <string UIWidget = "none";> = 1.0;
half2 ScreenSize : VIEWPORTPIXELSIZE < string UIWidget="None"; >;
/**
* Default texture
*/
texture textureMap : diffuse
<
string UIName = "Objects texture";
string ResourceName = "dm2.jpg";
string ResourceType = "2D";
>;
sampler textureSampler = sampler_state
{
texture = <textureMap>;
//addressU = clamp;
//addressV = clamp;
mipFilter = linear;
minFilter = linear;
magFilter = linear;
//mipFilter = point;
//minFilter = linear;
//magFilter = linear;
};
/**
* Normal + Depth texture
*
* Extracted from the model render.
*/
texture normalDepthMap : renderColorTarget
<
float2 viewPortRatio = {1.0f, 1.0f};
int mipLevels = 1;
string format = "A8R8G8B8";
//string format = "A16B16G16R16";
string UIWidget = "none";
>;
// Sampler
sampler normalDepthMapSampler = sampler_state
{
texture = <normalDepthMap>;
addressU = clamp;
addressV = clamp;
//mipFilter = point;
//minFilter = linear;
//magFilter = linear;
};
/**
* Hatching texture
*/
texture hatching1Map : diffuse
<
string UIName = "Hatching map lv1";
string ResourceName = "dm2.jpg";
string ResourceType = "2D";
//int mipLevels = 5;
>;
sampler hatching1MapSample = sampler_state
{
texture = <hatching1Map>;
addressU = clamp;
addressV = clamp;
//mipFilter = linear;
//minFilter = linear;
//magFilter = linear;
};
texture hatching2Map : diffuse
<
string UIName = "Hatching map lv2";
string ResourceName = "dm2.jpg";
string ResourceType = "2D";
//int mipLevels = 5;
>;
sampler hatching2MapSample = sampler_state
{
texture = <hatching2Map>;
addressU = clamp;
addressV = clamp;
//mipFilter = linear;
//minFilter = linear;
//magFilter = linear;
};
/**
* Rendered Scene
*
* I had problems blending the scene
*/
texture tonsMap : renderColorTarget
<
float2 viewPortRatio = {1.0f, 1.0f};
int mipLevels = 1;
string format = "A8R8G8B8";
string UIWidget = "none";
>;
// Sampler
sampler tonsMapSampler = sampler_state
{
texture = <tonsMap>;
addressU = clamp;
addressV = clamp;
//mipFilter = point;
//minFilter = linear;
//magFilter = linear;
};
texture depthMap : renderDepthStencilTarget
<
float2 viewPortRatio = {1.0f, 1.0f};
// TODO Olhar os formatos no manual do Dx9
//string format = "D16";
string format = "D24X8";
string UIWidget = "none";
>;
// Sampler
sampler depthSampler = sampler_state
{
texture = <depthMap>;
addressU = clamp;
addressV = clamp;
//mipFilter = point;
//minFilter = linear;
//magFilter = linear;
};
/**
* Vertex structures
*/
struct vsPass1Input
{
half3 position : position;
half3 normal : normal0;
half2 texcoord : texcoord0;
};
struct psPass1Input
{
float4 hpos : position;
half4 normal : texcoord0;
half3 lightVec : texcoord1;
half3 halfVec : texcoord2;
half2 texcoord : texcoord3;
//half zbuffer : texcoord4;
};
struct vsPass2Input
{
float4 position : position;
half2 texcoord : texcoord0;
};
// Use 5 texture acess
struct psPass2Input
{
float4 hpos : position;
half2 uv0 : texcoord0;
half2 uv1 : texcoord1;
half2 uv2 : texcoord2;
half2 uv3 : texcoord3;
half2 uv4 : texcoord4;
};
// Use 9 texture acess
struct ps2Pass2Input
{
float4 hpos : position;
half2 uv0 : texcoord0;
half2 uv1 : texcoord1;
half2 uv2 : texcoord2;
half2 uv3 : texcoord3;
//half2 uv4 : texcoord4;
half2 uv5 : texcoord4;
half2 uv6 : texcoord5;
half2 uv7 : texcoord6;
half2 uv8 : texcoord7;
};
/**
* Shaders
*/
psPass1Input normalDepthVS(vsPass1Input vertexIn)
{
psPass1Input vertexOut;
// Vertex in clip space
float4 pos = float4(vertexIn.position.xyz, 1.0f);
vertexOut.hpos = mul(pos, matWVP);
// Vertex in World_View space
half3 vpos = mul(pos, matWV).xyz;
// Light position in View Space
half3 lightPos = mul(half4(pointLightPosition.xyz, 1.0f), matV).xyz;
//vertexOut.lightPos = mul(lightPos, matV).xyz;
//vertexOut.lightPos = lightPos.xyz;
// Calculate light direction vector
vertexOut.lightVec = lightPos - vpos;
// Calculate the half vec (LightVec+EyeVec) * 0.5
vertexOut.halfVec = vertexOut.lightVec - vpos;
// Per-vertex depth approach (Interpola, por pixel)
//vertexOut.zbuffer = (vpos.z - near) / (far - near);
//half depth = (vertexIn.vpos.z - near) / (far - near);
// Normal in world space
half4 normal = mul(half4(vertexIn.normal.xyz, 0.0f), matWV);
// Normal (X, Y, Z), Depth W
vertexOut.normal = half4(normal.xyz, (vpos.z - near) / (far-near));
// Texcoord
vertexOut.texcoord = vertexIn.texcoord;
return vertexOut;
}
// ---------------------------------------------------------
float4 normalDepth3tonsPS(
psPass1Input vertexIn,
out half4 normalDepthMap : COLOR1
) : COLOR0
{
// Normalize normal and depth
//half4 normalDepth = normalize(vertexIn.normal);
//half3 n = normalDepth.xyz;
half3 n = normalize(vertexIn.normal.xyz);
float w = normalize(vertexIn.normal.w);
// Normalize all other components
half3 l = normalize(vertexIn.lightVec);
half3 h = normalize(vertexIn.halfVec);
// Write the normal depth map
//normalDepthMap = normalDepth;
//normalDepthMap = half4(n.x, n.y, -n.z, w);
float4 depthColor = tex2D(depthSampler, vertexIn.texcoord);
half3 nCopy = (n * 0.5) + 0.5;
normalDepthMap = half4(nCopy.x, nCopy.y, nCopy.z, w);
//normalDepthMap = half4(depthColor.x, depthColor.y, depthColor.z, 1.0);
// Light intensity (ambient + diffuse + specular)
half lightIntensity = ambientLight;
// Diffuse light
half diffInt = saturate(dot(l, n));
if (diffInt >= 0.3)
lightIntensity += diffuseLight;
// Specular light (Need optimize in POW)
half specInt = saturate(dot(h, n));
if (pow(specInt, shininess) > 0.4)
lightIntensity += specularLight;
return float4((lightIntensity *
tex2D(textureSampler, vertexIn.texcoord)).xyz, 1.0f);
/*
depthColor *= 1000000;
return float4(depthColor.x, depthColor.y, depthColor.z, depthColor.w);
*/
}
// ---------------------------------------------------------
float4 normalDepth3tonsHatchingPS(
psPass1Input vertexIn,
out half4 normalDepthMap : COLOR1
) : COLOR0
{
// Normalize normal and depth
//half4 normalDepth = normalize(vertexIn.normal);
//half3 n = normalDepth.xyz;
half3 n = normalize(vertexIn.normal.xyz);
float w = normalize(vertexIn.normal.w);
// Normalize all other components
half3 l = normalize(vertexIn.lightVec);
half3 h = normalize(vertexIn.halfVec);
// Write the normal depth map
//normalDepthMap = normalDepth;
half3 nCopy = (n * 0.5) + 0.5;
normalDepthMap = half4(nCopy.x, nCopy.y, nCopy.z, w);
//normalDepthMap = half4(n.x, n.y, -n.z, w);
// Light intensity (ambient + diffuse + specular)
//half lightIntensity = ambientLight;
// Invert UV coords
half x = vertexIn.texcoord.x;
vertexIn.texcoord.x = vertexIn.texcoord.y;
vertexIn.texcoord.y = x;
half3 hatchTex = tex2D(hatching2MapSample, vertexIn.texcoord);
float lightIntensity = (hatchTex.x + hatchTex.y + hatchTex.z) * 0.5;
if (lightIntensity > ambientLight)
lightIntensity = ambientLight;
// Diffuse light
half diffInt = saturate(dot(l, n));
if (diffInt >= 0.3)
{
hatchTex = tex2D(hatching1MapSample, vertexIn.texcoord);
lightIntensity = (hatchTex.x + hatchTex.y + hatchTex.z) * 0.5;
if (lightIntensity > diffuseLight)
lightIntensity = diffuseLight;
// Specular light (Need optimize in POW)
half specInt = saturate(dot(h, n));
if (pow(specInt, shininess) > 0.4)
lightIntensity += specularLight;
}
return float4((lightIntensity *
tex2D(textureSampler, vertexIn.texcoord)).xyz, 1.0f);
}
// ---------------------------------------------------------
float4 depthPS(psPass1Input vertexIn) : COLOR0
{
// Normalize normal and depth
half4 normalDepth = normalize(vertexIn.normal);
return float4(vertexIn.normal.w, vertexIn.normal.w,
vertexIn.normal.w, 1.0f);
}
// ---------------------------------------------------------
float4 normalPS(psPass1Input vertexIn) : COLOR0
{
// Normalize normal and depth
half3 n = normalize(vertexIn.normal.xyz);
n = (n * 0.5) + 0.5;
return float4(n.x, n.y, n.z, 1.0f);
}
// ---------------------------------------------------------
psPass2Input edgeVS(
vsPass2Input vertexInput,
uniform half u,
uniform half v)
{
psPass2Input vertexOut;
// Final position
vertexOut.hpos = vertexInput.position;
// Faster if used as a function parameter?
//half u = edgeWidth/ScreenSize.x;
//half v = edgeWidth/ScreenSize.y;
half2 texcoord = vertexInput.texcoord;
vertexOut.uv0 = texcoord + half2(0.0, v);
vertexOut.uv1 = texcoord + half2(-u, 0.0f);
vertexOut.uv2 = texcoord;
vertexOut.uv3 = texcoord + half2(u, 0.0f);
vertexOut.uv4 = texcoord + half2(0.0, -v);
return vertexOut;
}
// ---------------------------------------------------------
ps2Pass2Input edge8VS(
vsPass2Input vertexInput,
uniform half u,
uniform half v)
{
ps2Pass2Input vertexOut;
// Final position
vertexOut.hpos = vertexInput.position;
// Faster if used as a function parameter?
//half u = edgeWidth/ScreenSize.x;
//half v = edgeWidth/ScreenSize.y;
half2 texcoord = vertexInput.texcoord;
vertexOut.uv0 = texcoord + half2(-u, v);
vertexOut.uv1 = texcoord + half2(0.0f, v);
vertexOut.uv2 = texcoord + half2(u, v);
vertexOut.uv3 = texcoord + half2(-u, 0.0f);
//vertexOut.uv4 = texcoord + half2(0.0f, 0.0f);
vertexOut.uv5 = texcoord + half2(u, 0.0f);
vertexOut.uv6 = texcoord + half2(-u, -v);
vertexOut.uv7 = texcoord + half2(0.0f, -v);
vertexOut.uv8 = texcoord + half2(u, -v);
return vertexOut;
}
// ---------------------------------------------------------
float4 laplacianEdgePS(psPass2Input vertexInput) : color0
{
// Read five pixels
half4 a = tex2D(normalDepthMapSampler, vertexInput.uv0);
half4 b = tex2D(normalDepthMapSampler, vertexInput.uv1);
half4 c = tex2D(normalDepthMapSampler, vertexInput.uv2);
half4 d = tex2D(normalDepthMapSampler, vertexInput.uv3);
half4 e = tex2D(normalDepthMapSampler, vertexInput.uv4);
// Optional ?
a = normalize(a - 0.5);
b = normalize(b - 0.5);
c = normalize(c - 0.5);
d = normalize(d - 0.5);
e = normalize(e - 0.5);
// Edge detection
float4 filter = abs(-a -b + 4*c -d -e);
float filterFactorN = (filter.x + filter.y + filter.z) * normalTimesFactor;
float filterFactorD = filter.w * depthTimesFactor;
float filterFactor = filterFactorN + filterFactorD;
// Blend scene
//float4 finalColor = float4(0.0f, 0.0f, 0.0f, 1.0f);
float4 finalColor = float4(edgeColor, edgeColor, edgeColor, 1.0f);
if (filterFactor < 1.0f/borderDetectionFactor)
finalColor = tex2D(tonsMapSampler, vertexInput.uv2);
/*
//finalColor = float4(filter.xyz, 1.0f);
filterFactor *= 0.2 * borderDetectionFactor;
finalColor = float4(filterFactor, filterFactor, filterFactor, 1.0f);
*/
return finalColor;
}
// ---------------------------------------------------------
float4 laplacian8EdgePS(ps2Pass2Input vertexInput) : color0
{
// Read five pixels
half4 a = tex2D(normalDepthMapSampler, vertexInput.uv0);
half4 b = tex2D(normalDepthMapSampler, vertexInput.uv1);
half4 c = tex2D(normalDepthMapSampler, vertexInput.uv2);
half4 d = tex2D(normalDepthMapSampler, vertexInput.uv3);
half2 texcoord = (vertexInput.uv3 + vertexInput.uv5) * 0.5f;
half4 e = tex2D(normalDepthMapSampler, texcoord);
half4 f = tex2D(normalDepthMapSampler, vertexInput.uv5);
half4 g = tex2D(normalDepthMapSampler, vertexInput.uv6);
half4 h = tex2D(normalDepthMapSampler, vertexInput.uv7);
half4 i = tex2D(normalDepthMapSampler, vertexInput.uv8);
// Optional
a = normalize(a - 0.5);
b = normalize(b - 0.5);
c = normalize(c - 0.5);
d = normalize(d - 0.5);
e = normalize(e - 0.5);
f = normalize(f - 0.5);
g = normalize(g - 0.5);
h = normalize(h - 0.5);
i = normalize(i - 0.5);
// Edge detection
float4 filter = abs(-a -b -c -d + 8*e -f -g -h -i);
float filterFactorN = (filter.x + filter.y + filter.z) * normalTimesFactor;
float filterFactorD = filter.w * depthTimesFactor;
float filterFactor = filterFactorN + filterFactorD;
// Blend scene
//float4 finalColor = float4(0.0f, 0.0f, 0.0f, 1.0f);
float4 finalColor = float4(edgeColor, edgeColor, edgeColor, 1.0f);
if (filterFactor * 0.5f < 1.0f/borderDetectionFactor)
finalColor = tex2D(tonsMapSampler, texcoord);
/*
filterFactor = max(filterFactor / 1.0f, 0);
float4 finalColor = float4(filterFactor, filterFactor, filterFactor, 1.0f);
*/
//finalColor = float4(filter.xyz, 1.0f);
return finalColor;
}
/**
* Techniques
*/
technique depthMap <
string ScriptClass = "scene";
string ScriptOrder = "standard";
string ScriptOutput = "color";
string Script =
"Pass=MRT_NormalDepth_Color;";
>
{
pass MRT_NormalDepth_Color <
string Script =
"RenderColorTarget0=;"
"ClearSetColor=ClearColor;"
"ClearSetDepth=ClearDepth;"
"Clear=Color;"
"Clear=Depth;"
"Draw=Geometry;"
;
>
{
//CullMode = CCW;
ZEnable = true;
ZWriteEnable = true;
VertexShader = compile vs_1_1 normalDepthVS();
PixelShader = compile ps_2_0 depthPS();
}
}
// ---------------------------------------------------------
technique normalMap <
string ScriptClass = "scene";
string ScriptOrder = "standard";
string ScriptOutput = "color";
string Script =
"Pass=MRT_NormalDepth_Color;";
>
{
pass MRT_NormalDepth_Color <
string Script =
"RenderColorTarget0=;"
"ClearSetColor=ClearColor;"
"ClearSetDepth=ClearDepth;"
"Clear=Color;"
"Clear=Depth;"
"Draw=Geometry;"
;
>
{
//CullMode = CCW;
ZEnable = true;
ZWriteEnable = true;
VertexShader = compile vs_1_1 normalDepthVS();
PixelShader = compile ps_2_0 normalPS();
}
}
// ---------------------------------------------------------
technique laplacianEdge3tons <
string ScriptClass = "scene";
string ScriptOrder = "standard";
string ScriptOutput = "color";
string Script =
"Pass=MRT_NormalDepth_Color;"
"Pass=Border;";
>
{
pass MRT_NormalDepth_Color <
string Script =
"RenderColorTarget0=tonsMap;"
"RenderColorTarget1=normalDepthMap;"
"RenderDepthStencilTarget=depthMap;"
"ClearSetColor=ClearColor;"
"ClearSetDepth=ClearDepth;"
"Clear=Color;"
"Clear=Depth;"
"Draw=Geometry;"
;
>
{
//CullMode = CCW;
ZEnable = true;
ZWriteEnable = true;
VertexShader = compile vs_1_1 normalDepthVS();
PixelShader = compile ps_2_0 normalDepth3tonsPS();
}
pass Border <
string Script =
"RenderColorTarget0=;"
"RenderColorTarget1=;"
"RenderDepthStencilTarget=;"
"Draw=Buffer;";
>
{
//CullMode = CCW;
ZEnable = false;
ZWriteEnable = false;
VertexShader = compile vs_1_1 edgeVS(edgeWidth/ScreenSize.x,
edgeWidth/ScreenSize.y);
PixelShader = compile ps_2_0 laplacianEdgePS();
}
}
// ---------------------------------------------------------
technique laplacianEdge3tonsHatching <
string ScriptClass = "scene";
string ScriptOrder = "standard";
string ScriptOutput = "color";
string Script =
"Pass=MRT_NormalDepth_Color;"
"Pass=Border;";
>
{
pass MRT_NormalDepth_Color <
string Script =
"RenderColorTarget0=tonsMap;"
"RenderColorTarget1=normalDepthMap;"
"ClearSetColor=ClearColor;"
"ClearSetDepth=ClearDepth;"
"Clear=Color;"
"Clear=Depth;"
"Draw=Geometry;"
;
>
{
//CullMode = CCW;
ZEnable = true;
ZWriteEnable = true;
VertexShader = compile vs_1_1 normalDepthVS();
PixelShader = compile ps_2_0 normalDepth3tonsHatchingPS();
}
pass Border <
string Script =
"RenderColorTarget0=;"
"RenderColorTarget1=;"
"Draw=Buffer;";
>
{
//CullMode = CCW;
ZEnable = false;
ZWriteEnable = false;
VertexShader = compile vs_1_1 edgeVS(edgeWidth/ScreenSize.x,
edgeWidth/ScreenSize.y);
PixelShader = compile ps_2_0 laplacianEdgePS();
}
}
// ---------------------------------------------------------
/**
* Algumas vezes essa técnica diminui o alising da borda
*/
technique laplacian8Edge3tons <
string ScriptClass = "scene";
string ScriptOrder = "standard";
string ScriptOutput = "color";
string Script =
"Pass=MRT_NormalDepth_Color;"
"Pass=Border;";
>
{
pass MRT_NormalDepth_Color <
string Script =
"RenderColorTarget0=tonsMap;"
"RenderColorTarget1=normalDepthMap;"
"ClearSetColor=ClearColor;"
"ClearSetDepth=ClearDepth;"
"Clear=Color;"
"Clear=Depth;"
"Draw=Geometry;"
;
>
{
//CullMode = CCW;
ZEnable = true;
ZWriteEnable = true;
VertexShader = compile vs_1_1 normalDepthVS();
PixelShader = compile ps_2_0 normalDepth3tonsPS();
}
pass Border <
string Script =
"RenderColorTarget0=;"
"RenderColorTarget1=;"
"Draw=Buffer;";
>
{
//CullMode = CCW;
ZEnable = false;
ZWriteEnable = false;
VertexShader = compile vs_1_1 edge8VS(edgeWidth/ScreenSize.x,
edgeWidth/ScreenSize.y);
PixelShader = compile ps_2_0 laplacian8EdgePS();
}
}
/**
Depth vs. Unique Objects
Parece que o depth só encontra bordas entre objetos,
não no mesmo objeto. Apesar disso, segundo o paper da
nVidia o depth é utilizado em conjunto com a normal para
diminuir a precisão da detecção de bordas.
TESTES:
Modifiquei o fator de distância para 10x e não houve mudança
na detecção de bordas, talvez seja melhor modificar isso
por um id de objetos únicos utilizando 16 bits.
ALESSANDRO:
Parece que as espessuras de bordas de normais e profundidade
eram diferentes
*/
/**
4 acessos a textura vs. 8 acessos a textura
Parece que a única diferença é a melhora no alising
na borda em alguns treços onde tem falha nas fordas em
alguns pontos. No entando em muitos objetos o aling é
aumentado na verdade.
SOLUÇÂO:
Talves fosse melhor aplicar um filtro nas bordas.
*/
/**
Problemas sanados:
- Adicionado CullMode = CCW em todas as técnicas
- Uso de MRT
- Renderização direta para textura
- Trabalhando com pontos flutuantes de 16 bits para cálculos
- Adição de hatching básico
- Considerando normais positivas e negativas, mesma formula do
bump mapping
- Consertar normais, antes de fazer (n * 0.5 + 0.5) tem que
normalizar a normal
- Melhorar balanceamento passando vários cálculos para o VS
TODO:
- mostrar o efeito de só adicionar o especular por último
- No artigo
- Utilizar filtro blur ao invés de super sampling
- Utilizar o Maya, Exporter do MAX, ou Pete's OGL2 Plugin,
para aplicar o shader a jogos reais
- Usar modificadores de GAMMA nos mapas internos para controlar a
densidade das bordas
- Usar filtros de segundo nível, ao invés do sobel de primeiro nível
- Melhorar hatching
- Considerar LOD
- Testar a detecção com tangente e binormal ao invés da normal
- Adicionar sombra
- Adicionar aquele quadriculado na cena de imagens antigas
- Exportar ambientes com o Viewer e testar o shader
- Adicionar cor única aos objetos
- Adicionar super sampling (falar do paper do McGuire que tem o filling de
gap dos traços)
- Usar blending ao invés de renderizar para texturas
- Usar blending ADD para fazer cor única dos objetos
- Adicionar deffered, par facilitar cálculo com várias luzes
(Ambient Occlusion using Hardware Shadow Maps)
http://download.nvidia.com/developer/SDK/Individual_Samples/samples.html
- Adicionar Deph of Field pode ser uma boa! =)
// Clean up inaccurracies
Pos.xy = sign(Pos.xy);
Out.Pos = float4(Pos.xy, 0, 1);
// ---------------------------------------------
// Cartoon shader
// Two pass cartoon rendering technique featuring
// three-tone shading and silhouette detection
//
// Author: Bruno P. Evangelista
// www.brunoevangelista.com
// ---------------------------------------------
/**
* Execution script
*/
float Script : STANDARDSGLOBAL <
string UIWidget = "none";
string ScriptClass = "scene";
string ScriptOrder = "standard";
string ScriptOutput = "color";
string Script = "Technique=technique?depthMap:normalMap:laplacianEdge3tons:laplacian8Edge3tons:laplacianEdge3tonsHatching;";
> = 0.8; // version #
/**
* Projection, View and World matrix
*/
float4x4 matWVP : WorldViewProjection <string UIWidget = "none";>;
float4x4 matWV : WorldView <string UIWidget = "none";>;
float4x4 matV : View <string UIWidget = "none";>;
float4x4 matW : World <string UIWidget = "none";>;
/**
* Scene objects
*/
float near
<
string UIName = "Z Near Plane";
string UIWidget = "slider";
float UIMin = 1.0f;
float UIMax = 5.0f;
float UIStep = 0.5f;
> = {1.0f};
float far
<
string UIName = "Z Far Plane";
string UIWidget = "slider";
float UIMin = 10.0f;
float UIMax = 100.0f;
float UIStep = 1.0f;
> = {12.0f};
float3 pointLightPosition : position
<
string UIWidget = "none";
//string space = "World";
string object = "Pointlight";
//> = { -3.0, 5.0, -2.5 };
> = { 0.0, 1.0, -1.0 };
float ambientLight <
string UIName = "Ambient Light Intensity";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 1.0f;
float UIStep = 0.1f;
> = {0.3f};
float diffuseLight <
string UIName = "Diffuse Light Intensity";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 1.0f;
float UIStep = 0.1f;
> = {0.6f};
float specularLight <
string UIName = "Specular Light Intensity";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 1.0f;
float UIStep = 0.1f;
> = {0.4f};
float shininess <
string UIName = "Specular shininess";
string UIWidget = "slider";
float UIMin = 8.0f;
float UIMax = 128.0f;
float UIStep = 8.0f;
> = {24.0f};
float4 ClearColor <
string UIWidget = "color";
string UIName = "Scene Background";
> = {1.0, 1.0, 1.0, 1.0};
float depthTimesFactor <
string UIName = "Depth times factor";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 10.0f;
float UIStep = 1.0f;
> = {3.0f};
float normalTimesFactor <
string UIName = "Normal times factor";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 10.0f;
float UIStep = 1.0f;
> = {1.0f};
float borderDetectionFactor <
string UIName = "Border detection";
string UIWidget = "slider";
float UIMin = 0.2f;
float UIMax = 10.0f;
float UIStep = 0.2f;
> = {2.4f};
float edgeWidth <
string UIName = "Edge width";
string UIWidget = "slider";
float UIMin = 0.9f;
float UIMax = 4.0f;
float UIStep = 0.1f;
> = {1.0f};
float edgeColor <
string UIName = "Edge color";
string UIWidget = "slider";
float UIMin = 0.0f;
float UIMax = 1.0f;
float UIStep = 0.1f;
> = {0.0f};
float ClearDepth <string UIWidget = "none";> = 1.0;
half2 ScreenSize : VIEWPORTPIXELSIZE < string UIWidget="None"; >;
/**
* Default texture
*/
texture textureMap : diffuse
<
string UIName = "Objects texture";
string ResourceName = "dm2.jpg";
string ResourceType = "2D";
>;
sampler textureSampler = sampler_state
{
texture = <textureMap>;
//addressU = clamp;
//addressV = clamp;
mipFilter = linear;
minFilter = linear;
magFilter = linear;
//mipFilter = point;
//minFilter = linear;
//magFilter = linear;
};
/**
* Normal + Depth texture
*
* Extracted from the model render.
*/
texture normalDepthMap : renderColorTarget
<
float2 viewPortRatio = {1.0f, 1.0f};
int mipLevels = 1;
string format = "A8R8G8B8";
//string format = "A16B16G16R16";
string UIWidget = "none";
>;
// Sampler
sampler normalDepthMapSampler = sampler_state
{
texture = <normalDepthMap>;
addressU = clamp;
addressV = clamp;
//mipFilter = point;
//minFilter = linear;
//magFilter = linear;
};
/**
* Hatching texture
*/
texture hatching1Map : diffuse
<
string UIName = "Hatching map lv1";
string ResourceName = "dm2.jpg";
string ResourceType = "2D";
//int mipLevels = 5;
>;
sampler hatching1MapSample = sampler_state
{
texture = <hatching1Map>;
addressU = clamp;
addressV = clamp;
//mipFilter = linear;
//minFilter = linear;
//magFilter = linear;
};
texture hatching2Map : diffuse
<
string UIName = "Hatching map lv2";
string ResourceName = "dm2.jpg";
string ResourceType = "2D";
//int mipLevels = 5;
>;
sampler hatching2MapSample = sampler_state
{
texture = <hatching2Map>;
addressU = clamp;
addressV = clamp;
//mipFilter = linear;
//minFilter = linear;
//magFilter = linear;
};
/**
* Rendered Scene
*
* I had problems blending the scene
*/
texture tonsMap : renderColorTarget
<
float2 viewPortRatio = {1.0f, 1.0f};
int mipLevels = 1;
string format = "A8R8G8B8";
string UIWidget = "none";
>;
// Sampler
sampler tonsMapSampler = sampler_state
{
texture = <tonsMap>;
addressU = clamp;
addressV = clamp;
//mipFilter = point;
//minFilter = linear;
//magFilter = linear;
};
texture depthMap : renderDepthStencilTarget
<
float2 viewPortRatio = {1.0f, 1.0f};
// TODO Olhar os formatos no manual do Dx9
//string format = "D16";
string format = "D24X8";
string UIWidget = "none";
>;
// Sampler
sampler depthSampler = sampler_state
{
texture = <depthMap>;
addressU = clamp;
addressV = clamp;
//mipFilter = point;
//minFilter = linear;
//magFilter = linear;
};
/**
* Vertex structures
*/
struct vsPass1Input
{
half3 position : position;
half3 normal : normal0;
half2 texcoord : texcoord0;
};
struct psPass1Input
{
float4 hpos : position;
half4 normal : texcoord0;
half3 lightVec : texcoord1;
half3 halfVec : texcoord2;
half2 texcoord : texcoord3;
//half zbuffer : texcoord4;
};
struct vsPass2Input
{
float4 position : position;
half2 texcoord : texcoord0;
};
// Use 5 texture acess
struct psPass2Input
{
float4 hpos : position;
half2 uv0 : texcoord0;
half2 uv1 : texcoord1;
half2 uv2 : texcoord2;
half2 uv3 : texcoord3;
half2 uv4 : texcoord4;
};
// Use 9 texture acess
struct ps2Pass2Input
{
float4 hpos : position;
half2 uv0 : texcoord0;
half2 uv1 : texcoord1;
half2 uv2 : texcoord2;
half2 uv3 : texcoord3;
//half2 uv4 : texcoord4;
half2 uv5 : texcoord4;
half2 uv6 : texcoord5;
half2 uv7 : texcoord6;
half2 uv8 : texcoord7;
};
/**
* Shaders
*/
psPass1Input normalDepthVS(vsPass1Input vertexIn)
{
psPass1Input vertexOut;
// Vertex in clip space
float4 pos = float4(vertexIn.position.xyz, 1.0f);
vertexOut.hpos = mul(pos, matWVP);
// Vertex in World_View space
half3 vpos = mul(pos, matWV).xyz;
// Light position in View Space
half3 lightPos = mul(half4(pointLightPosition.xyz, 1.0f), matV).xyz;
//vertexOut.lightPos = mul(lightPos, matV).xyz;
//vertexOut.lightPos = lightPos.xyz;
// Calculate light direction vector
vertexOut.lightVec = lightPos - vpos;
// Calculate the half vec (LightVec+EyeVec) * 0.5
vertexOut.halfVec = vertexOut.lightVec - vpos;
// Per-vertex depth approach (Interpola, por pixel)
//vertexOut.zbuffer = (vpos.z - near) / (far - near);
//half depth = (vertexIn.vpos.z - near) / (far - near);
// Normal in world space
half4 normal = mul(half4(vertexIn.normal.xyz, 0.0f), matWV);
// Normal (X, Y, Z), Depth W
vertexOut.normal = half4(normal.xyz, (vpos.z - near) / (far-near));
// Texcoord
vertexOut.texcoord = vertexIn.texcoord;
return vertexOut;
}
// ---------------------------------------------------------
float4 normalDepth3tonsPS(
psPass1Input vertexIn,
out half4 normalDepthMap : COLOR1
) : COLOR0
{
// Normalize normal and depth
//half4 normalDepth = normalize(vertexIn.normal);
//half3 n = normalDepth.xyz;
half3 n = normalize(vertexIn.normal.xyz);
float w = normalize(vertexIn.normal.w);
// Normalize all other components
half3 l = normalize(vertexIn.lightVec);
half3 h = normalize(vertexIn.halfVec);
// Write the normal depth map
//normalDepthMap = normalDepth;
//normalDepthMap = half4(n.x, n.y, -n.z, w);
float4 depthColor = tex2D(depthSampler, vertexIn.texcoord);
half3 nCopy = (n * 0.5) + 0.5;
normalDepthMap = half4(nCopy.x, nCopy.y, nCopy.z, w);
//normalDepthMap = half4(depthColor.x, depthColor.y, depthColor.z, 1.0);
// Light intensity (ambient + diffuse + specular)
half lightIntensity = ambientLight;
// Diffuse light
half diffInt = saturate(dot(l, n));
if (diffInt >= 0.3)
lightIntensity += diffuseLight;
// Specular light (Need optimize in POW)
half specInt = saturate(dot(h, n));
if (pow(specInt, shininess) > 0.4)
lightIntensity += specularLight;
return float4((lightIntensity *
tex2D(textureSampler, vertexIn.texcoord)).xyz, 1.0f);
/*
depthColor *= 1000000;
return float4(depthColor.x, depthColor.y, depthColor.z, depthColor.w);
*/
}
// ---------------------------------------------------------
float4 normalDepth3tonsHatchingPS(
psPass1Input vertexIn,
out half4 normalDepthMap : COLOR1
) : COLOR0
{
// Normalize normal and depth
//half4 normalDepth = normalize(vertexIn.normal);
//half3 n = normalDepth.xyz;
half3 n = normalize(vertexIn.normal.xyz);
float w = normalize(vertexIn.normal.w);
// Normalize all other components
half3 l = normalize(vertexIn.lightVec);
half3 h = normalize(vertexIn.halfVec);
// Write the normal depth map
//normalDepthMap = normalDepth;
half3 nCopy = (n * 0.5) + 0.5;
normalDepthMap = half4(nCopy.x, nCopy.y, nCopy.z, w);
//normalDepthMap = half4(n.x, n.y, -n.z, w);
// Light intensity (ambient + diffuse + specular)
//half lightIntensity = ambientLight;
// Invert UV coords
half x = vertexIn.texcoord.x;
vertexIn.texcoord.x = vertexIn.texcoord.y;
vertexIn.texcoord.y = x;
half3 hatchTex = tex2D(hatching2MapSample, vertexIn.texcoord);
float lightIntensity = (hatchTex.x + hatchTex.y + hatchTex.z) * 0.5;
if (lightIntensity > ambientLight)
lightIntensity = ambientLight;
// Diffuse light
half diffInt = saturate(dot(l, n));
if (diffInt >= 0.3)
{
hatchTex = tex2D(hatching1MapSample, vertexIn.texcoord);
lightIntensity = (hatchTex.x + hatchTex.y + hatchTex.z) * 0.5;
if (lightIntensity > diffuseLight)
lightIntensity = diffuseLight;
// Specular light (Need optimize in POW)
half specInt = saturate(dot(h, n));
if (pow(specInt, shininess) > 0.4)
lightIntensity += specularLight;
}
return float4((lightIntensity *
tex2D(textureSampler, vertexIn.texcoord)).xyz, 1.0f);
}
// ---------------------------------------------------------
float4 depthPS(psPass1Input vertexIn) : COLOR0
{
// Normalize normal and depth
half4 normalDepth = normalize(vertexIn.normal);
return float4(vertexIn.normal.w, vertexIn.normal.w,
vertexIn.normal.w, 1.0f);
}
// ---------------------------------------------------------
float4 normalPS(psPass1Input vertexIn) : COLOR0
{
// Normalize normal and depth
half3 n = normalize(vertexIn.normal.xyz);
n = (n * 0.5) + 0.5;
return float4(n.x, n.y, n.z, 1.0f);
}
// ---------------------------------------------------------
psPass2Input edgeVS(
vsPass2Input vertexInput,
uniform half u,
uniform half v)
{
psPass2Input vertexOut;
// Final position
vertexOut.hpos = vertexInput.position;
// Faster if used as a function parameter?
//half u = edgeWidth/ScreenSize.x;
//half v = edgeWidth/ScreenSize.y;
half2 texcoord = vertexInput.texcoord;
vertexOut.uv0 = texcoord + half2(0.0, v);
vertexOut.uv1 = texcoord + half2(-u, 0.0f);
vertexOut.uv2 = texcoord;
vertexOut.uv3 = texcoord + half2(u, 0.0f);
vertexOut.uv4 = texcoord + half2(0.0, -v);
return vertexOut;
}
// ---------------------------------------------------------
ps2Pass2Input edge8VS(
vsPass2Input vertexInput,
uniform half u,
uniform half v)
{
ps2Pass2Input vertexOut;
// Final position
vertexOut.hpos = vertexInput.position;
// Faster if used as a function parameter?
//half u = edgeWidth/ScreenSize.x;
//half v = edgeWidth/ScreenSize.y;
half2 texcoord = vertexInput.texcoord;
vertexOut.uv0 = texcoord + half2(-u, v);
vertexOut.uv1 = texcoord + half2(0.0f, v);
vertexOut.uv2 = texcoord + half2(u, v);
vertexOut.uv3 = texcoord + half2(-u, 0.0f);
//vertexOut.uv4 = texcoord + half2(0.0f, 0.0f);
vertexOut.uv5 = texcoord + half2(u, 0.0f);
vertexOut.uv6 = texcoord + half2(-u, -v);
vertexOut.uv7 = texcoord + half2(0.0f, -v);
vertexOut.uv8 = texcoord + half2(u, -v);
return vertexOut;
}
// ---------------------------------------------------------
float4 laplacianEdgePS(psPass2Input vertexInput) : color0
{
// Read five pixels
half4 a = tex2D(normalDepthMapSampler, vertexInput.uv0);
half4 b = tex2D(normalDepthMapSampler, vertexInput.uv1);
half4 c = tex2D(normalDepthMapSampler, vertexInput.uv2);
half4 d = tex2D(normalDepthMapSampler, vertexInput.uv3);
half4 e = tex2D(normalDepthMapSampler, vertexInput.uv4);
// Optional ?
a = normalize(a - 0.5);
b = normalize(b - 0.5);
c = normalize(c - 0.5);
d = normalize(d - 0.5);
e = normalize(e - 0.5);
// Edge detection
float4 filter = abs(-a -b + 4*c -d -e);
float filterFactorN = (filter.x + filter.y + filter.z) * normalTimesFactor;
float filterFactorD = filter.w * depthTimesFactor;
float filterFactor = filterFactorN + filterFactorD;
// Blend scene
//float4 finalColor = float4(0.0f, 0.0f, 0.0f, 1.0f);
float4 finalColor = float4(edgeColor, edgeColor, edgeColor, 1.0f);
if (filterFactor < 1.0f/borderDetectionFactor)
finalColor = tex2D(tonsMapSampler, vertexInput.uv2);
/*
//finalColor = float4(filter.xyz, 1.0f);
filterFactor *= 0.2 * borderDetectionFactor;
finalColor = float4(filterFactor, filterFactor, filterFactor, 1.0f);
*/
return finalColor;
}
// ---------------------------------------------------------
float4 laplacian8EdgePS(ps2Pass2Input vertexInput) : color0
{
// Read five pixels
half4 a = tex2D(normalDepthMapSampler, vertexInput.uv0);
half4 b = tex2D(normalDepthMapSampler, vertexInput.uv1);
half4 c = tex2D(normalDepthMapSampler, vertexInput.uv2);
half4 d = tex2D(normalDepthMapSampler, vertexInput.uv3);
half2 texcoord = (vertexInput.uv3 + vertexInput.uv5) * 0.5f;
half4 e = tex2D(normalDepthMapSampler, texcoord);
half4 f = tex2D(normalDepthMapSampler, vertexInput.uv5);
half4 g = tex2D(normalDepthMapSampler, vertexInput.uv6);
half4 h = tex2D(normalDepthMapSampler, vertexInput.uv7);
half4 i = tex2D(normalDepthMapSampler, vertexInput.uv8);
// Optional
a = normalize(a - 0.5);
b = normalize(b - 0.5);
c = normalize(c - 0.5);
d = normalize(d - 0.5);
e = normalize(e - 0.5);
f = normalize(f - 0.5);
g = normalize(g - 0.5);
h = normalize(h - 0.5);
i = normalize(i - 0.5);
// Edge detection
float4 filter = abs(-a -b -c -d + 8*e -f -g -h -i);
float filterFactorN = (filter.x + filter.y + filter.z) * normalTimesFactor;
float filterFactorD = filter.w * depthTimesFactor;
float filterFactor = filterFactorN + filterFactorD;
// Blend scene
//float4 finalColor = float4(0.0f, 0.0f, 0.0f, 1.0f);
float4 finalColor = float4(edgeColor, edgeColor, edgeColor, 1.0f);
if (filterFactor * 0.5f < 1.0f/borderDetectionFactor)
finalColor = tex2D(tonsMapSampler, texcoord);
/*
filterFactor = max(filterFactor / 1.0f, 0);
float4 finalColor = float4(filterFactor, filterFactor, filterFactor, 1.0f);
*/
//finalColor = float4(filter.xyz, 1.0f);
return finalColor;
}
/**
* Techniques
*/
technique depthMap <
string ScriptClass = "scene";
string ScriptOrder = "standard";
string ScriptOutput = "color";
string Script =
"Pass=MRT_NormalDepth_Color;";
>
{
pass MRT_NormalDepth_Color <
string Script =
"RenderColorTarget0=;"
"ClearSetColor=ClearColor;"
"ClearSetDepth=ClearDepth;"
"Clear=Color;"
"Clear=Depth;"
"Draw=Geometry;"
;
>
{
//CullMode = CCW;
ZEnable = true;
ZWriteEnable = true;
VertexShader = compile vs_1_1 normalDepthVS();
PixelShader = compile ps_2_0 depthPS();
}
}
// ---------------------------------------------------------
technique normalMap <
string ScriptClass = "scene";
string ScriptOrder = "standard";
string ScriptOutput = "color";
string Script =
"Pass=MRT_NormalDepth_Color;";
>
{
pass MRT_NormalDepth_Color <
string Script =
"RenderColorTarget0=;"
"ClearSetColor=ClearColor;"
"ClearSetDepth=ClearDepth;"
"Clear=Color;"
"Clear=Depth;"
"Draw=Geometry;"
;
>
{
//CullMode = CCW;
ZEnable = true;
ZWriteEnable = true;
VertexShader = compile vs_1_1 normalDepthVS();
PixelShader = compile ps_2_0 normalPS();
}
}
// ---------------------------------------------------------
technique laplacianEdge3tons <
string ScriptClass = "scene";
string ScriptOrder = "standard";
string ScriptOutput = "color";
string Script =
"Pass=MRT_NormalDepth_Color;"
"Pass=Border;";
>
{
pass MRT_NormalDepth_Color <
string Script =
"RenderColorTarget0=tonsMap;"
"RenderColorTarget1=normalDepthMap;"
"RenderDepthStencilTarget=depthMap;"
"ClearSetColor=ClearColor;"
"ClearSetDepth=ClearDepth;"
"Clear=Color;"
"Clear=Depth;"
"Draw=Geometry;"
;
>
{
//CullMode = CCW;
ZEnable = true;
ZWriteEnable = true;
VertexShader = compile vs_1_1 normalDepthVS();
PixelShader = compile ps_2_0 normalDepth3tonsPS();
}
pass Border <
string Script =
"RenderColorTarget0=;"
"RenderColorTarget1=;"
"RenderDepthStencilTarget=;"
"Draw=Buffer;";
>
{
//CullMode = CCW;
ZEnable = false;
ZWriteEnable = false;
VertexShader = compile vs_1_1 edgeVS(edgeWidth/ScreenSize.x,
edgeWidth/ScreenSize.y);
PixelShader = compile ps_2_0 laplacianEdgePS();
}
}
// ---------------------------------------------------------
technique laplacianEdge3tonsHatching <
string ScriptClass = "scene";
string ScriptOrder = "standard";
string ScriptOutput = "color";
string Script =
"Pass=MRT_NormalDepth_Color;"
"Pass=Border;";
>
{
pass MRT_NormalDepth_Color <
string Script =
"RenderColorTarget0=tonsMap;"
"RenderColorTarget1=normalDepthMap;"
"ClearSetColor=ClearColor;"
"ClearSetDepth=ClearDepth;"
"Clear=Color;"
"Clear=Depth;"
"Draw=Geometry;"
;
>
{
//CullMode = CCW;
ZEnable = true;
ZWriteEnable = true;
VertexShader = compile vs_1_1 normalDepthVS();
PixelShader = compile ps_2_0 normalDepth3tonsHatchingPS();
}
pass Border <
string Script =
"RenderColorTarget0=;"
"RenderColorTarget1=;"
"Draw=Buffer;";
>
{
//CullMode = CCW;
ZEnable = false;
ZWriteEnable = false;
VertexShader = compile vs_1_1 edgeVS(edgeWidth/ScreenSize.x,
edgeWidth/ScreenSize.y);
PixelShader = compile ps_2_0 laplacianEdgePS();
}
}
// ---------------------------------------------------------
/**
* Algumas vezes essa técnica diminui o alising da borda
*/
technique laplacian8Edge3tons <
string ScriptClass = "scene";
string ScriptOrder = "standard";
string ScriptOutput = "color";
string Script =
"Pass=MRT_NormalDepth_Color;"
"Pass=Border;";
>
{
pass MRT_NormalDepth_Color <
string Script =
"RenderColorTarget0=tonsMap;"
"RenderColorTarget1=normalDepthMap;"
"ClearSetColor=ClearColor;"
"ClearSetDepth=ClearDepth;"
"Clear=Color;"
"Clear=Depth;"
"Draw=Geometry;"
;
>
{
//CullMode = CCW;
ZEnable = true;
ZWriteEnable = true;
VertexShader = compile vs_1_1 normalDepthVS();
PixelShader = compile ps_2_0 normalDepth3tonsPS();
}
pass Border <
string Script =
"RenderColorTarget0=;"
"RenderColorTarget1=;"
"Draw=Buffer;";
>
{
//CullMode = CCW;
ZEnable = false;
ZWriteEnable = false;
VertexShader = compile vs_1_1 edge8VS(edgeWidth/ScreenSize.x,
edgeWidth/ScreenSize.y);
PixelShader = compile ps_2_0 laplacian8EdgePS();
}
}
/**
Depth vs. Unique Objects
Parece que o depth só encontra bordas entre objetos,
não no mesmo objeto. Apesar disso, segundo o paper da
nVidia o depth é utilizado em conjunto com a normal para
diminuir a precisão da detecção de bordas.
TESTES:
Modifiquei o fator de distância para 10x e não houve mudança
na detecção de bordas, talvez seja melhor modificar isso
por um id de objetos únicos utilizando 16 bits.
ALESSANDRO:
Parece que as espessuras de bordas de normais e profundidade
eram diferentes
*/
/**
4 acessos a textura vs. 8 acessos a textura
Parece que a única diferença é a melhora no alising
na borda em alguns treços onde tem falha nas fordas em
alguns pontos. No entando em muitos objetos o aling é
aumentado na verdade.
SOLUÇÂO:
Talves fosse melhor aplicar um filtro nas bordas.
*/
/**
Problemas sanados:
- Adicionado CullMode = CCW em todas as técnicas
- Uso de MRT
- Renderização direta para textura
- Trabalhando com pontos flutuantes de 16 bits para cálculos
- Adição de hatching básico
- Considerando normais positivas e negativas, mesma formula do
bump mapping
- Consertar normais, antes de fazer (n * 0.5 + 0.5) tem que
normalizar a normal
- Melhorar balanceamento passando vários cálculos para o VS
TODO:
- mostrar o efeito de só adicionar o especular por último
- No artigo
- Utilizar filtro blur ao invés de super sampling
- Utilizar o Maya, Exporter do MAX, ou Pete's OGL2 Plugin,
para aplicar o shader a jogos reais
- Usar modificadores de GAMMA nos mapas internos para controlar a
densidade das bordas
- Usar filtros de segundo nível, ao invés do sobel de primeiro nível
- Melhorar hatching
- Considerar LOD
- Testar a detecção com tangente e binormal ao invés da normal
- Adicionar sombra
- Adicionar aquele quadriculado na cena de imagens antigas
- Exportar ambientes com o Viewer e testar o shader
- Adicionar cor única aos objetos
- Adicionar super sampling (falar do paper do McGuire que tem o filling de
gap dos traços)
- Usar blending ao invés de renderizar para texturas
- Usar blending ADD para fazer cor única dos objetos
- Adicionar deffered, par facilitar cálculo com várias luzes
(Ambient Occlusion using Hardware Shadow Maps)
http://download.nvidia.com/developer/SDK/Individual_Samples/samples.html
- Adicionar Deph of Field pode ser uma boa! =)
// Clean up inaccurracies
Pos.xy = sign(Pos.xy);
Out.Pos = float4(Pos.xy, 0, 1);