2014-12-19 83 views
2

我目前正嘗試從SetData <>手動設置Texture2D對象上的紋理數據,然後從文件加載它。已經使用MipMaps創建了Texture2D。數據已經從DXT1壓縮保存的.dds文件中加載,並且大小爲512x512。Texture2D SetData錯誤

這是負責創建紋理並將數據加載到其中的代碼。

texture = new Texture2D(graphics, (int)ddsHeader.Width, (int)ddsHeader.Height, mipMapCount > 1, sFormat); 

for (int i = 0; i < (int)mipMapCount; i++) 
{ 
    int pow = (int)Math.Pow(2, i); 

    int width = (int)ddsHeader.Width/pow; 
    int height = (int)ddsHeader.Height/pow; 

    Rectangle? rect = null; 

    // get image size 
    int blockSize = GetBlockSize(width, height); 
    Console.WriteLine(string.Format("Width {0} Height {1}", width, height)); 
    Console.WriteLine("Block size: " + blockSize + " " + (int)ddsHeader.PitchOrLinearSize); 
    // read the texture 
    byte[] textureData = reader.ReadBytes(blockSize); 
    rect = new Rectangle(0, 0, width, height); 

    // set the color into the appropriate level of the texture 
    if (sFormat == SurfaceFormat.Color && dxFormat == DXGIFormat.A8B8G8R8) 
    { 
     Color[] colors = ProcessUncompressedTexture(textureData, width, height); 
     texture.SetData<Color>(i, rect, colors, 0, width * height); 
    } 
    else 
    { 
     texture.SetData<byte>(i, rect, textureData, 0, blockSize); 
    } 
} 

它工作正常,數據是否正確,並設置到每個MIP水平正常 - 直到它達到9級,它引發以下:ArgumentException was unhandled: The size of the data passed in is too large or too small for this resource.

這是輸出。

Width 512 Height 512  // level 0 
Block size: 262144 262144 
Width 256 Height 256  // level 1 
Block size: 65536 262144 
Width 128 Height 128  // level 2 
Block size: 16384 262144 
Width 64 Height 64  // level 3 
Block size: 4096 262144 
Width 32 Height 32  // level 4 
Block size: 1024 262144 
Width 16 Height 16  // level 5 
Block size: 256 262144 
Width 8 Height 8  // level 6 
Block size: 64 262144 
Width 4 Height 4  // level 7 
Block size: 16 262144 
Width 2 Height 2  // level 8 
Block size: 4 262144 

現在,textureData的計數爲4.此mip級別的寬度和高度爲2.矩形的大小也是2個單位。我看不到是什麼導致這個錯誤發生,因爲前8個級別設置正確。

有沒有人知道這裏可能會發生什麼導致這種情況?

回答

1

好的,我想我已經找到了答案,而且它有道理。

此線程here似乎表明DXT壓縮的mipmap的最小允許大小是4x4塊。這與我所看到的相匹配,因爲上面的DXT1和5都有錯誤,但如果我改用DXGIFormat.A8B8G8R8,它會下降到1x1 mip-mapped大小的塊。

最小4x4塊大小的原因是DXT壓縮算法將塊壓縮到最小4x1。

在任何情況下,如果我使用的是DXT壓縮紋理,我已經修改了代碼來調整塊的大小,使其至少爲4x4,並且它可以工作。

對於誰遇到同樣的問題,旁邊的人(誰,他們可能會)的緣故,這裏是我更新的紋理貼圖集代碼:

// create the texture 
texture = new Texture2D(graphics, (int)ddsHeader.Width, (int)ddsHeader.Height, mipMapCount > 1, sFormat); 

Console.WriteLine(texture.LevelCount); 

for (int i = 0; i < (int)mipMapCount; i++) 
{ 
    int pow = (int)Math.Pow(2, i); 

    int width = (int)ddsHeader.Width/pow; 
    int height = (int)ddsHeader.Height/pow; 

    Rectangle? rect = new Rectangle(0, 0, width, height); 

    if (dxFormat == DXGIFormat.DXT1 || dxFormat == DXGIFormat.DXT5) 
    { 
     if (width < 4 && height < 4) 
     { 
      width = 4; 
      height = 4; 
     } 
    } 

    // get image size 
    int blockSize = GetBlockSize(width, height); 
    Console.WriteLine(string.Format("Width {0} Height {1}  // level {2}", width, height, i)); 
    Console.WriteLine("Block size: " + blockSize + " " + (int)ddsHeader.PitchOrLinearSize); 
    // read the texture 
    byte[] textureData = reader.ReadBytes(blockSize); 
    Console.WriteLine("Data size: " + textureData.Length); 

    // set the color into the appropriate level of the texture 
    if (sFormat == SurfaceFormat.Color && dxFormat == DXGIFormat.A8B8G8R8) 
    { 
     Color[] colors = ProcessUncompressedTexture(textureData, width, height); 
     texture.SetData<Color>(i, rect, colors, 0, width * height); 
    } 
    else 
    { 
     texture.SetData<byte>(i, rect, textureData, 0, blockSize); 
    } 
} 

我感動Rectangle? rect = ...調出,並放置在DXT少低於它的4×4塊檢測。它不是最整潔,但它的作品。

0

你可能想看看圖像壓縮後的格式類型(該問題的答案可以發現here的完整說明):

Here是可能的格式類型。

您將不得不檢查texture.Format並使用SurfaceFormat的正確數據結構。

例如。

var b = new Bgr565[result.Width * result.Height]; 
tex.SetData(b); 

下面SurfaceFormat有一個對應的值可以使用的類型。

Color 
Bgr565 
Bgra5551 
Bgra4444 
NormalizedByte2 
NormalizedByte4 
Rgba1010102 
Rg32 
Rgba64 
Alpha8 
Single 
Vector2 
Vector4 
HalfSingle 
HalfVector2 
HalfVector4 

Dxt格式,則意味着紋理壓縮,你將需要知道的大小也被壓縮後,獲得數據,然後解壓。

您可能能夠在某處找到DXT1和DXT5解壓縮庫。不幸的是,我找不到任何管理如此不安全的C#代碼可能是轉換它的最佳選擇。根據維基百科,16個像素存儲在8個字節中,每個像素都有一個字節,所以理論上byte[] data = new byte[(Width * Height)/2]應該用於提取數據。

Dxt1 
Dxt3 
Dxt5 

這是一個特殊情況只是使用HalfVector4爲類型,你很好。 HdrBlendable

+1

事情是,一旦我指定了正確的表面格式,我只需要傳遞原始數據 - Texture2D會自動解壓縮/轉換/應用它,以便紋理在我的遊戲中可用。我在dds頭文件中檢測到DXT1壓縮文件,使用SurfaceFormat.Dxt1創建Texture2D,並將壓縮數據塊傳遞給它,它只是起作用。只有我需要手動轉換的時候是使用DXGIFormat.A8B8G8R8類型,將其更改爲DXGIFormat.A8R8G8B8,因此它可以與SurfaceFormat.Color正常工作 – 2014-12-19 09:46:18