提高 Direct3D 中纹理样本的质量
Improve the quality of texture sample in Direct3D
我正在使用 directx 11 渲染 video.I 创建一个 Texture2D 并将 rgba 视频数据复制到 it.Also 它是像素的资源 shader.Here 是代码:
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);
}
以下是我创建交换链和设置渲染目标的方法:
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);
}
我已经为设备上下文设置了示例状态:
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);
}
我的像素着色器非常简单:
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;
}
我的问题是这次window显示的视频尺寸小于video.At尺寸时如何提高渲染质量,shaderTexture.Sample 在像素着色器中是关键 point.But 我不知道如何获得更好的样本 result.I 我尝试更改样本状态的参数但没有 work.I'不熟悉 DirectX.So 我是不是漏掉了什么?
PS:I 有两张对比图。
这是 d3d 方式:
DirectX render
这是 gdi 方式和自己缩放图像:
gdi render
我们可以看到,尤其是文本是模糊的。
您可能需要研究的一件事是为相关纹理生成一个 mip 链,因为您的 D3D11_FILTER_MIN_MAG_MIP_LINEAR
过滤状态(这是您使用的最佳选择)将利用纹理的 mip 级别纹理。
mip 计数应与 1 + log2(max(width, height))
一致,但根据最小显示尺寸,您可以使用更少的 mip。然后设置 textureDesc.MiscFlags
以包含 D3D11_RESOURCE_MISC_GENERATE_MIPS
标志,并确保 BindFlags
成员包含 D3D11_BIND_SHADER_RESOURCE
和 D3D11_BIND_RENDER_TARGET
。然后,一旦你填充了纹理内容(在 Unmap 之后),你就可以在即时上下文中调用 ID3D11DeviceContext::GenerateMips()
。
请注意,绑定和生成 mip 标志不适用于动态资源,因此您需要保持原始动态纹理不变,并添加标记为 [=18 的第二个纹理=] 与 >1 mip 级别和上面指定的其他标志。然后,一旦您完成了暂存(动态)纹理的填充,调用 ID3D11DeviceContext::CopyResource
复制到新纹理。你也会让你的着色器资源视图指向这个新人。
这可能会有一点帮助,但它仍然不如真正高质量的缩小滤波器好。
我正在使用 directx 11 渲染 video.I 创建一个 Texture2D 并将 rgba 视频数据复制到 it.Also 它是像素的资源 shader.Here 是代码:
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);
}
以下是我创建交换链和设置渲染目标的方法:
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);
}
我已经为设备上下文设置了示例状态:
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);
}
我的像素着色器非常简单:
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;
}
我的问题是这次window显示的视频尺寸小于video.At尺寸时如何提高渲染质量,shaderTexture.Sample 在像素着色器中是关键 point.But 我不知道如何获得更好的样本 result.I 我尝试更改样本状态的参数但没有 work.I'不熟悉 DirectX.So 我是不是漏掉了什么? PS:I 有两张对比图。 这是 d3d 方式: DirectX render 这是 gdi 方式和自己缩放图像: gdi render 我们可以看到,尤其是文本是模糊的。
您可能需要研究的一件事是为相关纹理生成一个 mip 链,因为您的 D3D11_FILTER_MIN_MAG_MIP_LINEAR
过滤状态(这是您使用的最佳选择)将利用纹理的 mip 级别纹理。
mip 计数应与 1 + log2(max(width, height))
一致,但根据最小显示尺寸,您可以使用更少的 mip。然后设置 textureDesc.MiscFlags
以包含 D3D11_RESOURCE_MISC_GENERATE_MIPS
标志,并确保 BindFlags
成员包含 D3D11_BIND_SHADER_RESOURCE
和 D3D11_BIND_RENDER_TARGET
。然后,一旦你填充了纹理内容(在 Unmap 之后),你就可以在即时上下文中调用 ID3D11DeviceContext::GenerateMips()
。
请注意,绑定和生成 mip 标志不适用于动态资源,因此您需要保持原始动态纹理不变,并添加标记为 [=18 的第二个纹理=] 与 >1 mip 级别和上面指定的其他标志。然后,一旦您完成了暂存(动态)纹理的填充,调用 ID3D11DeviceContext::CopyResource
复制到新纹理。你也会让你的着色器资源视图指向这个新人。
这可能会有一点帮助,但它仍然不如真正高质量的缩小滤波器好。