January 2013

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.

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 (2) | Tags: directx | Author: Adam Sawicki | Share

23:20
Sun
27
Jan 2013

Global Game Jam 2013 - Our Game Octovirus

Global Game Jam 2013 came to an end. The local event in Gdańsk, Poland - 3city Game Jam (Facebook page) was organized by playsoft gamedev company in their office. During the jam, a lot was happening on Twitter in hashtag #ggj13 and #3citygamejam. Here are my several photos of the event. The theme this year was "sound of a heartbeat".

I joined a team of 5 playsoft employees. Together we created a 2D game called "Octovirus" about an actopus-like virus swimming inside veins, collecting blood cells and avoiding evil bacteria. We made all the graphics, including fonts and even sounds during the event. As for the code, there were two of us programmers. We developed in Windows, using Visual C++ 2010 Express. We used Cocos2d-x framework and Box2D for physics. I didn't know both of these libraries before GGJ, so I had to learn the basics quickly :)

The game works on Windows using OpenGL, but it's also portable to Android and iOS. Here is Windows binary: Octovirus.zip (6.09 MB).

Comments (0) | Tags: events competitions productions ggj | Author: Adam Sawicki | Share

22:06
Thu
24
Jan 2013

Global Game Jam Starts Tomorrow

Tomorrow Global Game Jam 2013 starts - annual, 48-hour, worldwide event about game development. Just like last year, big Polish cities will also host this event (Warsaw, Poznań, Gdańsk, £ód¼, Kraków), but this time the local edition in my city - Gdańsk - is organized as 3City Global Game Jam 2013 (Facebook page) by playsoft company. I will go there despite I have no team and no idea what technology to use. I will just see what happens :)

Comments (1) | Tags: competitions events ggj | Author: Adam Sawicki | Share

22:18
Wed
23
Jan 2013

SBX - Scale-Bias Transform

A class of 2D or 3D point and vector transformations called affine transformations (that is - linear transformation plus translation) can be conveniently represented by matrix. But sometimes we don't need possibility of input x to influence output y or vice versa. For example, that's the case when we want to convert coordinates of mouse cursor from pixels, like we take it from WinAPI (where X goes right from 0 to e.g. 1280 and Y goes down from 0 to e.g. 720) to post-projective 3D space (where X goes right from -1.0 to +1.0 and Y goes up from -1.0 on the bottom to +1.0 on the top). Then every component can be transformed independently using linear transform, like this:

Parameters are: scale.xy, bias.xy.
Given input point i.xy, output point o.xy is:

o.x = i.x * scale.x + bias.x
o.y = i.y * scale.y + bias.y

This seems trivial, but what if we wanted to encapsulate such transformation in a new data structure and define operations on it, like we do on matrices? Let's call it SBX - Scale-Bias Transform. I propose following structure:

struct ScaleBiasXform
{
    static const ScaleBiasXform IDENTITY;
    vec2 Scale;
    vec2 Bias;
};

And following functions:

void Construct(ScaleBiasXform& out,
    const vec2& input1, const vec2& output1,
    const vec2& input2, const vec2& output2);
void Scaling(ScaleBiasXform& out, float scale);
void Scaling(ScaleBiasXform& out, const vec2& scale);
void Translation(ScaleBiasXform& out, const vec2& vec);
void Inverse(ScaleBiasXform& out, const ScaleBiasXform& sbx);
void Combine(ScaleBiasXform& out, const ScaleBiasXform& sbx1, const ScaleBiasXform& sbx2);
void TransformPoint(vec2& out, const vec2& point, const ScaleBiasXform& sbx);
void UntransformPoint(vec2& out, const vec2& point, const ScaleBiasXform& sbx);
void TransformVector(vec2& out, const vec2& vec, const ScaleBiasXform& sbx);
void UntransformVector(vec2& out, const vec2& vec, const ScaleBiasXform& sbx);

Full source code with additional comments and function bodies is here: ScaleBiasTransform.hpp, ScaleBiasTransform.cpp. Some additional notes:

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

21:16
Mon
21
Jan 2013

Mesh of Box

Too many times I had to come up with triangle mesh of a box to hardcode it in my program, written just from memory or with help of a sheet of paper. It's easy to make a mistake and have a box with one face missing or something like that. So in case me or somebody in the future will need it, here it is. Parameters:

Box spanning from (-1, -1, -1) to (+1, +1, +1). Contains 3D positions and normals. Topology is triangle strip, using strip-cut index. Backface culling can be used, front faces are clockwise (using Direct3D coordinate system).

// H file

struct SVertex {
    vec3 Position;
    vec3 Normal;
};

const size_t BOX_VERTEX_COUNT = 6 * 4;
const size_t BOX_INDEX_COUNT  = 6 * 5;
extern const SVertex BOX_VERTICES[];
extern const uint16_t BOX_INDICES[];

// CPP file

const SVertex BOX_VERTICES[] = {
    // -X
    { vec3(-1.f, -1.f,  1.f), vec3(-1.f,  0.f,  0.f) },
    { vec3(-1.f,  1.f,  1.f), vec3(-1.f,  0.f,  0.f) },
    { vec3(-1.f, -1.f, -1.f), vec3(-1.f,  0.f,  0.f) },
    { vec3(-1.f,  1.f, -1.f), vec3(-1.f,  0.f,  0.f) },
    // -Z
    { vec3(-1.f, -1.f, -1.f), vec3( 0.f,  0.f, -1.f) },
    { vec3(-1.f,  1.f, -1.f), vec3( 0.f,  0.f, -1.f) },
    { vec3( 1.f, -1.f, -1.f), vec3( 0.f,  0.f, -1.f) },
    { vec3( 1.f,  1.f, -1.f), vec3( 0.f,  0.f, -1.f) },
    // +X
    { vec3( 1.f, -1.f, -1.f), vec3( 1.f,  0.f,  0.f) },
    { vec3( 1.f,  1.f, -1.f), vec3( 1.f,  0.f,  0.f) },
    { vec3( 1.f, -1.f,  1.f), vec3( 1.f,  0.f,  0.f) },
    { vec3( 1.f,  1.f,  1.f), vec3( 1.f,  0.f,  0.f) },
    // +Z
    { vec3( 1.f, -1.f,  1.f), vec3( 0.f,  0.f,  1.f) },
    { vec3( 1.f,  1.f,  1.f), vec3( 0.f,  0.f,  1.f) },
    { vec3(-1.f, -1.f,  1.f), vec3( 0.f,  0.f,  1.f) },
    { vec3(-1.f,  1.f,  1.f), vec3( 0.f,  0.f,  1.f) },
    // -Y
    { vec3(-1.f, -1.f,  1.f), vec3( 0.f, -1.f,  0.f) },
    { vec3(-1.f, -1.f, -1.f), vec3( 0.f, -1.f,  0.f) },
    { vec3( 1.f, -1.f,  1.f), vec3( 0.f, -1.f,  0.f) },
    { vec3( 1.f, -1.f, -1.f), vec3( 0.f, -1.f,  0.f) },
    // +Y
    { vec3(-1.f,  1.f, -1.f), vec3( 0.f,  1.f,  0.f) },
    { vec3(-1.f,  1.f,  1.f), vec3( 0.f,  1.f,  0.f) },
    { vec3( 1.f,  1.f, -1.f), vec3( 0.f,  1.f,  0.f) },
    { vec3( 1.f,  1.f,  1.f), vec3( 0.f,  1.f,  0.f) },
};

const uint16_t BOX_INDICES[] = {
     0,  1,  2,  3, 0xFFFF, // -X
     4,  5,  6,  7, 0xFFFF, // -Z
     8,  9, 10, 11, 0xFFFF, // +X
    12, 13, 14, 15, 0xFFFF, // +Z
    16, 17, 18, 19, 0xFFFF, // -Y
    20, 21, 22, 23, 0xFFFF, // +Y
};

Comments (2) | Tags: rendering | 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 (2) | Tags: rendering productions directx | Author: Adam Sawicki | Share

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