Shader從入門到跑路:顏色自定義輸出、紋理取樣
前言
我們來加深一下目前理解到的內容,並且著手解決一些在學習過程中遇到的疑惑(如果有疑惑但我沒提到歡迎在評論留下我會隨後加上)。
首先,以往我們寫程式是在CPU上跑,但寫shader則是在GPU上跑,我們會用兩對好兄弟,分別是vertex shader和fragment shader。
vertex shader是每個頂點都會呼叫一次的程式,它可以訪問頂點的位置、法線、紋理等資訊,這些值在經過一些處理之後,會先跑一個叫做“光柵化(Rasterization)”的過程。我們都知道,顯示器是由紅綠藍 LED 組成的顯示單元,因此單元之間是離散的,而“連續”的三維影象要渲染到螢幕上,就要經過一系列的修改,稱之為光柵化。
此時得到就是片元(fragment),我之前說過片元與最終的影象單位是非常接近的(我甚至鼓勵大家以圖形的方式來理解它們實在是抱歉),但它們之間仍存在著微妙的差別。這是因為片元需要先通過一些測試,比如深度測試、透明度測試等,以決定它們是需要被使用還是被拋棄。其實在這裡並不需要太糾結片元到底是不是畫素,因為這不是這個系列的重點。
而由每個片元分別呼叫一次的就是fragment shader,它可以獲取片元的二維、深度、顏色等資訊。注意,fragment shader獲取的片元顏色是根據片元的三個頂點顏色插值計算後得到的,也就是說如果三個頂點顏色並不相同,那麼最終顏色便是漸變的。
shader的計算是在CGPROGRAM內完成的,並且應該符合以下結構
- struct appdata{}; // 獲取模型資料
- struct v2f{}; // 存放計算結果
- v2f vert(appdata v){} // 拿取模型資料計算後傳給fragment shader
- float4 frag(v2f i) : SV_Target{} // 拿取計算結果作用於目標
注意,在結構體內定義的輸入輸出是由語義限定的,舉個栗子:
- struct appdata{
- float4 vertex : POSITION; // 把模型頂點座標填充到vertex中
- float2 uv : TEXCOORD1; // 第一組紋理座標
- float3 normal : NORMAL; // 把法線方向填充到normal中
- };
- struct v2f{
- float4 vertex : SV_POSITION; // 輸出到裁剪空間中的頂點座標
- float3 color : COLOR; // 輸出顏色
- };
- float4 frag(v2f i) : SV_Target{ // frag輸出值直接用於渲染
- return float4(i.color, 1.0);
- }
語義是很聰明的一種設計,它能夠讓Shader知道從哪裡獲取資料,並且還知道把輸出的資料放到哪裡(或者怎麼放)
問題1:頂點位置是一種座標系,uv也是一種座標系,既然都是座標為什麼不能只算一個多方便啊?
好問題!(拍大腿)這兩種座標系的應用是不一樣的,頂點是一個和網格(mesh)相關的區域性點,以xyz為座標軸;而uv則是貼圖對映到模型表面的依據,以uvw為座標軸,或者可以將uv看作一張紋理查詢表格。因為xyz軸已經被網格佔用了,所以貼圖用的座標軸就只能用uvw了,簡稱uv。很多同學看了一些shader教程經常見到它們兩一齊出現,自己寫的時候不知所以索性就一齊計算了。
5.4 魯迅名言
問題2:有些shader程式的frag函式輸出的COLOR,而另一些則是SV_TARGET,有什麼區別啊?
沒啥不同,SV開頭的是Direct3D定義的一種System Value語義,SV_TARGET對應的就是COlOR,但有些平臺支援SV語義,而有些則不支援。但這並不重要,因為編譯器會自動幫我們做轉換,它們兩的功能是一樣的。類似還有SV_POSITION與POSITION,SV_DEPTH與DEPTH等等。反正無腦寫SV_Target就沒錯了(狗頭)
自我小測:
在寫過一些shader之後,我們已經是個shader程式設計師了,當然要學會自己寫shader咯,下面是一些可以努力的方向,並獲取圖中的渲染效果(因為是讀者自我測驗,因此筆者不會提供答案,但如果實在想不明白可以私信筆者問思路)
練習1 : 新增一個_Color屬性,並將其與主紋理的顏色相乘
注:顏色在屬性區塊內是以Color型別存在,在CGPROGRAM使用內需被預定義為float4型別
練習2 : 用第二章講到,用uv值計算顏色值的方法,將其結果與主紋理的顏色想乘,獲得下面的效果
練習3 : 使用兩張紋理,以及第五章講到的拖動條,當移動滑桿時在兩張紋理中進行插值
練習4 : 在圖片的設定皮膚內將圖片的wrap mode設為repeat。在對紋理取樣時,將uv乘2
練習5 : 使用明亮度(luminance)公式來算出一個明亮度值,然後將紅綠藍通道都設定為明亮度值,透明度通道則用對圖片取樣獲得的透明度,最終獲得灰度效果
注: luminance = 0.2125 * Red + 0.07154 * Green + 0.0721 * Blue
練習6 : 將練習5的返回顏色與自定義的顏色屬性相乘
相關閱讀:
Shader從入門到跑路:樸實無華的圖形學基礎
Shader從入門到跑路:自定義紋理輸入
Shader從入門到跑路:螢幕後處理效果
Shader從入門到跑路:實作螢幕扭曲效果
作者:俊銘
專欄地址:https://zhuanlan.zhihu.com/p/86192364
相關文章
- Shader從入門到跑路:自定義紋理輸入
- Shader從入門到跑路:螢幕後處理效果
- Shader從入門到跑路:實作螢幕扭曲效果
- babel從入門到跑路Babel
- Shader從入門到跑路:樸實無華的圖形學基礎
- WebGL 紋理顏色原理Web
- Kotlin從入門到跑路(一)Kotlin
- Docker實戰-從入門到跑路Docker
- 微信小程式-自定義placeholder顏色和樣式微信小程式
- Django 自定義管理命令:從入門到高階Django
- 小程式自定義swiper的指示點樣式及顏色
- Linux 從入門到跑路第二十一講 -- 字串擷取Linux字串
- Vue入門到跑路---VuexVue
- Shader 中的顏色計算
- 塗顏色(數論,大資料輸入處理)大資料
- Re:《Unity Shader入門精要》13.3全域性霧效--如何從深度紋理重構世界座標Unity
- easyexcel匯出頭部樣式設定,多個tab匯出,頭部自定義RGB顏色Excel
- Print輸出顏色字型方法
- WebGL程式設計指南(4)顏色與紋理Web程式設計
- Linux Shell 從入門到刪除根目錄跑路指南Linux
- 《Golang 從入門到跑路》之開發環境搭建Golang開發環境
- 利用CAGradientLayer自定義顏色漸變viewView
- MySQL 效能壓測工具,從入門到自定義測試項MySql
- 一文詳解 OpenGL ES 紋理顏色混合
- Shader 中的顏色混合模式(Blend Mode)模式
- MySQL 效能壓測工具-sysbench,從入門到自定義測試項MySql
- Service Worker 從入門到出門
- linux改變shell的輸出顏色Linux
- 在Mac裡給Terminal終端自定義顏色Mac
- 小程式中 icon 顏色自定義解決方案
- 自定義Toast的背景顏色大小及字型大小AST
- 快取從入門到放棄快取
- VSCode自定義快捷輸入VSCode
- echart使用自定義單個柱狀顏色實現
- Python自定義詞雲圖形狀和文字顏色Python
- 純 CSS 解決自定義 CheckBox 背景顏色問題CSS
- 0x04_My-OS實現自定義顏色
- python seaborn畫熱力圖,自定義顏色漸變Python