2016-06-16 7 views
1

enter image description here다이렉트 X 11 텍스처 플리커

당신이 첨부 된 GIF를 보면, 특히 원 (문제를보고이를 확대해야 할 수도 있습니다), 일어나는 이상한 효과가있다. 텍스처가 변환 될 때 픽셀이 약간 변경되는 것과 같습니다. 이유가 확실하지 않습니다. 광장 중앙에있는 파란색 선과 마찬가지로 약간 앞뒤로 움직이는 것처럼 보입니다. 나는 DirectX를 처음 접했을뿐 무엇이 이것을 유발할 수 있는지 전혀 모른다.

의 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); 

텍스처 정점 설치/업데이트 코드

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

대부분의 경우 한 번에 전체 픽셀을 이동하지 않거나 정수 하위 단계까지 이동하지 않도록 개체를 이동하고있는 것 같습니다. –

+0

나는 +1 위치의 새로운 위치 (또는 내가 증가하는 곳)에서 정수를 한 번에 하나씩 증가시켜 버립니다. – Oblivion

+0

@Jake 텍셀의 중심은 0.5 좌표에 있습니다. 완벽한 텍스처 검색을 수행하는 한 가지 방법은 척추 쉐이더의 투영 공간에서 쿼드를 -1/rtDim만큼 오프셋하는 것입니다. – galop1n

답변

1

귀하의 문제는 텍셀의 실제 중심을 고려하지 않는 것입니다. 구석에 있지 않고 그의 중심에 있습니다.

텍스처가 256x256 인 경우 왼쪽 상단의 픽셀을 읽으려는 경우 사용할 텍스처 좌표는 float2(0,0)이 아니라 float2(0.5,0.5)/256.f이고 오른쪽 하단은 float2(255.5,255.5)/256.f입니다.

이제 체인 기하학> 투영> 뷰포트> 픽셀 셰이더가있는 버텍스 셰이더. 오프셋을 다른 방법으로 적용 할 수 있습니다.

픽셀 쉐이더에서 절반의 텍셀 오프셋을 더할 수는 있지만, 상수로 값을 보내거나 상당히 나쁜 GetDimensions을 사용하는 것이 좋습니다. 지오메트리에서 직접 할 수는 있지만, 내 취향에 너무 많이 앞서 있습니다 (암시 적 UV 또는 위치를 사용하면 어떨까요?).

가장 단순하고 덜 관입하는 솔루션은 정점 셰이더의 끝 부분에 오프셋을 적용하거나, 정사영을 프로젝션에서 베이킹하거나, 영사 된 위치를 직접 조정하는 것입니다.

투영 된 공간은 차원의 사각형] -1..1 [X 축과 Y 축에서 나중에 뷰포트에 의해 실제 화면 좌표로 픽셀 단위로 변환됩니다. 우리는 형상 것입니다 가정하면 질감이 범위에서 문제 [0..1] 다음이 코드가 해결됩니다 좌표 : GPU가 W에 의해 분할 것이기 때문에

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

을, 우리는 W 곱하여 것을 취소해야 , 그리고 투영 된 공간이 2의 len이기 때문에, 투영 된 공간의 반 화소 오프셋은 그 오프셋의 두 배가됩니다. 그래서 여러분은 backbuffer 치수의 역수를 사용합니다.

그 라인을 사용하면 텍스쳐 좌표의 보간이 잘될 것이며, 픽셀 쉐이더는 적절하게 오프셋 된 텍스쳐 좌표를 받게 될 것입니다.

+0

전체 화면으로 실행했는데 수정하지 않아도 문제가 해결되었습니다. Windows 모드에서 계속 유지됩니다. 왜 그런가? 이것의 뒤에 이론은 무엇인가? – Oblivion

+1

Afaik Directex 11에서 하프 텍셀 오프셋 문제가 없어졌으며 DX9에서만 발생했습니다. http://www.asawicki.info/news_1516_half-pixel_offset_in_directx_11.html을 참조하십시오. – Gnietschow

+1

@Jake 오, 그 경우에는 창 크기가 적절하지 않기 때문에 윈도우를 크기 조정을 위해 AdjustWindowRect를 Backbuffer 치수로 호출해야합니다. 프레임의 너비와 높이. – galop1n

관련 문제