2016-06-16 1 views
1

enter image description hereDirectX 11 Texture Flicker

Si vous regardez le gif ci-joint, en particulier le cercle (pourrait avoir pour l'agrandir pour voir la question), il y a un effet étrange qui se passe. C'est comme si les pixels étaient légèrement modifiés au fur et à mesure que la texture était en cours de traduction. Je ne suis pas sûr pourquoi. Comme avec la ligne bleue au centre du carré, il semble aller et venir légèrement. Je suis très nouveau sur DirectX et je n'ai aucune idée de ce qui pourrait en être la cause.

code de configuration DirectX:

// Create a DirectX graphics interface factory. 
result = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory); 
Error::ErrorCheck(result, TEXT("CreateDXGIFactory()")); 

// Use the factory to create an adapter for the primary graphics interface (video card). 
result = factory->EnumAdapters(0, &adapter); 
Error::ErrorCheck(result, TEXT("factory->EnumAdapters()")); 

// Enumerate the primary adapter output (monitor). 
result = adapter->EnumOutputs(0, &adapterOutput); 
Error::ErrorCheck(result, TEXT("adapter->EnumOutputs()")); 

// Get the number of modes that fit the DXGI_FORMAT_R8G8B8A8_UNORM display format for the adapter output (monitor). 
result = adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, NULL); 
Error::ErrorCheck(result, TEXT("adapterOutput->GetDisplayModeList()")); 

// Create a list to hold all the possible display modes for this monitor/video card combination. 
displayModeList = new DXGI_MODE_DESC[numModes]; 

// Now fill the display mode list structures. 
result = adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, displayModeList); 
Error::ErrorCheck(result, TEXT("adapterOutput->GetDisplayModeList()")); 

// Now go through all the display modes and find the one that matches the screen width and height. 
// When a match is found store the numerator and denominator of the refresh rate for that monitor. 
for(i=0; i<numModes; i++) 
{ 
    if(displayModeList[i].Width == (unsigned int)screenWidth) 
    { 
     if(displayModeList[i].Height == (unsigned int)screenHeight) 
     { 
      numerator = displayModeList[i].RefreshRate.Numerator; 
      denominator = displayModeList[i].RefreshRate.Denominator; 
     } 
    } 
} 

// Get the adapter (video card) description. 
result = adapter->GetDesc(&adapterDesc); 
Error::ErrorCheck(result, TEXT("adapter->GetDesc()")); 

// Store the dedicated video card memory in megabytes. 
m_videoCardMemory = (int)(adapterDesc.DedicatedVideoMemory/1024/1024); 

// Convert the name of the video card to a character array and store it. 
error = wcstombs_s(&stringLength, m_videoCardDescription, 128, adapterDesc.Description, 128); 

// Release the display mode list. 
delete [] displayModeList; 
displayModeList = 0; 

// Release the adapter output. 
adapterOutput->Release(); 
adapterOutput = 0; 

// Release the adapter. 
adapter->Release(); 
adapter = 0; 

// Release the factory. 
factory->Release(); 
factory = 0; 

// Initialize the swap chain description. 
ZeroMemory(&swapChainDesc, sizeof(swapChainDesc)); 

// Set to a single back buffer. 
swapChainDesc.BufferCount = 1; 

// Set the width and height of the back buffer. 
swapChainDesc.BufferDesc.Width = screenWidth; 
swapChainDesc.BufferDesc.Height = screenHeight; 

// Set regular 32-bit surface for the back buffer. 
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 

// Set the refresh rate of the back buffer. 
if(m_vsync_enabled) 
{ 
    swapChainDesc.BufferDesc.RefreshRate.Numerator = numerator; 
    swapChainDesc.BufferDesc.RefreshRate.Denominator = denominator; 
} 
else 
{ 
    swapChainDesc.BufferDesc.RefreshRate.Numerator = 0; 
    swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; 
} 

// Set the usage of the back buffer. 
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 

// Set the handle for the window to render to. 
swapChainDesc.OutputWindow = hwnd; 

// Turn multisampling off. 
swapChainDesc.SampleDesc.Count = 1; 
swapChainDesc.SampleDesc.Quality = 0; 

// Set to full screen or windowed mode. 
if(fullscreen) 
{ 
    swapChainDesc.Windowed = false; 
} 
else 
{ 
    swapChainDesc.Windowed = true; 
} 

// Set the scan line ordering and scaling to unspecified. 
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; 
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; 

// Discard the back buffer contents after presenting. 
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 

// Don't set the advanced flags. 
swapChainDesc.Flags = 0; 

// Set the feature level to DirectX 11. 
featureLevel = D3D_FEATURE_LEVEL_11_0; 

// Create the swap chain, Direct3D device, and Direct3D device context. 
result = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, &featureLevel, 1, 
         D3D11_SDK_VERSION, &swapChainDesc, &m_swapChain, &m_device, NULL, &m_deviceContext); 
Error::ErrorCheck(result, TEXT("D3D11CreateDeviceAndSwapChain()")); 

// Get the pointer to the back buffer. 
result = m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferPtr); 
Error::ErrorCheck(result, TEXT("m_swapChain->GetBuffer()")); 

// Create the render target view with the back buffer pointer. 
result = m_device->CreateRenderTargetView(backBufferPtr, NULL, &m_renderTargetView); 
Error::ErrorCheck(result, TEXT("m_swapChain->GetBuffer()")); 

// Release pointer to the back buffer as we no longer need it. 
backBufferPtr->Release(); 
backBufferPtr = 0; 

// Initialize the description of the depth buffer. 
ZeroMemory(&depthBufferDesc, sizeof(depthBufferDesc)); 

// Set up the description of the depth buffer. 
depthBufferDesc.Width = screenWidth; 
depthBufferDesc.Height = screenHeight; 
depthBufferDesc.MipLevels = 1; 
depthBufferDesc.ArraySize = 1; 
depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; 
depthBufferDesc.SampleDesc.Count = 1; 
depthBufferDesc.SampleDesc.Quality = 0; 
depthBufferDesc.Usage = D3D11_USAGE_DEFAULT; 
depthBufferDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; 
depthBufferDesc.CPUAccessFlags = 0; 
depthBufferDesc.MiscFlags = 0; 

// Create the texture for the depth buffer using the filled out description. 
result = m_device->CreateTexture2D(&depthBufferDesc, NULL, &m_depthStencilBuffer); 
Error::ErrorCheck(result, TEXT("m_device->CreateTexture2D()")); 

// Initialize the description of the stencil state. 
ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc)); 

// Set up the description of the stencil state. 
depthStencilDesc.DepthEnable = true; 
depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; 
depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS; 

depthStencilDesc.StencilEnable = true; 
depthStencilDesc.StencilReadMask = 0xFF; 
depthStencilDesc.StencilWriteMask = 0xFF; 

// Stencil operations if pixel is front-facing. 
depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; 
depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR; 
depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; 
depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; 

// Stencil operations if pixel is back-facing. 
depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; 
depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR; 
depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; 
depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; 

// Create the depth stencil state. 
result = m_device->CreateDepthStencilState(&depthStencilDesc, &m_depthStencilState); 
Error::ErrorCheck(result, TEXT("m_device->CreateDepthStencilState()")); 

// Set the depth stencil state. 
m_deviceContext->OMSetDepthStencilState(m_depthStencilState, 1); 

// Initailze the depth stencil view. 
ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc)); 

// Set up the depth stencil view description. 
depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; 
depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; 
depthStencilViewDesc.Texture2D.MipSlice = 0; 

// Create the depth stencil view. 
result = m_device->CreateDepthStencilView(m_depthStencilBuffer, &depthStencilViewDesc, &m_depthStencilView); 
Error::ErrorCheck(result, TEXT("m_device->CreateDepthStencilView()")); 

// Bind the render target view and depth stencil buffer to the output render pipeline. 
m_deviceContext->OMSetRenderTargets(1, &m_renderTargetView, m_depthStencilView); 

// Setup the raster description which will determine how and what polygons will be drawn. 
rasterDesc.AntialiasedLineEnable = false; 
rasterDesc.CullMode = D3D11_CULL_NONE; 
rasterDesc.DepthBias = 0; 
rasterDesc.DepthBiasClamp = 0.0f; 
rasterDesc.DepthClipEnable = true; 
rasterDesc.FillMode = D3D11_FILL_SOLID; 
rasterDesc.FrontCounterClockwise = false; 
rasterDesc.MultisampleEnable = false; 
rasterDesc.ScissorEnable = false; 
rasterDesc.SlopeScaledDepthBias = 0.0f; 

// Create the rasterizer state from the description we just filled out. 
result = m_device->CreateRasterizerState(&rasterDesc, &m_rasterState); 
Error::ErrorCheck(result, TEXT("m_device->CreateRasterizerState()")); 

// Now set the rasterizer state. 
m_deviceContext->RSSetState(m_rasterState); 

// Setup the viewport for rendering. 
viewport.Width = (float)screenWidth; 
viewport.Height = (float)screenHeight; 
viewport.MinDepth = 0.0f; 
viewport.MaxDepth = 1.0f; 
viewport.TopLeftX = 0.0f; 
viewport.TopLeftY = 0.0f; 

// Create the viewport. 
m_deviceContext->RSSetViewports(1, &viewport); 

Texture Vertex Setup/code mise à jour

void Bitmap::InitializeBuffers(ID3D11Device* device) { 
VertexType* vertices; 
unsigned long* indices; 
D3D11_BUFFER_DESC vertexBufferDesc, indexBufferDesc; 
D3D11_SUBRESOURCE_DATA vertexData, indexData; 
HRESULT result; 
int i; 

// Set the number of vertices in the vertex array. 
m_vertexCount = 6; 

// Set the number of indices in the index array. 
m_indexCount = m_vertexCount; 

// Create the vertex array. 
vertices = new VertexType[m_vertexCount]; 

// Create the index array. 
indices = new unsigned long[m_indexCount]; 

// Initialize vertex array to zeros at first. 
memset(vertices, 0, (sizeof(VertexType) * m_vertexCount)); 

// Load the index array with data. 
for(i=0; i<m_indexCount; i++) 
{ 
    indices[i] = i; 
} 

// Set up the description of the static vertex buffer. 
vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC; 
vertexBufferDesc.ByteWidth = sizeof(VertexType) * m_vertexCount; 
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; 
vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 
vertexBufferDesc.MiscFlags = 0; 
vertexBufferDesc.StructureByteStride = 0; 

// Give the subresource structure a pointer to the vertex data. 
vertexData.pSysMem = vertices; 
vertexData.SysMemPitch = 0; 
vertexData.SysMemSlicePitch = 0; 

// Now create the vertex buffer. 
result = device->CreateBuffer(&vertexBufferDesc, &vertexData, &m_vertexBuffer); 
Error::ErrorCheck(result, TEXT("CreateBuffer()")); 

// Set up the description of the static index buffer. 
indexBufferDesc.Usage = D3D11_USAGE_DEFAULT; 
indexBufferDesc.ByteWidth = sizeof(unsigned long) * m_indexCount; 
indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; 
indexBufferDesc.CPUAccessFlags = 0; 
indexBufferDesc.MiscFlags = 0; 
indexBufferDesc.StructureByteStride = 0; 

// Give the subresource structure a pointer to the index data. 
indexData.pSysMem = indices; 
indexData.SysMemPitch = 0; 
indexData.SysMemSlicePitch = 0; 

// Create the index buffer. 
result = device->CreateBuffer(&indexBufferDesc, &indexData, &m_indexBuffer); 
Error::ErrorCheck(result, TEXT("CreateBuffer()")); 

// Release the arrays now that the vertex and index buffers have been created and loaded. 
delete [] vertices; 
vertices = 0; 

delete [] indices; 
indices = 0; 
} 

void Bitmap::Render(ID3D11DeviceContext* deviceContext, int positionX, int positionY, bool flipped) { 
// Re-build the dynamic vertex buffer for rendering to possibly a different location on the screen. 
UpdateBuffers(deviceContext, positionX, positionY, flipped); 

// Put the vertex and index buffers on the graphics pipeline to prepare them for drawing. 
RenderBuffers(deviceContext); 
} 

void Bitmap::UpdateBuffers(ID3D11DeviceContext* deviceContext, int positionX, int positionY, bool flipped) { 
int left, right, top, bottom; 
VertexType* vertices; 
D3D11_MAPPED_SUBRESOURCE mappedResource; 
VertexType* verticesPtr; 
HRESULT result; 

// If the position we are rendering this bitmap to has not changed then don't update the vertex buffer since it 
// currently has the correct parameters. 
if((positionX == m_previousPosX) && (positionY == m_previousPosY)) { 
    if(m_flipped == flipped) { 
     return; 
    } 
} 

// If it has changed then update the position it is being rendered to. 
m_previousPosX = positionX; 
m_previousPosY = positionY; 

// Calculate the screen coordinates of the left side of the bitmap. 
left = ((m_screenWidth/2) * -1) + positionX; 

// Calculate the screen coordinates of the right side of the bitmap. 
right = left + m_bitmapWidth; 

// Calculate the screen coordinates of the top of the bitmap. 
top = (m_screenHeight/2) - positionY; 

// Calculate the screen coordinates of the bottom of the bitmap. 
bottom = top - m_bitmapHeight; 

// Create the vertex array. 
vertices = new VertexType[m_vertexCount]; 

// Load the vertex array with data. 
if(!flipped) { 
    // First triangle. 
    vertices[0].position = D3DXVECTOR3(left, top, 0.0f); // Top left. 
    vertices[0].texture = D3DXVECTOR2(0.0f, 0.0f); 

    vertices[1].position = D3DXVECTOR3(right, bottom, 0.0f); // Bottom right. 
    vertices[1].texture = D3DXVECTOR2(1.0f, 1.0f); 

    vertices[2].position = D3DXVECTOR3(left, bottom, 0.0f); // Bottom left. 
    vertices[2].texture = D3DXVECTOR2(0.0f, 1.0f); 

    // Second triangle. 
    vertices[3].position = D3DXVECTOR3(left, top, 0.0f); // Top left. 
    vertices[3].texture = D3DXVECTOR2(0.0f, 0.0f); 

    vertices[4].position = D3DXVECTOR3(right, top, 0.0f); // Top right. 
    vertices[4].texture = D3DXVECTOR2(1.0f, 0.0f); 

    vertices[5].position = D3DXVECTOR3(right, bottom, 0.0f); // Bottom right. 
    vertices[5].texture = D3DXVECTOR2(1.0f, 1.0f); 
} else { 
    // First triangle. 
    vertices[0].position = D3DXVECTOR3(left, top, 0.0f); // Top left. 
    vertices[0].texture = D3DXVECTOR2(1.0f, 0.0f); 

    vertices[1].position = D3DXVECTOR3(right, bottom, 0.0f); // Bottom right. 
    vertices[1].texture = D3DXVECTOR2(0.0f, 1.0f); 

    vertices[2].position = D3DXVECTOR3(left, bottom, 0.0f); // Bottom left. 
    vertices[2].texture = D3DXVECTOR2(1.0f, 1.0f); 

    // Second triangle. 
    vertices[3].position = D3DXVECTOR3(left, top, 0.0f); // Top left. 
    vertices[3].texture = D3DXVECTOR2(1.0f, 0.0f); 

    vertices[4].position = D3DXVECTOR3(right, top, 0.0f); // Top right. 
    vertices[4].texture = D3DXVECTOR2(0.0f, 0.0f); 

    vertices[5].position = D3DXVECTOR3(right, bottom, 0.0f); // Bottom right. 
    vertices[5].texture = D3DXVECTOR2(0.0f, 1.0f); 
} 

m_flipped = flipped; 

// Lock the vertex buffer so it can be written to. 
result = deviceContext->Map(m_vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); 
Error::ErrorCheck(result, TEXT("deviceContext->Map()")); 

// Get a pointer to the data in the vertex buffer. 
verticesPtr = (VertexType*)mappedResource.pData; 

// Copy the data into the vertex buffer. 
memcpy(verticesPtr, (void*)vertices, (sizeof(VertexType) * m_vertexCount)); 

// Unlock the vertex buffer. 
deviceContext->Unmap(m_vertexBuffer, 0); 

// Release the vertex array as it is no longer needed. 
delete [] vertices; 
vertices = 0; 
} 

void Bitmap::RenderBuffers(ID3D11DeviceContext* deviceContext) 
{ 
unsigned int stride; 
unsigned int offset; 

// Set vertex buffer stride and offset. 
stride = sizeof(VertexType); 
offset = 0; 

// Set the vertex buffer to active in the input assembler so it can be rendered. 
deviceContext->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset); 

// Set the index buffer to active in the input assembler so it can be rendered. 
deviceContext->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0); 

// Set the type of primitive that should be rendered from this vertex buffer, in this case triangles. 
deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 
} 
+1

Il est très probable que vous déplacez l'objet de sorte qu'il ne déplace pas un pixel complet à la fois, ou même pas un nombre entier de sous-étapes. Cela provoque un filtrage, un anti-crénelage, etc. –

+0

J'incrémente les positions de vertex 1 entier à la fois, en les recréant à la nouvelle position de +1 (ou tout ce que j'incrémente). – Oblivion

+0

@Jake Le centre d'un texel est à une coordonnée de 0.5. Une façon d'obtenir une recherche de texture parfaite est de décaler votre quad par -1/rtDim dans l'espace projectif dans votre vertey shader. – galop1n

Répondre

1

Votre problème est que vous ne pensez pas le vrai centre d'un texel. Ce n'est pas au coin mais à son centre.

Disons que vous avez une texture 256x256, lire le pixel en haut à gauche, la texture de coordonnées à utiliser n'est pas float2(0,0) mais float2(0.5,0.5)/256.f et en bas à droite est float2(255.5,255.5)/256.f. Maintenant, dans la géométrie de la chaîne> vertex shader avec projection> viewport> pixel shader. Vous pouvez appliquer le décalage de différentes manières.

Nous pourrions ajouter le décalage du demi-texel dans le pixel shader mais cela signifierait envoyer la valeur dans une constante ou utiliser GetDimensions ce qui est assez mauvais. Vous pouvez le faire directement dans la géométrie, mais cela a trop avancé le problème à mon goût (que faire si vous faites des UV ou des positions implicites?).

La solution la plus simple et la moins intrusive pour votre cas est d'appliquer le décalage à la fin du vertex shader, en le cuisant dans la projection orthographique ou en ajustant directement la position projetée.

L'espace plan projeté est un carré de dimension] -1..1 [sur l'axe X et Y qui est ensuite transformé par la fenêtre en coordonnées réelles en pixels. Si nous supposons que la géométrie sera coordonnée de texture dans l'intervalle [0..1] alors ce code résoudre votre problème:

float4 projPos; // this is your current vertex shader output sv_position 
projPos.xy -= projPos.w * 1.f/backBufferDim.xy; 

Parce que le GPU divisera par W, il faut l'annuler en multipliant par W et parce que l'espace projeté est d'une longueur de 2, un demi-pixel de décalage dans l'espace projeté est le double de ce décalage, donc vous utilisez la réciproque de la dimension de backbuffer.

Avec cette ligne, l'interpolation de la coordonnée de texture fonctionnera pour vous, et votre pixel shader recevra une coordonnée de texture correctement décalée.

+0

Je l'ai couru en plein écran et le problème est maintenant allé, même sans votre correctif. Persiste toujours en mode fenêtré. Une idée pourquoi? Quelle est la théorie derrière cela? – Oblivion

+1

Afaik le problème de décalage de demi-texel est allé sous DirectX 11 et seulement s'est produit avec DX9. Voir http://www.asawicki.info/news_1516_half-pixel_offset_in_directx_11.html – Gnietschow

+1

@Jake oh, dans ce cas, c'est parce que votre fenêtre n'est pas correctement dimensionnée, vous devez appeler AdjustWindowRect avec votre dimension backbuffer pour dimensionner la fenêtre avec le supplément largeur et hauteur pour le cadre. – galop1n