日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Unreal Engine 4 手绘风滤镜(Paint Filter)即 桑原滤镜(Kuwahara Filter)教程(下)

發布時間:2023/12/10 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Unreal Engine 4 手绘风滤镜(Paint Filter)即 桑原滤镜(Kuwahara Filter)教程(下) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文是《Unreal Engine 4 手繪風濾鏡(Paint Filter)即 桑原濾鏡(Kuwahara Filter)教程》的下半部分,上半部分請見《Unreal Engine 4 手繪風濾鏡(Paint Filter)即 桑原濾鏡(Kuwahara Filter)教程(上)》
作者|Tommy Tran May 1 2018 | 翻譯 開發游戲的老王

文章目錄

      • 選擇方差最低的核
      • 方向性桑原濾鏡(Directional Kuwahara filter)
      • 索貝爾是如何工作的
      • 獲取局部走向
      • 什么是矩陣
      • 旋轉核
      • 構造旋轉矩陣

選擇方差最低的核

添加如下代碼獲得方差最低的核

// 1 float3 FinalColor = MeanAndVariance[0].rgb; float MinimumVariance = MeanAndVariance[0].a;// 2 for (int i = 1; i < 4; i++) {if (MeanAndVariance[i].a < MinimumVariance){FinalColor = MeanAndVariance[i].rgb;MinimumVariance = MeanAndVariance[i].a;} }return FinalColor;

解釋一下上述代碼:

  • 創建了兩個變量保存最終的顏色和最小方差(都是用第一個核的平均值和方差作為初始值)。
  • 遍歷其余的三個核,如果當前核的方差小于最小方差,就意味著找到了新的FinalColorMinimumVariance。遍歷完畢以后所輸出FinalColor當熱就是方差最低的核的平均值了。
  • 然后找到 Materials\PostProcess文件夾,打開PP_Kuwahara,點擊應用,再回到主編輯界面就可以看到效果了。

    效果看起來不錯,但是如果你貼近一看,會發現一些奇怪的“塊狀斑”。下圖中我把它們高亮標注了一下:


    這是使用軸向平行核(axis-aligned kernel)產生的副作用。一種除去這種塊狀斑的方法就是使用改進版的濾鏡,我們稱之為方向性桑原濾鏡(Directional Kuwahara filter)

    方向性桑原濾鏡(Directional Kuwahara filter)

    這種濾鏡和之前的很類似,只不過它平行于像素的局部走向。下面是個核大小為3×5的方向性桑原濾鏡:

    注:因為我們把一個核視為一個矩陣(matrix),所以以Height x Width的形式書寫它的維度,而不是像往常一樣寫成Width x Height。下文中我們會繼續介紹矩陣的知識。

    核首先要計算出像素邊緣的走向,然后將整個核旋轉使其平行。

    我們使用索貝爾算子(Sobel)進行卷積運算來獲得局部走向。如果索貝爾這個詞你聽起來很熟悉,八成因為它是一非常經典的邊緣檢測技術。既然它是一種邊緣檢測技術,我們能用它來獲取局部走向么?我們先來了解一下索貝爾的工作原理,你就明白了。

    索貝爾是如何工作的

    索貝爾使用2個核

    Gx用于獲取水平方向的梯度;Gy用于獲取垂直方向的梯度。我們以下面3×3的灰度圖為例:

    首先,使用中間的像素核每個核進行卷積。

    譯者注:對應單元格中的值相乘再相加


    如果把每對值都標記到一個2D平面上,那么我們就可以將這個向量所指的方向視為像素的邊緣走向

    然后我們可以對這個斜度值求反正切(arc tangent 或 atan),然后就可以用這個角度對核進行旋轉了。

    這就是我們利用索貝爾來計算像素局部走向的方法。

    獲取局部走向

    打開Global.usf將下列代碼添加到 GetPixelAngle():

    float GradientX = 0; float GradientY = 0; float SobelX[9] = {-1, -2, -1, 0, 0, 0, 1, 2, 1}; float SobelY[9] = {-1, 0, 1, -2, 0, 2, -1, 0, 1}; int i = 0;

    注意:GetPixelAngle()函數的}一定不要寫!!!前面文章講過的知識點!

    解釋一下每個變量的意義:

    • GradientX: 保存水平方向的斜度
    • GradientY: 保存垂直方向的斜度
    • SobelX: 將水平索貝爾核存儲到一個數組中
    • SobelY: 將垂直索貝爾核存儲到一個數組中
    • i: 用于訪問SobelX和SobelY數組中的元素

    接下來使用SobelX 和 SobelY 實施卷積,代碼如下:

    for (int x = -1; x <= 1; x++) {for (int y = -1; y <= 1; y++){// 1float2 Offset = float2(x, y) * TexelSize;float3 PixelColor = SceneTextureLookup(UV + Offset, 14, false).rgb;float PixelValue = dot(PixelColor, float3(0.3,0.59,0.11));// 2GradientX += PixelValue * SobelX[i];GradientY += PixelValue * SobelY[i];i++;} }

    解釋一下代碼:

  • 前2行獲取采樣像素顏色。第3行對該顏色去色轉換成一維灰度值。相較于計算每個顏色通道的灰度這樣做更簡單。
  • 對于每一個核,讓它乘以對應格子里的像素灰度,然后把值累加到相應的斜度變量中(即GradientX和GradientY),然后i++繼續處理下一個核元素。
  • 直接把斜度值代入atan()函數。將下面的代碼添加到for循環的下面:

    return atan(GradientY / GradientX);

    現在我們擁有了獲取像素角度的函數,還需要研究一下如何旋轉核。一種方法就是使用矩陣(matrix)。

    注:實際上你也可以使用基本的三角方法來旋轉,只不過我覺得這里是一個學習矩陣的好機會,因為它們實在是好用。

    什么是矩陣

    矩陣就是一個數字組成的二維數組。例如,下面是一個2×3的矩陣(2行 3列):

    矩陣本身看起來沒什么意思。但當你用一個向量和矩陣相乘的時候,就會體會到它的強大威力了。它可以讓你很方便地進行旋轉縮放等操作。如何使用矩陣來實現旋轉呢?

    在坐標系統中,每個維度都可以用向量表示。我們稱之為基向量,它們定義了坐標軸的正方向。

    下面是幾個不同基向量的例子。紅色箭頭表示X方向,綠箭頭表示Y方向。

    我們可以使用基向量構建一個旋轉矩陣,來旋轉一個向量。簡單地說,就是一個包含著旋轉后基向量位置的矩陣。舉個例子:你有一個向量(橙色箭頭所示)(1, 1)

    假設我們想順時針將它旋轉90度。首先,我們要把基向量先旋轉該角度。

    然后,以新的基向量位置構造一個2×2的矩陣。第一列是紅色箭頭的位置,第二列是綠色箭頭的位置

    最后,使用橙色向量和旋轉矩陣進行矩陣乘法。其結果就是橙色向量的新位置。

    注:你沒必要知道矩陣如何相乘,因為HLSL已經內置了相關函數。

    驚喜不驚喜?更牛X的是你甚至可以使用上面的矩陣將任意二維向量順時針旋轉90度。對于濾鏡來講,這就意味著我們只需為每個像素構造一次旋轉矩陣,就可以為整個核所使用。

    接下來該使用旋轉矩陣旋轉核了。

    旋轉核

    首先,修改GetKernelMeanAndVariance()函數使其能夠接受2×2的矩陣。這是因為,我們得在Kuwahara.usf 中構建這旋轉矩陣并把它傳入其中。將GetKernelMeanAndVariance()改為:

    float4 GetKernelMeanAndVariance(float2 UV, float4 Range, float2x2 RotationMatrix)

    接著把里層for循環的第一行改為:

    float2 Offset = mul(float2(x, y) * TexelSize, RotationMatrix);

    mul()函數將使用偏移量和RotationMatrix進行矩陣乘法。這樣就可以以當前像素旋轉了。

    接下來,我們要構造旋轉矩陣。

    構造旋轉矩陣

    我們使用正弦(sine)和 余弦(cosine)來構造旋轉矩陣:

    關閉 Global.usf并打開Kuwahara.usf,然后將下面的代碼添加到變量列表的底端:

    float Angle = GetPixelAngle(UV); float2x2 RotationMatrix = float2x2(cos(Angle), -sin(Angle), sin(Angle), cos(Angle));

    第一行計算出當前像素的角度,第二行使用該角度創建旋轉矩陣。

    最后,我們將RotationMatrix傳給每一個核。把GetKernelMeanAndVariance()改為如下形式:

    GetKernelMeanAndVariance(UV, Range, RotationMatrix)

    這就是方向性桑原濾鏡的全部啦!關閉Kuwahara.usf并回到PP_Kuwahara,點擊應用并關閉它。

    下面就是原始的桑原濾鏡和方向性桑原濾鏡的對比。請尤其注意,方向性桑原濾鏡不再有那些塊狀斑了。

    注: 我們可以使用PPI_Kuwahara修改濾鏡的大小。我建議將濾鏡設為X半徑大于Y半徑。這將提高核沿邊緣走向的大小,對于提高方向性有一定好處。

    總結

    以上是生活随笔為你收集整理的Unreal Engine 4 手绘风滤镜(Paint Filter)即 桑原滤镜(Kuwahara Filter)教程(下)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。