在DirectX中加载和保存PNG纹理时缺少一些颜色?

8
我使用标准的DirectX函数(例如CreateTexture2DD3DX11SaveTextureToFileD3DX11CreateShaderResourceViewFromFile)来加载PNG图像,将其渲染到新创建的纹理上,然后保存到文件。所有纹理都是2的幂大小。
但是,在此期间,我注意到PNG中的一些颜色略有损坏(与源纹理的颜色相似但不同)。透明度也是如此(对于0和100%的透明度部分有效,但对于例如34%的透明度无效)。
是存在某些大的颜色近似值,还是我做错了什么?如果是这样,我该如何解决?
以下是这两个图像(左侧是源:颜色略有不同,底部有一些渐变透明度;右侧是在新纹理上加载第一张图像并呈现它后保存的图像):

source image new image

我不知道是什么原因导致了这种行为,可能是新纹理的描述:
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;

我尝试将其更改为DXGI_FORMAT_R32G32B32A32_FLOAT,但效果更奇怪:

with DXGI_FORMAT_R32G32B32A32_FLOAT

以下是呈现源纹理在新纹理上的代码:

context->OMSetRenderTargets(1, &renderTargetView, depthStencilView); //to render on new texture instead of the screen
float clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f}; //red, green, blue, alpha
context->ClearRenderTargetView(renderTargetView, clearColor);
//clear the depth buffer to 1.0 (max depth)
context->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
//rendering
turnZBufferOff();
shader->set(context);
object->render(shader, camera, textureManager, context, 0);
swapChain->Present(0, 0);

object->render()中:

UINT stride;
stride = sizeof(Vertex);
UINT offset = 0;
context->IASetVertexBuffers( 0, 1, &buffers->vertexBuffer, &stride, &offset ); //set vertex buffer
context->IASetIndexBuffer( buffers->indexBuffer, DXGI_FORMAT_R16_UINT, 0 ); //set index buffer
context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); //set primitive topology

if(textureID){
    context->PSSetShaderResources( 0, 1, &textureManager->get(textureID)->texture);
}

ConstantBuffer2DStructure cbPerObj;
cbPerObj.positionAndScale = XMFLOAT4(center.getX(), center.getY(), halfSize.getX(), halfSize.getY());
cbPerObj.textureCoordinates =  XMFLOAT4(textureRectToUse[0].getX(), textureRectToUse[0].getY(), textureRectToUse[1].getX(), textureRectToUse[1].getY());
context->UpdateSubresource(constantBuffer, 0, NULL, &cbPerObj, 0, 0);
context->VSSetConstantBuffers(0, 1, &constantBuffer);
context->PSSetConstantBuffers(0, 1, &constantBuffer);

context->DrawIndexed(6, 0, 0);

着色器非常简单:
VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD)
{

    VS_OUTPUT output;
    output.Pos.zw = float2(0.0f, 1.0f);

    //inPos(x,y) = {-1,1}
    output.Pos.xy = (inPos.xy * positionAndScale.zw) + positionAndScale.xy;
    output.TexCoord.xy = inTexCoord.xy * (textureCoordinates.zw - textureCoordinates.xy) + textureCoordinates.xy;

    return output;
}


float4 PS(VS_OUTPUT input) : SV_TARGET
{
return ObjTexture.Sample(ObjSamplerState, input.TexCoord);
}

为了优化一些内容,我将精灵的大小解析为着色器的参数(它可以很好地工作,纹理大小,边框等都是正确的)。

请将渲染源纹理到第二个纹理的代码和相应的着色器发布在此处。 - Dzmitry93
好的,我希望我没有错过任何重要部分。 - PolGraphic
2个回答

4

你是否设置了混合状态?默认情况下,透明度不起作用,因为默认混合状态是完全没有混合。

这是一个标准的透明度混合状态:

    D3D11_BLEND_DESC desc;
desc.AlphaToCoverageEnable=false;
desc.IndependentBlendEnable = false;

for (int i =0; i < 8 ; i++)
{
    desc.RenderTarget[i].BlendEnable = true;
    desc.RenderTarget[i].BlendOp = D3D11_BLEND_OP::D3D11_BLEND_OP_ADD;
    desc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP::D3D11_BLEND_OP_ADD;
    desc.RenderTarget[i].DestBlend = D3D11_BLEND::D3D11_BLEND_INV_SRC_ALPHA;
    desc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND::D3D11_BLEND_ONE;
    desc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE::D3D11_COLOR_WRITE_ENABLE_ALL;
    desc.RenderTarget[i].SrcBlend = D3D11_BLEND::D3D11_BLEND_SRC_ALPHA;
    desc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND::D3D11_BLEND_ONE;
}

ID3D11BlendState* state;
device->CreateBlendState(&desc,&state);
return state;

此处建议使用alpha分量为1的Clear,而非0。

2
我建议你的问题源于导入一个分层的Fireworks PNG文件。Fireworks分层PNG在导入到其他软件如Flash和Freehand时会保留它们的图层。然而,为了在Photoshop中精确复制分层的Fireworks PNG,必须将其导出为一个扁平的PNG。因此,在Photoshop中打开并扁平化不是解决方案;解决方案是在Fireworks中打开并扁平化它。(注意:PNG可以是8、24或32位...也许需要在你的分析中考虑到这一点。)

当我在Photoshop中打开PNG文件时,它们都在单层上,所以我想它们没有分层。在该程序中使用“压平图像”选项仍会将透明度从它们中移除。 - PolGraphic
没有分层PNG这样的东西。 - leonbloy
我想补充一下,我根本不使用Fireworks(所以我不明白为什么会出现“导入Fireworks文件问题”)- 我在Photoshop中创建我的PNG或从网上下载它们(对于所有这些文件,处理方式都是相同的)。从我的应用程序生成的PNG在任何PNG查看器中看起来都是一样的,包括Windows默认图片查看器和Photoshop。 - PolGraphic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接