各位同学大家好
我已经很久没有没有写教程了,最近项目比较忙。各种加班各种带小孩儿,不过,老师一有机会也在给尽可能服务大家,今天来一个硬菜:移动端高效魔系符文如何制作,国庆起来,老师抽了点儿时间做了一个宝石模型和贴图:
老规矩,先看效果:
Unity URP Shader——魔系符文宝石是如何练成的
实现原理:
1:菲尼尔实现边缘光,
菲尼尔共公式:Fresnel =(1-dot (v,n))^power ;
v : ViewDir n: normalWorld
2:模拟反射
因为移动端处理,所以我们做模拟,不做真实的,大致原理是:
取一张贴图*2次菲尼尔运算。最后去控制强度和颜色,实现我们想要的效果。
half4 Reflect =reflect * saturate(XionmgMaoWuDao_Fresnel(normalWorld,viewDir,3)*XionmgMaoWuDao_Fresnel(normalWorld,viewDir,3)) *_ReflectIntensity*_ReflectColor;
3:模拟宝石内部效果
UV计算: 宝石是在不同的视角下观看宝石,会看见 视乎宝石里面的画面与镜子相同,都是无穷大。那么计算机科学也是同样的原理,也是从观察角度去看,所以UV的计算方式如下:
视角方向的(XY方向)-原点的XY方向,然后再做模型的Tiling运算。最后再计算出模型法线在世界空间中的XY方向 。加在一起实现视觉错觉运算。
half2 InsideUV = (viewDir.xy - float3 (0,0,0).xy)*_InsideUvTiling.xy+_InsideUvTiling.zw;
InsideUV+= normalWorld.xy * _InsideUvIntensity ;
最终代码如下:
//熊猫悟道
Shader "XiongMaoWuDao/XiongMaoLaoShi_Gem"
{
Properties
{
_normalPaner ("normal Panner",vector) =(0,0,0,0)
[MainColor] _BaseColor("BaseColor", Color) = (1,1,1,1)
_ReflectColor ("Reflect Color ",Color) = (1,1,1,1)
[HDR]_RimColor ("Rim Color" ,Color)= (1,1,1,1)
_EimissionMap ("Eimiss Map",2D) = "white" {}
_ReflectIntensity ("Reflect Intensity",float) =1
_InsideUvTiling ("Inside UV Tiling" , vector) =(1,1,1,1)
_InsideUvIntensity ("Inside Uv Intensity" ,float) = 1
_InsideMap ("Inside Map",2D)="white"{}
}
SubShader
{
Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalRenderPipeline" "Queue"="Geometry"}
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
half3 normal :NORMAL ;
half2 uv : TEXCOORD0;
};
struct Varyings
{
half2 uv : TEXCOORD0;
float4 positionHCS : SV_POSITION;
half3 viewDir :TEXCOORD1;
half3 normalWorld :TEXCOORD2 ;
};
TEXTURE2D(_EimissionMap);
SAMPLER(sampler_EimissionMap);
TEXTURE2D(_InsideMap);
SAMPLER(sampler_InsideMap);
CBUFFER_START(UnityPerMaterial)
float4 _EimissionMap_ST;
half4 _RimColor;
half3 _normalPaner;
half _ReflectIntensity;
half4 _InsideUvTiling;
half _InsideUvIntensity;
half4 _InsideMap_ST;
half4 _BaseColor;
half4 _ReflectColor;
CBUFFER_END
//宝石菲尼尔反射
half XionmgMaoWuDao_Fresnel( half3 normal ,half3 viewDir ,half power)
{
//菲尼尔公式: (1-dot (v,n))^power ;
return pow( 1.0- saturate(dot(normal,viewDir).x) ,power);
}
Varyings vert(Attributes v)
{
Varyings o;
half3 posWS = TransformObjectToWorld (v.positionOS.xyz);
o.positionHCS = TransformObjectToHClip(v.positionOS.xyz);
o.normalWorld = TransformObjectToWorldNormal (v.normal +_normalPaner);
o.viewDir =GetWorldSpaceNormalizeViewDir(posWS);
o.uv = TRANSFORM_TEX(v.uv, _EimissionMap);
return o;
}
half4 frag(Varyings i) : SV_Target
{
//初始化数据
half3 normalWorld = normalize (i.normalWorld);
half3 viewDir = normalize (i.viewDir);
//DIFFUSE
half4 Emiss = SAMPLE_TEXTURE2D(_EimissionMap, sampler_EimissionMap, i.uv);
half4 DiffuseA = (XionmgMaoWuDao_Fresnel(normalWorld,viewDir,3)+Emiss.r)*_RimColor;
//reflect
half reflect = SAMPLE_TEXTURE2D(_EimissionMap, sampler_EimissionMap, normalWorld.xy).g;
half4 Reflect =reflect * saturate(XionmgMaoWuDao_Fresnel(normalWorld,viewDir,3)*XionmgMaoWuDao_Fresnel(normalWorld,viewDir,3)) *_ReflectIntensity*_ReflectColor;
//Inside
half2 InsideUV = (viewDir.xy - float3 (0,0,0).xy)*_InsideUvTiling.xy+_InsideUvTiling.zw;
InsideUV+= normalWorld.xy * _InsideUvIntensity ;
half4 InsideMap = SAMPLE_TEXTURE2D(_InsideMap, sampler_InsideMap, InsideUV);
half4 totalColor = (DiffuseA+InsideMap)*_BaseColor + Reflect ;
return totalColor;
}
ENDHLSL
}
}
}