前言
【本文持续更新中】
终于把一直想做一做的仿原神渲染做了一下。
原神出来也有段时间了,各路大佬的逆向早就做完了,所以最近做的其实复刻大佬们的工程,难度并不大。
废话不多说,先看效果。
Unity
UE
(UE的边缘光老是闪就关了)
两个版本都没有加上雾效,泛光之间的后处理效果,本篇随笔也不会讲述相关内容,有能力的可以自己加上,效果应该会上一个档次
UE最近一段时间才开始用起来,材质蓝图比我想象的要简单一些,但是UE的PBR渲染几乎是高度封装的,导致几乎相同的流程UE会和Unity效果差异很明显。
这次的UE版本效果也就差强人意吧,后续继续做UE项目的话可能会改进。
贴图、模型什么的网上一找就能找到,实在找不到就评论区或者私信问我吧,本随笔默认已经准备好所有模型贴图。
概念
- Matcap
- ILM
- Ramp
- Rim
- fresnel
实现流程
源码
1 Shader "Custom/Cel_Base" 2 { 3 Properties 4 { 5 _AmbientColor ("Ambient Color", Color) = (1,1,1,1) 6 _AmbientFac("Ambient Fac", Range(0, 1)) = 0 7 _SphereTex("Sphere Tex", 2D) = "white" {} 8 _SphereTexFac("Sphere Fac", Range(0, 1)) = 0 9 _OutlineOffset("Outline Offset", Float) = 0.01 10 _OutlineShadowColor("Outline Shadow", Color) = (1, 1, 1, 1) 11 _BaseTex ("Base Tex", 2D) = "white" {} 12 [Toggle(_True)]_IsSkin("Is Skin", Float) = 1 13 _ToonTex ("Toon Tex", 2D) = "white" {} 14 _SkinTex ("Skin Tex", 2D) = "white" {} 15 _MatcapFac("Matcap Fac", Range(0, 1)) = 0 16 _MetalTex("Metal Tex", 2D) = "white" {} 17 _ILM_Tex("ILM Tex", 2D) = "white" {} 18 _ILM_R_TMP("ILM R", 2D) = "white" {} 19 [Toggle(_True)]_IsEye("Is Eye", Float) = 1 20 _Eye_Mask_Tex("Eye Mask Tex", 2D) = "white" {} 21 _Gloss("Gloss", Float) = 50 22 _KsNonMetallic("Non Metallic", Float) = 1 23 _KsMetallic("Metallic", Float) = 1 24 _KsHairMetallic("Hair Metallic", Float) = 1 25 [Toggle(_True)]_IsHair("Is Hair", Float) = 1 26 _RampTex ("Ramp Tex", 2D) = "white" {} 27 _ShadowColor ("Shadow Color", Color) = (1, 1, 1, 1) 28 _RimColor ("Rim Color", Color) = (1, 1, 1, 1) 29 _RimFac ("Rim Fac", Float) = 0 30 31 } 32 SubShader 33 { 34 Tags {"LightMode" = "ForwardBase" "RenderType" = "Opaque" } 35 Pass 36 { 37 Cull Off 38 CGPROGRAM 39 #include "UnityCG.cginc" 40 #include "Lighting.cginc" 41 #include "AutoLight.cginc" 42 43 #pragma vertex vert 44 #pragma fragment frag 45 #pragma multi_compile_fwdbase 46 47 sampler2D _CameraDepthTexture; 48 49 sampler2D _BaseTex; 50 sampler2D _ToonTex; 51 sampler2D _RampTex; 52 sampler2D _SkinTex; 53 sampler2D _SphereTex; 54 sampler2D _ILM_Tex; 55 sampler2D _ILM_R_TMP; 56 sampler2D _MetalTex; 57 float4 _AmbientColor; 58 float4 _ShadowColor; 59 float4 _RimColor; 60 float _MatcapFac; 61 float _AmbientFac; 62 float _SphereTexFac; 63 float _Gloss; 64 float _KsNonMetallic; 65 float _KsMetallic; 66 float _KsHairMetallic; 67 float _IsHair; 68 float _IsSkin; 69 float _RimFac; 70 71 struct a2v 72 { 73 float4 vertex : POSITION; 74 float3 normal : NORMAL; 75 float2 texcoord : TEXCOORD0; 76 }; 77 78 struct v2f 79 { 80 float4 pos : SV_POSITION; 81 float4 scrPos : TEXCOORD3; 82 float4 worldPos : TEXCOORD2; 83 float3 worldNormal : TEXCOORD1; 84 float2 uv : TEXCOORD0; 85 SHADOW_COORDS(4) 86 }; 87 88 v2f vert(a2v v) 89 { 90 v2f o; 91 o.pos = UnityObjectToClipPos(v.vertex); 92 o.scrPos = ComputeScreenPos(o.pos); 93 o.uv = v.texcoord; 94 o.worldPos = mul(unity_ObjectToWorld, v.vertex); 95 o.worldNormal = mul(unity_ObjectToWorld, v.normal); 96 TRANSFER_SHADOW(o); 97 return o; 98 } 99 100 float4 frag(v2f i) : SV_Target 101 { 102 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos); 103 //Context 104 float3 LightDir = normalize(_WorldSpaceLightPos0); 105 float3 ViewDir = normalize(_WorldSpaceCameraPos); 106 float3 viewNormal = mul(unity_WorldToCamera, i.worldNormal); 107 float NOL = dot(i.worldNormal, LightDir); 108 float NOV = dot(i.worldNormal, ViewDir); 109 110 //Lambert HalfLambert 111 float Lambert = max(0, NOL); 112 float HalfLambert = pow((NOL * 0.5 + 0.5), 1); 113 114 //Ramp采样用 HalfLambert_Ramp 115 116 float HalfLambert_Ramp = smoothstep(0.0, 0.5, HalfLambert); 117 118 //DarkRamp平滑用 LambertStep 119 float LambertStep = smoothstep(0.423, 0.465, HalfLambert); 120 121 //BaseColor 122 float4 BaseTexColor = tex2D(_BaseTex, i.uv); 123 //return float4(BaseTexColor.rgb, 1); 124 125 //MatcapUV 126 float3 ViewDir_CameraSpace = mul(unity_WorldToCamera, i.worldNormal); 127 ViewDir_CameraSpace = ViewDir_CameraSpace * 0.5 + 0.5; 128 float2 MatcapUV = ViewDir_CameraSpace.xy; 129 130 //ToonColor SkinColor 131 float3 ToonColor = tex2D(_ToonTex, MatcapUV); 132 float3 SkinColor = tex2D(_SkinTex, MatcapUV); 133 134 //MatcapColor 135 float3 MatcapColor; 136 if (_IsSkin == 1) MatcapColor = SkinColor; 137 else MatcapColor = ToonColor; 138 139 //BaseColor 140 float3 BaseColor = lerp(BaseTexColor, BaseTexColor * MatcapColor, _MatcapFac); 141 BaseColor = lerp(BaseColor, BaseColor * _AmbientColor, _AmbientFac); 142 float3 SphereColor = tex2D(_SphereTex, MatcapUV); 143 BaseColor = lerp(BaseColor, BaseColor * SphereColor, _SphereTexFac); 144 145 //ILM 146 float4 ILM_RGBA = tex2D(_ILM_Tex, i.uv); 147 float ILM_R = ILM_RGBA.x; 148 float ILM_G = ILM_RGBA.y; 149 float ILM_B = ILM_RGBA.z; 150 float ILM_A = ILM_RGBA.w; 151 152 //NightRamp_V 153 float ILM_Alpha_0 = 0.15; 154 float ILM_Alpha_1 = 0.40; 155 float ILM_Alpha_2 = 0.60; 156 float ILM_Alpha_3 = 0.85; 157 float ILM_Alpha_4 = 1.0; 158 float ILM_Value_0 = 1.0; 159 float ILM_Value_1 = 4.0; 160 float ILM_Value_2 = 3.0; 161 float ILM_Value_3 = 5.0; 162 float ILM_Value_4 = 2.0; 163 ILM_Value_0 = 0.55 - ILM_Value_0 / 10; 164 ILM_Value_1 = 0.55 - ILM_Value_1 / 10; 165 ILM_Value_2 = 0.55 - ILM_Value_2 / 10; 166 ILM_Value_3 = 0.55 - ILM_Value_3 / 10; 167 ILM_Value_4 = 0.55 - ILM_Value_4 / 10; 168 float NightRamp_V = lerp(ILM_Value_4, ILM_Value_3, step(ILM_A, ILM_Alpha_3)); 169 NightRamp_V = lerp(NightRamp_V, ILM_Value_2, step(ILM_A, ILM_Alpha_2)); 170 NightRamp_V = lerp(NightRamp_V, ILM_Value_1, step(ILM_A, ILM_Alpha_1)); 171 NightRamp_V = lerp(NightRamp_V, ILM_Value_0, step(ILM_A, ILM_Alpha_0)); 172 173 //DayRamp_V 174 float DayRamp_V = NightRamp_V + 0.5; 175 176 //IsDay 177 float IsDay = (LightDir.y + 1) / 2; 178 179 //RampColor 180 //采样Ramp时,HalfLmabert * AO可以得到带 AO的 RampColor 181 float3 DayRampColor = tex2D(_RampTex, float2(HalfLambert_Ramp, DayRamp_V)); 182 float3 DayDarkRampColor = tex2D(_RampTex, float2(0.003, DayRamp_V)); 183 float3 NightRampColor = tex2D(_RampTex, float2(HalfLambert_Ramp, NightRamp_V)); 184 float3 NightDarkRampColor = tex2D(_RampTex, float2(0.003, NightRamp_V)); 185 float3 RampColor = lerp(NightRampColor, DayRampColor, IsDay); 186 float3 DarkRampColor = lerp(NightDarkRampColor, DayDarkRampColor, IsDay); 187 188 //Diffuse 189 //使用 LambertStep平滑 190 float3 Diffuse = lerp(BaseColor * RampColor * _ShadowColor, BaseColor, LambertStep); 191 Diffuse = lerp(BaseColor * DarkRampColor * _ShadowColor, Diffuse, 1); 192 //使用 ILM_G增加AO,同时AO使用Ramp图最左侧颜色 193 //ILM_G范围为 0-0.5,大于等于0.5的部分为非AO部分,故映射为 0-1 194 Diffuse = lerp(BaseColor * DarkRampColor * _ShadowColor, Diffuse, ILM_G * 2); 195 196 197 //BlinnPhong 198 float3 HalfDir = normalize(ViewDir + LightDir); 199 float NOH = dot(i.worldNormal, HalfDir); 200 float BlinnPhong = step(0, NOL) * pow(max(0, NOH), _Gloss); 201 202 //IsMetallic 203 float IsMetallic = step(0.95, ILM_R); 204 float ILM_Hair_R = tex2D(_ILM_R_TMP, i.uv).r; 205 206 //Specular 207 float NonMetallic_Specular = step(1.04 - BlinnPhong, ILM_B) * ILM_R * _KsNonMetallic; 208 float3 HairMetallic_Specular = 0; 209 if (_IsHair == 1) HairMetallic_Specular = ILM_B * LambertStep * BaseColor * ILM_Hair_R * _KsHairMetallic; 210 float3 KsMetallic_Specular = BlinnPhong * ILM_B * (LambertStep * 0.8 + 0.2) * BaseColor * _KsMetallic; 211 float3 Specular = lerp(NonMetallic_Specular + HairMetallic_Specular, KsMetallic_Specular, IsMetallic); 212 213 //Metallic 214 float3 Metallic = lerp(0, tex2D(_MetalTex, MatcapUV).r * BaseColor, IsMetallic); 215 216 //Albedo 217 float3 Albedo = Diffuse + Specular + Metallic; 218 219 float rimOffset = 13; 220 float rimThreshold = 0.08; 221 float rimStrength = 0.6; 222 float rimMax = 0.3; 223 224 float rawDepth = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, i.scrPos); 225 226 float linearDepth = LinearEyeDepth(rawDepth); 227 float Offset = lerp(-1, 1, step(0, viewNormal.x)) * rimOffset / _ScreenParams.x; 228 //float Offset = lerp(-1, 1, step(0, viewNormal.x)) * rimOffset / _ScreenParams.x / max(1, pow(linearDepth, 0.5)); 229 float4 screenOffset = float4(Offset, 0, 0, 0); 230 float offsetDepth = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, i.scrPos + screenOffset); 231 float offsetLinearDepth = LinearEyeDepth(offsetDepth); 232 233 float rim = saturate(offsetLinearDepth - linearDepth); 234 rim = step(rimThreshold, rim) * clamp(rim * rimStrength, 0, rimMax); 235 236 float fresnelPower = 6; 237 float fresnelClamp = 0.8; 238 float fresnel = 1 - saturate(NOV); 239 fresnel = pow(fresnel, fresnelPower); 240 fresnel = fresnel * fresnelClamp + (1 - fresnelClamp); 241 242 Albedo = 1 - (1 - rim * fresnel * _RimColor * BaseTexColor * _RimFac) * (1 - Albedo); 243 244 float4 FinalColor = float4(Albedo, BaseTexColor.a); 245 return FinalColor; 246 } 247 248 ENDCG 249 } 250 251 Pass 252 { 253 Name "DrawOutline" 254 Tags {"RenderPipeline" = "UniversalPipeline" "RenderType" = "Opaque"} 255 Cull Front 256 257 CGPROGRAM 258 259 #pragma vertex vert 260 #pragma fragment frag 261 #pragma multi_compile_fog 262 #include "UnityCG.cginc" 263 264 sampler2D _BaseTex; 265 sampler2D _ILM_Tex; 266 sampler2D _RampTex; 267 sampler2D _Eye_Mask_Tex; 268 269 float4 _OutlineShadowColor; 270 float _OutlineOffset; 271 float _IsEye; 272 273 float GetCameraFOV() 274 { 275 //https://answers.unity.com/questions/770838/how-can-i-extract-the-fov-information-from-the-pro.html 276 float t = unity_CameraProjection._m11; 277 float Rad2Deg = 180 / 3.1415; 278 float fov = atan(1.0f / t) * 2.0 * Rad2Deg; 279 return fov; 280 } 281 float ApplyOutlineDistanceFadeOut(float inputMulFix) 282 { 283 //make outline "fadeout" if character is too small in camera's view 284 return saturate(inputMulFix); 285 } 286 float GetOutlineCameraFovAndDistanceFixMultiplier(float positionVS_Z) 287 { 288 float cameraMulFix; 289 if(unity_OrthoParams.w == 0) 290 { 291 //////////////////////////////// 292 // Perspective camera case 293 //////////////////////////////// 294 295 // keep outline similar width on screen accoss all camera distance 296 cameraMulFix = abs(positionVS_Z); 297 298 // can replace to a tonemap function if a smooth stop is needed 299 cameraMulFix = ApplyOutlineDistanceFadeOut(cameraMulFix); 300 301 // keep outline similar width on screen accoss all camera fov 302 cameraMulFix *= GetCameraFOV(); 303 } 304 else 305 { 306 //////////////////////////////// 307 // Orthographic camera case 308 //////////////////////////////// 309 float orthoSize = abs(unity_OrthoParams.y); 310 orthoSize = ApplyOutlineDistanceFadeOut(orthoSize); 311 cameraMulFix = orthoSize * 50; // 50 is a magic number to match perspective camera's outline width 312 } 313 314 return cameraMulFix * 0.00005; // mul a const to make return result = default normal expand amount WS 315 } 316 317 float3 TransformPositionWSToOutlinePositionWS(float3 positionWS, float positionVS_Z, float3 normalWS) 318 { 319 //you can replace it to your own method! Here we will write a simple world space method for tutorial reason, it is not the best method! 320 float outlineExpandAmount = _OutlineOffset * GetOutlineCameraFovAndDistanceFixMultiplier(positionVS_Z); 321 return positionWS + normalWS * outlineExpandAmount; 322 } 323 324 struct a2v 325 { 326 float4 vertex : POSITION; 327 float3 normal : NORMAL; 328 float4 tangent : TANGENT; 329 float2 uv : TEXCOORD0; 330 float4 uv7 : TEXCOORD7; 331 }; 332 333 struct v2f 334 { 335 float4 position : SV_POSITION; 336 float2 uv : TEXCOORD0; 337 }; 338 339 v2f vert(a2v v) 340 { 341 v2f o; 342 343 /*float3 worldPos = mul(UNITY_MATRIX_M, v.vertex).xyz; 344 float3 worldNormal = UnityObjectToWorldNormal(v.normal); 345 float3 worldTangent = UnityObjectToWorldDir(v.tangent); 346 float3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; 347 float3 ViewPos = mul((float3x3)UNITY_MATRIX_IT_MV, v.vertex); 348 349 float3x3 tbn = float3x3(worldTangent, worldBinormal, worldNormal); 350 float3 normalWS = mul(v.normal.rgb, tbn); 351 352 float EyeMask = 1; 353 if (_IsEye == 1) EyeMask = tex2Dlod(_Eye_Mask_Tex, float4(v.uv, 0, 0)).a; 354 _OutlineOffset = lerp(0, _OutlineOffset, EyeMask); 355 356 float3 positionWS = TransformPositionWSToOutlinePositionWS( 357 worldPos, ViewPos.z, normalWS); 358 359 o.position = UnityObjectToClipPos(positionWS); 360 o.uv = v.uv;*/ 361 362 float4 pos = UnityObjectToClipPos(v.vertex); 363 //float3 viewNormal = mul((float3x3)UNITY_MATRIX_IT_MV, v.uv7.xyz); 364 float3 viewNormal = mul((float3x3)UNITY_MATRIX_IT_MV, v.tangent.xyz); 365 float3 ndcNormal = normalize(TransformViewToProjection(viewNormal.xyz)) * pos.w;//将法线变换到NDC空间 366 float4 nearUpperRight = mul(unity_CameraInvProjection, float4(1, 1, UNITY_NEAR_CLIP_VALUE, _ProjectionParams.y));//将近裁剪面右上角的位置的顶点变换到观察空间 367 float aspect = abs(nearUpperRight.y / nearUpperRight.x);//求得屏幕宽高比 368 ndcNormal.x *= aspect; 369 pos.xy += 0.001 * clamp(_OutlineOffset * ndcNormal.xy, -50, 50); 370 371 o.position = pos; 372 o.uv = v.uv; 373 374 return o; 375 } 376 float4 frag(v2f i) : SV_Target 377 { 378 379 //Context 380 float3 LightDir = normalize(_WorldSpaceLightPos0); 381 382 //BaseColor 383 float4 BaseTexColor = tex2D(_BaseTex, i.uv); 384 385 float4 ILM_RGBA = tex2D(_ILM_Tex, i.uv); 386 float ILM_A = ILM_RGBA.w; 387 388 //NightRamp_V 389 float ILM_Alpha_0 = 0.15; 390 float ILM_Alpha_1 = 0.40; 391 float ILM_Alpha_2 = 0.60; 392 float ILM_Alpha_3 = 0.85; 393 float ILM_Alpha_4 = 1.0; 394 float ILM_Value_0 = 1.0; 395 float ILM_Value_1 = 4.0; 396 float ILM_Value_2 = 3.0; 397 float ILM_Value_3 = 5.0; 398 float ILM_Value_4 = 2.0; 399 ILM_Value_0 = 0.55 - ILM_Value_0 / 10; 400 ILM_Value_1 = 0.55 - ILM_Value_1 / 10; 401 ILM_Value_2 = 0.55 - ILM_Value_2 / 10; 402 ILM_Value_3 = 0.55 - ILM_Value_3 / 10; 403 ILM_Value_4 = 0.55 - ILM_Value_4 / 10; 404 float NightRamp_V = lerp(ILM_Value_4, ILM_Value_3, step(ILM_A, ILM_Alpha_3)); 405 NightRamp_V = lerp(NightRamp_V, ILM_Value_2, step(ILM_A, ILM_Alpha_2)); 406 NightRamp_V = lerp(NightRamp_V, ILM_Value_1, step(ILM_A, ILM_Alpha_1)); 407 NightRamp_V = lerp(NightRamp_V, ILM_Value_0, step(ILM_A, ILM_Alpha_0)); 408 409 //DayRamp_V 410 float DayRamp_V = NightRamp_V + 0.5; 411 412 //IsDay 413 float IsDay = (LightDir.y + 1) / 2; 414 415 //RampColor 416 float3 DayDarkRampColor = tex2D(_RampTex, float2(0.003, DayRamp_V)); 417 float3 NightDarkRampColor = tex2D(_RampTex, float2(0.003, NightRamp_V)); 418 float3 DarkRampColor = lerp(NightDarkRampColor, DayDarkRampColor, IsDay); 419 420 421 return float4(BaseTexColor * DarkRampColor * _OutlineShadowColor, BaseTexColor.a); 422 } 423 ENDCG 424 } 425 } 426 FallBack "Diffuse" 427 }
标签:仿原,float,lerp,ILM,Value,float4,Unity,UE,float3 From: https://www.cnblogs.com/IslandZ/p/17608128.html