Missing some colors from PNG texture in DirectX during loading and saving?
Asked Answered
C

2

8

I use standard DirectX functions (like CreateTexture2D, D3DX11SaveTextureToFile and D3DX11CreateShaderResourceViewFromFile) to load the PNG image, render it on new created texture and than save to file. All the textures are the power of two sizes.

But during it, I have noticed, that some colors from PNG are a little corrupted (similar but not the same as the colors from the source texture). The same with transparency (it works for 0 and 100% transparency parts, but not for e.g. 34%).

Are there some big color-approximations or I do something wrong? If so, how can I solve it?

Here are these two images (left is source: a little different colors and some gradient transparency on the bottom; right is image after loading first image and render it on the new texture, that was than saved to file):

source image new image

I don't know what cause that behaviour, maybe the new texture's description:

textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;

I have tried to change it to DXGI_FORMAT_R32G32B32A32_FLOAT, but the effect was even stranger:

with DXGI_FORMAT_R32G32B32A32_FLOAT

Here is the code for rendering source texture on the new texture:

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);

And in 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);

The shader is very simple:

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);
}

For some optimalisation I parse the sprite's size as the shader's param (it works fine, the size of texture, borders etc. are right).

Chez answered 6/1, 2013 at 17:55 Comment(2)
Please post your code where are you render source texture to second texture and shader that do it.Wilson
Ok, I hope I haven't missed any important parts of it.Chez
M
4

Did you set blend states around? Alpha will not work by default since default blend is no blend at all.

Here is a standard alpha blend state:

    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;

Also I would use Clear with alpha component set to 1 instead of 0

Mccollough answered 19/1, 2013 at 18:10 Comment(0)
C
2

I'm suggesting that your problems are stemming from importing a layered Fireworks PNG file. Fireworks layered PNGs retain their layers when imported into other softwares like Flash and Freehand. However, in order to have an exact replication of a layered Fireworks PNG in Photoshop, it's necessary to export that layered PNG as a flattened PNG. Thus, opening it in Photoshop and flattening it is not the solution; the solution lies in opening it and flattening it in Fireworks. (Note: PNGs can be 8, 24 or 32-bit...maybe that needs to be accounted for in your analysis.)

Cachexia answered 6/1, 2013 at 18:24 Comment(3)
When I open the PNGs in Photoshop they are on the single layer, so I guess they're not layered. Using "Flatten image" option in that program removes the transparency from them anyway.Chez
They is no such thing as layered PNG.Eurydice
I want to add, that I don't use Fireworks at all (so I don't understand why it could be "importing a Fireworks file issue) - I create my PNGs in Photoshop or download it from web (with all of them it works the same way). The generated PNGs (from my application) looks the same in any PNG viewer, including Windows default picture viewer and Photoshop.Chez

© 2022 - 2024 — McMap. All rights reserved.