Hey! I’m trying to apply simple shaders in Unity but I have a little problem with my shader code.
Shader "Hidden/Toon Effect" {
Properties {
_MainTex ("Base (RGB)", RECT) = "white" {}
_LightDir ("Light Direction", Vector) = (5.2,10,1,1)
}
SubShader {
Pass {
ZTest Always Cull Off ZWrite Off
Fog { Mode off }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
uniform samplerRECT _MainTex;
uniform float4 _LightDir;
struct v2f {
float4 vertex : POSITION;
float3 normal;
float2 texcoord;
};
v2f vert (appdata_base v) {
v2f o;
o.vertex = mul(glstate.matrix.mvp, v.vertex);
o.normal = mul((float3x3)glstate.matrix.invtrans.modelview[0], v.normal );
o.texcoord = float2(v.texcoord);
return o;
}
float4 frag (v2f data) : COLOR {
float intensity = 0.0;
float cos = dot(data.normal,float3(_LightDir));
float4 pixelColor = texRECT(_MainTex,data.texcoord);
if (cos > 0.95) {
intensity = 1;
} else if (cos > 0.65) {
intensity = 0.7;
} else if (cos > 0.25) {
intensity = 0.55;
} else {
intensity = 0.3;
}
pixelColor.rgb *= intensity;
return pixelColor;
}
ENDCG
}
}
Fallback off
}
My code does not detect different levels, it only applies the effects to the last condition, any ideas on what’s wrong?
Quick guess: You need to dot against the negative lightdir.
Edit: Oh - and you may want to normalize the LightDir.
Shader "Hidden/Toon Effect" {
Properties {
_MainTex ("Base (RGB)", RECT) = "white" {}
_LightDir ("Light Direction", Vector) = (5.2,10,1,1)
}
SubShader {
Pass {
ZTest Always Cull Off ZWrite Off
Tags { "LightMode" = "Always" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
uniform samplerRECT _MainTex;
uniform float4 _LightDir;
struct v2f {
float4 vertex : POSITION;
float3 normal;
float2 texcoord;
};
v2f vert (appdata_base v) {
v2f o;
o.vertex = mul(glstate.matrix.mvp, v.vertex);
o.normal = mul((float3x3)glstate.matrix.invtrans.modelview[0], v.normal );
o.texcoord = float2(v.texcoord);
return o;
}
float4 frag (v2f data) : COLOR {
float intensity = 0.0;
float3 norm = normalize(float3(_LightDir));
float cos = dot(data.normal,-norm);
float4 pixelColor = texRECT(_MainTex,data.texcoord);
if (cos > 0.95) {
intensity = 1;
} else if (cos > 0.65) {
intensity = 0.7;
} else if (cos > 0.25) {
intensity = 0.55;
} else {
intensity = 0.3;
}
pixelColor.rgb *= intensity;
return pixelColor;
}
ENDCG
}
}
Fallback off
}
I changed the code but nothing different happened. Any ideias?
I tried your shader, and it seems to work somewhat (at least better) if you replace texRECT with tex2D. Not sure why, though.
Edited the script a bit (not saying that this is the best solution):
Shader "Hidden/Toon Effect" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_LightDir ("Light Direction", Vector) = (5.2,10,1,1)
}
SubShader {
Pass {
//ZTest Always
//Cull Off
//ZWrite On
Tags { "LightMode" = "Always" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
uniform sampler2D _MainTex;
uniform float4 _LightDir;
struct v2f {
float4 vertex : POSITION;
float3 normal;
float2 texcoord;
float3 objSpaceLightDir;
};
v2f vert (appdata_base v) {
v2f o;
o.vertex = mul(glstate.matrix.mvp, v.vertex);
o.normal = v.normal;
o.texcoord = float2(v.texcoord);
float4 lightDir = _LightDir;
lightDir.w = 0.0;
o.objSpaceLightDir = mul(_World2Object, normalize(lightDir)).xyz;
return o;
}
float4 frag (v2f data) : COLOR {
float intensity = 0.0;
float cos = dot(data.normal,-data.objSpaceLightDir);
float4 pixelColor = tex2D(_MainTex,data.texcoord);
//An alternative here is a ramp-type texture. Not sure what is recommended.
if (cos > 0.95) {
intensity = 1;
} else if (cos > 0.65) {
intensity = 0.7;
} else if (cos > 0.25) {
intensity = 0.55;
} else {
intensity = 0.3;
}
pixelColor.rgb *= intensity;
return pixelColor;
}
ENDCG
}
}
Fallback off
}
Every time that I tried to use 2D instead of RECT, this error appears: Error assigning 2D rectangle texture to 2D texture property ‘_MainTex’: Dimensions must match
And it happened again with this shader that you posted =/
Do you know why that happens?
Did I forget to import something?
Thx for the help
Well…
If this could help, I’ll post the C# code
void OnRenderImage (RenderTexture source, RenderTexture destination) {
ImageEffects.BlitWithMaterial (material, source, destination);
}
public static void BlitWithMaterial (Material material, RenderTexture source, RenderTexture destination)
{
RenderTexture.active = destination;
material.SetTexture("_MainTex", source);
/*material.hideFlags = HideFlags.HideAndDontSave;
material.shader.hideFlags = HideFlags.HideAndDontSave;*/
GL.PushMatrix ();
GL.LoadOrtho ();
for (int i = 0; i < material.passCount; i++) {
material.SetPass (i);
ImageEffects.DrawQuad();
}
GL.PopMatrix ();
}
Sorry!
I forgot to post the DrawQuad function
public static void DrawQuad()
{
GL.Begin (GL.QUADS);
GL.TexCoord2( 0.0f, 0.0f ); GL.Vertex3( 0.0f, 0.0f, 0.1f );
GL.TexCoord2( 1.0f, 0.0f ); GL.Vertex3( 1.0f, 0.0f, 0.1f );
GL.TexCoord2( 1.0f, 1.0f ); GL.Vertex3( 1.0f, 1.0f, 0.1f );
GL.TexCoord2( 0.0f, 1.0f ); GL.Vertex3( 0.0f, 1.0f, 0.1f );
GL.End();
}
Aha, I understand. Yeah, that texture is probably a RECT texture. Anyway - are you sure you want to apply that shader as a post-effect? What results do you expect? I assumed you were using it on a per-object basis.
Sorry for the mistake. I really want to apply the shader on a per-object basis, but I don’t know how to do this. I used this code because that was the shader code in Island Demo and ALL shaders in that project are post-effect (I see this clear now)
How do I apply this shader in per-object basis?
I am newbie in ShaderLab and CGProgram. I coded shaders in HLSL a long time ago.
Another question. What the basic differece between 2D and RECT? I didn’t see something like this in HLSL. It was just Texture2D
Right-click on your shader file and choose “Create Material”. Drag’n’drop this material onto your object. That should work as far as I know.
The difference between 2D and RECT is that 2D textures are looked up in the uv-range 0-1, while RECT uses 0-size (I’m not completely sure of this, as it seems like it is using 0-1 on windows - anyone, feel free to fill in/correct me on this). Also, RECT does not have to be power of two sized, which is currently the case for 2D textures in Unity.
Yeah! It works!!
Thanks ToreTank!!