提高Direct3D中纹理样本的质量 [英] Improve the quality of texture sample in Direct3D

查看:128
本文介绍了提高Direct3D中纹理样本的质量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用DirectX 11渲染视频,我创建了Texture2D并将rgba视频数据复制到其中,这也是像素着色器的资源,下面是代码:

I'm using directx 11 to render video.I create a Texture2D and copy rgba video data into it.Also it is the resource of pixel shader.Here is code:

void CreateTexture(int nWidth, int nHeight)
{
    D3D11_TEXTURE2D_DESC textureDesc;
    textureDesc.Width = nWidth;//Video width
    textureDesc.Height = nHeight;//Video height
    textureDesc.MipLevels = 1;
    textureDesc.ArraySize = 1;
    textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    textureDesc.SampleDesc.Count = 1;
    textureDesc.Usage = D3D11_USAGE_DYNAMIC;
    textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    textureDesc.MiscFlags = 0;
    m_pD3dDevice->CreateTexture2D(&textureDesc, NULL, &m_pRGBATexture);

    D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc;
    ZeroMemory(&shaderResourceViewDesc, 
               sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
    shaderResourceViewDesc.Format = textureDesc.Format;
    shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
    shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
    shaderResourceViewDesc.Texture2D.MipLevels = 1;
    m_pD3dDevice->CreateShaderResourceView(m_pRGBATexture, &shaderResourceViewDesc, &m_pRGBAShaderResouceView);

    ID3D11ShaderResourceView* pArrResources[] = {m_pRGBAShaderResouceView};
    m_pD3dDeviceContext->PSSetShaderResources(0, 1, &pArrShaderResourceView[0]);
}

void WriteVideoData(BYTE *pData, DWORD nSize)
{
    D3D11_MAPPED_SUBRESOURCE textureResource;
    ZeroMemory(&textureResource, sizeof(D3D11_MAPPED_SUBRESOURCE));
    hr = m_pD3dDeviceContext->Map(m_pRGBATexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &textureResource);
    FAIL_RETURN_FALSE("Fail to map rgba texture resource.");
    BYTE *pMappedData = reinterpret_cast<BYTE*>(textureResource.pData);
    BYTE *pTmpBuffer = pFrameBuffer;
    for (int i = 0; i < nHeight; ++i)
    {
        CopyMemory(pMappedData, pTmpBuffer, nWidth * 4);
        pMappedData += rgbaTextureResource.RowPitch;
        pTmpBuffer += nWidth * 4;
    }
    m_pD3dDeviceContext->Unmap(m_pRGBATexture, 0);
}

这是我创建交换链和设置渲染目标的方法:

Here is how I create swap chain and set render target:

void InitSwapChain(int nWidth, int nHeight)//Displayed window size
{
    DXGI_SWAP_CHAIN_DESC swapChainDesc;
    ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
    swapChainDesc.BufferDesc.Width = nWidth;
    swapChainDesc.BufferDesc.Height = nHeight;
    swapChainDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;

    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.BufferCount = 1;
    swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_STRETCHED;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.OutputWindow = m_hWnd;
    swapChainDesc.Windowed = true;

    IDXGIDevice * dxgiDevice = NULL;
    hr = m_pD3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void **)&dxgiDevice);
    FAIL_RETURN_FALSE("Fail to Query IDXGIDevice");

    IDXGIAdapter * dxgiAdapter = NULL;
    hr = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void **)&dxgiAdapter);
    SAFE_RELEASE(dxgiDevice);
    FAIL_RETURN_FALSE("Fail to Query IDXGIAdapter");

    IDXGIFactory * dxgiFactory = NULL;
    hr = dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void **)&dxgiFactory);
    SAFE_RELEASE(dxgiAdapter);
    FAIL_RETURN_FALSE("Fail to Query IDXGIFactory");

    hr = dxgiFactory->CreateSwapChain(m_pD3dDevice, &swapChainDesc, &m_pSwapChain);
    FAIL_RETURN_FALSE("Fail to create swap chain");
    ID3D11Texture2D *pBackBuffer = NULL;
    m_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
    hr = m_pD3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &m_pBackBufferTargetView);
    m_pD3dDeviceContext->OMSetRenderTargets(1, &m_pBackBufferTargetView, m_pDepthStencilView);
}

我已为设备上下文设置了示例状态:

I've set sample state for device context:

void SetSampleState()
{
    D3D11_SAMPLER_DESC samplerDesc;
    ZeroMemory(&samplerDesc, sizeof(D3D11_SAMPLER_DESC));

    samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.MipLODBias = 0.0f;
    samplerDesc.MaxAnisotropy = 16;
    samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
    samplerDesc.BorderColor[0] = 0;
    samplerDesc.BorderColor[1] = 0;
    samplerDesc.BorderColor[2] = 0;
    samplerDesc.BorderColor[3] = 0;
    samplerDesc.MinLOD = 0;
    samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;

    HRESULT hr = m_pD3dDevice->CreateSamplerState(&samplerDesc, &m_pSamplerState);
    FAIL_RETURN_FALSE("Fail to create sampler state");

    m_pD3dDeviceContext->PSSetSamplers(0, 1, &m_pSamplerState);
}

我的像素着色器非常简单:

My pixel shader is very simple:

Texture2D shaderTexture;
SamplerState SampleType;

struct PixelInputType
{
    float4 position : SV_POSITION;
    float4 blendingColor : COLOR;
    float2 tex : TEXCOORD0;
};

struct PiXelOutput
{
    float4 color : SV_TARGET;
};

PiXelOutput main(PixelInputType input)
{
    PiXelOutput output;
    float4 color = shaderTexture.Sample(SampleType, input.tex);
    output.color.x = color.z;
    output.color.y = color.y;
    output.color.z = color.x;
    output.color.w = 1.0;
    return output;
}

我的问题是当显示视频的窗口大小时如何提高渲染质量小于视频的大小。这时,像素着色器中的 shaderTexture.Sample 是关键点。但是我不知道如何获得更好的采样结果。样本状态,它不起作用。我对DirectX不熟悉,所以我错过了一些东西吗?
PS:我有两张照片可供对比。
这是一种d3d方法:
DirectX渲染
这是我自己的gdi方式和缩放图像:
gdi渲染
我们可以看到特别是文本是模糊的。

My problem is how to improve the render quality when the size of window displaying video is smaller than the size of video.At this time, shaderTexture.Sample in pixel shader is the key point.But I have no idea how to get better sample result.I've trie to change parameter for sample state and it didn't work.I'm not familiar with DirectX.So did I miss something? PS:I have tow pictures for contrast. This one is d3d way: DirectX render This one is gdi way and scaling image myself: gdi render We can see that especially texts are fuzzy.

推荐答案

您可能要研究的一件事是生成一个mip有问题的纹理的链,因为您的 D3D11_FILTER_MIN_MAG_MIP_LINEAR 过滤状态(这是您使用的最佳选择)将利用纹理的mip级别。

One thing you may want to look into is generating a mip chain for the texture in question, since your D3D11_FILTER_MIN_MAG_MIP_LINEAR filtering state (which is the best option for your usage) will leverage the mip levels of the texture.

Mip计数应为 1 + log2(max(width,height)),但取决于最小显示尺寸您可以使用更少的mips。然后将 textureDesc.MiscFlags 设置为包含 D3D11_RESOURCE_MISC_GENERATE_MIPS 标志,并确保 BindFlags 成员包括 D3D11_BIND_SHADER_RESOURCE D3D11_BIND_RENDER_TARGET 。然后,在填充纹理内容之后(在取消映射之后),您可以在直接上下文中调用 ID3D11DeviceContext :: GenerateMips()

The mip count should be along the lines of 1 + log2(max(width, height)), but depending on the minimum display size you can use fewer mips. Then set the textureDesc.MiscFlags to include the D3D11_RESOURCE_MISC_GENERATE_MIPS flag, and make sure the BindFlags member includes D3D11_BIND_SHADER_RESOURCE and D3D11_BIND_RENDER_TARGET. Then once you've filled the texture contents (after Unmap) you can call ID3D11DeviceContext::GenerateMips() on the immediate context.

请注意,绑定和generate-mip标志在动态资源上不起作用,因此您需要保持原始的动态纹理不变,并添加标记为<$ c的第二个纹理$ c> D3D11_USAGE_DEFAULT ,其mip级别大于1,并且上面指定了其他标志。然后,当您完成填充(动态)纹理后,调用 ID3D11DeviceContext :: CopyResource 复制到新纹理。您也将使着色器资源视图也指向这个新手。

Note that the binding and generate-mip flags won't work on a dynamic resource, so you'll need to keep your original, dynamic texture as-is, and add a second texture that's marked as D3D11_USAGE_DEFAULT with the >1 mip levels and the other flags specified above. Then once you've finished filling the staging (dynamic) texture, call ID3D11DeviceContext::CopyResource to copy to the new texture. You'd make your shader resource view point to this new guy too.

这可能会有所帮助,但仍不如真正高质量的小尺寸过滤器好。

This may help a little, but it still won't be as good as a really high-quality down-scale filter.

这篇关于提高Direct3D中纹理样本的质量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆