Advertisement

Can't get antialiased picture from Direct3D

Started by August 16, 2018 07:51 PM
4 comments, last by Sergey-Kh 6 years, 3 months ago

I'm taking my first steps in programming with Direct3D. I have a very basic pipeline setup, and all I want to get from it is an antialiased smooth image. But I get this:

screenshot

First, I can't get rid of stair effect though I have 4x MSAA enabled already in my pipeline (DXGI_SAMPLE_DESC::Count is 4 and Quality is 0): 

stairs

And second, I get this noisy texturing though I have mipmaps generated and LINEAR filtering set in the sampler state.

noisy texturing

Am I missing something or doing wrong? I would appreciate any advice on that.

Here is my code:

1) Renderer class:

Spoiler


#include "Scene.h" // Custom class that contains vertex and index buffer contents for every rendered mesh.
#include "Camera.h" // Custom class that contains camera position and fov.

#include <wrl/client.h>
using Microsoft::WRL::ComPtr;

#include <DirectXMath.h>
using namespace DirectX;

#include <map>

#include "generated\VertexShader.h"
#include "generated\PixelShader.h"

class Renderer
{
public:
    Renderer(HWND hWnd, int wndWidth, int wndHeight, const Scene& scene, const Camera& camera);

    void Render();

    void SwitchToWireframe();
    void SwitchToSolid();

protected:
    void CreateDeviceAndSwapChain();
    void CreateDepthStencil();
    void CreateInputLayout();
    void CreateVertexShader();
    void CreatePixelShader();
    void CreateRasterizerStates();
    void CreateBlendState();
    void CreateSamplerState();
    void CreateBuffer(ID3D11Buffer** buffer, 
        D3D11_USAGE usage, D3D11_BIND_FLAG bindFlags,
        UINT cpuAccessFlags, UINT miscFlags,
        UINT sizeOfBuffer, UINT sizeOfBufferElement, const void* initialData);
    void CreateTexture2DAndSRV(const Scene::Texture& texture, ID3D11ShaderResourceView** view);
    void CreateTexturesAndViews();
    void GenerateMips();

protected:
    const Scene& m_scene;

    const Camera& m_camera;
    DWORD m_cameraLastUpdateTickCount;

    HWND m_windowHandle;
    int m_windowWidth; 
    int m_windowHeight;

    DXGI_SAMPLE_DESC m_sampleDesc;

    ComPtr<IDXGISwapChain> m_swapChain;
    ComPtr<ID3D11Texture2D> m_swapChainBuffer;
    ComPtr<ID3D11RenderTargetView> m_swapChainBufferRTV;
    ComPtr<ID3D11Device> m_device;
    ComPtr<ID3D11DeviceContext> m_deviceContext;
    ComPtr<ID3D11Debug> m_debugger;
    ComPtr<ID3D11Texture2D> m_depthStencilTexture;
    ComPtr<ID3D11DepthStencilState> m_depthStencilState;
    ComPtr<ID3D11DepthStencilView> m_depthStencilView;
    ComPtr<ID3D11InputLayout> m_inputLayout;
    ComPtr<ID3D11VertexShader> m_vertexShader;
    ComPtr<ID3D11PixelShader> m_pixelShader;
    ComPtr<ID3D11RasterizerState> m_solidRasterizerState;
    ComPtr<ID3D11RasterizerState> m_wireframeRasterizerState;
    ComPtr<ID3D11BlendState> m_blendState;
    ComPtr<ID3D11SamplerState> m_linearSamplerState;

    std::map<std::string, ComPtr<ID3D11ShaderResourceView>> m_diffuseMapViews;
    std::map<std::string, ComPtr<ID3D11ShaderResourceView>> m_normalMapViews;

    XMMATRIX m_worldViewMatrix;

    ID3D11RasterizerState* m_currentRasterizerState;
};

void Renderer::CreateDeviceAndSwapChain()
{
    HRESULT hr;

    DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
    swapChainDesc.BufferDesc.Width = m_windowWidth;
    swapChainDesc.BufferDesc.Height = m_windowHeight;
    swapChainDesc.BufferDesc.RefreshRate.Numerator = 1;
    swapChainDesc.BufferDesc.RefreshRate.Denominator = 60;
    swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
    swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
    swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
    swapChainDesc.SampleDesc = m_sampleDesc;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.BufferCount = 1;
    swapChainDesc.OutputWindow = m_windowHandle;
    swapChainDesc.Windowed = TRUE;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

    D3D_FEATURE_LEVEL desiredFeatureLevels[] = { D3D_FEATURE_LEVEL_10_1 };
    D3D_FEATURE_LEVEL featureLevel;

    hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL,
        D3D11_CREATE_DEVICE_DEBUG | D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
        desiredFeatureLevels, 1, D3D11_SDK_VERSION, &swapChainDesc,
        m_swapChain.GetAddressOf(), m_device.GetAddressOf(), &featureLevel, 
        m_deviceContext.GetAddressOf());

    if (FAILED(hr))
    {
        hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_WARP, NULL,
            D3D11_CREATE_DEVICE_DEBUG | D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
            desiredFeatureLevels, 1, D3D11_SDK_VERSION, &swapChainDesc,
            m_swapChain.GetAddressOf(), m_device.GetAddressOf(), &featureLevel,
            m_deviceContext.GetAddressOf());
    }

    if (FAILED(hr))
        throw std::exception("Failed to create device or swap chain");

    hr = m_device->QueryInterface(m_debugger.GetAddressOf());

    if (FAILED(hr))
        throw std::exception("Failed to get debugger interface");

    hr = m_swapChain->GetBuffer(0, __uuidof(m_swapChainBuffer),
        (void**)m_swapChainBuffer.GetAddressOf());

    if (FAILED(hr))
        throw std::exception("Failed to get swap chain buffer");

    hr = m_device->CreateRenderTargetView(m_swapChainBuffer.Get(), NULL, 
        m_swapChainBufferRTV.GetAddressOf());

    if (FAILED(hr))
        throw std::exception("Failed to create RTV for swap chain buffer");
}

void Renderer::CreateDepthStencil()
{
    HRESULT hr;

    D3D11_TEXTURE2D_DESC tdesc;
    tdesc.Width = m_windowWidth;
    tdesc.Height = m_windowHeight;
    tdesc.MipLevels = 1;
    tdesc.ArraySize = 1;
    tdesc.Format = DXGI_FORMAT_D16_UNORM;
    tdesc.SampleDesc = m_sampleDesc;
    tdesc.Usage = D3D11_USAGE_DEFAULT;
    tdesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    tdesc.CPUAccessFlags = 0;
    tdesc.MiscFlags = 0;

    hr = m_device->CreateTexture2D(&tdesc, NULL, m_depthStencilTexture.GetAddressOf());

    if (FAILED(hr))
        throw std::exception("Failed to create depth stencil texture");

    D3D11_DEPTH_STENCIL_VIEW_DESC dsvdesc;
    dsvdesc.Format = DXGI_FORMAT_D16_UNORM;
    dsvdesc.ViewDimension = m_sampleDesc.Count > 1 
        ? D3D11_DSV_DIMENSION_TEXTURE2DMS 
        : D3D11_DSV_DIMENSION_TEXTURE2D;
    dsvdesc.Flags = 0;
    dsvdesc.Texture2D.MipSlice = 0;

    hr = m_device->CreateDepthStencilView(m_depthStencilTexture.Get(), &dsvdesc, 
        m_depthStencilView.GetAddressOf());

    if (FAILED(hr))
        throw std::exception("Failed to create depth stencil view");

    D3D11_DEPTH_STENCIL_DESC dsdesc;
    dsdesc.DepthEnable = TRUE;
    dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
    dsdesc.DepthFunc = D3D11_COMPARISON_LESS;
    dsdesc.StencilEnable = FALSE;
    dsdesc.StencilReadMask = 0;
    dsdesc.StencilWriteMask = 0;
    dsdesc.FrontFace = {};
    dsdesc.BackFace = {};

    hr = m_device->CreateDepthStencilState(&dsdesc, m_depthStencilState.GetAddressOf());

    if (FAILED(hr))
        throw std::exception("Failed to create depth stencil state");
}

void Renderer::CreateInputLayout()
{
    HRESULT hr;

    D3D11_INPUT_ELEMENT_DESC iedescs[] = {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    };

    hr = m_device->CreateInputLayout(iedescs, 3,
        g_vertexShader, sizeof(g_vertexShader),
        m_inputLayout.GetAddressOf());

    if (FAILED(hr))
        throw std::exception("Failed to create input layout");
}

void Renderer::CreateVertexShader()
{
    HRESULT hr;

    hr = m_device->CreateVertexShader(g_vertexShader, sizeof(g_vertexShader), 
        NULL, m_vertexShader.GetAddressOf());

    if (FAILED(hr))
        throw std::exception("Failed to create vertex shader");
}

void Renderer::CreatePixelShader()
{
    HRESULT hr;

    hr = m_device->CreatePixelShader(g_pixelShader, sizeof(g_pixelShader), 
        NULL, m_pixelShader.GetAddressOf());

    if (FAILED(hr))
        throw std::exception("Failed to create pixel shader");
}

void Renderer::CreateRasterizerStates()
{
    HRESULT hr;

    D3D11_RASTERIZER_DESC rdesc;
    rdesc.FillMode = D3D11_FILL_SOLID;
    rdesc.CullMode = D3D11_CULL_FRONT;
    rdesc.FrontCounterClockwise = FALSE;
    rdesc.DepthBias = 0;
    rdesc.DepthBiasClamp = 0.0f;
    rdesc.SlopeScaledDepthBias = 0.0f;
    rdesc.DepthClipEnable = TRUE;
    rdesc.ScissorEnable = FALSE;
    rdesc.MultisampleEnable = m_sampleDesc.Count > 1 ? TRUE : FALSE;
    rdesc.AntialiasedLineEnable = m_sampleDesc.Count > 1 ? TRUE : FALSE;

    hr = m_device->CreateRasterizerState(&rdesc, m_solidRasterizerState.GetAddressOf());

    if (FAILED(hr))
        throw std::exception("Failed to create rasterizer state");

    rdesc.FillMode = D3D11_FILL_WIREFRAME;

    hr = m_device->CreateRasterizerState(&rdesc, m_wireframeRasterizerState.GetAddressOf());

    if (FAILED(hr))
        throw std::exception("Failed to create rasterizer state");

    m_currentRasterizerState = m_solidRasterizerState.Get();
}

void Renderer::CreateSamplerState()
{
    HRESULT hr;

    D3D11_SAMPLER_DESC smdesc;
    smdesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    smdesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    smdesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    smdesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    smdesc.MipLODBias = 0.0f;
    smdesc.MaxAnisotropy = 0;
    smdesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
    smdesc.BorderColor[4] = {};
    FLOAT MinLOD = 0.0;
    FLOAT MaxLOD = 0.0;

    hr = m_device->CreateSamplerState(&smdesc, m_linearSamplerState.GetAddressOf());

    if (FAILED(hr))
        throw new std::exception("Failed to create sampler state");
}

void Renderer::CreateBlendState()
{
    HRESULT hr;

    D3D11_BLEND_DESC bdesc;
    bdesc.AlphaToCoverageEnable = FALSE;
    bdesc.IndependentBlendEnable = FALSE;
    bdesc.RenderTarget[0].BlendEnable = FALSE;
    bdesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
    bdesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
    bdesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
    bdesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
    bdesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
    bdesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
    bdesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

    hr = m_device->CreateBlendState(&bdesc, m_blendState.GetAddressOf());

    if (FAILED(hr))
        throw std::exception("Failed to create blend state");
}

 void Renderer::CreateBuffer(ID3D11Buffer** buffer, 
     D3D11_USAGE usage, D3D11_BIND_FLAG bindFlags,
    UINT cpuAccessFlags, UINT miscFlags, 
    UINT sizeOfBuffer, UINT sizeOfBufferElement, const void* initialData)
{
    HRESULT hr;

    D3D11_BUFFER_DESC bdesc;
    bdesc.ByteWidth = sizeOfBuffer;
    bdesc.Usage = usage;
    bdesc.BindFlags = bindFlags;
    bdesc.CPUAccessFlags = cpuAccessFlags;
    bdesc.MiscFlags = miscFlags;
    bdesc.StructureByteStride = sizeOfBufferElement;

    D3D11_SUBRESOURCE_DATA bdata;
    bdata.pSysMem = initialData;
    bdata.SysMemPitch = 0;
    bdata.SysMemSlicePitch = 0;

    hr = m_device->CreateBuffer(&bdesc, &bdata, buffer);

    if (FAILED(hr))
        throw std::exception("Failed to create buffer");
}

 void Renderer::CreateTexture2DAndSRV(const Scene::Texture& sceneTexture, ID3D11ShaderResourceView** view)
 {
     HRESULT hr;

     constexpr DXGI_FORMAT texformat = DXGI_FORMAT_R32G32B32A32_FLOAT;

     D3D11_TEXTURE2D_DESC tdesc;
     tdesc.Width = sceneTexture.width;
     tdesc.Height = sceneTexture.height;
     tdesc.MipLevels = 0;
     tdesc.ArraySize = 1;
     tdesc.Format = texformat;
     tdesc.SampleDesc.Count = 1;
     tdesc.SampleDesc.Quality = 0;
     tdesc.Usage = D3D11_USAGE_DEFAULT;
     tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
     tdesc.CPUAccessFlags = 0;
     tdesc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;

     ComPtr<ID3D11Texture2D> texture2d;

     hr = m_device->CreateTexture2D(&tdesc, NULL, texture2d.GetAddressOf());

     if (FAILED(hr))
         throw std::exception("Failed to create texture");


     D3D11_SUBRESOURCE_DATA srdata;
     srdata.pSysMem = sceneTexture.data;
     srdata.SysMemPitch = sceneTexture.width * sizeof(float) * 4;
     srdata.SysMemSlicePitch = 0;

     m_deviceContext->UpdateSubresource(texture2d.Get(), 0, NULL, 
         srdata.pSysMem, srdata.SysMemPitch, srdata.SysMemSlicePitch);


     D3D11_SHADER_RESOURCE_VIEW_DESC srvdesc;
     srvdesc.Format = texformat;
     srvdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
     srvdesc.Texture2D.MostDetailedMip = 0;
     srvdesc.Texture2D.MipLevels = -1;

     ComPtr<ID3D11ShaderResourceView> shaderResourceView;

     hr = m_device->CreateShaderResourceView(texture2d.Get(), &srvdesc, view);

     if (FAILED(hr))
         throw std::exception("Failed to create shader resource view");
 }

 void Renderer::CreateTexturesAndViews()
 {
     for (auto it = m_scene.materials.cbegin(); it != m_scene.materials.cend(); it++)
     {
         //don't know what's the problem but if I don't place initialized ComPtr<...> instance into a map
         //then further .GetAddessOf() fails.
         m_diffuseMapViews.emplace(it->first, ComPtr<ID3D11ShaderResourceView>());
         m_normalMapViews.emplace(it->first, ComPtr<ID3D11ShaderResourceView>()); 

         CreateTexture2DAndSRV(it->second.diffuseMap, m_diffuseMapViews[it->first].GetAddressOf());
         CreateTexture2DAndSRV(it->second.normalMap, m_normalMapViews[it->first].GetAddressOf());
     }
 }

 void Renderer::GenerateMips()
 {
     for (auto it = m_diffuseMapViews.begin(); it != m_diffuseMapViews.end(); it++)
         m_deviceContext->GenerateMips(it->second.Get());
     for (auto it = m_normalMapViews.begin(); it != m_normalMapViews.end(); it++)
         m_deviceContext->GenerateMips(it->second.Get());
 }

Renderer::Renderer(HWND hWnd, int windowWidth, int windowHeight, 
    const Scene& scene, const Camera& camera)
    : m_scene(scene)
    , m_camera(camera)
    , m_cameraLastUpdateTickCount(0)
    , m_windowHandle(hWnd)
    , m_windowWidth(windowWidth)
    , m_windowHeight(windowHeight)
{
    m_sampleDesc.Count = 4;
    m_sampleDesc.Quality = 0;

    CreateDeviceAndSwapChain();
    CreateDepthStencil();
    CreateInputLayout();
    CreateVertexShader();
    CreatePixelShader();
    CreateRasterizerStates();
    CreateBlendState();
    CreateSamplerState();
    CreateTexturesAndViews();
    GenerateMips();

    // Setting up IA stage

    m_deviceContext->IASetPrimitiveTopology(
        D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    m_deviceContext->IASetInputLayout(m_inputLayout.Get());

    // Setting up VS stage

    m_deviceContext->VSSetShader(m_vertexShader.Get(), 0, 0);

    // Setting up RS stage

    D3D11_VIEWPORT viewport;
    viewport.TopLeftX = 0.0f;
    viewport.TopLeftY = 0.0f;
    viewport.Width = static_cast<FLOAT>(m_windowWidth);
    viewport.Height = static_cast<FLOAT>(m_windowHeight);
    viewport.MinDepth = 0.0f;
    viewport.MaxDepth = 1.0f;

    m_deviceContext->RSSetViewports(1, &viewport);

    // Setting up PS stage

    m_deviceContext->PSSetSamplers(0, 1, m_linearSamplerState.GetAddressOf());
    m_deviceContext->PSSetShader(m_pixelShader.Get(), 0, 0);

    // Setting up OM stage

    m_deviceContext->OMSetBlendState(m_blendState.Get(), NULL, 0xffffffff);
    m_deviceContext->OMSetDepthStencilState(m_depthStencilState.Get(), 0);
    m_deviceContext->OMSetRenderTargets(1, m_swapChainBufferRTV.GetAddressOf(), m_depthStencilView.Get());
}

void Renderer::Render()
{
    constexpr float background[4] = { 0.047f, 0.0487f, 0.066f, 1.0f };

    // Setting up view matix

    if (m_cameraLastUpdateTickCount
        != m_camera.GetLastUpdateTickCount())
    {
        const Float3& camFrom = m_camera.GetFrom();
        const Float3& camAt = m_camera.GetAt();
        const Float3& camUp = m_camera.GetUp();

        m_cameraLastUpdateTickCount = m_camera.GetLastUpdateTickCount();

        FXMVECTOR from = XMVectorSet(camFrom.x, camFrom.y, camFrom.z, 1.0f);
        FXMVECTOR at = XMVectorSet(camAt.x, camAt.y, camAt.z, 1.0f);
        FXMVECTOR up = XMVectorSet(camUp.x, camUp.y, camUp.z, 0.0f);

        FXMVECTOR dir = XMVectorSubtract(at, from);

        FXMVECTOR x = XMVector3Cross(dir, up);
        FXMVECTOR up2 = XMVector3Cross(x, dir);

        XMMATRIX lookTo = XMMatrixLookToRH(from, dir, up2);

        float scalef = 1.0f / XMVectorGetByIndex(XMVector3Length(dir), 0);

        XMMATRIX scale = XMMatrixScaling(scalef, scalef, scalef);

        float aspect = float(m_windowWidth) / m_windowHeight;
        float fov = m_camera.GetFov() / 180.0f * 3.14f;

        XMMATRIX persp = XMMatrixPerspectiveFovRH(fov, aspect, 0.1f, 1000.0f);

        m_worldViewMatrix = XMMatrixMultiply(XMMatrixMultiply(lookTo, scale), persp);
    }
    else
    {
        return; // Since there's no animation yet I redraw frame only if camera position was changed.
    }

    m_deviceContext->ClearDepthStencilView(m_depthStencilView.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);
    m_deviceContext->ClearRenderTargetView(m_swapChainBufferRTV.Get(), background);

    for (auto imesh = m_scene.meshes.cbegin(); imesh != m_scene.meshes.cend(); imesh++)
    {
        // Creating vertex buffer

        ComPtr<ID3D11Buffer> vertexBuffer;

        CreateBuffer(vertexBuffer.GetAddressOf(), 
            D3D11_USAGE_DEFAULT, D3D11_BIND_VERTEX_BUFFER, 0, 0,
            sizeof(Scene::Vertex) * imesh->vertices.size(), sizeof(Scene::Vertex),
            imesh->vertices.data());

        // Creating index buffer

        ComPtr<ID3D11Buffer> indexBuffer;

        CreateBuffer(indexBuffer.GetAddressOf(),
            D3D11_USAGE_DEFAULT, D3D11_BIND_INDEX_BUFFER, 0, 0,
            sizeof(unsigned int) * imesh->indices.size(), sizeof(unsigned int),
            imesh->indices.data());

        // Creating constant buffer

        ComPtr<ID3D11Buffer> constantBuffer;

        CreateBuffer(constantBuffer.GetAddressOf(),
            D3D11_USAGE_IMMUTABLE, D3D11_BIND_CONSTANT_BUFFER, 0, 0,
            sizeof(XMMATRIX), sizeof(XMMATRIX),
            &m_worldViewMatrix);

        // Setting up IA stage

        ID3D11Buffer* vertexBuffers[8] = { vertexBuffer.Get() };
        unsigned int vertexBufferStrides[8] = { sizeof(Scene::Vertex) };
        unsigned int vertexBufferOffsets[8] = { 0 };

        m_deviceContext->IASetVertexBuffers(0, 8,
            vertexBuffers, vertexBufferStrides, vertexBufferOffsets);

        m_deviceContext->IASetIndexBuffer(indexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);

        // Setting up VS stage

        m_deviceContext->VSSetConstantBuffers(0, 1, constantBuffer.GetAddressOf());

        // Setting up RS stage

        m_deviceContext->RSSetState(m_currentRasterizerState);

        // Setting up PS stage

        ID3D11ShaderResourceView* srvs[2] = { };
        srvs[0] = m_diffuseMapViews.at(imesh->material).Get();
        srvs[1] = m_normalMapViews.at(imesh->material).Get();

        m_deviceContext->PSSetShaderResources(0, 2, srvs);

        // Drawing

        m_deviceContext->DrawIndexed(imesh->indices.size(), 0, 0);
    }

    m_swapChain->Present(0, 0);
}

void Renderer::SwitchToWireframe()
{
    m_currentRasterizerState = m_wireframeRasterizerState.Get();
    m_camera.UpdateLastUpdateTickCount();
}

void Renderer::SwitchToSolid()
{
    m_currentRasterizerState = m_solidRasterizerState.Get();
    m_camera.UpdateLastUpdateTickCount();
}

 

 

2) Vertex shader:

Spoiler


struct VS_INPUT
{
    float3 position : POSITION;
    float3 normal : NORMAL;
    float2 texcoord : TEXCOORD;
};

struct VS_OUTPUT
{
    float4 position : SV_POSITION;
    float3 normal : NORMAL;
    float2 texcoord : TEXCOORD;
};

cbuffer Matrices
{
    matrix worldViewMatrix;
}

VS_OUTPUT main(VS_INPUT input)
{
    VS_OUTPUT output;

    output.position = mul(worldViewMatrix, float4(input.position.xyz, 1.0));
    output.normal = input.normal;
    output.texcoord = input.texcoord;

    return output;
}

 

3) Pixel shader:

Spoiler


Texture2D DiffuseMap : register(t0);
Texture2D NormalMap: register(t1);

SamplerState LinearSampler : register(s0);

float4 main(VS_OUTPUT input) : SV_TARGET
{
    float3 light = normalize(float3(2.87, -0.36, 1.68));

    float3 diffuseColor = DiffuseMap.Sample(LinearSampler, input.texcoord);
    float3 normalDisplace = float3(0.0, 0.0, 1.0) - NormalMap.Sample(LinearSampler, input.texcoord);

    float illumination = clamp(dot(light, input.normal + normalDisplace), 0.2, 1.0);

    return float4(mul(diffuseColor, illumination), 1.0);
}

 

Thank you in advance!

Looking at the first picture, it does have msaa enabled, it's just subtle and the blockiness is still noticeable because of the extreme change in contrast at the edge, as well as the lower resolution being rendered (which just makes things more noticeable overall).  Note the shades of red/gray along the lines when you zoom in, you wouldn't get that if msaa weren't enabled.  You may need to increase the level of msaa, or look at a different method of antialiasing, if this isn't enough for your needs.

For the second image, mipmaps wouldn't fix that and aren't intended to address that type of aliasing.  Have you tried enabling anisotropoc filtering though?  That takes into account more than just the depth and does actually help reduce the type of aliasing that you are seeing from the texture filtering.

Advertisement
11 hours ago, xycsoscyx said:

Have you tried enabling anisotropoc filtering though?  That takes into account more than just the depth and does actually help reduce the type of aliasing that you are seeing from the texture filtering.

2

I've just tried to switch to anisotropic filtering (D3D11_SAMPLER_DESC::Filter is D3D11_FILTER_ANISOTROPIC now and D3D11_SAMPLER_DESC::MaxAnisotropy is 1). Now, it doesn't help with texture aliasing either :(

image.png.3872502cccb52d208f8703c104d09078.png

Okay, I've just figured the reason of this stairs effect:

stairs

The reason is that I passed the same width and height values for CreateWindow WinApi function, and for DXGI_SWAP_CHAIN_DESC::BufferDesc. Meanwhile, these should be different because CreateWindow takes *outer* width and height of a window to create (window rectangle), while BufferDesc should receive *inner* values (window client area rectangle). Because of that actual area on screen was *smaller* than swap chain buffer and the result of rendering was presumably resampled to fit the rectangle, which was introducing the aliasing after MSAA was already applied.

Fixing the issue gave a much cleaner result (4x MSAA is applied here):

image.png.e94cb2bd8175d5409dfab869b6f2ce0a.png

 

But the question with texture aliasing is still open:

image.png.f79e44f49589b7ef736a215e62bb628f.png

Kudos for fixing the window scaling issue, I didn't even notice that, I thought you meant the minutia (forest through the trees and all that jazz).

6 hours ago, Sergey-Kh said:

I've just tried to switch to anisotropic filtering (D3D11_SAMPLER_DESC::Filter is D3D11_FILTER_ANISOTROPIC now and D3D11_SAMPLER_DESC::MaxAnisotropy is 1). Now, it doesn't help with texture aliasing either :(

For anisotropic filtering, you'll need to increase the samples to more than 1 to notice the difference.  I think a single sample is actually the same as having it disabled (don't quote me on that), since without multiple samples it won't be able to even it out over the surface.  At the least, only using a single sample won't offer nearly the same enhancement as more samples.  Note that increasing the sample size does decrease performance, but that's the price of enabling the filtering.  This is why it's typically left as a user option, if they are ok with the stippling or have lower end hardware and need those few extra cycles, then they can decrease/disable the filtering.

I finally get the desired picture!

image.thumb.png.cef8b52000a810ea17e0579d8a907578.png

 

The texture-aliasing issue was in D3D11_SAMPLER_DESC setup code. There was a typo around MinLOD, MaxLOD members. Because of that sampler was prevented from using any MIP level other than 1 (which is yet too large in most cases in the scene).

As soon as I resolved this, both trilinear and anisotropic filtering gave predictable, smooth results.

Thanks all.

 

This topic is closed to new replies.

Advertisement