之前也說過引擎能不能提供一個一般化的開發環境給使用者, 這樣使用者只需要指定他要的開發環境, 就能用它最熟悉的方式去寫Shader了.
從提供者的角度來看, 因為有太多的應用場景無法確定, 所以提供無數多套的設定才能滿足需求, 比如你要用來做一般Shader還是用來做后處理用, 后處理中的頂點位置在片元階段的插值得到的就絕對不是所顯示的物件的世界坐標.
從使用者的角度來說, 在經過多平臺, 多版本的迭代之后, 要維護的代碼量只會越來越多, 到最后簡直不知道怎樣去維護了, 舉個例子 :
0. 變數宣告
sampler2D _MainTex; half4 _MainTex_ST; half4 _MainTex_TexelSize; struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; };
1. 初始代碼
v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; }
2. UV 有拉伸位移的代碼 -- 多用于物體渲染
v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; }
3. 我要用在VR上! -- 官方后處理效果可見
v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = UnityStereoScreenSpaceUVAdjust(v.uv, _MainTex_ST); return o; }
4. 我要用在后處理上! -- 后處理對于螢屏起始點敏感
v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) { o.uv.y = 1 - o.uv.y; } #endif return o; }
5. 后處理UV有拉伸位移! -- 我都不知道這段代碼對不對了! (后處理的縮放系數始終為1, 偏移始終為0, 被引擎強制處理了)
v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) { o.uv.y = 1 - o.uv.y; } #endif return o; }
6. 我要繼續用到VR的后處理上! -- 我已經飄了!
v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = UnityStereoScreenSpaceUVAdjust(v.uv, _MainTex_ST); #if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0.0) o.uv.y = 1.0 - o.uv.y; #endif return o; }
這些不是隨便臆想出來的, 它的官方代碼也是一樣的, 隨著版本的更迭提供了更多的目標平臺, 所以官方的代碼也在一直變化, 這只是單一個UV的變數問題, 其它問題比這多的多......有一份代碼就要改一份, 各種各樣Shader用的多的專案組估計要升天的.
像上面的UV變數, 正常來說你有 _MainTex_ST 的設定的話, 一定會用 TRANSFORM_TEX(v.uv, _MainTex); 的吧, 或者我使用VR 并且使用Single Pass模式的話, 肯定要去呼叫 UnityStereoScreenSpaceUVAdjust(v.uv, _MainTex_ST); 的吧, 就不能在頂點階段傳入的時候給我自動計算好嗎, 每次還要開發者自己去加宏判斷平臺嗎, 這些在編輯器下加個平臺選項不就好了嗎.
像 UNITY_UV_STARTS_AT_TOP 這種判斷, 應該是每個螢屏后處理都要加的吧, 看看它出現的次數, 如果給使用者設定這個Shader是使用D3D或者OpenGL標準的話, 我們就能明確知道螢屏(0,0)點的位置在哪了, 習慣opengl的就從左上角開始計算, 習慣D3D的從左下角開始計算, 這些不就又能省掉了么, 太能折騰了.
(2020.03.10)
今天發現似乎平臺Graphics APIs是可以選擇的, 就在PlayerBuild Settings里面, 通過手動添加目標API就可以設定了:

運行時它會從上往下選擇當前平臺可用的API, 我們來測驗一下吧, 為了減少變數, 只留目標API, 先測驗一下OpenGL的:

用一個簡單的后處理Shader來跑一下
using UnityEngine; public class EditorCamera : MonoBehaviour { public Shader shader; private Material m_mat; void Start() { if(shader) { m_mat = new Material(shader); } } private void OnRenderImage(RenderTexture source, RenderTexture destination) { if(m_mat) { Graphics.Blit(source, destination, m_mat); } else { Graphics.Blit(source, destination); } } }
Shader "Unlit/StandardTest" { Properties { _MainTex("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType" = "Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; float t : TEXCOORD1; }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); #if UNITY_UV_STARTS_AT_TOP o.t = 1.0; #else o.t = 0.2; #endif return o; } fixed4 frag(v2f i) : SV_Target { return i.t > 0.5 ? 1 : 0; } ENDCG } } }
很簡單, OpenGL螢屏是從左下角開始的, D3D從螢屏左上角開始的.
運行起來看看, 現在是OpenGL標準, 可見螢屏是黑的, 沒有進到UNITY_UV_STARTS_AT_TOP宏里面 :

下來切換API標準, 使用D3D11 :

代碼不用改, 直接重新運行看看, 螢屏是白色的了 :
所以這里的設定是可以進行不同API的測驗的, 跟我前面說的差不多, 只是不能在運行時進行強行設定, 并且只選擇一個API的話, 在不使用這個API的平臺上應該是不能轉換的了, 前面說的是希望它能做成IL代碼一樣, 把所有的API當成不同平臺的底層代碼, 把Shader編譯成中間代碼, 這樣就沒有"硬"轉換了.
又碰到個問題, 使用Surface Shader的模板寫多個pass的情況, 不能把surface框在Pass里面, 會報錯:
[Parse error: syntax error, unexpected TOK_PASS, expecting TOK_SETTEXTURE or '}'......]
錯誤寫法:
SubShader { Pass { CGPROGRAM #pragma surface surf Standard fullforwardshadows ...... ENDCG } Pass { CGPROGRAM ...... ENDCG } }
直接在原代碼上添加新Pass就行了:
SubShader { CGPROGRAM #pragma surface surf Standard fullforwardshadows ...... ENDCG Pass { CGPROGRAM ...... ENDCG } }
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/6741.html
標籤:其他
