1. 程式人生 > >【Shader Forge】Refraction實現折射效果的研究

【Shader Forge】Refraction實現折射效果的研究

這裡寫圖片描述

Refraction
Refraction is a screen-space UV offset for refracting the background pixels. Make sure you set the alpha to something below 1 before using, so that the refraction effect is visible.

這是SF官方給出的折射節點的說明。
在生成的shader中對摺射節點進行跟蹤,使用的shader如下

// Shader created with Shader Forge v1.35 
// Shader Forge (c) Neat Corporation / Joachim Holmer - http://www.acegikmo.com/shaderforge/
//對Shader Forge 內建折射節點的研究 //使用了一個名為Test的Color屬性來確定SF如何使用節點的輸入資料,此種用法並不正確 Shader "Shader Forge/Default_Refraction" { Properties { _Alpha ("Alpha", Range(0, 1)) = 0.5 _Test ("Test", Color) = (0,0,0,1) } SubShader { Tags { "IgnoreProjector"="True"
"Queue"="Transparent" "RenderType"="Transparent" } GrabPass{ }//SF生成的程式碼使用了無引數的GrabPass來進行抓屏處理 Pass { Name "FORWARD" Tags { "LightMode"="ForwardBase" } Blend SrcAlpha OneMinusSrcAlpha ZWrite Off CGPROGRAM #define
UNITY_PASS_FORWARDBASE
#include "UnityCG.cginc" #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdbase #pragma only_renderers d3d9 d3d11 glcore gles #pragma target 3.0 uniform sampler2D _GrabTexture;//GrabPass傳出的預設紋理名稱為_GrabTexture,方便後續使用 uniform float _Alpha; uniform float4 _Test; struct VertexInput { float4 vertex : POSITION; }; struct VertexOutput { float4 pos : SV_POSITION; float4 screenPos : TEXCOORD0; }; VertexOutput vert (VertexInput v) { VertexOutput o = (VertexOutput)0; o.pos = mul(UNITY_MATRIX_MVP, v.vertex ); o.screenPos = o.pos; return o; } float4 frag(VertexOutput i) : COLOR { //從此處到sceneColor 計算結束之間的語句實現了計算螢幕座標的過程,也可使用內建函式ComputeScreenPos() //螢幕座標的計算方式參考《Unity shader 入門精要》第一版\90頁\4.9.3節 // //對內建變數_ProjectionParams 的 Unity官方說明如下: //_ProjectionParams (float4) //x is 1.0 (or –1.0 if currently rendering with a flipped projection matrix), y is the camera’s near plane, z is the camera’s far plane and w is 1/FarPlane. //消除平臺差異,翻轉螢幕座標 #if UNITY_UV_STARTS_AT_TOP float grabSign = -_ProjectionParams.x; #else float grabSign = _ProjectionParams.x; #endif i.screenPos = float4( i.screenPos.xy / i.screenPos.w, 0, 0 ); i.screenPos.y *= _ProjectionParams.x; //下面的語句完成了螢幕座標的最終偏移計算以及節點輸入值的使用 //————即輸入一個float2向量,之間加在螢幕座標上以實現偏移 float2 sceneUVs = float2(1,grabSign)*i.screenPos.xy*0.5+0.5 + _Test.rgb.rg; float4 sceneColor = tex2D(_GrabTexture, sceneUVs);//利用計算好的已經偏移過的螢幕座標對抓取紋理進行取樣 float3 finalColor = 0; return fixed4(lerp(sceneColor.rgb, finalColor,_Alpha),1);//使用傳入Opacity節點的值作為引數,對摺射的顏色和之前 計算的顏色進行線性插值混合 } ENDCG } } FallBack "Diffuse" CustomEditor "ShaderForgeMaterialInspector" }

使用的節點檢視如下:

跟蹤測試節點檢視

GT給出的實現方案如下:
GT_Glass_1

效果如下:
單層平面的折射效果

球體的折射效果

在不使用shadowcaster的情況下,通過指定不透明物體的fallback(legacy\Bumped Specular)來強制投射陰影
投射陰影

SF示例場景中的折射shader(簡化版)如下
原本的shader是使用了PBL光照,雙面顯示;修改後為簡單的Lambert光照,單面顯示。
這個shader的特點在於折射強度引數可以同時控制法線貼圖的強度(作為線性插值的引數)
SF折射shader(簡化版)

效果如下:
SF折射shader(簡化版)效果

完整的shader編碼方法可以參考《Unity Shader 入門精要》第10章節。

總結:
使用SF生成折射效果,一般使用法線節點的XY分量。折射節點只支援float二維向量輸入,輸入之後直接和螢幕座標相加。
由SF生成的折射shader使用了無引數的GrabPass,有可能會對效能造成影響。

補充:
利用Scene Color節點配合uv偏移實現在不使用Alpha混合的情況下形成折射效果。

SF官方對於Scene Color節點的介紹如下:
Scene Color
A texture containing a render of the scene before this object was rendered. By default, its UVs are in screen space, making each pixel represent the color behind the object. This can be used for more advanced blending/transparency effects, or a manual way of making refraction if the UVs are altered, among other things
Scene Color (場景顏色)
包含渲染此物件前的場景渲染的紋理。預設其 UV 位於螢幕空間中,從而讓每個畫素都代表物件背後的顏色。這可用於更加高階的混合/透明度效果,或作為 UV 改變時形成折射的其中一種手動方法

Scene Color 的實現其實和Refraction節點一樣,使用了無引數的GrabPass來進行抓屏。Refraction節點相當於對Scene Color 的封裝。

GT給出的利用Parallax (視差)節點偏移uv的方案如下:
這裡寫圖片描述

筆者在實現這種效果時沒有考慮到法線擾動對映對摺射效果的影響,所以缺乏真實感。

效果如下:
這裡寫圖片描述