locked
DirectXTK draw stretch bad color mix

    Question

  • This is all the image, and the small Rect size is 32x32.

    I use the follow code to draw:

    	XMVECTORF32 color2 = { 1.0, 1.0, 1.0, 1.0 };
    
    	RECT srcRect = { 0, 0, 0 + 32, 0 + 32 };
    
    	RECT dstRect = { LONG(63.0), LONG(9.0), LONG(63.0 + 4.0), LONG(9.0 + 400.0) };
    	g_Sprites->Draw(m_pTexture, dstRect, &srcRect, color2);
    	XMVECTORF32 color2 = { 1.0, 1.0, 1.0, 1.0 };
    
    	RECT srcRect = { 0, 0, 0 + 32, 0 + 32 };
    
    	RECT dstRect = { LONG(27.0), LONG(9.0), LONG(27.0 + 32.0), LONG(9.0 + 32.0) };
    	g_Sprites->Draw(m_pTexture, dstRect, &srcRect, color2);

    If the destination rect is same as the source rect, the color is right.
    If the destination rect is not same as the source rect, the color is mix and wrong.

    Look at the white line end at the left, the end color is become to yellow.

    I want to draw stretch and got a destination image with not color mix wrong.
    Please help me to fix this.




    • Edited by lihuipeng49 Wednesday, February 25, 2015 3:41 AM
    Wednesday, February 25, 2015 3:33 AM

Answers

  • Classic atlas bleeding.

    When using anisotropic filtering, you need a texture border that sits on the boundary of the box filter for that mip level.  Position atlased textures on a power-of-two boundary and don't use mip levels beyond that level.

    Choose your solution:

    a) Limit anisotropic filtering by constraining the maximum mip level according to your padding and expected maximum anisotropy.  (maximum ratio to which your rectangle will grow in one dimension with respect to the other)  Disabling mip-mapping entirely is the extreme version of this option.

    b) Provide more padding if necessary.

    c) Use separate textures to take advantage of the intrinsic clamping during mip-map generation and multi-texture.  Multi-texturing means that you provide N discrete textures instead of 1 texture with N sub-images.  (Caching will actually perform very well with multi-texturing if the sampled pixel of the non-selected texture is always the same.  You must adjust your multi-texturing texture coordinates in your shader to do this (simply sample (0,0) for non-selected textures).  But you're stepping outside the capability of the sprite renderer.

    d) Forgo atlasing or multi-texturing entirely and batch your sprites by texture.

    e) since it appears from your example that you are using solid colors, you can simply contrive the color in your shader rather than sample it from a texture.  (If your image is representative of your actual rendering task.)

    • Marked as answer by lihuipeng49 Thursday, February 26, 2015 4:34 AM
    Wednesday, February 25, 2015 2:12 PM

All replies

  • Classic atlas bleeding.

    When using anisotropic filtering, you need a texture border that sits on the boundary of the box filter for that mip level.  Position atlased textures on a power-of-two boundary and don't use mip levels beyond that level.

    Choose your solution:

    a) Limit anisotropic filtering by constraining the maximum mip level according to your padding and expected maximum anisotropy.  (maximum ratio to which your rectangle will grow in one dimension with respect to the other)  Disabling mip-mapping entirely is the extreme version of this option.

    b) Provide more padding if necessary.

    c) Use separate textures to take advantage of the intrinsic clamping during mip-map generation and multi-texture.  Multi-texturing means that you provide N discrete textures instead of 1 texture with N sub-images.  (Caching will actually perform very well with multi-texturing if the sampled pixel of the non-selected texture is always the same.  You must adjust your multi-texturing texture coordinates in your shader to do this (simply sample (0,0) for non-selected textures).  But you're stepping outside the capability of the sprite renderer.

    d) Forgo atlasing or multi-texturing entirely and batch your sprites by texture.

    e) since it appears from your example that you are using solid colors, you can simply contrive the color in your shader rather than sample it from a texture.  (If your image is representative of your actual rendering task.)

    • Marked as answer by lihuipeng49 Thursday, February 26, 2015 4:34 AM
    Wednesday, February 25, 2015 2:12 PM
  • My atlas image size is power-of-two (128x128).

    I want to Disabling mip-mapping entirely.

    The follow is my code for create device:

    HRESULT InitDevice()
    {
    	HRESULT hr = S_OK;
    
    	RECT rc;
    	GetClientRect(g_hWnd, &rc);
    	UINT width = rc.right - rc.left;
    	UINT height = rc.bottom - rc.top;
    
    	ASSERT(width > 0);
    	ASSERT(height > 0);
    
    	UINT createDeviceFlags = 0;
    #ifdef _DEBUG
    	createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
    #endif
    
    	D3D_DRIVER_TYPE driverTypes[] =
    	{
    		D3D_DRIVER_TYPE_HARDWARE,
    		D3D_DRIVER_TYPE_WARP,
    		D3D_DRIVER_TYPE_REFERENCE,
    	};
    	UINT numDriverTypes = ARRAYSIZE(driverTypes);
    
    	D3D_FEATURE_LEVEL featureLevels[] =
    	{
    		D3D_FEATURE_LEVEL_11_0,
    		D3D_FEATURE_LEVEL_10_1,
    		D3D_FEATURE_LEVEL_10_0,
    	};
    	UINT numFeatureLevels = ARRAYSIZE(featureLevels);
    
    	DXGI_SWAP_CHAIN_DESC sd;
    	ZeroMemory(&sd, sizeof(sd));
    	sd.BufferCount = 1;
    	sd.BufferDesc.Width = width;
    	sd.BufferDesc.Height = height;
    	sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    	sd.BufferDesc.RefreshRate.Numerator = 60;
    	sd.BufferDesc.RefreshRate.Denominator = 1;
    	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    	sd.OutputWindow = g_hWnd;
    	sd.SampleDesc.Count = 1;
    	sd.SampleDesc.Quality = 0;
    	sd.Windowed = TRUE;
    
    	for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++)
    	{
    		g_driverType = driverTypes[driverTypeIndex];
    		hr = D3D11CreateDeviceAndSwapChain(nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels,
    			D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext);
    		if (SUCCEEDED(hr))
    			break;
    	}
    	if (FAILED(hr))
    		return hr;
    
    	// Create a render target view
    	ID3D11Texture2D* pBackBuffer = nullptr;
    	hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
    	if (FAILED(hr))
    		return hr;
    
    	hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_pRenderTargetView);
    	pBackBuffer->Release();
    	if (FAILED(hr))
    		return hr;
    
    	// Create depth stencil texture
    	D3D11_TEXTURE2D_DESC descDepth;
    	ZeroMemory(&descDepth, sizeof(descDepth));
    	descDepth.Width = width;
    	descDepth.Height = height;
    	descDepth.MipLevels = 1;
    	descDepth.ArraySize = 1;
    	descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    	descDepth.SampleDesc.Count = 1;
    	descDepth.SampleDesc.Quality = 0;
    	descDepth.Usage = D3D11_USAGE_DEFAULT;
    	descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    	descDepth.CPUAccessFlags = 0;
    	descDepth.MiscFlags = 0;
    	hr = g_pd3dDevice->CreateTexture2D(&descDepth, nullptr, &g_pDepthStencil);
    	if (FAILED(hr))
    		return hr;
    
    	// Create the depth stencil view
    	D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
    	ZeroMemory(&descDSV, sizeof(descDSV));
    	descDSV.Format = descDepth.Format;
    	descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    	descDSV.Texture2D.MipSlice = 0;
    	hr = g_pd3dDevice->CreateDepthStencilView(g_pDepthStencil, &descDSV, &g_pDepthStencilView);
    	if (FAILED(hr))
    		return hr;
    
    	g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, g_pDepthStencilView);
    
    	// Setup the viewport
    	g_screenViewport.Width = (FLOAT)width;
    	g_screenViewport.Height = (FLOAT)height;
    	g_screenViewport.MinDepth = 0.0f;
    	g_screenViewport.MaxDepth = 1.0f;
    	g_screenViewport.TopLeftX = 0;
    	g_screenViewport.TopLeftY = 0;
    	g_pImmediateContext->RSSetViewports(1, &g_screenViewport);
    
    	// Create DirectXTK objects
    	g_States.reset(new CommonStates(g_pd3dDevice));
    	g_Sprites.reset(new SpriteBatch(g_pImmediateContext));
    	g_FXFactory.reset(new EffectFactory(g_pd3dDevice));
    	g_Batch.reset(new PrimitiveBatch<VertexPositionColor>(g_pImmediateContext));
    
    	g_BatchEffect.reset(new BasicEffect(g_pd3dDevice));
    	g_BatchEffect->SetVertexColorEnabled(true);
    
    	{
    		void const* shaderByteCode;
    		size_t byteCodeLength;
    
    		g_BatchEffect->GetVertexShaderBytecode(&shaderByteCode, &byteCodeLength);
    
    		hr = g_pd3dDevice->CreateInputLayout(VertexPositionColor::InputElements,
    			VertexPositionColor::InputElementCount,
    			shaderByteCode, byteCodeLength,
    			&g_pBatchInputLayout);
    		if (FAILED(hr))
    			return hr;
    	}
    
    	g_Shape = GeometricPrimitive::CreateTeapot(g_pImmediateContext, 4.f, 8, false);
    
    	// Initialize the world matrices
    	g_World = XMMatrixIdentity();
    
    	// Initialize the view matrix
    	XMVECTOR Eye = XMVectorSet(0.0f, 3.0f, -6.0f, 0.0f);
    	XMVECTOR At = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
    	XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
    	g_View = XMMatrixLookAtLH(Eye, At, Up);
    
    	g_BatchEffect->SetView(g_View);
    
    	// Initialize the projection matrix
    	g_Projection = XMMatrixPerspectiveFovLH(XM_PIDIV4, width / (FLOAT)height, 0.01f, 100.0f);
    
    	g_BatchEffect->SetProjection(g_Projection);
    
    	return S_OK;
    }


    I want to know where and what code I must add to my code.

    I have just started learning  DirectX 11.
    Thanks!





    • Edited by lihuipeng49 Thursday, February 26, 2015 6:00 AM
    Thursday, February 26, 2015 4:32 AM
  • I don't see the texture you've created for use with the sprites.  Nor do I see the sprite drawing code, in particular the SamplerState that you provide to the SpriteBatch Begin command or the effects that you've used.
    Thursday, February 26, 2015 3:53 PM
  • The follow code is define:

    HINSTANCE                           g_hInst = nullptr;
    HWND                                g_hWnd = nullptr;
    D3D_DRIVER_TYPE                     g_driverType = D3D_DRIVER_TYPE_NULL;
    D3D_FEATURE_LEVEL                   g_featureLevel = D3D_FEATURE_LEVEL_11_0;
    ID3D11Device*                       g_pd3dDevice = nullptr;
    ID3D11DeviceContext*                g_pImmediateContext = nullptr;
    IDXGISwapChain*                     g_pSwapChain = nullptr;
    ID3D11RenderTargetView*             g_pRenderTargetView = nullptr;
    ID3D11Texture2D*                    g_pDepthStencil = nullptr;
    ID3D11DepthStencilView*             g_pDepthStencilView = nullptr;
    D3D11_VIEWPORT      g_screenViewport;

    ID3D11InputLayout*                  g_pBatchInputLayout = nullptr;

    std::unique_ptr<CommonStates>                           g_States;
    std::unique_ptr<BasicEffect>                            g_BatchEffect;
    std::unique_ptr<EffectFactory>                          g_FXFactory;
    std::unique_ptr<GeometricPrimitive>                     g_Shape;
    std::unique_ptr<PrimitiveBatch<VertexPositionColor>>    g_Batch;
    std::unique_ptr<SpriteBatch>                            g_Sprites;

    XMMATRIX                            g_World;
    XMMATRIX                            g_View;
    XMMATRIX                            g_Projection;

    class CEngineImageImpl : public IEngineImage { // ... ID3D11ShaderResourceView* m_pTexture; };

    The follow code is texture create:

    void CEngineImageImpl::Load(LPCWSTR filename, const BYTE* fileDataPtr, DWORD fileDataSize)
    {
    	ASSERT(m_pDevice);
    	HRESULT hr = CreateDDSTextureFromMemory(g_pd3dDevice, fileDataPtr, fileDataSize, nullptr, &m_pTexture);
    }


    The follow code is texture draw:

    void CEngineImageImpl::Draw(float x, float y, float w, float h, int sx, int sy, int sw, int sh, EngineColor color)
    {
    	ASSERT(m_pDevice);
    	ASSERT(g_Sprites);
    
    	float a = float(color.Alpha) / 255; // unsigned char color.Alpha
    	float r = float(color.Red) / 255;
    	float g = float(color.Green) / 255;
    	float b = float(color.Blue) / 255;
    	XMVECTORF32 color2 = { r, g, b, a };
    
    	RECT srcRect = { sx, sy, sx + sw, sy + sh };
    
    	ASSERT(w > 0);
    	ASSERT(h > 0);
    	RECT dstRect = { LONG(x), LONG(y), LONG(x + w), LONG(y + h) };
    	g_Sprites->Draw(m_pTexture, dstRect, &srcRect, color2);
    }


    The follow code is Begin-End pair:

    void CEngineDeviceImpl::Render(IGuiFrame* pGuiFrame)
    {
    	m_timer.Tick();
    
    	//
    	// Clear the back buffer
    	//
    	g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, Colors::Black);
    
    	//
    	// Clear the depth buffer to 1.0 (max depth)
    	//
    	g_pImmediateContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
    
    	g_Sprites->Begin(SpriteSortMode_Deferred, g_States->NonPremultiplied());
    	m_pEngineReceiver->Render(); // call CEngineImageImpl::Draw
    	if (m_pInputWnd->IsWindowVisible())	g_Sprites->Draw(m_pTexture, XMFLOAT2(0, 0), nullptr, Colors::White);
    
    	WCHAR str[MAX_PATH];
    	_stprintf_s(str, _T("FPS %d"), m_timer.GetFramesPerSecond());
    	auto x = m_pEngineCore->GetCanvasFactor()->canvasSize.width;
    	auto y = m_pEngineCore->GetCanvasFactor()->canvasSize.height;
    	m_pEngineCore->Fpk(FPK_MIDDLE)->DrawByAnchor(1.0f, 1.0f, str, x, y, FONTCOLOR_CONSOLE);
    
    	g_Sprites->End();
    
    	//
    	// Present our back buffer to our front buffer
    	//
    	g_pSwapChain->Present(0, 0);
    }




    • Edited by lihuipeng49 Friday, February 27, 2015 2:06 PM
    Friday, February 27, 2015 2:00 PM