戰(zhàn)精讀(08):GLSL 二維矩陣變換——平移、旋轉(zhuǎn)與縮放)
【免費(fèi)下載鏈接】thebookofshadersStep-by-step guide through the abstract and complex universe of Fragment Shaders.項(xiàng)目地址https://gitcode.com/gh_mirrors/th/thebookofshaders點(diǎn)擊查看免費(fèi)下載導(dǎo)讀本章是《The Book of Shaders》倉(cāng)庫(kù)根目錄的第八課主題為2D Matrices二維矩陣。在上一章用坐標(biāo)系統(tǒng)繪制出形狀之后本章解決如何讓形狀動(dòng)起來的問題通過矩陣這一強(qiáng)大的向量操作工具自由地對(duì)圖形進(jìn)行平移Translate、旋轉(zhuǎn)Rotate與縮放Scale。由于該技術(shù)可以等量應(yīng)用于任何用向量表達(dá)的事物學(xué)完本章后你不僅能操控幾何圖形還能用同樣的手段處理顏色空間如 YUV為后續(xù)的程序化圖案創(chuàng)作打下扎實(shí)基礎(chǔ)。本章核心思想矩陣是操作向量的萬(wàn)能工具本章開篇08/SUMMARY-pt.md給出了全章提綱挈領(lǐng)的論斷矩陣是操作向量的強(qiáng)大工具。精通矩陣用法后你可以自由地平移、縮放和旋轉(zhuǎn)形狀。由于這套技術(shù)可以等量地應(yīng)用于任何用向量表達(dá)的事物本書后面還會(huì)看到矩陣更多進(jìn)階用法。矩陣乍看之下很復(fù)雜但一旦掌握概念就會(huì)發(fā)現(xiàn)它非常實(shí)用。讓我們?cè)谶@里通過一些簡(jiǎn)單示例練習(xí)并掌握基礎(chǔ)。這段概括蘊(yùn)含三個(gè)要點(diǎn)矩陣的本質(zhì)是向量變換器在片元著色器中坐標(biāo)、顏色、法線都是向量矩陣乘法是改變向量取值最規(guī)范的手段操作對(duì)象是坐標(biāo)系而非形狀本身Shader 里沒有選中某個(gè)物體的概念所有變換都是對(duì)每個(gè)片元的坐標(biāo)空間進(jìn)行整體操作學(xué)的是可遷移的方法論同樣的mat2/mat3/mat4技巧后面章節(jié)會(huì)在噪聲、紋理、光照等場(chǎng)景反復(fù)出現(xiàn)。前置認(rèn)知變換形狀 變換坐標(biāo)系在上一章07 形狀中我們學(xué)會(huì)了用smoothstep在歸一化坐標(biāo)st即gl_FragCoord.xy / u_resolution.xy取值范圍0.0 ~ 1.0上裁出矩形、圓形等形狀。移動(dòng)這些形狀的訣竅不是修改形狀的定義而是移動(dòng)坐標(biāo)系統(tǒng)本身——只需向保存每個(gè)片元位置的變量st加上一個(gè)向量整個(gè)空間坐標(biāo)系就會(huì)隨之移動(dòng)。這種動(dòng)空間而不是動(dòng)物體的思想貫穿本章全部三個(gè)操作平移是加向量旋轉(zhuǎn)和縮放則是左乘一個(gè)矩陣。平移Translate給 st 加一個(gè)向量平移是最直觀的變換。參考倉(cāng)庫(kù)中的 cross-translate.frag作者 patriciogv2015// Author patriciogv ( patriciogonzalezvivo.com ) - 2015 #ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; uniform float u_time; float box(in vec2 _st, in vec2 _size){ _size vec2(0.5) - _size*0.5; vec2 uv smoothstep(_size, _sizevec2(0.001), _st); uv * smoothstep(_size, _sizevec2(0.001), vec2(1.0)-_st); return uv.x*uv.y; } float cross(in vec2 _st, float _size){ return box(_st, vec2(_size,_size/4.)) box(_st, vec2(_size/4.,_size)); } void main(){ vec2 st gl_FragCoord.xy/u_resolution.xy; vec3 color vec3(0.0); // To move the cross we move the space vec2 translate vec2(cos(u_time),sin(u_time)); st translate*0.35; // Show the coordinates of the space on the background // color vec3(st.x,st.y,0.0); // Add the shape on the foreground color vec3(cross(st,0.25)); gl_FragColor vec4(color,1.0); }代碼要點(diǎn)box()與cross()是上一章的形狀函數(shù)cross由兩個(gè)矩形拼成十字關(guān)鍵一行st translate * 0.35;其中translate vec2(cos(u_time), sin(u_time))是一個(gè)繞單位圓運(yùn)動(dòng)的向量乘以0.35把運(yùn)動(dòng)幅度限制在畫布中央附近練習(xí)一取消第 35 行color vec3(st.x,st.y,0.0);的注釋即可看到空間本身的坐標(biāo)顏色隨十字一起移動(dòng)直觀驗(yàn)證移動(dòng)的是空間。本章給出的進(jìn)階練習(xí)很有價(jià)值結(jié)合u_time與第 5 章的塑造函數(shù)shaping functions參見 05 章讓十字按你感興趣的運(yùn)動(dòng)品質(zhì)移動(dòng)——例如海浪的往復(fù)、單擺的擺動(dòng)、彈跳的球、加速的汽車或剎車的自行車。建議先從真實(shí)世界錄制一段參考運(yùn)動(dòng)再反推數(shù)學(xué)表達(dá)這是訓(xùn)練運(yùn)動(dòng)感的經(jīng)典方法。旋轉(zhuǎn)Rotate2D 旋轉(zhuǎn)矩陣旋轉(zhuǎn)同樣需要移動(dòng)整個(gè)空間系統(tǒng)但手段升級(jí)為矩陣矩陣是按行列組織的一組數(shù)字向量按照精確的規(guī)則與矩陣相乘從而以特定方式修改向量取值。GLSL 中的矩陣類型GLSL 原生支持二、三、四維矩陣mat22×2、mat33×3、mat44×4——浮點(diǎn)矩陣類型支持矩陣乘法運(yùn)算符*內(nèi)置矩陣專用函數(shù)matrixCompMult()對(duì)兩個(gè)矩陣做逐分量相乘。倉(cāng)庫(kù) glossary/mat2/README.md 給出了mat2的完整聲明方式值得細(xì)讀mat2 aMat2 mat2(1.0, 0.0, // 第 1 列 0.0, 1.0); // 第 2 列 mat2 bMat2 mat2(1.0); // 只給一個(gè)值填充主對(duì)角線 mat2 cMat2 mat2(aVec2, bVec2); // 用向量組合 mat2 dMat2 mat2(aVec3, aFloat); // 向量與標(biāo)量混合關(guān)鍵細(xì)節(jié)GLSL 矩陣按列主序column-major初始化即參數(shù)按列填寫同時(shí)支持分量訪問與按列訪問mat2 aMat2; aMat2[1][1] 1.0; float aFloat aMat2[1][1]; aMat2[0] vec2(1.0); vec2 aVec2 aMat2[0];mat3、mat4的聲明規(guī)則相同見 glossary/mat3/README.mdmatrixCompMult()則逐分量相乘result[i][j] x[i][j] * y[i][j]見 glossary/matrixCompMult/README.md。構(gòu)造 2D 旋轉(zhuǎn)矩陣基于矩陣行為可以構(gòu)造出特定功能的矩陣。二維旋轉(zhuǎn)矩陣的標(biāo)準(zhǔn)公式如下mat2 rotate2d(float _angle){ return mat2(cos(_angle),-sin(_angle), sin(_angle),cos(_angle)); }按照列主序展開這個(gè)矩陣的第一列是(cos, sin)第二列是(-sin, cos)對(duì)應(yīng)二維向量繞原點(diǎn)vec2(0.0)逆時(shí)針旋轉(zhuǎn)_angle弧度的標(biāo)準(zhǔn)公式。關(guān)鍵套路移到原點(diǎn) → 旋轉(zhuǎn) → 移回去但直接套用上面的公式并不滿足我們的需求本章的十字形狀畫在畫布中心即位置vec2(0.5)附近而rotate2d繞原點(diǎn)vec2(0.0)旋轉(zhuǎn)。因此旋轉(zhuǎn)空間之前必須先把形狀從center移到vec2(0.0)坐標(biāo)旋轉(zhuǎn)空間最后再移回原位。對(duì)應(yīng)代碼見 cross-rotate.frag// Author patriciogv ( patriciogonzalezvivo.com ) - 2015 #ifdef GL_ES precision mediump float; #endif #define PI 3.14159265359 uniform vec2 u_resolution; uniform float u_time; mat2 rotate2d(float _angle){ return mat2(cos(_angle),-sin(_angle), sin(_angle),cos(_angle)); } float box(in vec2 _st, in vec2 _size){ _size vec2(0.5) - _size*0.5; vec2 uv smoothstep(_size, _sizevec2(0.001), _st); uv * smoothstep(_size, _sizevec2(0.001), vec2(1.0)-_st); return uv.x*uv.y; } float cross(in vec2 _st, float _size){ return box(_st, vec2(_size,_size/4.)) box(_st, vec2(_size/4.,_size)); } void main(){ vec2 st gl_FragCoord.xy/u_resolution.xy; vec3 color vec3(0.0); // move space from the center to the vec2(0.0) st - vec2(0.5); // rotate the space st rotate2d( sin(u_time)*PI ) * st; // move it back to the original place st vec2(0.5); // Show the coordinates of the space on the background // color vec3(st.x,st.y,0.0); // Add the shape on the foreground color vec3(cross(st,0.4)); gl_FragColor vec4(color,1.0); }代碼中的三段式注釋直接點(diǎn)明了套路第 38 行st - vec2(0.5);—— 把空間從中心移到原點(diǎn)第 40 行st rotate2d( sin(u_time)*PI ) * st;—— 用隨時(shí)間變化的角度sin(u_time)*PI范圍-π ~ π做往復(fù)擺動(dòng)旋轉(zhuǎn)空間第 42 行st vec2(0.5);—— 旋轉(zhuǎn)完成后移回原位。本章給出的旋轉(zhuǎn)練習(xí)同樣值得親手驗(yàn)證取消第 45 行背景坐標(biāo)代碼的注釋觀察空間坐標(biāo)如何隨旋轉(zhuǎn)改變注釋掉第 37、39 行的平移即旋轉(zhuǎn)前后的兩次位移觀察后果——會(huì)發(fā)現(xiàn)十字繞著左下角原點(diǎn)旋轉(zhuǎn)而不是繞畫布中心從而深刻理解原點(diǎn)居中的必要性用旋轉(zhuǎn)改進(jìn)你在平移練習(xí)中模擬的動(dòng)畫例如讓擺動(dòng)中的物體同時(shí)自轉(zhuǎn)??s放Scale2D 縮放矩陣如果你用過 3D 建模軟件或 Processing 的pushMatrix/popMatrix就知道矩陣同樣可以用來改變物體大小。仿照旋轉(zhuǎn)矩陣的推導(dǎo)思路二維縮放矩陣為mat2 scale(vec2 _scale){ return mat2(_scale.x,0.0, 0.0,_scale.y); }對(duì)角線上的兩個(gè)因子分別控制 x、y 方向的縮放倍數(shù)大于 1 放大小于 1 縮小負(fù)值可做鏡像。完整示例見 cross-scale.frag// Author patriciogv ( patriciogonzalezvivo.com ) - 2015 #ifdef GL_ES precision mediump float; #endif #define PI 3.14159265359 uniform vec2 u_resolution; uniform float u_time; mat2 scale(vec2 _scale){ return mat2(_scale.x,0.0, 0.0,_scale.y); } float box(in vec2 _st, in vec2 _size){ _size vec2(0.5) - _size*0.5; vec2 uv smoothstep(_size, _sizevec2(0.001), _st); uv * smoothstep(_size, _sizevec2(0.001), vec2(1.0)-_st); return uv.x*uv.y; } float cross(in vec2 _st, float _size){ return box(_st, vec2(_size,_size/4.)) box(_st, vec2(_size/4.,_size)); } void main(){ vec2 st gl_FragCoord.xy/u_resolution.xy; vec3 color vec3(0.0); st - vec2(0.5); st scale( vec2(sin(u_time)1.0) ) * st; st vec2(0.5); // Show the coordinates of the space on the background // color vec3(st.x,st.y,0.0); // Add the shape on the foreground color vec3(cross(st,0.2)); gl_FragColor vec4(color,1.0); }注意第 38 行scale( vec2(sin(u_time)1.0) )sin(u_time)范圍-1.0 ~ 1.0加1.0后縮放因子范圍是0.0 ~ 2.0十字在縮到看不見與放大兩倍之間脈動(dòng)。同樣沿用了移到原點(diǎn) → 縮放 → 移回的三段式。本章的縮放練習(xí)給出了幾個(gè)極具工程價(jià)值的訓(xùn)練取消第 42 行注釋查看空間坐標(biāo)被縮放的效果注釋第 37、39 行的平移觀察縮放中心從畫布中心漂移到原點(diǎn)嘗試把旋轉(zhuǎn)矩陣與縮放矩陣組合——牢記矩陣乘法順序敏感先構(gòu)造矩陣相乘再用結(jié)果矩陣乘向量即M_combined * st其中M_combined rotate2d(...) * scale(...)綜合運(yùn)用既然已經(jīng)會(huì)畫形狀又會(huì)移動(dòng)、旋轉(zhuǎn)、縮放就可以做真正的合成了——設(shè)計(jì)并構(gòu)造一個(gè)假的 UI 或 HUD抬頭顯示界面參考 ShaderToy 社區(qū)中 Ndel 的 HUD 類示例作為靈感。矩陣不止用于幾何YUV 顏色空間的矩陣變換本章最精彩的收尾是把矩陣從幾何空間遷移到顏色空間。YUV是用于照片和視頻模擬編碼的一種顏色空間它考慮到人類視覺感知的特性以降低色度chrominance分量的帶寬。GLSL 中可以直接用矩陣把顏色從一個(gè)空間變換到另一個(gè)空間見 yuv.frag// Author patriciogv - 2015 // http://patriciogonzalezvivo.com #ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; uniform float u_time; // YUV to RGB matrix mat3 yuv2rgb mat3(1.0, 0.0, 1.13983, 1.0, -0.39465, -0.58060, 1.0, 2.03211, 0.0); // RGB to YUV matrix mat3 rgb2yuv mat3(0.2126, 0.7152, 0.0722, -0.09991, -0.33609, 0.43600, 0.615, -0.5586, -0.05639); void main(){ vec2 st gl_FragCoord.xy/u_resolution; vec3 color vec3(0.0); // UV values goes from -1 to 1 // So we need to remap st (0.0 to 1.0) st - 0.5; // becomes -0.5 to 0.5 st * 2.0; // becomes -1.0 to 1.0 // we pass st as the y z values of // a three dimensional vector to be // properly multiply by a 3x3 matrix color yuv2rgb * vec3(0.5, st.x, st.y); gl_FragColor vec4(color,1.0); }這段代碼的示范意義在于把顏色當(dāng)作向量與矩陣相乘從而搬動(dòng)顏色分量的取值rgb2yuvRGB → YUV 的 3×3 轉(zhuǎn)換矩陣第一行是亮度系數(shù)0.2126、0.7152、0.0722即 Rec.601 標(biāo)準(zhǔn)亮度權(quán)重yuv2rgb其逆變換矩陣由于 UV 分量范圍是-1 ~ 1而st范圍是0 ~ 1需要先st - 0.5再st * 2.0完成重映射最終以vec3(0.5, st.x, st.y)作為 YUV 輸入Y 固定為 0.5 中灰左乘yuv2rgb得到 RGB 彩色輸出畫布上會(huì)呈現(xiàn)與坐標(biāo)位置對(duì)應(yīng)的色相漸變。倉(cāng)庫(kù)源碼級(jí)深化從 2D 到 3D/4D 的矩陣工具箱本章倉(cāng)庫(kù)內(nèi)還有兩份源碼可以幫你把視野從 2D 拓展到更高維度章節(jié)頭部的動(dòng)態(tài)演示 matrix.frag這是章節(jié)頁(yè)面頂部 canvas 播放的矩陣雨效果——用floor(st*rows)切出 80 行網(wǎng)格借助random()與u_time讓字符按行墜落本質(zhì)上是把空間重復(fù)切分 隨機(jī)函數(shù)的預(yù)演為第 9 章程序化圖案埋下伏筆進(jìn)階矩陣庫(kù) matrices.frag完整給出了rotate2D以及三維、四維版本——rotateX3D/rotateY3D/rotateZ3D、對(duì)應(yīng)的mat4四維版本以及scale4D、translate4D。例如繞 X 軸旋轉(zhuǎn)的 3×3 矩陣mat3 rotateX3D(float phi){ return mat3( vec3(1.,0.,0.), vec3(0.,cos(phi),-sin(phi)), vec3(0.,sin(phi),cos(phi))); }這份文件展示了矩陣變換的可組合、可復(fù)用特性旋轉(zhuǎn)、縮放、平移都是把單位矩陣相應(yīng)位置替換為變換參數(shù)并且低維公式可以一致地推廣到高維這正是后續(xù)章節(jié)做復(fù)雜空間操作如噪聲擾動(dòng)、紋理坐標(biāo)變換的基礎(chǔ)工具。另外值得留意的是 GLSL 的矩陣乘法語(yǔ)義matrixCompMult()與*完全不同——前者逐分量相乘對(duì)應(yīng)數(shù)學(xué)上的 Hadamard 積后者才是線性代數(shù)意義上的矩陣乘法。做幾何變換時(shí)必須使用*本章所有rotate2d(...) * st、scale(...) * st均是后者。本章小結(jié)與下一步本章我們學(xué)會(huì)了用矩陣變換來平移、旋轉(zhuǎn)、縮放向量平移是給st加向量旋轉(zhuǎn)與縮放是構(gòu)造mat2并左乘坐標(biāo)且都遵循移到原點(diǎn) → 變換 → 移回的通用套路。這些變換對(duì)把上一章學(xué)到的形狀組織成復(fù)雜構(gòu)圖至關(guān)重要而 YUV 示例則證明了同一套矩陣工具可以跨界作用于顏色空間——凡是向量皆可變換。下一章09 圖案將把本章所學(xué)全部應(yīng)用到程序化圖案的創(chuàng)作中通過包裝與重復(fù)空間用并行而非逐對(duì)象的方式繪制重復(fù)圖案。你會(huì)發(fā)現(xiàn)編碼重復(fù)與變化是一件令人興奮的實(shí)踐。工具箱備注若想深入學(xué)習(xí)用矩陣操縱空間的實(shí)用函數(shù)集合可參考 LYGIA 的 space functions 庫(kù)——一套面向 GLSL 空間操作的細(xì)粒度、可復(fù)用函數(shù)庫(kù)設(shè)計(jì)上注重復(fù)用、性能與靈活性可輕松集成到任意項(xiàng)目與框架中。贊分享【免費(fèi)下載鏈接】thebookofshadersStep-by-step guide through the abstract and complex universe of Fragment Shaders.項(xiàng)目地址https://gitcode.com/gh_mirrors/th/thebookofshaders點(diǎn)擊查看免費(fèi)下載相關(guān)推薦The Book of Shaders 精讀用 GLSL 二維矩陣變換平移、旋轉(zhuǎn)與縮放坐標(biāo)空間The Book of Shaders 精讀用 GLSL 二維矩陣變換平移、旋轉(zhuǎn)與縮放坐標(biāo)空間 本篇文章精讀開源項(xiàng)目 thebookofshaders httThe Book of Shaders 第 8 章精讀用 GLSL 二維矩陣驅(qū)動(dòng)平移、旋轉(zhuǎn)與縮放變換The Book of Shaders 第 8 章精讀用 GLSL 二維矩陣驅(qū)動(dòng)平移、旋轉(zhuǎn)與縮放變換 本文基于開源倉(cāng)庫(kù) thebookofshaders 第The Book of Shaders 第 08 章GLSL 二維矩陣變換實(shí)戰(zhàn)指南 —— 平移、旋轉(zhuǎn)、縮放與 YUV 色彩空間The Book of Shaders 第 08 章GLSL 二維矩陣變換實(shí)戰(zhàn)指南 —— 平移、旋轉(zhuǎn)、縮放與 YUV 色彩空間 本章 08/README v上一篇AIOpsLab革命性AI運(yùn)維評(píng)估框架 - 一站式解決60云故障場(chǎng)景下一篇OBS Studio 應(yīng)用LUT調(diào)色4步給直播畫面加電影感創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考