/* * The MIT License * * Copyright 2018-2021 whiteflare. * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INC_UNLIT_WF_FAKEFUR #define INC_UNLIT_WF_FAKEFUR #include "WF_INPUT_FakeFur.cginc" #include "WF_UnToon.cginc" struct appdata_fur { float4 vertex : POSITION; float2 uv : TEXCOORD0; float3 normal : NORMAL; float4 tangent : TANGENT; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2g { float2 uv : TEXCOORD0; float3 ws_vertex : TEXCOORD1; float3 ws_normal : TEXCOORD2; float4 ws_light_dir : TEXCOORD3; float3 ws_fur_vector : TEXCOORD4; float3 light_color : COLOR1; #ifdef _TS_ENABLE float shadow_power : COLOR2; #endif UNITY_VERTEX_OUTPUT_STEREO }; struct g2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; float3 ws_vertex : TEXCOORD1; float3 ws_normal : TEXCOORD2; float height : COLOR0; float3 light_color : COLOR1; #ifdef _TS_ENABLE float shadow_power : COLOR2; #endif float4 ws_light_dir : TEXCOORD3; UNITY_VERTEX_OUTPUT_STEREO }; //////////////////////////// // vertex & fragment shader //////////////////////////// float3 calcFurVector(float3 ws_tangent, float3 ws_bitangent, float3 ws_normal, float2 uv) { // Tangent Transform 計算 float3x3 tangentTransform = float3x3(ws_tangent, ws_bitangent, ws_normal); // Static Fur Vector 計算 float3 vec_fur = SafeNormalizeVec3Normal(_FR_Vector.xyz); #ifndef _FR_DISABLE_NORMAL_MAP // NormalMap Fur Vector 計算 float2 uv_main = TRANSFORM_TEX(uv, _MainTex); float3 vec_map = UnpackNormal( PICK_VERT_TEX2D_LOD(_FR_BumpMap, uv_main, 0) ); vec_fur = BlendNormals(vec_fur, vec_map); #endif return mul(vec_fur , tangentTransform); } v2g vert_fakefur(appdata_fur v) { v2g o; UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_OUTPUT(v2g, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.uv = v.uv; o.ws_vertex = UnityObjectToWorldPos(v.vertex); o.ws_light_dir = calcWorldSpaceLightDir(o.ws_vertex); float3 ws_tangent; float3 ws_bitangent; localNormalToWorldTangentSpace(v.normal, v.tangent, o.ws_normal, ws_tangent, ws_bitangent, _FR_FlipMirror & 1, _FR_FlipMirror & 2); // 環境光取得 float3 ambientColor = sampleSHLightColor(); // 影コントラスト calcToonShadeContrast(o.ws_vertex, o.ws_light_dir, ambientColor, o.shadow_power); // Anti-Glare とライト色ブレンドを同時に計算 o.light_color = calcLightColorVertex(o.ws_vertex, ambientColor); // ファーを伸ばす方向を計算 o.ws_fur_vector = calcFurVector(ws_tangent, ws_bitangent, o.ws_normal, o.uv) #ifdef _FR_HEIGHT_PARAM * _FR_HEIGHT_PARAM ; #else * _FR_Height ; #endif return o; } g2f initGeomOutput(v2g p) { g2f o; UNITY_INITIALIZE_OUTPUT(g2f, o); UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(g2f, o); o.uv = p.uv; o.ws_vertex = p.ws_vertex; o.ws_normal = p.ws_normal; o.light_color = p.light_color; #ifdef _TS_ENABLE o.shadow_power = p.shadow_power; #endif o.ws_light_dir = p.ws_light_dir; return o; } void transferGeomVertex(inout g2f o, float3 vb, float3 vu, float height) { o.ws_vertex = lerp(vb, vu, height); o.vertex = UnityWorldToClipPos( o.ws_vertex ); o.height = height; } v2g lerp_v2g(v2g x, v2g y, float div) { v2g o; UNITY_INITIALIZE_OUTPUT(v2g, o); o.uv = lerp(x.uv, y.uv, div); o.ws_vertex = lerp(x.ws_vertex, y.ws_vertex, div); o.ws_normal = lerp(x.ws_normal, y.ws_normal, div); o.light_color = lerp(x.light_color, y.light_color, div); #ifdef _TS_ENABLE o.shadow_power = lerp(x.shadow_power, y.shadow_power, div); #endif o.ws_light_dir = lerp(x.ws_light_dir, y.ws_light_dir, div); o.ws_fur_vector = lerp(x.ws_fur_vector, y.ws_fur_vector, div); return o; } void fakefur(v2g v[3], inout TriangleStream triStream) { // 底辺座標 float3 vb[3] = { v[0].ws_vertex, v[1].ws_vertex, v[2].ws_vertex }; // 頂点座標 float3 vu[3] = vb; // normal方向に従ってfurを伸ばす { for (uint i = 0; i < 3; i++) { // 頂点移動 vu[i].xyz += v[i].ws_fur_vector; } } // ファーを増殖 { for (uint i = 0; i < 4; i++) { uint n = i % 3; g2f o = initGeomOutput(v[n]); transferGeomVertex(o, vb[n], vu[n], 0); triStream.Append(o); transferGeomVertex(o, vb[n], vu[n], 1); triStream.Append(o); } } } [maxvertexcount(48)] void geom_fakefur(triangle v2g v[3], inout TriangleStream triStream) { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(v[0]); v2g c = lerp_v2g(v[0], lerp_v2g(v[1], v[2], 0.5), 2.0 / 3.0); for (uint i = 0; i < _FR_Repeat; i++) { float rate = i / (float) _FR_Repeat; v2g v2[3] = { lerp_v2g(v[0], c, rate), lerp_v2g(v[1], c, rate), lerp_v2g(v[2], c, rate) }; fakefur(v2, triStream); } } fixed4 frag_fakefur(g2f gi) : SV_Target { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); v2f i = (v2f) 0; i.uv = gi.uv; i.ws_vertex = gi.ws_vertex; i.normal = gi.ws_normal; i.light_color = gi.light_color; #ifdef _TS_ENABLE i.shadow_power = gi.shadow_power; #endif i.ws_light_dir = gi.ws_light_dir; // メイン float2 uv_main = TRANSFORM_TEX(i.uv, _MainTex); float4 color = PICK_MAIN_TEX2D(_MainTex, uv_main) * _Color; // アルファマスク適用 affectAlphaMask(uv_main, color); // 色変換 affectColorChange(color); // カメラとライトの位置関係: -1(逆光) ~ +1(順光) float angle_light_camera = calcAngleLightCamera(i.ws_vertex, i.ws_light_dir); // 階調影 affectToonShade(i, uv_main, i.normal, i.normal, angle_light_camera, color); // Anti-Glare とライト色ブレンドを同時に計算 color.rgb *= i.light_color; // Alpha は 0-1 にクランプ color.a = saturate(color.a); float4 maskTex = PICK_SUB_TEX2D(_FR_MaskTex, _MainTex, uv_main); if (maskTex.r < 0.01 || maskTex.r <= gi.height) { discard; } // ファーノイズを追加 float noise = PICK_MAIN_TEX2D(_FR_NoiseTex, TRANSFORM_TEX(i.uv, _FR_NoiseTex)).r; color = float4(color.rgb * saturate(1 - (1 - noise) * _FR_ShadowPower), saturate(noise - pow(gi.height, 4))); return color; } fixed4 frag_fakefur_cutoff(g2f i) : SV_Target { float4 color = frag_fakefur(i); color.a = smoothstep(_Cutoff - 0.0625, _Cutoff + 0.0625, color.a); if (TGL_OFF(_AL_AlphaToMask) && color.a < 0.5) { discard; } return color; } #endif