首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Texture2D SetData误差

Texture2D SetData误差
EN

Stack Overflow用户
提问于 2014-12-19 05:58:05
回答 2查看 532关注 0票数 2

我目前正在尝试在从文件中加载Texture2D对象之后,用SetData<>手动设置纹理数据。Texture2D是在启用MipMaps的情况下创建的。数据是从用.dds压缩保存的DXT1文件中加载的,大小为512x512。

这是负责创建纹理并将数据加载到其中的代码。

代码语言:javascript
复制
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.

这是输出。

代码语言:javascript
复制
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个级别设置得很好。

有人知道这里可能发生了什么吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-12-19 10:33:59

好吧,我想我找到了答案,这有点道理。

这个线程这里似乎表明DXT压缩的mipmap的最小允许大小是一个4x4块。这与我所看到的匹配,因为上面的DXT1和5错误,但是如果我切换到DXGIFormat.A8B8G8R8,它会下降到1x1MIP映射的大小块。

最小4x4块大小的原因是DXT压缩算法将块压缩到最小4x1。

在任何情况下,如果我使用的是DXT压缩纹理,我已经修改了代码以调整块的大小,使其至少读为4x4,而且它可以工作。

为了下一个遇到同样问题的人(无论是谁),下面是我更新的mipmap集代码:

代码语言:javascript
复制
// 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 = ...调用向上移动,并将小于4x4块检测的DXT置于其下方。这不是最整洁的,但很有效。

票数 1
EN

Stack Overflow用户

发布于 2014-12-19 09:15:58

您可能希望查看图像压缩后的格式类型(对问题的完整解释-答案可以找到这里):

这里是可能的格式类型。

您必须检查texture.Format并为其SurfaceFormat使用正确的数据结构。

例如。

代码语言:javascript
复制
var b = new Bgr565[result.Width * result.Height];
tex.SetData(b);

下面的SurfaceFormat有一个可以使用的相应值类型。

代码语言:javascript
复制
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]应该可以用来提取数据。

代码语言:javascript
复制
Dxt1
Dxt3
Dxt5

这是一个特例,只需对类型使用HalfVector4,您就可以了。HdrBlendable

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27560496

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档