I have, for a while, been trying to wrangle HLSL to add support for billboarding 2D NPCs in think DOOM or Hexen: Beyond Heretic, but I just can't seem to figure it out, or may be missing something entirely.Full code snippet below:
Shader "Sprites/Bumped Diffuse both sides with Shadows & Chroma"
{
Properties
{
[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
_BumpMap("Normalmap", 2D) = "bump" {}
_Color("Tint", Color) = (1,1,1,1)
[MaterialToggle] PixelSnap("Pixel snap", Float) = 0
_Cutoff("Alpha Cutoff", Range(0,1)) = 0.5
_ChromaKeyColour("Chroma Key Colour", Color) = (1,1,1,1)
_ChromaKeyHueRange("ChromaKey Hue Range", Float) = 0
_ChromaKeySaturationRange("ChromaKey Saturation Range", Float) = 0
_ChromaKeyBrightnessRange("ChromaKey Brightness Range", Float) = 0
_ChromaKeyNewColour("New Colour From Chroma", Color) = (1,1,1,1)
_ChromaKeyColour2("Chroma Key Colour", Color) = (1,1,1,1)
_ChromaKeyHueRange2("ChromaKey Hue Range", Float) = 0
_ChromaKeySaturationRange2("ChromaKey Saturation Range", Float) = 0
_ChromaKeyBrightnessRange2("ChromaKey Brightness Range", Float) = 0
_ChromaKeyNewColour2("New Colour From Chroma", Color) = (1,1,1,1)
_ChromaKeyColour3("Chroma Key Colour", Color) = (1,1,1,1)
_ChromaKeyHueRange3("ChromaKey Hue Range", Float) = 0
_ChromaKeySaturationRange3("ChromaKey Saturation Range", Float) = 0
_ChromaKeyBrightnessRange3("ChromaKey Brightness Range", Float) = 0
_ChromaKeyNewColour3("New Colour From Chroma", Color) = (1,1,1,1)
}
SubShader
{
Tags
{
"Queue" = "Transparent"
"IgnoreProjector" = "True"
"RenderType" = "TransparentCutOut"
"PreviewType" = "Plane"
"CanUseSpriteAtlas" = "True"
}
LOD 300
Cull Off
Lighting On
ZWrite Off
Fog { Mode Off }
CGPROGRAM
#pragma surface surf Lambert alpha vertex:vert addshadow alphatest:_Cutoff billboard
#pragma multi_compile DUMMY PIXELSNAP_ON
sampler2D _MainTex;
sampler2D _BumpMap;
fixed4 _Color;
fixed4 _ChromaKeyColour;
fixed4 _ChromaKeyNewColour;
float _ChromaKeyHueRange;
float _ChromaKeySaturationRange;
float _ChromaKeyBrightnessRange;
fixed4 _ChromaKeyColour2;
fixed4 _ChromaKeyNewColour2;
float _ChromaKeyHueRange2;
float _ChromaKeySaturationRange2;
float _ChromaKeyBrightnessRange2;
fixed4 _ChromaKeyColour3;
fixed4 _ChromaKeyNewColour3;
float _ChromaKeyHueRange3;
float _ChromaKeySaturationRange3;
float _ChromaKeyBrightnessRange3;
float _ScaleX;
struct Input
{
float2 uv_MainTex;
float2 uv_BumpMap;
fixed4 color : COLOR;
};
void vert(inout appdata_full v, out Input o)
{
#if defined(PIXELSNAP_ON) && !defined(SHADER_API_FLASH)
v.vertex = UnityPixelSnap(v.vertex);
#endif
float3 normal = v.normal;
float3 cameraToVertex = normalize(v.vertex.xyz - _WorldSpaceCameraPos.xyz);
v.normal = float3(0,1,1);
v.tangent = float4(1, 0, 0, 1);
UNITY_INITIALIZE_OUTPUT(Input, o);
o.color += _Color;
}
inline float3 ChromaKeyRGB2HSV(float3 rgb)
{
float4 k = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
float4 p = lerp(float4(rgb.bg, k.wz), float4(rgb.gb, k.xy), step(rgb.b, rgb.g));
float4 q = lerp(float4(p.xyw, rgb.r), float4(rgb.r, p.yzx), step(p.x, rgb.r));
float d = q.x - min(q.w, q.y);
float e = 1e-10;
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
inline float3 ChromaKeyHSV2RGB(float3 hsv)
{
float4 k = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
float3 p = abs(frac(hsv.xxx + k.xyz) * 6.0 - k.www);
return hsv.z * lerp(k.xxx, clamp(p - k.xxx, 0.0, 1.0), hsv.y);
}
inline float3 ChromaKeyCalcDiffrence(float4 col, float4 col_key)
{
float3 hsv = ChromaKeyRGB2HSV(col);
float3 key = ChromaKeyRGB2HSV(col_key);
return abs(hsv - key);
}
inline float3 ChromaKeyGetRange(float chromaKeyHueRange, float chromaKeySaturationRange, float chromaKeyBrightnessRange)
{
return float3(chromaKeyHueRange, chromaKeySaturationRange, chromaKeyBrightnessRange);
}
inline void ChromaKeyApplyCutout(float4 col, float4 key, float hueRange, float satRange, float briRange)
{
float3 d = ChromaKeyCalcDiffrence(col, key);
if (all(step(0.0, ChromaKeyGetRange(hueRange, satRange, briRange) - d))) discard;
}
inline void ChromaKeyApplyAlpha(inout float4 col, float4 key, float hueRange, float satRange, float briRange)
{
float3 d = ChromaKeyCalcDiffrence(col, key);
if (all(step(0.0, ChromaKeyGetRange(hueRange, satRange, briRange) - d))) discard;
col.a *= saturate(length(d / ChromaKeyGetRange(hueRange, satRange, briRange)) - 1.0);
}
inline void ChromaKeyApplyColour(inout float4 col, float4 key, float4 new_col, float hueRange, float satRange, float briRange)
{
float3 d = ChromaKeyCalcDiffrence(col, key);
if (all(step(0.0, ChromaKeyGetRange(hueRange, satRange, briRange) - d)))
{
float3 colHSV = ChromaKeyRGB2HSV(col.rgb);
float3 newColHSV = ChromaKeyRGB2HSV(new_col.rgb);
newColHSV.b *= colHSV.b;
col.rgb = ChromaKeyHSV2RGB(newColHSV);
}
}
void surf(Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * IN.color;
ChromaKeyApplyColour(c, _ChromaKeyColour, _ChromaKeyNewColour, _ChromaKeyHueRange, _ChromaKeySaturationRange, _ChromaKeyBrightnessRange);
ChromaKeyApplyColour(c, _ChromaKeyColour2, _ChromaKeyNewColour2, _ChromaKeyHueRange2, _ChromaKeySaturationRange2, _ChromaKeyBrightnessRange2);
ChromaKeyApplyColour(c, _ChromaKeyColour3, _ChromaKeyNewColour3, _ChromaKeyHueRange3, _ChromaKeySaturationRange3, _ChromaKeyBrightnessRange3);
o.Albedo = c.rgb;
o.Alpha = c.a;
o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
o.Normal.z *= -1;
}
ENDCG
}
Fallback "Transparent/Cutout/Diffuse"
}
As far as I know I want to do this through the vertex part of the shader, but I'm not sure what I actually want to manipulate - the normal would make some sense but I am not sure.
Related
So, I have found this glitch effect shader online which is working fine in the editor but when I'm building it for mobile it does not work it just shows the transparent image. I've added that shader below. I have searched online for answers and applied some of them (like always include shader in graphics settings and all that) but nothing worked.
Shader "Avi/Glitch"
{
Properties
{
[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
__CompressionFX_Value_1("__CompressionFX_Value_1", Range(0, 16)) = 3
//_SpriteFade("SpriteFade", Range(0, 1)) = 1.0
// required for UI.Mask
[HideInInspector]_StencilComp("Stencil Comparison", Float) = 8
[HideInInspector]_Stencil("Stencil ID", Float) = 0
[HideInInspector]_StencilOp("Stencil Operation", Float) = 0
[HideInInspector]_StencilWriteMask("Stencil Write Mask", Float) = 255
[HideInInspector]_StencilReadMask("Stencil Read Mask", Float) = 255
[HideInInspector]_ColorMask("Color Mask", Float) = 15
}
SubShader
{
Tags
{
"Queue" = "Transparent" "IgnoreProjector" = "true" "RenderType" = "Transparent" "PreviewType"="Plane" "CanUseSpriteAtlas"="True"
}
ZWrite Off Blend SrcAlpha OneMinusSrcAlpha Cull Off
// required for UI.Mask
Stencil
{
Ref [_Stencil]
Comp [_StencilComp]
Pass [_StencilOp]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float2 texcoord : TEXCOORD0;
float4 vertex : SV_POSITION;
float4 color : COLOR;
};
sampler2D _MainTex;
// float _SpriteFade;
float __CompressionFX_Value_1;
v2f vert(appdata_t IN)
{
v2f OUT;
OUT.vertex = UnityObjectToClipPos(IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color;
return OUT;
}
float CMPFXrng2(float2 seed)
{
return frac(sin(dot(seed * floor(50 + (_Time + 0.1) * 12.), float2(127.1, 311.7))) * 43758.5453123);
}
float CMPFXrng(float seed)
{
return CMPFXrng2(float2(seed, 1.0));
}
float4 CompressionFX(float2 uv, sampler2D source, float Value)
{
float2 blockS = floor(uv * float2(24., 19.)) * 4.0;
float2 blockL = floor(uv * float2(38., 14.)) * 4.0;
float r = CMPFXrng2(uv);
float lineNoise = pow(CMPFXrng2(blockS), 3.0) * Value * pow(CMPFXrng2(blockL), 3.0);
float4 col1 = tex2D(source, uv + float2(lineNoise * 0.02 * CMPFXrng(2.0), 0));
float4 result = float4(float3(col1.x, col1.y, col1.z), 1.0);
result.a = col1.a;
return result;
}
float4 frag(v2f i) : COLOR
{
float4 _CompressionFX_1 = CompressionFX(i.texcoord, _MainTex, __CompressionFX_Value_1);
float4 FinalResult = _CompressionFX_1;
FinalResult.rgb *= i.color.rgb;
FinalResult.a = FinalResult.a * i.color.a;
return FinalResult;
}
ENDCG
}
}
Fallback "Sprites/Default"
}
I am using unity.
I used Triplanar to make the top of the cube as snow terrain and the rest of the sides as cliff terrain.
Here I have to insert a normal map.
However, if the normal map is applied, the image of the cliff face is covered with the image of the snow terrain.
The phenomenon is shown in the following image.
Properties
{
[NoScaleOffset]_MainTex ("TopTex", 2D) = "white" {}
_MainTexUV("tileU, tileV, offsetU, offsetV", vector) = (1, 1, 0, 0)
[NoScaleOffset]_MainTex2("sideTex", 2D) = "white" {}
_MainTex2UV("tileU, tileV, offsetU, offsetV", vector) = (1, 1, 0, 0)
_Bumpmap ("NormalMap", 2D) = "bump" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
CGPROGRAM
#pragma surface surf Standard fullforwardshadows
sampler2D _MainTex;
sampler2D _MainTex2;
sampler2D _Bumpmap;
float4 _MainTexUV;
float4 _MainTex2UV;
struct Input
{
float2 uv_Bumpmap;
float3 worldPos;
float3 worldNormal;
INTERNAL_DATA
};
void surf (Input IN, inout SurfaceOutputStandard o)
{
float2 topUV = float2(IN.worldPos.x, IN.worldPos.z);
float2 frontUV = float2(IN.worldPos.x, IN.worldPos.y);
float2 sideUV = float2(IN.worldPos.z, IN.worldPos.y);
o.Normal = UnpackNormal(tex2D(_Bumpmap, IN.uv_Bumpmap));
float4 topTex = tex2D(_MainTex, topUV * _MainTexUV.xy + _MainTexUV.zw);
float4 frontTex = tex2D (_MainTex2, frontUV * _MainTex2UV.xy + _MainTex2UV.zw);
float4 sideTex = tex2D (_MainTex2, sideUV * _MainTex2UV.xy + _MainTex2UV.zw);
o.Albedo = lerp(topTex, frontTex, abs(IN.worldNormal.z));
o.Albedo = lerp(o.Albedo, sideTex, abs(IN.worldNormal.x));
o.Alpha = 1;
}
ENDCG
}
FallBack "Diffuse"
Why does this happen?
Also, how do I apply the normal map to only one side?
According to the documentation, you need to use WorldNormalVector(IN, o.Normal) instead of IN.worldNormal if you modify o.Normal;
And, to apply the normal to only one side, you can simply use a neutral normal (.5,.5,1) for the other sides and use the same lerp trick you do with the albedo:
Properties
{
[NoScaleOffset] _MainTex("TopTex", 2D) = "white" {}
_MainTexUV("tileU, tileV, offsetU, offsetV", vector) = (1, 1, 0, 0)
[NoScaleOffset]_MainTex2("sideTex", 2D) = "white" {}
_MainTex2UV("tileU, tileV, offsetU, offsetV", vector) = (1, 1, 0, 0)
_Bumpmap("NormalMap", 2D) = "bump" {}
}
SubShader
{
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Standard fullforwardshadows
sampler2D _MainTex;
sampler2D _MainTex2;
sampler2D _Bumpmap;
float4 _MainTexUV;
float4 _MainTex2UV;
struct Input
{
float2 uv_Bumpmap;
float3 worldPos;
float3 worldNormal;
INTERNAL_DATA
};
void surf(Input IN, inout SurfaceOutputStandard o)
{
float2 topUV = float2(IN.worldPos.x, IN.worldPos.z);
float2 frontUV = float2(IN.worldPos.x, IN.worldPos.y);
float2 sideUV = float2(IN.worldPos.z, IN.worldPos.y);
float3 worldNormal = WorldNormalVector(IN, o.Normal);
float3 topNormal = float3(.5, .5, 1);
float3 frontNormal = float3(.5, .5, 1);
float3 sideNormal = UnpackNormal(tex2D(_Bumpmap, IN.uv_Bumpmap));
o.Normal = lerp(topNormal, frontNormal, abs(worldNormal.z));
o.Normal = lerp(o.Normal, sideNormal, abs(worldNormal.x));
float4 topTex = tex2D(_MainTex, topUV * _MainTexUV.xy + _MainTexUV.zw);
float4 frontTex = tex2D(_MainTex2, frontUV * _MainTex2UV.xy + _MainTex2UV.zw);
float4 sideTex = tex2D(_MainTex2, sideUV * _MainTex2UV.xy + _MainTex2UV.zw);
o.Albedo = lerp(topTex, frontTex, abs(worldNormal.z));
o.Albedo = lerp(o.Albedo, sideTex, abs(worldNormal.x));
o.Alpha = 1;
}
ENDCG
}
FallBack "Diffuse"
I'm trying to convert some code from ShaderToy to Unity. This is the shader that I'm attempting to convert: https://www.shadertoy.com/view/Ws23WD.
I've successfully compiled my code, however, when I look at my shader on a sphere in Unity, it appears to be a static yellow circle. I've only changed the syntax from ShaderToy to the Unity equivalents; what could be going wrong?
Shader "Unlit/Lava"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
iChannel0 ("iChannel0", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
sampler2D iChannel0;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
#define pi (3.14159265358979323846)
#define EPSILON (0.0001)
float2 rotate(float2 v, float a)
{
float c = cos(a);
float s = sin(a);
return float2(
v.x*c-v.y*s,
v.x*s+v.y*c
);
}
float sphere(float3 p, float r)
{
return length(p)-r;
}
float scene(float3 p)
{
float b = sphere(p, 1.6);
if(b > 0.001) return b; // optimisation
float3 disp = 0;
float f = 0.5;
disp.x = tex2D(iChannel0, p.zy * 0.05 + _Time.y * 0.02).x * f;
disp.z = tex2D(iChannel0, p.xy * 0.05 + _Time.y * 0.03).z * f;
disp.y = tex2D(iChannel0, p.xz * 0.05 + _Time.y * 0.04).y * f;
return sphere(p + disp, 1.0 + sin(_Time.y*2.4) * 0.15);
}
fixed4 frag (v2f i) : SV_Target
{
//float2 uv = float2(fragCoord.x / iResolution.x, fragCoord.y / iResolution.y);
float2 uv = float2(i.uv);
uv -= 0.5;
//uv /= float2(iResolution.y / iResolution.x, 1);
float3 cam = float3(0, -0.15, -3.5);
float3 dir = normalize(float3(uv,1));
float cam_a2 = sin(_Time.y) * pi * 0.1;
cam.yz = rotate(cam.yz, cam_a2);
dir.yz = rotate(dir.yz, cam_a2);
float cam_a = _Time.y * pi * 0.1;
cam.xz = rotate(cam.xz, cam_a);
dir.xz = rotate(dir.xz, cam_a);
float4 color = float4(0.16, 0.12, 0.10, 1.0);
float t = 0.00001;
const int maxSteps = 128;
for(int i = 0; i < maxSteps; ++i) {
float3 p = cam + dir * t;
float d = scene(p);
if(d < 0.0001 * t) {
color = float4(1.0, length(p) * (0.6 + (sin(_Time.y*3.0)+1.0) * 0.5 * 0.4), 0, 0);
break;
}
t += d;
}
//fragColor.rgb = color;
return color;
//fragColor.a = 1.0;
}
ENDCG
}
}
}
You need press PLAY button to see the shader animation.
The shader works.
I made some changes to your shader. Mostly to the UV calculation and alpha blend settings.
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Unlit/Lava"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
iChannel0 ("iChannel0", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="TransparentCutout" }
LOD 100
Blend OneMinusSrcAlpha SrcAlpha // Specify blend mode. This is inverted from usual usage.
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag lambert alpha:blend // Enable alpha blend
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
float4 screenPos : TEXCOORD1;
};
sampler2D _MainTex;
sampler2D iChannel0;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.screenPos = ComputeScreenPos(o.vertex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
#define pi (3.14159265358979323846)
#define EPSILON (0.0001)
float2 rotate(float2 v, float a)
{
float c = cos(a);
float s = sin(a);
return float2(
v.x*c-v.y*s,
v.x*s+v.y*c
);
}
float sphere(float3 p, float r)
{
return length(p)-r;
}
float scene(float3 p)
{
float b = sphere(p, 1.6);
if(b > 0.001) return b; // optimisation
float3 disp = 0;
float f = 0.5;
disp.x = tex2D(iChannel0, p.zy * 0.05 + _Time.y * 0.02).x * f;
disp.z = tex2D(iChannel0, p.xy * 0.05 + _Time.y * 0.03).z * f;
disp.y = tex2D(iChannel0, p.xz * 0.05 + _Time.y * 0.04).y * f;
return sphere(p + disp, 1.0 + sin(_Time.y*2.4) * 0.15);
}
fixed4 frag (v2f i) : SV_Target
{
//float2 uv = float2(fragCoord.x / iResolution.x, fragCoord.y / iResolution.y);
float2 uv = float2(i.screenPos.x , i.screenPos.y); // Unity equivalent of the above
uv -= 0.5;
uv /= float2((_ScreenParams.y / _ScreenParams.x)*0.5, (_ScreenParams.y / _ScreenParams.x)*0.5); // Shrink the globule
float3 cam = float3(0, -0.15, -3.5);
float3 dir = normalize(float3(uv,1));
float cam_a2 = sin(_Time.y) * pi * 0.1;
cam.yz = rotate(cam.yz, cam_a2);
dir.yz = rotate(dir.yz, cam_a2);
float cam_a = _Time.y * pi * 0.1;
cam.xz = rotate(cam.xz, cam_a);
dir.xz = rotate(dir.xz, cam_a);
float4 color = float4(0.16, 0.12, 0.10, 1.0);
float t = 0.00001;
const int maxSteps = 128;
for(int i = 0; i < maxSteps; ++i) {
float3 p = cam + dir * t;
float d = scene(p);
if(d < 0.0001 * t) {
color = float4(1.0, length(p) * (0.6 + (sin(_Time.y*3.0)+1.0) * 0.5 * 0.4), 0, 0);
break;
}
t += d;
}
return color;
}
ENDCG
}
}
}
The result is not perfect, but closer:
I think the issue with the ShaderToy shader is that it is meant for screen space. You will see that when you move the camera, the lava freaks out. I think this is because of the screen space uv calculation. You will need to find a different method.
Good luck
I'm looking to make a toon shader that has both the cell shading effect from one shader as well as an outline from another shader.
Is there a relatively straightforward way to combine these two?
The outline references a simple flat shader using "UsePass" is there a way I could reference the cell shaded shader instead?
This is the outline shader:
Shader "TSF/BaseOutline1"
{
Properties
{
[MaterialToggle(_TEX_ON)] _DetailTex ("Enable Detail texture", Float) = 0 //1
_MainTex ("Detail", 2D) = "white" {} //2
_ToonShade ("Shade", 2D) = "white" {} //3
[MaterialToggle(_COLOR_ON)] _TintColor ("Enable Color Tint", Float) = 0 //4
_Color ("Base Color", Color) = (1,1,1,1) //5
[MaterialToggle(_VCOLOR_ON)] _VertexColor ("Enable Vertex Color", Float) = 0//6
_Brightness ("Brightness 1 = neutral", Float) = 1.0 //7
_OutlineColor ("Outline Color", Color) = (0.5,0.5,0.5,1.0) //10
_Outline ("Outline width", Float) = 0.01 //11
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 250
Lighting Off
Fog { Mode Off }
UsePass "TSF/Base1/BASE"
Pass
{
Cull Front
ZWrite On
CGPROGRAM
#include "UnityCG.cginc"
#pragma fragmentoption ARB_precision_hint_fastest
#pragma glsl_no_auto_normalization
#pragma vertex vert
#pragma fragment frag
struct appdata_t
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
};
fixed _Outline;
v2f vert (appdata_t v)
{
v2f o;
o.pos = v.vertex;
o.pos.xyz += normalize(v.normal.xyz) *_Outline*0.01;
o.pos = UnityObjectToClipPos(o.pos);
return o;
}
fixed4 _OutlineColor;
fixed4 frag(v2f i) :COLOR
{
return _OutlineColor;
}
ENDCG
}
}
Fallback "Legacy Shaders/Diffuse"
}
And the cell shaded shader is here:
Shader "Toon/Cutoff"
{
Properties
{
_Color("Color(RGBA)", Color) = (1,1,1,1)
_MainTex("Texture", 2D) = "white" {}
_Shininess ("Shininess(0.0:)", Float) = 1.0
_ShadowThreshold ("Shadow Threshold(0.0:1.0)", Float) = 0.5
_ShadowColor ("Shadow Color(RGBA)", Color) = (0,0,0,0.5)
_ShadowSharpness ("Shadow Sharpness(0.0:)", Float) = 100
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.9
}
SubShader
{
// Settings
Tags {"Queue" = "Transparent" "IgnoreProjector"="False" "RenderType" = "TransparentCutout"}
// Surface Shader Pass ( Front )
Cull Back
ZWrite On
AlphaTest Greater 0.9
//AlphaTest Equal 1
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma surface surf Toon alphatest:_Cutoff vertex:vert
// Toon Surface Shader for Unity
// File : ToonSurface.cginc
// Title : Toon Surface Shader with Alpha
// Language : Cg Language
// Include : ToonSurface.cginc
/*
How To Use :
CGPROGRAM
#pragma surface surf Toon
#include "ToonSurface.cginc"
ENDCG
*/
float4 _Color;
sampler2D _MainTex;
float _ShadowThreshold;
float4 _ShadowColor;
float _ShadowSharpness;
float _Shininess;
struct ToonSurfaceOutput
{
half3 Albedo;
half3 Normal;
half3 Emission;
half3 Gloss;
half Specular;
half Alpha;
half4 Color;
};
inline half4 LightingToon (ToonSurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
{
//Lighting paramater
float4 lightColor = _LightColor0 * atten;
float lightStrength = dot(lightDir, s.Normal) * 0.5 + 0.5;
//ToonMapping
half shadowRate = abs( max( -1, ( min( lightStrength, _ShadowThreshold ) -_ShadowThreshold)*_ShadowSharpness ) )*_ShadowColor.a;
float4 toon = float4(1,1,1,1) * (1-shadowRate) + _ShadowColor *shadowRate;
//Output
//float4 color = saturate( _Color * (lightColor*2) ) * s.Color;
float4 color = _Color * (lightColor) * s.Color * (atten*2) * _Shininess;
color *= toon;
color.a = s.Alpha;
return color;
}
struct Input
{
float2 uv_MainTex;
};
void vert (inout appdata_full v, out Input o) {
UNITY_INITIALIZE_OUTPUT(Input,o);
}
void surf (Input IN, inout ToonSurfaceOutput o)
{
// Defaults
o.Albedo = 0.0;
o.Emission = 0.0;
o.Gloss = 0.0;
o.Specular = 0.0;
half4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
//o.Albedo = c;
o.Color = c;
o.Alpha = c.a;
}
ENDCG
// // Outline Pass
// Pass
// {
// Cull Off
// ZWrite On
// Lighting Off
// CGPROGRAM
// #pragma vertex vert
// #pragma fragment frag
// #include "UnityCG.cginc"
// #include "ToonOutlineVertFrag.cginc"
// ENDCG
// }
// Surface Shader Pass ( Back )
Cull Front
ZWrite On
//AlphaTest Equal 1
AlphaTest Greater 0.9
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma surface surf Toon alphatest:_Cutoff vertex:vert
// Toon Surface Shader for Unity
// File : ToonSurface.cginc
// Title : Toon Surface Shader with Alpha
// Language : Cg Language
// Include : ToonSurface.cginc
/*
How To Use :
CGPROGRAM
#pragma surface surf Toon
#include "ToonSurface.cginc"
ENDCG
*/
float4 _Color;
sampler2D _MainTex;
float _ShadowThreshold;
float4 _ShadowColor;
float _ShadowSharpness;
float _Shininess;
struct ToonSurfaceOutput
{
half3 Albedo;
half3 Normal;
half3 Emission;
half3 Gloss;
half Specular;
half Alpha;
half4 Color;
};
inline half4 LightingToon (ToonSurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
{
//Lighting paramater
float4 lightColor = _LightColor0 * atten;
float lightStrength = dot(lightDir, s.Normal) * 0.5 + 0.5;
//ToonMapping
half shadowRate = abs( max( -1, ( min( lightStrength, _ShadowThreshold ) -_ShadowThreshold)*_ShadowSharpness ) )*_ShadowColor.a;
float4 toon = float4(1,1,1,1) * (1-shadowRate) + _ShadowColor *shadowRate;
//Output
//float4 color = saturate( _Color * (lightColor*2) ) * s.Color;
float4 color = _Color * (lightColor) * s.Color * (atten*2) * _Shininess;
color *= toon;
color.a = s.Alpha;
return color;
}
struct Input
{
float2 uv_MainTex;
};
void vert (inout appdata_full v, out Input o) {
UNITY_INITIALIZE_OUTPUT(Input,o);
}
void surf (Input IN, inout ToonSurfaceOutput o)
{
// Defaults
o.Albedo = 0.0;
o.Emission = 0.0;
o.Gloss = 0.0;
o.Specular = 0.0;
half4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
//o.Albedo = c;
o.Color = c;
o.Alpha = c.a;
}
ENDCG
}
// Other Environment
Fallback "Diffuse"
}
I am writing a toon water shader, and I want it to be lit by a directional light. I got it working but I think there is somthing wrong with the normals because there are no shadows between the wave. I hope that someone can find the mistake I made and thank you in advance.
Shader "Custom/NoobShader_03" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_Scale ("Wave Scale", float) = 0.6
_Frequency ("Frequency", float) = 1
_Speed ("Speed", float) = 0.5
_Scale2 ("Wave Scale", float) = 0.6
_Frequency2 ("Frequency", float) = 1
_Speed2 ("Speed", float) = 1
}
SubShader {
Pass{
Tags { "LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 _Color;
float _Scale;
float _Frequency;
float _Speed;
float _Scale2;
float _Frequency2;
float _Speed2;
float4 _LightColor0;
struct VertexOutput
{
float4 pos : SV_POSITION;
float3 nor : NORMAL;
float4 col : COLOR;
};
struct VertexInput
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct FragmentOutput
{
float4 color : COLOR;
};
VertexOutput vert (VertexInput i)
{
VertexOutput VOUT;
float randomNum = 1 / _Time;
float newPos = _Scale * sin(_Time.w * _Speed + i.vertex.x * _Frequency);
float newPos2 = _Scale2 * cos(_Time.w * _Speed2 + i.vertex.z * _Frequency2);
//i.vertex.y += newPos;
float4 tempPos = i.vertex;
tempPos.y += newPos * newPos2;
VOUT.pos = mul(UNITY_MATRIX_MVP,tempPos);
VOUT.nor = float3(mul(UNITY_MATRIX_MVP,tempPos).xyz);
float3 normalDirection = normalize( mul( float4( VOUT.nor, 0.0 ), _World2Object).xyz);
float3 lightDirection;
float atten = 1.0;
lightDirection = normalize(_WorldSpaceLightPos0.xyz);
float3 diffuseRefflection = atten * _LightColor0.xyz * _Color.rgb * max( 0.0, dot(normalDirection, lightDirection));
VOUT.col = float4(diffuseRefflection, 0.0);
return VOUT;
}
FragmentOutput frag(VertexOutput v)
{
FragmentOutput FOUT;
FOUT.color = v.col + _Color;
return FOUT;
}
ENDCG
}
}
FallBack "Diffuse"
}
Just a quick answer about your normals
float3 normalDirection = normalize( mul( float4( VOUT.nor, 0.0 ), _World2Object).xyz);
Normals are given in local aka object space. You need to convert to world space. The order of your multiplication is wrong. It should be:
float3 normalDirection = normalize( mul( _World2Object, float4( VOUT.nor, 0.0 )).xyz);
which is equivalent to:
float3 normalDirection = normalize( mul( float4( VOUT.nor, 0.0 ), _Object2World).xyz);
You generally put the transform matrix before the vector you're transforming.