-
-
Save kayk5654/75ed9a3289a44aea41698a573f306bb2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Shader "3DDrawing/InkSplash" | |
{ | |
Properties | |
{ | |
_SplatMap("Splat Map", 2D) = "white" {} | |
_ShadePower("Shade Power", Float) = 0.3 | |
_OutlineWidth("Outline Width", Float) = 0.03 | |
_MaxOutlineWidth("Max Outline Width", Float) = 0.05 | |
[Toggle] _UseVColorForOutline("Use Vertex Color for Outline", Float) = 0 | |
_OcclusionMap("Ambient Occlusion", 2D) = "white" {} | |
_NormalMap("Normal Map", 2D) = "bump"{} | |
_ShadowIntensity("Shadow Intensity", Float) = 1 | |
_RubbedAreaMap("RubbedAreaMap", 2D) = "black" {} | |
_Splash("Splash Texture", 2D) = "black" {} | |
_SpriteSize("Sprite Size", Float) = 0.01 | |
_SpriteDistance("Sprite Distance", Float) = 0.1 | |
} | |
SubShader | |
{ | |
Tags { "RenderType"="Opaque"} | |
LOD 100 | |
// shadowcaster pass | |
Pass | |
{ | |
Name "ShadowCast" | |
Tags {"LightMode" = "ShadowCaster"} | |
CGPROGRAM | |
#pragma vertex vert | |
#pragma fragment frag | |
#pragma multi_compile_shadowcaster | |
#include "UnityCG.cginc" | |
struct v2f { | |
V2F_SHADOW_CASTER; | |
}; | |
v2f vert(appdata_base v) | |
{ | |
v2f o; | |
TRANSFER_SHADOW_CASTER_NORMALOFFSET(o) | |
return o; | |
} | |
float4 frag(v2f i) : SV_Target | |
{ | |
SHADOW_CASTER_FRAGMENT(i) | |
} | |
ENDCG | |
} | |
// main pass | |
Pass | |
{ | |
Tags{ "LightMode" = "ForwardBase"} | |
CGPROGRAM | |
#pragma vertex vert | |
#pragma fragment frag | |
#pragma multi_compile_fwdbase | |
#include "UnityCG.cginc" | |
// shadow helper functions and macros | |
#include "AutoLight.cginc" | |
struct appdata | |
{ | |
float4 vertex : POSITION; | |
float2 uv : TEXCOORD0; | |
float3 normal : NORMAL; | |
float2 lightmapUv : TEXCOORD1; | |
float4 tangent : TANGENT; | |
UNITY_VERTEX_INPUT_INSTANCE_ID | |
}; | |
struct v2f | |
{ | |
float2 uv : TEXCOORD0; | |
float4 vertex : SV_POSITION; | |
float3 normal : NORMAL; | |
float2 lightmapUv : TEXCOORD1; | |
float3 worldPos : TEXCOORD2; | |
float4 tangent : TANGENT; | |
float3 binormal : TEXCOORD4; | |
SHADOW_COORDS(3) // put shadows data into TEXCOORD3 | |
UNITY_VERTEX_OUTPUT_STEREO | |
}; | |
sampler2D _SplatMap; | |
float4 _SplatMap_ST; | |
fixed _ShadePower; | |
sampler2D _OcclusionMap; | |
sampler2D _NormalMap; | |
half _ShadowIntensity; | |
sampler2D _RubbedAreaMap; | |
v2f vert (appdata v) | |
{ | |
UNITY_SETUP_INSTANCE_ID(v); | |
v2f o; | |
o.vertex = UnityObjectToClipPos(v.vertex); | |
o.uv = v.uv; | |
o.normal = v.normal; | |
o.worldPos = mul(unity_ObjectToWorld, v.vertex); | |
o.lightmapUv = v.lightmapUv * unity_LightmapST.xy + unity_LightmapST.zw; | |
o.tangent = mul(unity_ObjectToWorld, v.tangent); | |
o.binormal = normalize(cross(v.normal, v.tangent.xyz) * v.tangent.w * unity_WorldTransformParams.w); | |
o.binormal = mul(unity_ObjectToWorld, o.binormal); | |
// compute shadows data | |
TRANSFER_SHADOW(o) | |
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); | |
return o; | |
} | |
fixed4 frag(v2f i) : SV_Target | |
{ | |
// sample the texture | |
fixed4 col = fixed4(1, 1, 1, 1); | |
// normal map | |
float3 normalMap = UnpackNormal(tex2D(_NormalMap, i.uv)); | |
// convert normal map from tangent space to world space | |
normalMap = (i.tangent * normalMap.x) + (i.binormal * normalMap.y) + (i.normal * normalMap.z); | |
// convert normal local to world space | |
float3 worldNormal = UnityObjectToWorldNormal(i.normal); | |
// test with simple lighting using dot product | |
float NdotL = dot(_WorldSpaceLightPos0.xyz, normalize(worldNormal + normalMap)); | |
// test with lightmap | |
half3 lightmap = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, i.lightmapUv)); | |
// test environmental lighting using a shading function on UnityCG.cginc | |
half3 indirectLighting = ShadeSH9(half4(i.normal, 1)); | |
// apply splat map on the result of lighting | |
float splatPattern = tex2D(_SplatMap, i.uv * _SplatMap_ST.xy + _SplatMap_ST.zw).r; | |
// make tiling pattern difficult to recognize | |
splatPattern *= tex2D(_SplatMap, i.uv * (_SplatMap_ST.xy * 2) + _SplatMap_ST.xy * 0.3).r; | |
splatPattern *= tex2D(_SplatMap, i.uv * (_SplatMap_ST.xy * 0.5) + _SplatMap_ST.xy * 0.7).r; | |
// cross hatching | |
//splatPattern = lerp(splatPattern, tex2D(_SplatMap, i.uv.yx * _SplatMap_ST.yx + _SplatMap_ST.yx).r, 0.5); | |
// adjust weight of splat pattern | |
splatPattern = pow(splatPattern, _ShadePower); | |
half3 lighting = lerp(1, clamp(NdotL, 0, 1), _ShadowIntensity) * 0.5 + lightmap + indirectLighting; | |
// compute shadow attenuation (1.0 = fully lit, 0.0 = fully shadowed) | |
fixed shadow = lerp(1, SHADOW_ATTENUATION(i), _ShadowIntensity); | |
lighting *= shadow; | |
lighting *= tex2D(_OcclusionMap, i.uv); | |
half grayscaleLighting = (lighting.r + lighting.g + lighting.b) / 3; | |
col.rgb = grayscaleLighting > splatPattern ? 1 : 0; | |
// rubbing indirect light area | |
//half rubbedArea = tex2D(_RubbedAreaMap, float2(0, grayscaleLighting)).r; | |
//col.rgb = lerp(col.rgb, tex2D(_SplatMap, i.uv * _SplatMap_ST.xy * 0.1 + _SplatMap_ST.zw + i.tangent.xy * abs(NdotL)).r * 0.1, rubbedArea); | |
//col.rgb = lighting; | |
return col; | |
} | |
ENDCG | |
} | |
// outline pass | |
Pass | |
{ | |
Cull Front | |
CGPROGRAM | |
#pragma vertex vert | |
#pragma fragment frag | |
#include "UnityCG.cginc" | |
struct appdata | |
{ | |
float4 vertex : POSITION; | |
float3 normal : NORMAL; | |
float3 color : COLOR; | |
UNITY_VERTEX_INPUT_INSTANCE_ID | |
}; | |
struct v2f | |
{ | |
float4 vertex : SV_POSITION; | |
float3 color : COLOR; | |
UNITY_VERTEX_OUTPUT_STEREO | |
}; | |
half _OutlineWidth; | |
fixed _UseVColorForOutline; | |
half _MaxOutlineWidth; | |
v2f vert(appdata v) | |
{ | |
UNITY_SETUP_INSTANCE_ID(v); | |
v2f o; | |
o.vertex = UnityObjectToClipPos(v.vertex); | |
// convert normal local to world space | |
float3 normal = normalize(mul((float3x3)UNITY_MATRIX_IT_MV, v.normal)); | |
//normal = UnityObjectToWorldNormal(v.normal); // another way to convert normal from local to world | |
float2 offset = TransformViewToProjection(normal.xy); | |
if (_UseVColorForOutline == 0) | |
{ | |
o.vertex.xy += offset * min(o.vertex.z * _OutlineWidth, _MaxOutlineWidth); | |
} | |
else | |
{ | |
// if the model contains curvature as vertex color, use this process | |
o.vertex.xy += offset * min(o.vertex.z * _OutlineWidth * (v.color.r + v.color.g) * 0.5, _MaxOutlineWidth); | |
} | |
o.color = v.color; | |
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); | |
return o; | |
} | |
fixed4 frag(v2f i) : SV_Target | |
{ | |
// set outline color | |
fixed4 col = fixed4(0, 0, 0, 1); | |
//fixed4 col = fixed4(i.color, 1); | |
return col; | |
} | |
ENDCG | |
} | |
// splash sprites pass | |
Pass | |
{ | |
Tags{ "RenderType" = "TransparentCutout" "Queue" = "Transparent+1" } | |
Blend DstColor Zero // multiply | |
CGPROGRAM | |
#pragma target 5.0 | |
#pragma vertex vert | |
#pragma geometry geom | |
#pragma fragment frag | |
// make fog work | |
#pragma multi_compile_fog | |
#include "UnityCG.cginc" | |
struct appdata | |
{ | |
float4 vertex : POSITION; | |
float2 uv : TEXCOORD0; | |
float3 normal : NORMAL; | |
float3 color : COLOR; | |
UNITY_VERTEX_INPUT_INSTANCE_ID | |
}; | |
struct v2g { | |
float2 uv : TEXCOORD0; | |
float4 vertex : SV_POSITION; | |
float3 normal : NORMAL; | |
float3 color : COLOR; | |
UNITY_VERTEX_OUTPUT_STEREO | |
}; | |
struct g2f { | |
float2 uv : TEXCOORD0; | |
float4 vertex : SV_POSITION; | |
UNITY_VERTEX_OUTPUT_STEREO | |
}; | |
sampler2D _Splash; | |
float4 _Splash_ST; | |
half _SpriteSize; | |
half _SpriteDistance; | |
v2g vert(appdata v) | |
{ | |
UNITY_SETUP_INSTANCE_ID(v); | |
v2g o; | |
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; | |
o.vertex = float4(worldPos, 1); | |
o.uv = TRANSFORM_TEX(v.uv, _Splash); | |
o.normal = UnityObjectToWorldNormal(v.normal); | |
o.color = v.color; | |
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); | |
return o; | |
} | |
[maxvertexcount(4)] | |
void geom(point v2g input[1], inout TriangleStream<g2f> outStream) | |
{ | |
// test with simple lighting using dot product | |
float NdotL = dot(_WorldSpaceLightPos0.xyz, normalize(input[0].normal)); | |
if(input[0].color.r > 0.001 && abs(NdotL) < 0.2) | |
{ | |
// define a base value | |
float4 pos = input[0].vertex + float4(input[0].normal, 1) * _SpriteDistance; | |
// prepare a matrix for billboards | |
float4x4 billboardMatrix = UNITY_MATRIX_V; | |
billboardMatrix._m03 = 0; | |
billboardMatrix._m13 = 0; | |
billboardMatrix._m23 = 0; | |
billboardMatrix._m33 = 0; | |
float spriteSize = _SpriteSize * input[0].color.r * saturate(abs(NdotL)); | |
// calculate position of each vertex of a sprite | |
g2f o0; | |
o0.uv = float2(0, 0); | |
o0.vertex = pos + mul(float4((o0.uv * 2 - float2(1, 1)) * spriteSize, 0, 1), billboardMatrix); | |
o0.vertex = mul(UNITY_MATRIX_VP, o0.vertex); | |
g2f o1; | |
o1.uv = float2(0, 1); | |
o1.vertex = pos + mul(float4((o1.uv * 2 - float2(1, 1)) * spriteSize, 0, 1), billboardMatrix); | |
o1.vertex = mul(UNITY_MATRIX_VP, o1.vertex); | |
g2f o2; | |
o2.uv = float2(1, 0); | |
o2.vertex = pos + mul(float4((o2.uv * 2 - float2(1, 1)) * spriteSize, 0, 1), billboardMatrix); | |
o2.vertex = mul(UNITY_MATRIX_VP, o2.vertex); | |
g2f o3; | |
o3.uv = float2(1, 1); | |
o3.vertex = pos + mul(float4((o3.uv * 2 - float2(1, 1)) * spriteSize, 0, 1), billboardMatrix); | |
o3.vertex = mul(UNITY_MATRIX_VP, o3.vertex); | |
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o0); | |
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o1); | |
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o2); | |
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o3); | |
outStream.Append(o0); | |
outStream.Append(o1); | |
outStream.Append(o2); | |
outStream.Append(o3); | |
} | |
} | |
fixed4 frag(g2f i) : SV_Target | |
{ | |
// sample the texture | |
fixed4 col = tex2D(_Splash, i.uv) * fixed4(0, 0, 0, 1); | |
fixed cutoff = 0.5; | |
clip(col.a - cutoff); | |
return col; | |
} | |
ENDCG | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment