簡體   English   中英

無法從 Godot 的着色器中正確讀取 FORMAT_R8 統一的 sampler2D 紋理

[英]Can't read a FORMAT_R8 uniform sampler2D texture correctly from within a shader in Godot

我需要將整數數組作為統一傳遞給着色器。 由於尚不支持統一的 arrays,因此我使用FORMAT_R8紋理/isampler2D 來實現此目的。

如果我從紋理中正確讀取字節,它們應該在 [0..7] 范圍內,然后通過規范化該值,我應該得到不同的紅色陰影,但這沒有發生。

在屏幕截圖中,您可以看到當值被讀取為 0 時,它正確地顯示為黑色,但當它不是 0 時,它是全紅色的,沒有陰影。 我嘗試比較讀取的值,它總是大於我可以嘗試的任何值,直到 32 位簽名 integer 的最大值,所以不知道我從紋理中讀回的值是什么。

有任何想法嗎?

完整的項目在這里: https://github.com/Drean64/clash-of-the-colors/tree/simple

GDScript:

extends ViewportContainer

func _ready():
    var attr_ink = PoolByteArray([])
    attr_ink.resize(32*24)
    for i in range(0, 32*24):
        attr_ink[i] = i % 8 # fill array with [0..7]
    
    var image = Image.new()
    image.create_from_data(32, 24, false, Image.FORMAT_R8, attr_ink)

    var ink = ImageTexture.new()
    ink.create_from_image(image, 0)
    
    (self.material as ShaderMaterial).set_shader_param("ink", ink)

着色器:

shader_type canvas_item;

uniform isampler2D ink;

void fragment() {
    COLOR = vec4(0., 0., 0., 1.); // Black
    ivec2 cell = ivec2(UV / TEXTURE_PIXEL_SIZE) / 8; // 8x8 pixel cell coordinate
    int ink_color = texelFetch(ink, cell, 0).r; // Should be [0..7]
    COLOR.r = float(ink_color) / 7.; // Should normalize the red value to [0..1]
    // Line above is a kind of debug to get a hint at what the ink_color value is
}

這對我有用:

  1. 使用sampler2D而不是isampler2D (這似乎是罪魁禍首)。
  2. 通過乘以32.0 (即256.0 / 8.0 )進行歸一化。

那是:

COLOR.r = texelFetch(ink, cell, 0).r * 32.0;

更新:顯然使用isampler2D時存在這些值,但編碼錯誤。

我首先確認紋理生成正確。 問題是在為着色器綁定紋理時。

我查看了 Godot 的源代碼,但沒有針對isampler2D的紋理進行投標。 這讓我認為它的處理方式與sampler2D相同(或者我不太擅長看,在任何一種情況下,我都應該嘗試找出與着色器代碼混淆的事情)。

首先要嘗試的是弄清楚值在哪里有多大。 他們來了大約1000000000 所以,我們似乎得到了 32 位的值。 在嘗試了每一個之后,這非常接近一個解決方案:

int x = texelFetch(ink, cell, 0).r;
COLOR.r = mod(float(x / (256 * 256)), 256.0) / 256.0;

這幾乎行得通。 由於我不清楚的原因,它應該有第二個紅色陰影,它是黑色的。 這讓我覺得也許這些值被編碼為浮點數。

根據這個想法,我決定將這些值除以2097152 (2²¹ = 256 * 256 * 32)。 這將擺脫大部分小數部分。

float                    binary                                integer
5.877471754111438e-39 -> 0 00000000 01000000000000000000000 -> 2097152
                    1 -> 0 01111111 00000000000000000000000 -> 1065353216
                    2 -> 0 10000000 00000000000000000000000 -> 1073741824
                    3 -> 0 10000000 10000000000000000000000 -> 1077936128
                    4 -> 0 10000001 00000000000000000000000 -> 1082130432
                    5 -> 0 10000001 01000000000000000000000 -> 1084227584
                    6 -> 0 10000001 10000000000000000000000 -> 1086324736
                    7 -> 0 10000001 11000000000000000000000 -> 1088421888
                                  X XX

我使用https://baseconvert.com/ieee-754-floating-point得到了浮點值的這些二進制表示

我的想法是采用我在上面標記為 X 的部分。 除以2097152后,它們將移至三個最低有效位。 這給我們留下了這段代碼:

int x = texelFetch(ink, cell, 0).r;
COLOR.r = mod(float(x / 2097152), 8.0) / 8.0;

那樣有用嗎? 再次,幾乎。 這與之前的結果相同。 除了根據上表對結果進行(部分)解釋外,因為我在上面標記為 X 的位上的值 2 為 0。 事實上,0 和 1 的值也需要修補。

現在,我只能修補這些值,不知何故,我們會有工作代碼,對吧? 我只需要弄清楚這些值最終是什么。

如果我嘗試將 2 的值1073741824除以2097152我得到512 哪個......沒有用(我會責怪baseconvert.com)。 但作為搜索實際值的良好起點。

我以以下代碼結束,它將給出預期的結果isampler2D

int x = texelFetch(ink, cell, 0).r;
int y = x / 2097152;
COLOR.r = mod(float(y), 8.0) / 8.0;
if (y == 476)
{
   COLOR.r = 1.0 / 8.0;
}
if (y == 480)
{
   COLOR.r = 2.0 / 8.0;
}
if (y == 482)
{
    COLOR.r = 3.0 / 8.0;
}

所以在那里,我的解釋是它將值作為浮點數傳遞,但將它們作為整數讀取。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM