You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

SharpDX 4.0(C# WPF)动态纹理更新异常技术问询

解决SharpDX 4.0动态纹理更新时的显示异常问题

从你给出的代码片段和描述来看,纹理过宽、格式不符这类问题大多和像素格式对齐纹理资源的创建参数或者数据更新时的内存拷贝逻辑有关,下面是几个针对性的排查和修复方向:

1. 确保像素格式与纹理创建完全匹配

这是最容易踩的坑!C#里int类型的颜色缓冲区通常是ARGB顺序,但DirectX/SharpDX默认采用BGRA格式。创建纹理时必须明确对应格式:

var textureDesc = new Texture2DDescription
{
    Width = surfaceWidth,
    Height = surfaceHeight,
    MipLevels = 1,
    ArraySize = 1,
    Format = Format.B8G8R8A8_UNorm, // 和int类型缓冲区的BGRA格式对应
    SampleDescription = new SampleDescription(1, 0),
    Usage = ResourceUsage.Dynamic, // 动态纹理必须指定这个
    BindFlags = BindFlags.ShaderResource,
    CpuAccessFlags = CpuAccessFlags.Write, // 允许CPU写入更新
    OptionFlags = ResourceOptionFlags.None
};
_dynamicTexture = new Texture2D(device, textureDesc);

2. 处理纹理行对齐问题

DirectX纹理的每行字节数要求对齐到4字节倍数,哪怕你的surfaceWidth*4刚好是4的倍数,也不能直接整数组拷贝——必须按行拷贝匹配纹理的Pitch参数:

// 锁定纹理获取可写入内存区域
var dataBox = _dynamicTexture.Map(0, MapMode.WriteDiscard, MapFlags.None);
try
{
    int pitch = dataBox.RowPitch; // DirectX实际的每行字节数
    int bytesPerPixel = 4;

    // 逐行拷贝,避免因Pitch不匹配导致数据错位
    for (int y = 0; y < surfaceHeight; y++)
    {
        int sourceStartIndex = y * surfaceWidth;
        IntPtr destRowPtr = dataBox.DataPointer + y * pitch;
        Marshal.Copy(_colorBuffer, sourceStartIndex, destRowPtr, surfaceWidth);
    }
}
finally
{
    _dynamicTexture.Unmap(0);
}

如果直接整数组拷贝,当Pitch不等于surfaceWidth*4时,后续行的数据会错位,视觉上就表现为纹理过宽。

3. 转换第三方库的颜色格式

如果第三方库输出的是RGBA顺序的颜色,需要转成SharpDX要求的BGRA格式,不然会出现颜色颠倒的问题:

// 遍历缓冲区转换RGBA到BGRA
for (int i = 0; i < _colorBuffer.Length; i++)
{
    int rgba = _colorBuffer[i];
    int b = (rgba >> 16) & 0xFF;
    int g = (rgba >> 8) & 0xFF;
    int r = rgba & 0xFF;
    int a = (rgba >> 24) & 0xFF;
    _colorBuffer[i] = (a << 24) | (r << 16) | (g << 8) | b;
}

能让第三方库直接输出BGRA格式的话,就省去转换开销。

4. 检查Shader采样器设置

如果纹理还是显示异常,看看Shader里的采样器是否用了错误的寻址模式,比如Wrap模式会导致纹理重复拉伸:

SamplerState samplerLinear
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Clamp;
    AddressV = Clamp; // 用Clamp避免超出纹理范围的拉伸
};

内容的提问来源于stack exchange,提问作者Dan

火山引擎 最新活动