Shader從入門到跑路:自定義紋理輸入

遊資網發表於2020-03-12
Shader從入門到跑路:自定義紋理輸入

上文:Shader從入門到跑路:樸實無華的圖形學基礎

上節課後作業答案

只需要將返回顏色的藍色通道更改為1,就可以得到課後作業的渲染結果

  1. float4 frag(v2f i) : SV_Target
  2. {
  3.         float4 color = float4(i.uv.r, i.uv.g, 1, 1);
  4.         return color;
  5. }
複製程式碼

Shader從入門到跑路:自定義紋理輸入
課後作業渲染結果

前言

實在是手殘,不小心把這篇文章刪掉了,問了客服好像並沒有解決辦法,希望知乎以後可以提供恢復誤刪文章的功能...只能再手打一遍了,欲哭無淚。

正文

上一章我們都是指揮unity來獲取渲染資訊,那麼接下來就介紹如何將圖片輸出到物體上。

Shader從入門到跑路:自定義紋理輸入
背景為透明的我老婆

為了展示接下來的內容,我在PS內製作了一張帶有透明通道的PNG圖片,正確的渲染效果應該是顯示人像,而背景部分則顯示圖片後面的場景物體(即應該為透明的)。

現於SubShader區塊上面新增一個Properties區塊,並在其中定義一個MainTexture的二維屬性。

  1. Properties{
  2.         _MainTex("Main Texture", 2D) = "white" {}
  3. }
複製程式碼


注意,在屬性區塊內被定義的資料在CGPROGRAM內被使用之前都要預定義一遍,不然會報錯。在CGPROGRAM內加入紋理的定義:

sampler2D _MainTex;

在這裡的sampler2D是一個GLSL的型別,表示用來儲存一個2D紋理

https://www.khronos.org/opengl/wiki/Sampler_(GLSL)

接下來,在frag函式中利用tex2D這個方法來獲取紋理中的顏色,並直接使用顏色進行著色。這個方法其實就是在一張紋理中對一個點進行取樣,我們要得到整個紋理的顏色,就需要所有畫素對應的uv點,程式碼如下:

  1. float4 frag(v2f i) : SV_Target
  2. {
  3.         return tex2D(_MainTex, i.uv);
  4. }
複製程式碼

然而我們卻得到了一些奇怪的渲染結果,來看一看為什麼。


Shader從入門到跑路:自定義紋理輸入
與預期不符的渲染結果,背景應該是透明的

可見得出的渲染結果並不符合我們的預期,本來在PNG裡背景被設定為透明的圖片,背景變成了白色。這是因為tex2D在處理紋理的時候會計算每一個對應uv點的畫素顏色,但是本應是透明的內容是不會有”顏色“這一屬性的,然而tex2D還是將它們視為待計算的顏色,這才出現了錯誤。

為了解決這個問題,我們需要一種叫Transparent Blend的技術。其實就是定義一下在shader裡面,目前處理的畫素如何與它後面畫素混合。混合模式有很多種:

https://docs.unity3d.com/Manual/SL-Blend.html

我們這次用的是一種叫做Alpha Blend的東西,定義CGPROGRAM外面,它長這樣:

Blend SrcAlpha OneMinusSrcAlpha

它的意思是將源顏色乘上源顏色的透明度,與目標顏色乘(1 - 原顏色的透明度)的結果相加,公式如下:

OutColor = SrcColor * ScrAlpha + DstColor * (1 - SrcAlpha)

或許這有些難以理解,但只要稍微思考一下就好了,將兩個顏色的減淡後疊加在一起,便產生了一種中間色,看起來就好像透過目前的物體看到了後面的物體一樣。

下一步則是要在SubShader的tag區塊內設定shader的渲染通道,以確保在非透明的物體渲染結束後才渲染我們的透明物體。

  1. Tags
  2. {
  3.         "Queue" = "Transparent"
  4. }
複製程式碼

如果你跳過了這一步,那麼就會出現一些奇怪的渲染效果。對於好奇心重的同學,歡迎跳過設定渲染通道來看看錯誤效果。

Shader從入門到跑路:自定義紋理輸入
正確的渲染結果,可以透過透明部分看到後面的物體

完整的shader程式碼:

  1. Shader "Custom/ShaderLearning"
  2. {
  3.         Properties{
  4.                 _MainTex("Main Texture", 2D) = "white"
  5.         }
  6.         SubShader
  7.         {
  8.                 Tags
  9.                 {
  10.                         "Queue" = "Transparent"
  11.                 }
  12.                 Pass
  13.                 {
  14.                         Blend SrcAlpha OneMinusSrcAlpha
  15.                         CGPROGRAM
  16.                         #pragma vertex vert
  17.                         #pragma fragment frag
  18.                         sampler2D _MainTex;
  19.                         #include "UnityCG.cginc"

  20.                         struct appdata
  21.                         {
  22.                                 float4 vertex : POSITION;
  23.                                 float2 uv: TEXCOORD0;
  24.                         };

  25.                         struct v2f
  26.                         {
  27.                                 float4 vertex : SV_POSITION;
  28.                                 float2 uv: TEXCOORD1;
  29.                         };

  30.                         v2f vert(appdata v)
  31.                         {
  32.                                 v2f o;
  33.                                 o.vertex = UnityObjectToClipPos(v.vertex);
  34.                                 o.uv = v.uv;
  35.                                 return o;
  36.                         }

  37.                         float4 frag(v2f i) : SV_Target
  38.                         {
  39.                                 return tex2D(_MainTex, i.uv);
  40.                         }
  41.                         ENDCG
  42.                 }
  43.         }
  44. }
複製程式碼

作者:俊銘
專欄地址:https://zhuanlan.zhihu.com/p/86096949

相關文章