Minecraft GLSL Shader著色器基礎(chǔ)教程#1后處理著色器的編寫和解析

前言
本教程面向的是JE1.17+的原版著色器,并不是Optifine的光影,資料大量引用至下文鏈接(目前b站無法直接引用站外鏈接),我將內(nèi)容作了一定修改,以適應(yīng)于1.17+的新版著色器
原版著色器指導(dǎo)(舊版):https://docs.google.com/document/d/15TOAOVLgSNEoHGzpNlkez5cryH3hFF3awXL5Py81EMk/edit,翻譯:https://spgoding.com/translation/2021/03/12/guite-to-vanilla-shader.html
本教程編者并未進行系統(tǒng)的GLSL學(xué)習(xí),面向的也是第一次接觸著色器的人,所以只會分享一些基礎(chǔ)知識和在Minecraft中的運用,可以基本滿足資源包的制作(如屏幕方塊、精美天空,水面反射、樹葉搖動等)
在本教程中第一次出現(xiàn)的重要名詞或注意事項將會以紅色粗體標出
無特殊說明,本教程提到的文件路徑都是相對于"資源包/assets/命名空間"的,如"shaders/post/creeper.json"代表的在資源包中的路徑是"資源包/assets/命名空間/shaders/post/creeper.json"
除了著色器的基本教程外,我還會在此系列更新一些實用技巧和玩家自制著色器的解析
注:本文大量提到的spgoding.com是一個個人網(wǎng)站,但該教程引用的資料翻譯于外網(wǎng),這里僅做圖片等資源引用的標注

著色器
著色器(Shader)是資源包功能的一部分,主要由JSON格式和GLSL編寫其文件,GLSL是一種類C語言,這意味著基本的語法和C語言相似。如果有C語言基礎(chǔ)的讀者可以選擇性的略讀有關(guān)代碼書寫規(guī)范的部分。
后處理著色器早在1.7.2就已經(jīng)加入游戲,顧名思義,后處理著色器將在屏幕內(nèi)容已經(jīng)渲染完成后,讀取所有的像素并通過一系列程序修改,從程序內(nèi)部角度,后處理著色器將同時讀取屏幕上的所有像素,在編寫時要考慮到這一點。以下是一些原版自帶的后處理著色器示例:

后處理著色器將在以下情況被使用:
(上文提到了后處理著色器的工作對象,這意味著當(dāng)屏幕出現(xiàn)發(fā)光實體時,entity_outline后處理著色器將自動啟動,并對整個屏幕生效,而不是只對發(fā)光實體生效)
后處理著色器儲存在shaders/post目錄下的后處理文件(post),定義了由著色器程序(program)組成的渲染管線(pipeline)。下圖展示的是由creeper.json后處理著色器所定義的管線:
(如果沒有閱讀外網(wǎng)資料的需求,不用特別記憶英文名稱)

著色器程序存放在shaders/program目錄下,一個完整的著色器包含:
shaders/core 下則儲存了由游戲(而非上面提到的后處理管線)直接調(diào)用的著色器程序,稱為核心著色器(Core)。這些著色器程序會在后處理著色器之前使用并渲染游戲內(nèi)的整個內(nèi)容,盡管他們的書寫是一樣的,但運算的內(nèi)容則完全不一樣。
編寫一個后處理JSON
后處理JSON應(yīng)該存放在shaders/post中,并且命名為上文提到的5種能被自動調(diào)用的著色器中的一種
(如果要參考原版文件,可以到?版本.jar/assets/minecraft/shaders中查看)
后處理JSON僅由兩個數(shù)組組成:
"targets"數(shù)組聲明了一系列幀緩沖(畫布),以便使用著色器之后指定存儲的位置(不允許由緩沖存儲到自身),緩沖可以是"swap"這樣的格式,寬度高度默認是窗口的寬度和高度,也可以是{"name":"swap","width
":"40","height
":"30"}這樣的格式以限制大小。兩種格式可以隨意混用。緩沖的名字應(yīng)該僅由可選的命名空間、小寫英文字母、數(shù)字和下劃線組成。
除了這些手動聲明的緩沖層,還有一些特殊的、預(yù)先定義好的緩沖。這些緩沖里面會自帶內(nèi)容,不需要聲明就可以直接使用。它們是:
Passes數(shù)組聲明了一系列的渲染管線,依照自上而下的順序依次執(zhí)行,由一個緩沖層(intarget)輸入,經(jīng)過一個著色器程序(name)更改,并輸出到一個新的緩沖層(outtarget)。有時需要用auxtargets和uniforms提供參數(shù),在后面會介紹到。
其中,blit著色器是一個不改變?nèi)魏蝺?nèi)容的著色器,用于在緩沖間傳遞數(shù)據(jù)。最終的數(shù)據(jù)應(yīng)當(dāng)傳遞到minecraft:main中
調(diào)用的著色器程序是一個json文件,由該json文件調(diào)用一個片段著色器和一個頂點著色器,大多數(shù)情況下這兩個著色器和json同名,如blit.json調(diào)用了blit.fsh和blit.vsh,但沒有硬性規(guī)定,比如不修改頂點但是修改顏色的著色器會調(diào)用blit.vsh和另一個自定的fsh。該程序的書寫在后文介紹。
著色器是每幀循環(huán)運行的,minecraft:main每次會在首個更新,如果要跨幀傳遞信息,需要在結(jié)尾將信息傳遞到一個緩沖,在下次覆蓋前讀取它。因為循環(huán)的流程,文件后面的緩沖會來到文件前面作為上一幀的緩沖。下文的代碼塊是通過tmp緩沖將上一幀的minecraft:main傳遞到了下一幀的swap中,并且給minecraft:main使用了color_convolve著色器

可選的auxtargets數(shù)組提供了一系列補充的緩沖或圖片,使得著色器程序能夠訪問它們(默認狀態(tài)下著色器程序只能訪問intarget提供的一個緩沖)。在 auxtargets數(shù)組中的對象應(yīng)當(dāng)包含:(本節(jié)靠后位置有示例)
如果定義了一個圖片,還應(yīng)該包含

圖片來自spgoding.com,文字因為不清晰經(jīng)過修改
一個示例后處理JSON如下,它使得著色器程序能夠訪問 qux 緩沖,以及一張叫作 abc.png 的圖片:
用這個參數(shù)導(dǎo)入的緩沖或者圖片被稱為采樣器,在代碼中一般以texture2D(采樣器,坐標)的方式讀取內(nèi)容,具體的用法會在下一節(jié)講到。
借此,我們可以讓著色器訪問到無需被渲染到屏幕上的本地圖片,這個功能在一個實用的“調(diào)試信息”資源包中被實用,我會在結(jié)尾附上鏈接,之后我會發(fā)布對該簡單著色器的解析。
Uniforms數(shù)組將會起到對著色器程序傳遞參數(shù)的作用,具體參數(shù)在不同著色器程序中有不同作用,我之后會出一篇專欄,列出各個著色器程序所需的參數(shù),如果你有編程基礎(chǔ),可以直接在著色器代碼中查看。
可運作的后處理著色器實例(來自spgoding.com):
以下是一個可以正常運作的完整的后處理 JSON 文件。它添加了一個 “notch” 抖動效果,并減少了顏色飽和度。

assets/minecraft/shaders/post/spider.json
熟悉上面的內(nèi)容后,你將能夠像修改材質(zhì)包貼圖一樣修改原版的著色器。
如果還需要進一步修改再閱讀下面的內(nèi)容。(這完全不必一次就看完?。?/p>
創(chuàng)建一個著色器程序JSON
著色器程序應(yīng)該存放于shaders/programs中,并命名為后處理JSON調(diào)用的名稱,其文件內(nèi)容為:
blend:理論上定義了著色器程序的輸出應(yīng)當(dāng)怎樣與目標緩沖(destination buffer)上已有的內(nèi)容合并,但被游戲硬編碼,修改沒有效果
vertex:指定了將要使用的 頂點著色器.vsh 文件的文件名。
fragment:指定了將要使用的 片段著色器.fsh 文件的文件名。
attributes:一個字符串?dāng)?shù)組,指定頂點的哪些屬性能夠被頂點著色器訪問到,但被游戲硬編碼,修改沒有效果
samplers:定義了片段著色器想要訪問緩沖需要用到的變量名(采樣器)。"DiffuseSampler" 是被自動給予 "intarget" 中定義的緩沖的采樣器,該采樣器允許使用texture2D函數(shù)訪問緩沖上的某一像素,并返回一個rgb的值,具體將在下節(jié)講到。其他的任何名字都需要與你在 后處理文件的 "auxtargets" 中指定的一致。(如前文的圖片dither指定的DitherSampler)
uniforms:定義了各種全局量(又譯統(tǒng)一量。對每個頂點或像素都保持不變的值)的名稱、類型和默認值。(如果這里沒有指定著色器調(diào)用的uniform變量則會報錯)
uniform中name字符串定義了在 GLSL 代碼中或者在向該著色器程序的該全局量傳值時用的名稱。特殊的有:(這些特殊的變量并不會在所有著色器中生效,注意生效位置)
"values" 應(yīng)為一個浮點數(shù)數(shù)組,而 "type" 則定義了這些浮點數(shù)會在 GLSL 代碼中被解析為的數(shù)據(jù)類型,不同的數(shù)據(jù)類型在上面的代碼塊中已列出
vec2/vec3/vec4指的是向量類型,即擁有 2?/ 3 / 4 個成員的浮點型列表,matrixn或matrixnxm指的是矩陣類型,同樣為有nxn或nxm個成員的浮點型列表。矩陣類型在著色器中為matn或matnxm
可運作的示例
以下是一個可以正常運作的完整的著色器程序 JSON 文件。這是原版的 “wobble” 著色器,未經(jīng)修改。
assets/minecraft/shaders/program/wobble.json
下節(jié)預(yù)告:核心著色器和編寫fsh和vsh。


下載地址:https://drive.google.com/open?id=1n-SjTRv6D7CnYXok7A4cB9sqnSw00wGS(需科學(xué)上網(wǎng))
旁觀苦力怕時生效,能夠顯示屏幕中心像素的RGBA4個值。聲明了effects/shader_font.png為FontSampler,在fsh中使用textrue2D訪問了這張貼圖,做到了打印文字的效果,由于代碼中不支持字符串,只能使用一個一個的單字拼接,不支持中文,但讀者可以嘗試添加。