Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 imagenew 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).

like image 605
PolGraphic Avatar asked Jan 06 '13 17:01

PolGraphic


2 Answers

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

like image 138
mrvux Avatar answered Nov 16 '22 14:11

mrvux


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

like image 2
Sergi Avatar answered Nov 16 '22 14:11

Sergi