Tag: directx

Entries for tag "directx", ordered from most recent. Entry count: 56.

Warning! Some information on this page is older than 3 years now. I keep it for reference, but it probably doesn't reflect my current knowledge and beliefs.

Pages: > 1 2 3 4 ... 7 >

19:44
Wed
30
Jan 2013

CConstantBuffer, CTypedConstantBuffer

DirectX 10 and 11 have new, redesigned API that has its pros and cons. One can say that it is now more clean and well organized, but on the other hand it requires more (or as those who code in higher-level languages than C++ or use existing game engines would say - *even more*) lines of code than old Direct3D 9. So I created classes that encapsulate some most typical boilerplate D3D11 code. Here is first one - CConstantBuffer, which handles constant buffer, required now to pass any uniform parameters to a shader.

class CConstantBuffer {
public:
    CConstantBuffer(
        size_t bytesLength,
        const void* initialData = nullptr,
        bool immutable = false );
    ~CConstantBuffer();
    ID3D11Buffer* Buffer() { return m_Buffer.get(); }
    void Update(const void* src);
    void SetForVS(UINT slot);
    // ...and so on for HS, DS, GS, PS, CS.
private:
    size_t m_Length;
    unique_ptr<ID3D11Buffer, ReleaseDeleter> m_Buffer;
};

Read full entry > | Comments (1) | Tags: directx | Author: Adam Sawicki | Share

16:09
Sat
19
Jan 2013

How to Flip Triangles in Triangle Mesh

Given triangle mesh, as we use it in real-time rendering of 3D graphics, we say that each triangle have two sides, depending on whether its vertices are oriented clockwise or counterclockwise from particular point of view. In Direct3D, by default, triangles oriented clockwise are considered front-facing and they are visible, while triangles oriented counterclockwise are invisible because they are discarded by the API feature called backface culling.

When we have backface culling enabled and we convert mesh between coordinate systems, we sometimes need to "flip triangles". When vertices of each triangle are separate, an algorithm for this is easy. We just need to swap first with third vertex of each triangle (or any other two vertices). So we can start implementing the flipping method like this:

class CMesh
{
    ...
    D3D11_PRIMITIVE_TOPOLOGY m_Topology;
    bool m_HasIndices;
    std::vector<SVertex> m_Vertices;
    std::vector<uint32_t> m_Indices;
};

void CMesh::FlipTriangles()
{
    if(m_Topology == D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST)
    {
        if(m_HasIndices)
            FlipTriangleListInArray<uint32_t>(m_Indices);
        else
            FlipTriangleListInArray<SVertex>(m_Vertices);
    }
    ...
}

Where the function template for flipping triangles in a vector is:

template<typename T>
void CMesh::FlipTriangleListInArray(std::vector<T>& values)
{
    for(size_t i = 0, count = values.size(); i < count - 2; i += 3)
        std::swap(values[i], values[i + 2]);
}

Simple reversing all elements in the vector with std::reverse would also do the job. But things get complicated when we consider triangle strip topology. (I assume here that you know how graphics API-s generate orientation of triangles in a triangle strip.) Reversing vertices works, but only when number of vertices in the strip is odd. When it's even, triangles stay oriented in the same way.

I asked question about this on forum.warsztat.gd (in Polish). User albiero proposed following solution: just duplicate first vertex. It will generate additional degenerate (invisible) triangle, but thanks to this all following triangles will be flipped. It seems to work!

I also wanted to handle strip-cut index (a special value -1 which starts new triangle strip), so the rest of my fully-featured algorithm for triangle flipping is:

    ...
    else if(m_Topology == D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP)
    {
        if(m_HasIndices)
        {
            size_t begIndex = 0;
            while(begIndex < m_Indices.size())
            {
                const size_t indexCount = m_Indices.size();
                while(begIndex < indexCount && m_Indices[begIndex] == UINT_MAX)
                    ++begIndex;
                if(begIndex == indexCount)
                    break;
                size_t endIndex = begIndex + 1;
                while(endIndex < indexCount && m_Indices[endIndex] != UINT_MAX)
                    ++endIndex;
                // m_Indices.size() can change here!
                FlipTriangleStripInArray<uint32_t>(m_Indices, begIndex, endIndex);
                begIndex = endIndex + 1;
            }
        }
        else
            FlipTriangleStripInArray<SVertex>(m_Vertices, 0, m_Vertices.size());
    }
}

Where function template for flipping triangles in selected part of a vector is:

template<typename T>
void CMesh::FlipTriangleStripInArray(std::vector<T>& values, size_t begIndex, size_t endIndex)
{
    const size_t count = endIndex - begIndex;
    if(count < 3) return;
    // Number of elements (and triangles) is odd: Reverse elements.
    if(count % 2)
        std::reverse(values.begin() + begIndex, values.begin() + endIndex);
    // Number of elements (and triangles) is even: Repeat first element.
    else
        values.insert(values.begin() + begIndex, values[begIndex]);
}

Comments (1) | Tags: directx rendering algorithms | Author: Adam Sawicki | Share

21:56
Wed
16
Jan 2013

DirectX 11 Renderer - a Screenshot

Here is what I've been working on in my free time recently. It's a renderer For PC, Windows, using DirectX 11.

It may not look spectacular here because I've just quickly put random stuff into this scene, but I already have lots of code that can do useful things, like deferred shading with dynamic directional and point lights, a bunch of material parameters, mesh processing and loading from OBJ file format, heightmap generation, particle effects and postprocessing (including bloom of course :)

In the next posts I will describe some pieces of my technology and share some C++ code.

Comments (1) | Tags: rendering productions directx | Author: Adam Sawicki | Share

21:58
Fri
09
Nov 2012

Half-Pixel Offset in DirectX 11

There is a problem graphics programmers often have to face known as half-pixel/half-texel offset. In Direct3D 9 the probably most official article about it was Directly Mapping Texels to Pixels. In Direct3D 10/11 they changed the way it works so it can be said that the problem is gone now. But I can see the entry about SV_Position in the Semantics article does not explain it clearly, so here is my short explanation.

A pixel on a screen or texel on a texture can be seen as a matrix cell, visualized as square filled with some color. That's the way we treat it in 2D graphics where we index pixels from left-top corner using integer (x, y) coordinates.

But in 3D graphics, texture can be sampled using floating-point coordinates and interpolation between texel colors can be performed. Texture coordinates in DirectX also starts from left-top corner, but position (0, 0) means the very corner of the texture, NOT the center of the first texel! Similarly, position (1, 1) on texture means its bottom-right corner. So to get exactly the color of the second texel of 8 x 8 texture, we have to sample with coordinates (1.5 / 8, 0.5 / 8).

Now if we rendered 3D scene onto a texture to perform e.g. deferred shading or some other screen-space postprocessing and we want to redraw it to the target back buffer, how do we determine coordinates for sampling this texture based on position of rendered pixel? There is a system value semantics available at pixel shader input called SV_Position which gives (x, y) pixel position. It is expressed in pixels, so it goes to e.g. (1920, 1080) and not to (1, 1) like texture coordinates. But it turns out that in Direct3D 10/11, the value of SV_Target for first pixels on the screen is not (0, 0), (1, 0), but (0.5, 0.5), (1.5, 0.5)!

Therefore to sample texture based on pixel position, it's enought to divide it by screen resolution. No need to perform any half-pixel offset - to add or subtract (0.5, 0.5), like it was done in Direct3D 9.

Texture2D g_Texture : register(t0);
SamplerState g_SamplerState : register(s0);

cbuffer : register(b0) {
    float2 g_ScreenResolution;
};

void PixelShader(float2 Position : SV_Position, out float4 Color : SV_Target)
{
    Color = g_Texture.Sample(g_SamplerState, Position / g_ScreenResolution);
}

Comments (0) | Tags: directx rendering | Author: Adam Sawicki | Share

20:56
Sat
03
Nov 2012

Implementing ID3D10Include

DirectX shaders in HLSL language can use #include preprocessor directive, just like C and C++ code. When you compile a shader from file using D3DX11CompileFromFile function, it works automatically. But what if you keep your shader source in memory and compile it with D3DX11CompileFromMemory? DirectX doesn't know the location of source file (if any), so it can't locate additional files to include.

But there is a solution. Parameter __in LPD3D10INCLUDE pInclude allows passing your own object implementing ID3D10Include interface (a typedef to ID3DInclude) that can help DirectX in loading included files while preprocessing shader source. We don't event have to deal with COM interfaces here. We can just implement and use a class like the one below. The code uses lots of stuff from my CommonLib, so it's not self-contained and ready to copy-paste, but it should give a clue about how to do it.

class CShaderInclude : public ID3DInclude
{
public:
    // shaderDir: Directory of current shader file, used by #include "FILE"
    // systemDir: Default shader includes directory, used by #include <FILE>
    CShaderInclude(const char* shaderDir, const char* systemDir) :
        m_ShaderDir(shaderDir),
        m_SystemDir(systemDir)
    {
    }

    HRESULT __stdcall Open(
        D3D_INCLUDE_TYPE IncludeType,
        LPCSTR pFileName,
        LPCVOID pParentData,
        LPCVOID *ppData,
        UINT *pBytes);
    
    HRESULT __stdcall Close(LPCVOID pData);

private:
    string m_ShaderDir;
    string m_SystemDir;
};

HRESULT __stdcall CShaderInclude::Open(
    D3D_INCLUDE_TYPE IncludeType,
    LPCSTR pFileName,
    LPCVOID pParentData,
    LPCVOID *ppData,
    UINT *pBytes)
{
    try
    {
        /*
        If pFileName is absolute: finalPath = pFileName.
        If pFileName is relative: finalPath = dir + "\\" + pFileName
        */
        string finalPath;
        switch(IncludeType)
        {
        case D3D_INCLUDE_LOCAL: // #include "FILE"
            common::RelativeToAbsolutePath(&finalPath, m_ShaderDir, pFileName);
            break;
        case D3D_INCLUDE_SYSTEM: // #include <FILE>
            common::RelativeToAbsolutePath(&finalPath, m_SystemDir, pFileName);
            break;
        default:
            assert(0);
        }

        common::FileStream fileStream(finalPath, common::FM_READ);
        uint32_t fileSize = fileStream.GetSize();

        if(fileSize)
        {
            char* buf = new char[fileSize];
            fileStream.MustRead(buf, fileSize);

            *ppData = buf;
            *pBytes = fileSize;
        }
        else
        {
            *ppData = nullptr;
            *pBytes = 0;
        }
        return S_OK;
    }
    catch(common::Error& err)
    {
        PrintError(err);
        return E_FAIL;
    }
}

HRESULT __stdcall CShaderInclude::Close(LPCVOID pData)
{
    // Here we must correctly free buffer created in Open.
    char* buf = (char*)pData;
    delete[] buf;
    return S_OK;
}

/*
Inputs:
    std::vector<char> shaderData
    const char* filePath
    const char* functionName
    const char* profile
Outputs:
    HRESULT hr
    ID3DBlob* shaderBlob
    ID3DBlob* errorBlob
*/

string shaderDir;
common::ExtractFilePath(&shaderDir, filePath);

CShaderInclude includeObj(shaderDir.c_str(), "Shaders/Include");

HRESULT hr = D3DX11CompileFromMemory(
    shaderData.data(),
    shaderData.size(),
    filePath,
    nullptr, // pDefines
    &includeObj,
    functionName,
    profile,
    0, // Flags1
    0, // Flags2
    nullptr, // pPump
    &shaderBlob,
    &errorBlob,
    nullptr); // pHResult

Comments (1) | Tags: directx | Author: Adam Sawicki | Share

23:50
Fri
02
Nov 2012

Flat Shading in DirectX 11

I code a terrain heightmap rendering and today I wanted to make it looking like in Darwinia. After preparing approporiate texture it turned out that normals of my mesh used for lighting are smoothed. That's not a suprise - after all there is a single vertex in every particular place, shared by surrounding triangles, refered multiple times from index buffer.

How to make triangles flat shaded? Make every vertex unique to its triangle to have different normal? In Direct3D 9 there was this state used by fixed function pipeline you could set to device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); What about Direct3D 10/11?

A simple solution is to use interpolation modifiers. Fields of structure passed from vertex shader to pixel shader can have these modifiers to tell GPU how to interpolate (or not to interpolate) particular value on the surface of a triangle. nointerpolation means the value will be taken from one of vertices. That solves the problem.

struct VS_TO_PS
{
    float4 Pos : SV_Position;
    nointerpolation float3 Normal : NORMAL;
    float2 TexCoord : TEXCOORD0;
};

Comments (1) | Tags: rendering directx | Author: Adam Sawicki | Share

22:52
Mon
23
Jul 2012

Direct3D 11 Checklist

In DirectX 9 there is a lot of states to be set in the device object, so there are these lengthy articles about what could be the cause of not seeing anything rendered on the screen. For example, you could forget to set D3DRS_LIGHTING to FALSE (default is TRUE) and all your geometry is totally black.

Direct3D 11, on the other hand, has more clean API. There is no fixed-function pipeline, only shaders and all remaining states are grouped into state objects. Still there are some things that need to be set before you make a successful draw call, so I prepared a handy checklist for that. Just remember that you can set NULL as any state object and it's still OK - some well defined defaults will be used in that case.

Of course that's not all what is possible, You can also change render target and depth-stencil, setup scissor rects, stream output, compute shader, unordered access views... Basically all you can find in ID3D11DeviceContext class. But I enlisted what I use most often.

Comments (3) | Tags: directx | Author: Adam Sawicki | Share

17:27
Sun
20
May 2012

Direct2D versus Direct3D

Direct2D library is not a completely new graphics API down to the driver level. It internally creates and uses Direct3D 10 device object. Of course it is a powerful library, not just a thin wrapper. But still everything ends up as a bunch of trianges uploaded to the buffer with Map/Unmap and sent to the GPU to be rendered using some vertex and pixel shader. PIX clearly shows all this:

Direct2D in PIX

As a result, Direct2D is able to exchange data with Direct3D 10. Unfortunately it's not the case with Direct3D 11. Topic How to use D2D with D3D11? at gamedev.net forum describes solution to this, full of problems and COM interface manipulation. Post DirectX Componentization and Interoperability by BenCon on DirectX Developer Blog nicely explains interop between different graphics API-s in Windows as a bigger picture. There is also a nasty hack to make D2D work (almost) directly with D3D11, described in post Hacking Direct2D to use directly Direct3D 11 instead of Direct3D 10.1 API on Code4k blog. But no clean and easy way exists.

So I give up with Direct2D for now. All in all, everything can be done by rendering triangles directly in Direct3D :P One thing I'll be missing is the perspective of easy high-quality text rendering with DirectWrite. Well, I'll go back to Bitmap Font Generator from AngelCode :P

Comments (0) | Tags: direct2d directx pix | Author: Adam Sawicki | Share

Pages: > 1 2 3 4 ... 7 >

STAT NO AD [Stat] [Admin] [STAT NO AD] [pub] [Mirror] Copyright © 2004-2017 Adam Sawicki
Copyright © 2004-2017 Adam Sawicki