带顶点动画的护盾效果——UnityShader学习笔记
生活随笔
收集整理的這篇文章主要介紹了
带顶点动画的护盾效果——UnityShader学习笔记
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
文章目錄
- 自言自語
- 一、效果
- 二、C#
- 三、Shader
- 總結
自言自語
最近又是很久沒有更新筆記了。原因有二。
一、最近一直再啃一個看起來酷炫的護盾效果 啃了好久啊。直至效果滿意 也理解了。 這個是一個同事傳授給我的 我算是偷師。
二、前不久難得出去旅游了一趟。五六年了,第一次出去旅游。真開心。不想回來。
所以導致很久沒更新筆記。今日就接著更新吧
一、效果
GIF限制大小,就不穿了。 放一個靜態(tài)圖,方便以后能快速查找區(qū)分。
二、C#
與上一筆記代碼一樣。就不重復貼了
三、Shader
同樣源碼貼出。并對上個筆記中不理解的地方 重新理解后做了更詳細的注釋筆記。 誰讓我腦子笨呢 不寫詳細點以后就又看不懂了。
Shader "ShaderFX/ShaderPractiseFX_BeeSphere" {Properties{[Header(BeeShape IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)]_EdgeMask ("EdgeMask", 2D) = "White" {}[HDR]_EdgeColor("BeeColor",Color) = (1,1,1,1)_BeeNoiseMap("EdgeNoiseMap",2D)="white"{}[HDR]_BeeColor("BeeEmissive",Color)=(1,1,1,1)[Space(10)][Header(RimColor IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)][HDR]_rimColor("RimColor",Color)=(1,1,1,1)_rimSmooth("RimSmooth",Range(0.001,4))=0.5_rimStrenth("RimStrenth",Float)=1_ShieldEdgeSmooth("ShieldEdgeSmooth",Range(0,10)) = 0.5_ShieldEdgePow("ShieldEdgePow",Range(0,2)) =1[Space(10)][Header(Distortion IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)][HDR]_DistortionColor("DistortionColor",Color) = (1,1,1,1)_NoiseIntensityDistor("NoiseDistortion",Float) =1_DistortionFactor("DistortionFactor",Float) = 1_DistortionSmooth ("DistortionSmooth",Float) =1_PositionOffset("DistortionPos",Vector) = (0,0,0,0)[Space(10)][Header(HitWave IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)]_rampmap("FadeRampTex",2D) = "white"{}[HDR]_WaveColor("WaveColor",Color) =(1,1,1,1)_NoiseMap ("NoiseMap",2D)="white"{}_WaveNoiseIntensity("WaveNoiseIntensity",Float) = 1_FadeScale ("WaveFadeScale",Float) = 1_FadeSmoosth("FadeSmooth",Float) = 0.5_FadeIntensity("FadeIntensity",Float) = 1_OffsetDistance("OffsetDistance",Float) = 1_OffsetWidth("OffsetWidth",Float) = 1[HDR]_NewVertexColor("OffsetColor",Color) = (1,1,1,1)[Space(10)][Header(FlowMap IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)][HDR]_FlowColor("FlowColor",Color) = (1,1,1,1)_FlowLightMap("FlowLightMap",2D)="white"{}_FlowMap("FlowMap",2D)="white"{}_FlowSpeed ("FlowSpeed",Float) = 0.2_FlowIntensityDirectional("FlowIntensityDirectional",Vector)=(0,0,0,0)[Space(10)][Header(Specular IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)][HDR]_specularColor("SpecularColor",Color) = (1,1,1,1)_Gloss("_Gloss",Float) = 100}SubShader{//Transparent+1 是為了在透明物體后邊渲染 不然看不見透明物體Tags { "RenderType"="Opaque" "Queue" = "Transparent+1"}LOD 100Pass{//因為是透明隊列,所以要注意混合模式 否則不會與前一幀進行有效的混合哦 Blend SrcAlpha OneMinusSrcAlpha//背面的應該先渲染 所以先剔除正面Cull FrontCGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbase#include "UnityCG.cginc"struct a2v{float4 vertex : POSITION;float2 texcoord0 : TEXCOORD0;float2 texcoord1 : TEXCOORD1;float2 texcoord2 : TEXCOORD2;float2 texcoord3 : TEXCOORD3;half3 normal : NORMAL;//實例化需要用到的UNITY宏UNITY_VERTEX_INPUT_INSTANCE_ID};struct v2f{float2 uv0 : TEXCOORD0;float2 uv1 : TEXCOORD1;float2 uv2 : TEXCOORD2;float2 uv3 : TEXCOORD3;float4 pos : SV_POSITION;float4 posWS : TEXCOORD5;float4 scrPos : TEXCOORD6;half3 normalWS : TEXCOORD4;float newVertexPos : TEXCOORD7;float3 newVertPos : TEXCOORD8;//實例化需要用到的UNITY宏UNITY_VERTEX_INPUT_INSTANCE_IDUNITY_VERTEX_OUTPUT_STEREO};sampler2D _EdgeMask;float4 _EdgeMask_ST; sampler2D _NoiseMap;float4 _NoiseMap_ST; sampler2D _BeeNoiseMap;float4 _BeeNoiseMap_ST;float4 _EdgeColor;float4 _rimColor;float _rimSmooth;float _rimStrenth;float _ShieldEdgeSmooth;float _ShieldEdgePow;float4 _BeeColor;sampler2D _rampmap;float4 _WaveColor;float _WaveNoiseIntensity;float _FadeScale ;float _FadeSmoosth ;float _FadeIntensity ;float _OffsetDistance;float _OffsetWidth;float4 _NewVertexColor;float _Gloss;float4 _specularColor;sampler2D _FlowMap;float4 _FlowMap_ST; sampler2D _FlowLightMap;float4 _FlowLightMap_ST;float4 _FlowIntensityDirectional;float4 _FlowColor;float _FlowSpeed;float4 _DistortionColor;float _NoiseIntensityDistor;float _DistortionFactor;float _DistortionSmooth;float3 _PositionOffset;//這3個參數(shù)時要傳進來的float MaxParticle;float waveSize[100];float4 circleCenter[100];//這3個參數(shù)時要傳進來的//聲明深度圖,拿到深度圖算邊界UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);float4 _CameraDepthTexture_TexelSize;//三平面映射 為的是讓沖擊波更好的能映射到模型表面 不受UV影響half4 TriPlanarnotime (float3 posWS,half3 normal,float smooth,sampler2D textures,float2 flow,float2 uv){half3 normalWS = normalize(normal);half3 weight = pow(abs(normalWS),smooth);//就是一個平均算法 記下就好了half3 uvWeight = weight /(weight.x+weight.y+weight.z);//flow是flowmap的干擾 可以要可以不要 *uv值 是為了做tiling縮放 其實可以不用half4 col0 = tex2D(textures,posWS.xy*uv+flow)*uvWeight.z;half4 col1 = tex2D(textures,posWS.xz*uv+flow)*uvWeight.y;half4 col2 = tex2D(textures,posWS.zy*uv+flow)*uvWeight.x;return col0+col1+col2;}//FlowMaphalf4 FlowMapFunction (float4 posws,float2 uv,float2 uv2,half Wave){//先算個時間float2 timeDelta = frac(_Time.y*_FlowSpeed)*_FlowIntensityDirectional;//再算個間隔幀時間float2 timeNext =frac(_Time.y*_FlowSpeed+0.5)*_FlowIntensityDirectional;//再算個兩個時間插值的插值因子float timeLerp = abs(frac(_Time.y*_FlowSpeed)*2-1);half2 flowDirection = 0.5-tex2D(_FlowMap,uv*_FlowMap_ST.xy+_FlowMap_ST.zw).rg+Wave;//前一狀態(tài)的流動效果half2 FlowMap = flowDirection*timeDelta;half4 mainTexpre = tex2D(_FlowLightMap,uv*_FlowLightMap_ST.xy+_FlowLightMap_ST.zw+FlowMap);//后一狀態(tài)的流動效果half2 flowMapNext = flowDirection*timeNext; half4 mainTex = tex2D(_FlowLightMap,uv*_FlowLightMap_ST.xy+_FlowLightMap_ST.zw+flowMapNext);//插值兩個流動效果 減少頓挫感half4 col = lerp(mainTexpre,mainTex,timeLerp);//做個MASK 是為了遮擋UV拉伸的地方float mask = 1-saturate(pow(1-smoothstep(uv2.y,1,0.98),1));col *= mask;//輸出最終效果return col; }//計算可以驅動整塊多邊形進行頂點動畫的方法float3 VertexToFaceCenterFirst (float3 worldPos,float3 normalWS){//利用模型中心點,頂點法線 等數(shù)據(jù)算出頂點到多邊形面中心點的向量,以此來移動頂點到模型法向量的中心點位置 //從而使得多邊形的頂點能夠統(tǒng)一朝一個方向變化float3 centerPositionWS = mul(unity_ObjectToWorld,float4(0,0,0,1)).xyz;float3 comparePositionWS = worldPos - centerPositionWS;//Rejection 算法float3 newPos = comparePositionWS -normalWS* dot(comparePositionWS,normalWS)/dot(normalWS,normalWS); return newPos;}float3 VertexToFaceCenter (float3 worldPos,float3 normalWS){//利用模型中心點,頂點法線 等數(shù)據(jù)算出頂點到多邊形面中心點的向量,以此來移動頂點到模型法向量的中心點位置 //從而使得多邊形的頂點能夠統(tǒng)一朝一個方向變化float3 temp = VertexToFaceCenterFirst (worldPos,normalWS);float3 newVertexPosition = worldPos.xyz -temp;return newVertexPosition;}//點擊沖擊波,這個直接copy上個筆記內容的東西half FinalWave (float3 worldPos,float2 uv){half ramp;for (int j = 0; j<MaxParticle; j++){//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//1 大概思路就是先求點擊生成粒子穿過來的沖擊波范圍的圓形大小,用世界坐標點來算. |//2 利用粒子傳過來的大小來算出這個圓形區(qū)域內形成的沖擊波的基本圈兒 |//3 再利用一個參數(shù)模擬一下淡出淡入的效果. 與算平滑的方法一樣 用除法 由于淡入其實是從小到大的縮放 并且很快速 所以這里相當于只是做了淡出效果 |//4 最后看需求是否添加一個貼圖來影響一下剛求出的這個圈兒的外形 當然 噪聲圖和三平面映射也都是看情況加 |//5 需要注意的是,由于C#腳本傳進來的是兩個數(shù)組,所以需要用for循環(huán)來遍歷每個數(shù)組里的位置和大小信息, 才能讓生成的每個粒子的信息 生成所有的像素 C#要傳數(shù)組進來 這個還得去研究理解下. |//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//求距離 函數(shù)作用是求空間中任意一點到物體表面的最小距離。此間我們假設坐標原點為000中心點//中心點到任意一點像素的最小距離可有如下兩個函數(shù)求出. 任意一點越接近000點則返回值越小越黑.減去半徑后則可以求畫出相應的圓形.//float dis = length(circleCenter - i.posWS.xyz);float dis = distance(circleCenter[j],worldPos);//再用dis - 傳進來的粒子大小,得到一個圈兒的大小float circleSize = dis - waveSize[j];float noisemap = tex2D(_NoiseMap, uv).r;//三平面映射方法調用 如果需要調用flowmap 則還要給方法增加參數(shù) 這里先不用//float noisemap = TriPlanarnotime(worldPos,normal,0.5,noise,0,uv2).r;//淡出范圍和淡出平滑 float fadesize =1- dis /_FadeScale;float fadeSmooth =saturate( fadesize * _FadeIntensity);//以上內容今后看可能就不理解了. 那就操作一遍 一行一行return輸出看過程float circleCol = saturate((circleSize + noisemap*_WaveNoiseIntensity)/_FadeSmoosth);float wave = tex2D (_rampmap,float2(circleCol,0.5)).r;float wavefade = wave *fadeSmooth;ramp += wavefade;}return clamp(0,1,ramp);}//計算texLOD的點擊沖擊波函數(shù) 用于頂點著色器中half FinalWaveVertex (float3 worldPos,float smooth,float2 uv2){half ramp;for (int j = 0; j<MaxParticle; j++){//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//1 大概思想就是先求點擊生成粒子穿過來的沖擊波范圍的圓形大小,用世界坐標點來算. |//2 利用粒子傳過來的大小來算出這個圓形區(qū)域內形成的沖擊波的基本圈兒 |//3 再利用一個參數(shù)模擬一下淡出淡入的效果. 與算平滑的方法一樣 用除法 由于淡入其實是從小到大的縮放 并且很快速 所以這里相當于只是做了淡出效果 |//4 最后看需求是否添加一個貼圖來影響一下剛求出的這個圈兒的外形 當然 噪聲圖和三平面映射也都是看情況加 |//5 需要注意的是,由于C#腳本傳進來的是兩個數(shù)組,所以需要用for循環(huán)來遍歷每個數(shù)組里的位置和大小信息, 才能讓生成的每個粒子的信息 生成所有的像素 C#要傳數(shù)組進來 這個還得去研究理解下. |//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//求距離 函數(shù)作用是求空間中任意一點到物體表面的最小距離。此間我們假設坐標原點為000中心點//中心點到任意一點像素的最小距離可有如下兩個函數(shù)求出. 任意一點越接近000點則返回值越小越黑.減去半徑后則可以求畫出相應的圓形.//float dis = length(circleCenter - i.posWS.xyz);float dis = distance(circleCenter[j],worldPos);//再用dis - 傳進來的粒子大小,得到一個圈兒的大小float circleSize = dis - waveSize[j];float noisemap = tex2Dlod(_NoiseMap, float4(uv2,0,0)).r;//三平面映射方法調用 如果需要調用flowmap 則還要給方法增加參數(shù) 這里先不用//float noisemap = TriPlanarlod(worldPos,normal,0.5,noise,0,uv2).r;//淡出范圍和淡出平滑 float fadesize =1- dis /_FadeScale;float fadeSmooth =saturate( fadesize * _FadeIntensity);float circleCol = saturate((circleSize + noisemap*_WaveNoiseIntensity*0.2)/smooth);float wave = tex2Dlod (_rampmap,float4(circleCol,0.5,0,0)).r;float wavefade = wave *fadeSmooth;ramp += wavefade;}return saturate(ramp);}//溶解算法 重新定義函數(shù) 用于頂點著色器 溶解時縮放多邊形half DistortionFunction (float3 newWorldPos,float2 uv){//先算出球體中心點的相對位置 用頂點世界坐標 減去 模型中心點的世界坐標空間下的位置 模型中心點一般在DCC軟件里居中 也就是000點的位置 點的位置有意義不是矢量 所以W值為1float3 centerpos =newWorldPos - mul(unity_ObjectToWorld,float4(0,0,0,1)).xyz;//傳入溶解起始點位置 float3 localPos = _PositionOffset;//計算一個動畫的noise干擾half distortionNoise = tex2Dlod(_NoiseMap,float4(uv+_Time.y*0.05,0,0)).r*_NoiseIntensityDistor;//通過distance函數(shù) 算出溶解黑白遮罩范圍half dispos = distance(centerpos,localPos);//再用范圍減去一個值算出邊界 減去noise干擾值 增加擾動效果 最后除以一個值來控制溶解變寬的平滑過渡范圍half distortion = saturate((dispos - _DistortionFactor-distortionNoise)/_DistortionSmooth);return distortion;}v2f vert (a2v v){v2f o;//實例化需要用到的UNITY宏UNITY_SETUP_INSTANCE_ID(v);UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);UNITY_TRANSFER_INSTANCE_ID(v,o);o.normalWS = (UnityObjectToWorldNormal(v.normal));o.posWS = mul(unity_ObjectToWorld,v.vertex);o.uv0 = v.texcoord0;o.uv1 = v.texcoord1;o.uv2 = v.texcoord2;o.uv3 = v.texcoord3;//計算點擊效果對頂點的偏移影響//算出點擊的中心點位置float3 newVertexPositionWS = VertexToFaceCenter(o.posWS.xyz,o.normalWS);//算出此位置下點擊對頂點的位移變化值half waveVertex = FinalWaveVertex (newVertexPositionWS,_OffsetWidth,o.uv2);//溶解頂點縮放float3 newVertPosCenter = VertexToFaceCenterFirst(o.posWS,o.normalWS);half distortionVertex = DistortionFunction(newVertexPositionWS,o.uv2);//用負號做個反向,來表示出現(xiàn)消失的正負方向float3 distortionNewPos = -distortionVertex*newVertPosCenter+o.posWS.xyz;//再將頂點溶解轉換到模型空間下 好做相對位置的位移縮放float3 localDistiortion = mul (unity_WorldToObject,distortionNewPos);//用算好的偏移值 去在他的法線方向上做擾動。 這里注意對法線擾動是用乘法來做 與outline的xy軸做乘法計算是一樣的 然后把擾動值 作為頂點偏移值 累加到vertex上v.normal *= waveVertex*0.01;//這一步就是相當于把頂點按照法線方向外拓 也就是按照發(fā)現(xiàn)方向位移float3 newVertex =v.vertex.xyz+v.normal*_OffsetDistance+localDistiortion;//因為之前都是在相對坐標下進行 所以要再減去原本的頂點坐標 來轉換成絕對坐標 原理同世界空間坐標 減去 模型頂點自身坐標在世界空間下的表示一樣 以防止起始位置會隨模型移動而相對于模型本身位置發(fā)生改變newVertex -=v.vertex.xyz;//最后再把相應的計算結果存到插槽中 傳到片元著色器o.pos = UnityObjectToClipPos(newVertex);o.scrPos = ComputeScreenPos(o.pos);o.newVertexPos = waveVertex;o.newVertPos = newVertexPositionWS;return o;}half4 frag (v2f i) : SV_Target{//點擊釋放沖擊波 half wave = saturate(FinalWave (i.posWS , i.uv3));//給沖擊波加個顏色 half4 waveCol = wave *_WaveColor;//把受頂點動畫影響的片也進行著色 最后加到最終結果中half4 newVertexColor = i.newVertexPos*_NewVertexColor;//多邊形遮罩half beeTex = tex2D(_EdgeMask,i.uv0).r;//噪聲擾動圖half beeNoise=tex2D(_BeeNoiseMap,i.uv3*_BeeNoiseMap_ST.xy+_BeeNoiseMap_ST.zw*_Time.y*0.01);//把噪聲一加完成half4 beeColor = beeTex*_EdgeColor+beeTex*beeNoise*_BeeColor;//求交叉邊緣 這一套亂七八糟的操作 只能背了//除以分量w來得到屏幕空間的頂點坐標位置float4 screenPos = i.scrPos/i.scrPos.w;//這里需要做個近裁剪面的正負值判斷 來修正Z值screenPos.z = UNITY_NEAR_CLIP_VALUE>=0 ? screenPos.z : screenPos.z*0.5+0.5;//利用屏幕空間中XY坐標也就是像素位置來采樣深度圖 得到實際深度值float depth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,screenPos.xy));//這步推測是為了根據(jù)深度值在屏幕空間下的交叉邊界的像體現(xiàn)float distanceDepth =saturate(abs((depth - LinearEyeDepth(screenPos.z))));//然后根據(jù)結果算出邊界的和非邊界的地方. 這里這么計算總覺得就把平滑過渡的計算給干掉了 氣氛上感覺還要除以一個smooth值 所以我擅自加上看看float EdgeSmooth =(1-saturate(smoothstep(0,_ShieldEdgePow,distanceDepth)))/_ShieldEdgeSmooth;//溶解float3 centerpos =i.newVertPos - mul(unity_ObjectToWorld,float4(0,0,0,1)).xyz;float3 localPos = _PositionOffset;//用uv2 來模擬閃爍效果half distortionNoise = tex2D(_NoiseMap,i.uv2+_Time.y*0.05).r*_NoiseIntensityDistor;half dispos = distance(localPos,centerpos);half distortion = saturate((dispos - _DistortionFactor+distortionNoise)/_DistortionSmooth);half distortionStep = step(0,saturate((dispos - _DistortionFactor+distortionNoise)));half4 distorCol = (distortion+distortion*distortionStep)*_DistortionColor;//邊緣光 NV 計算 要復雜點的話就用 shlick的 近似公式來計算//shlick近似等式 為 fresnel = f0 +(1-f0)*pow(1-NV,5);half3 viewDir = normalize(UnityWorldSpaceViewDir(i.posWS));half3 normalDir = normalize(i.normalWS);half3 lightDir = normalize(UnityWorldSpaceLightDir(i.posWS));half NV = abs(dot(viewDir,normalDir));//把邊緣交叉的部分算邊緣光里 half rimArea = saturate(1 - NV);half4 rimColor =saturate(((rimArea+EdgeSmooth)+_rimStrenth)/_rimSmooth)*_rimColor;//再加個表面高光吧 看起來可能更精致點half3 Hdir = normalize(viewDir+lightDir);half NH = saturate(dot(normalDir,Hdir));half spec = abs(pow(NH,_Gloss));half4 speccolor = spec*_specularColor;//護盾流動FlowMaphalf2 flowDirectionalIntensity = _FlowIntensityDirectional.xy;half4 FlowMapColor = FlowMapFunction(i.posWS,i.uv3,i.uv3,wave)*_FlowColor; half4 finalCol = rimColor+beeColor+FlowMapColor+waveCol+newVertexColor+speccolor;//溶解邊緣光插值合并//beeColor.rgb*4 為個人調整亮度值的經驗系數(shù)half3 col = lerp(finalCol.rgb,distorCol.rgb+distorCol.rgb*beeTex*beeColor.rgb*4,saturate(distortion));//Alpha計算 在透明物體計算的過程中 尤為重要 不要搞錯最終輸出的alpha值到底會受到哪些方面的影響half finalAlpha =saturate(1-distortion)*finalCol.a;//將這個pass由于是先剔除正面的 放在背面渲染 所以亮度相對降低一點,做出點前后層次感 0.65也是一個經驗值 所以計算在內 也可以直接給finalAlpha值進行一個縮小return float4(col*0.65,finalAlpha);}ENDCG}Pass{Blend SrcAlpha OneMinusSrcAlphaCull BackCGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbase#include "UnityCG.cginc"struct a2v{float4 vertex : POSITION;float2 texcoord0 : TEXCOORD0;float2 texcoord1 : TEXCOORD1;float2 texcoord2 : TEXCOORD2;float2 texcoord3 : TEXCOORD3;half3 normal : NORMAL;//實例化需要用到的UNITY宏UNITY_VERTEX_INPUT_INSTANCE_ID};struct v2f{float2 uv0 : TEXCOORD0;float2 uv1 : TEXCOORD1;float2 uv2 : TEXCOORD2;float2 uv3 : TEXCOORD3;float4 pos : SV_POSITION;float4 posWS : TEXCOORD5;float4 scrPos : TEXCOORD6;half3 normalWS : TEXCOORD4;float newVertexPos : TEXCOORD7;float3 newVertPos : TEXCOORD8;//實例化需要用到的UNITY宏UNITY_VERTEX_INPUT_INSTANCE_IDUNITY_VERTEX_OUTPUT_STEREO};sampler2D _EdgeMask;float4 _EdgeMask_ST; sampler2D _NoiseMap;float4 _NoiseMap_ST; sampler2D _BeeNoiseMap;float4 _BeeNoiseMap_ST;float4 _EdgeColor;float4 _rimColor;float _rimSmooth;float _rimStrenth;float _ShieldEdgeSmooth;float _ShieldEdgePow;float4 _BeeColor;sampler2D _rampmap;float4 _WaveColor;float _WaveNoiseIntensity;float _FadeScale ;float _FadeSmoosth ;float _FadeIntensity ;float _OffsetDistance;float _OffsetWidth;float4 _NewVertexColor;float _Gloss;float4 _specularColor;sampler2D _FlowMap;float4 _FlowMap_ST; sampler2D _FlowLightMap;float4 _FlowLightMap_ST;float4 _FlowIntensityDirectional;float4 _FlowColor;float _FlowSpeed;float4 _DistortionColor;float _NoiseIntensityDistor;float _DistortionFactor;float _DistortionSmooth;float3 _PositionOffset;//這3個參數(shù)時要傳進來的float MaxParticle;float waveSize[100];float4 circleCenter[100];//這3個參數(shù)時要傳進來的//聲明深度圖,拿到深度圖算邊界UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);float4 _CameraDepthTexture_TexelSize;//三平面映射 為的是讓沖擊波更好的能映射到模型表面 不受UV影響half4 TriPlanarnotime (float3 posWS,half3 normal,float smooth,sampler2D textures,float2 flow,float2 uv){half3 normalWS = normalize(normal);half3 weight = pow(abs(normalWS),smooth);half3 uvWeight = weight /(weight.x+weight.y+weight.z);//flow是flowmap的干擾 可以要可以不要 *uv值 是為了做tiling縮放 其實可以不用half4 col0 = tex2D(textures,posWS.xy*uv+flow)*uvWeight.z;half4 col1 = tex2D(textures,posWS.xz*uv+flow)*uvWeight.y;half4 col2 = tex2D(textures,posWS.zy*uv+flow)*uvWeight.x;return col0+col1+col2;}//FlowMaphalf4 FlowMapFunction (float4 posws,float2 uv,float2 uv2,half Wave){//先算個時間float2 timeDelta = frac(_Time.y*_FlowSpeed)*_FlowIntensityDirectional;//再算個間隔幀時間float2 timeNext =frac(_Time.y*_FlowSpeed+0.5)*_FlowIntensityDirectional;//再算個兩個時間插值的插值因子float timeLerp = abs(frac(_Time.y*_FlowSpeed)*2-1);half2 flowDirection = 0.5-tex2D(_FlowMap,uv*_FlowMap_ST.xy+_FlowMap_ST.zw).rg+Wave;//前一狀態(tài)的流動效果half2 FlowMap = flowDirection*timeDelta;half4 mainTexpre = tex2D(_FlowLightMap,uv*_FlowLightMap_ST.xy+_FlowLightMap_ST.zw+FlowMap);//后一狀態(tài)的流動效果half2 flowMapNext = flowDirection*timeNext; half4 mainTex = tex2D(_FlowLightMap,uv*_FlowLightMap_ST.xy+_FlowLightMap_ST.zw+flowMapNext);//插值兩個流動效果 減少頓挫感half4 col = lerp(mainTexpre,mainTex,timeLerp);float mask = 1-saturate(pow(1-smoothstep(uv2.y,1,0.98),1));col *= mask;//輸出最終效果return col; }//計算可以驅動整塊多邊形進行頂點動畫的方法float3 VertexToFaceCenterFirst (float3 worldPos,float3 normalWS){//利用模型中心點,頂點法線 等數(shù)據(jù)算出頂點到多邊形面中心點的向量,以此來移動頂點到模型法向量的中心點位置 //從而使得多邊形的頂點能夠統(tǒng)一朝一個方向變化float3 centerPositionWS = mul(unity_ObjectToWorld,float4(0,0,0,1)).xyz;float3 comparePositionWS = worldPos - centerPositionWS;float3 newPos = comparePositionWS -normalWS* dot(comparePositionWS,normalWS)/dot(normalWS,normalWS); return newPos;}float3 VertexToFaceCenter (float3 worldPos,float3 normalWS){//利用模型中心點,頂點法線 等數(shù)據(jù)算出頂點到多邊形面中心點的向量,以此來移動頂點到模型法向量的中心點位置 //從而使得多邊形的頂點能夠統(tǒng)一朝一個方向變化float3 temp = VertexToFaceCenterFirst (worldPos,normalWS);float3 newVertexPosition = worldPos.xyz -temp;return newVertexPosition;}//點擊沖擊波,這個直接copy原來的half FinalWave (float3 worldPos,float2 uv){half ramp;for (int j = 0; j<MaxParticle; j++){//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//1 大概思路就是先求點擊生成粒子穿過來的沖擊波范圍的圓形大小,用世界坐標點來算. |//2 利用粒子傳過來的大小來算出這個圓形區(qū)域內形成的沖擊波的基本圈兒 |//3 再利用一個參數(shù)模擬一下淡出淡入的效果. 與算平滑的方法一樣 用除法 由于淡入其實是從小到大的縮放 并且很快速 所以這里相當于只是做了淡出效果 |//4 最后看需求是否添加一個貼圖來影響一下剛求出的這個圈兒的外形 當然 噪聲圖和三平面映射也都是看情況加 |//5 需要注意的是,由于C#腳本傳進來的是兩個數(shù)組,所以需要用for循環(huán)來遍歷每個數(shù)組里的位置和大小信息, 才能讓生成的每個粒子的信息 生成所有的像素 C#要傳數(shù)組進來 這個還得去研究理解下. |//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//求距離 函數(shù)作用是求空間中任意一點到物體表面的最小距離。此間我們假設坐標原點為000中心點//中心點到任意一點像素的最小距離可有如下兩個函數(shù)求出. 任意一點越接近000點則返回值越小越黑.減去半徑后則可以求畫出相應的圓形.//float dis = length(circleCenter - i.posWS.xyz);float dis = distance(circleCenter[j],worldPos);//再用dis - 傳進來的粒子大小,得到一個圈兒的大小float circleSize = dis - waveSize[j];float noisemap = tex2D(_NoiseMap, uv).r;//三平面映射方法調用 如果需要調用flowmap 則還要給方法增加參數(shù) 這里先不用//float noisemap = TriPlanarnotime(worldPos,normal,0.5,noise,0,uv2).r;//淡出范圍和淡出平滑 float fadesize =1- dis /_FadeScale;float fadeSmooth =saturate( fadesize * _FadeIntensity);float circleCol = saturate((circleSize + noisemap*_WaveNoiseIntensity)/_FadeSmoosth);float wave = tex2D (_rampmap,float2(circleCol,0.5)).r;float wavefade = wave *fadeSmooth;ramp += wavefade;}return clamp(0,1,ramp);}//計算texLOD的點擊沖擊波函數(shù) 用于頂點著色器中half FinalWaveVertex (float3 worldPos,float smooth,float2 uv2){half ramp;for (int j = 0; j<MaxParticle; j++){//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//1 大概思想就是先求點擊生成粒子穿過來的沖擊波范圍的圓形大小,用世界坐標點來算. |//2 利用粒子傳過來的大小來算出這個圓形區(qū)域內形成的沖擊波的基本圈兒 |//3 再利用一個參數(shù)模擬一下淡出淡入的效果. 與算平滑的方法一樣 用除法 由于淡入其實是從小到大的縮放 并且很快速 所以這里相當于只是做了淡出效果 |//4 最后看需求是否添加一個貼圖來影響一下剛求出的這個圈兒的外形 當然 噪聲圖和三平面映射也都是看情況加 |//5 需要注意的是,由于C#腳本傳進來的是兩個數(shù)組,所以需要用for循環(huán)來遍歷每個數(shù)組里的位置和大小信息, 才能讓生成的每個粒子的信息 生成所有的像素 C#要傳數(shù)組進來 這個還得去研究理解下. |//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//求距離 函數(shù)作用是求空間中任意一點到物體表面的最小距離。此間我們假設坐標原點為000中心點//中心點到任意一點像素的最小距離可有如下兩個函數(shù)求出. 任意一點越接近000點則返回值越小越黑.減去半徑后則可以求畫出相應的圓形.//float dis = length(circleCenter - i.posWS.xyz);float dis = distance(circleCenter[j],worldPos);//再用dis - 傳進來的粒子大小,得到一個圈兒的大小float circleSize = dis - waveSize[j];float noisemap = tex2Dlod(_NoiseMap, float4(uv2,0,0)).r;//三平面映射方法調用 如果需要調用flowmap 則還要給方法增加參數(shù) 這里先不用//float noisemap = TriPlanarlod(worldPos,normal,0.5,noise,0,uv2).r;//淡出范圍和淡出平滑 float fadesize =1- dis /_FadeScale;float fadeSmooth =saturate( fadesize * _FadeIntensity);float circleCol = saturate((circleSize + noisemap*_WaveNoiseIntensity*0.2)/smooth);float wave = tex2Dlod (_rampmap,float4(circleCol,0.5,0,0)).r;float wavefade = wave *fadeSmooth;ramp += wavefade;}return saturate(ramp);}//溶解算法 重新定義函數(shù) 用于頂點著色器 溶解時縮放多邊形half DistortionFunction (float3 newWorldPos,float2 uv){float3 centerpos =newWorldPos - mul(unity_ObjectToWorld,float4(0,0,0,1)).xyz;float3 localPos = _PositionOffset;half distortionNoise = tex2Dlod(_NoiseMap,float4(uv+_Time.y*0.05,0,0)).r*_NoiseIntensityDistor;half dispos = distance(centerpos,localPos);half distortion = saturate((dispos - _DistortionFactor-distortionNoise)/_DistortionSmooth);return distortion;}v2f vert (a2v v){v2f o;//實例化需要用到的UNITY宏UNITY_SETUP_INSTANCE_ID(v);UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);UNITY_TRANSFER_INSTANCE_ID(v,o);o.normalWS = (UnityObjectToWorldNormal(v.normal));o.posWS = mul(unity_ObjectToWorld,v.vertex);o.uv0 = v.texcoord0;o.uv1 = v.texcoord1;o.uv2 = v.texcoord2;o.uv3 = v.texcoord3;//計算點擊效果對頂點的偏移影響float3 newVertexPositionWS = VertexToFaceCenter(o.posWS.xyz,o.normalWS);half waveVertex = FinalWaveVertex (newVertexPositionWS,_OffsetWidth,o.uv2);//溶解頂點縮放float3 newVertPosCenter = VertexToFaceCenterFirst(o.posWS,o.normalWS);half distortionVertex = DistortionFunction(newVertexPositionWS,o.uv2);float3 distortionNewPos = -distortionVertex*newVertPosCenter+o.posWS.xyz;float3 localDistiortion = mul (unity_WorldToObject,distortionNewPos);//用算好的偏移值 去在他的法線方向上做擾動。 然后把擾動值 作為頂點偏移值 累加到vertex上v.normal *= waveVertex*0.01;float3 newVertex =v.vertex.xyz+v.normal*_OffsetDistance+localDistiortion;newVertex -=v.vertex.xyz;o.pos = UnityObjectToClipPos(newVertex);o.scrPos = ComputeScreenPos(o.pos);o.newVertexPos = waveVertex;o.newVertPos = newVertexPositionWS;return o;}half4 frag (v2f i) : SV_Target{//點擊釋放沖擊波 half wave = saturate(FinalWave (i.posWS , i.uv3));half4 waveCol = wave *_WaveColor;//把受頂點動畫影響的片也進行著色 最后加到最終結果中half4 newVertexColor = i.newVertexPos*_NewVertexColor;//多邊形遮罩half beeTex = tex2D(_EdgeMask,i.uv0).r;//噪聲擾動圖half beeNoise=tex2D(_BeeNoiseMap,i.uv3*_BeeNoiseMap_ST.xy+_BeeNoiseMap_ST.zw*_Time.y*0.01);//把噪聲一加完成half4 beeColor = beeTex*_EdgeColor+beeTex*beeNoise*_BeeColor;//求交叉邊緣 float4 screenPos = i.scrPos/i.scrPos.w;screenPos.z = UNITY_NEAR_CLIP_VALUE>=0 ? screenPos.z : screenPos.z*0.5+0.5;float depth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,screenPos.xy));float distanceDepth =saturate(abs((depth - LinearEyeDepth(screenPos.z))));float EdgeSmooth =(1-saturate(smoothstep(0,_ShieldEdgePow,distanceDepth)))/_ShieldEdgeSmooth;//溶解float3 centerpos =i.newVertPos - mul(unity_ObjectToWorld,float4(0,0,0,1)).xyz;float3 localPos = _PositionOffset;//用uv2 來模擬閃爍效果half distortionNoise = tex2D(_NoiseMap,i.uv2+_Time.y*0.05).r*_NoiseIntensityDistor;half dispos = distance(localPos,centerpos);half distortion = saturate((dispos - _DistortionFactor+distortionNoise)/_DistortionSmooth);half distortionStep = step(0,saturate((dispos - _DistortionFactor+distortionNoise)));half4 distorCol = (distortion+distortion*distortionStep)*_DistortionColor;//邊緣光 NV 計算 要復雜點的話就用 shlick的 近似公式來計算//shlick近似等式 為 fresnel = f0 +(1-f0)*pow(1-NV,5);half3 viewDir = normalize(UnityWorldSpaceViewDir(i.posWS));half3 normalDir = normalize(i.normalWS);half3 lightDir = normalize(UnityWorldSpaceLightDir(i.posWS));half NV = abs(dot(viewDir,normalDir));//把邊緣交叉的部分算邊緣光里 half rimArea = saturate(1 - NV);half4 rimColor =saturate(((rimArea+EdgeSmooth)+_rimStrenth)/_rimSmooth)*_rimColor;//再加個表面高光吧 看起來可能更精致點half3 Hdir = normalize(viewDir+lightDir);half NH = saturate(dot(normalDir,Hdir));half spec = abs(pow(NH,_Gloss));half4 speccolor = spec*_specularColor;//護盾流動FlowMaphalf2 flowDirectionalIntensity = _FlowIntensityDirectional.xy;half4 FlowMapColor = FlowMapFunction(i.posWS,i.uv3,i.uv3,wave)*_FlowColor; half4 finalCol = rimColor+beeColor+FlowMapColor+waveCol+newVertexColor+speccolor;//溶解邊緣光插值合并half3 col = lerp(finalCol.rgb,distorCol.rgb+distorCol.rgb*beeTex*beeColor.rgb*4,saturate(distortion));half finalAlpha =saturate(1-distortion)*finalCol.a;return float4(col,finalAlpha);}ENDCG}} }總結
其實在寫這個筆記的時候,已經是做好效果一禮拜之后了。果不其然,很多我都看不懂額。所以重新對每一行進行理解再進行注釋。沒辦法,自己記憶力和腦子越來越不好。年齡和壓力擺在這兒。只能用這樣的笨辦法強迫自己反復去記憶理解吧。 雖然現(xiàn)在學習進度越來越慢,但我還是不會放棄的。 加油老男孩兒。
總結
以上是生活随笔為你收集整理的带顶点动画的护盾效果——UnityShader学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html5 red5,一个基于red5+
- 下一篇: 应运而生的环保APP