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

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

# Direct2D versus Direct3D

17:27

Sun

20

May 2012

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:

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 | #direct2d #directx #pix Share

# DirectXMath - A First Look

22:06

Sun

15

Apr 2012

Programmers using DirectX have access to the accompanying library full of routines that support various 3D math calculations. First it was D3DX - auxilliary library tightly coupled with DirectX itself. It's still there, but some time ago Microsoft released a new library called XNA Math. I've written about it here. This library also ships with latest versions of DirectX SDK (which was last updated in Jun 2010), but it is something completely new - a more independent, small, elegant and efficient library, portable between Windows (where it can use SSE2 or old FPU) and Xbox 360.

Now Microsoft comes up with another library called **DirectXMath**. See the official documentation and introductory blog post for details. As a successor of XNA Math, it looks very similar. Main differences are:

- They dropped support for Xbox 360. The library is now portable between Windows (using SSE2 or FPU) and ARM (using NEON).
- It is now a C++ library, makes use of namespaces and templates, so it no longer works with C.
- It makes use of new C++11 standard (and requires compiler that supports it), including integer types from <cstdint> like uint32_t instead of types from <Windows.h> like DWORD.

Sounds great? Well, I didn't tell yet how to get it. It's not shipped with DirectX SDK. You need the SDK for Windows 8. They say that:

*The library is annotated using SAL2 (rather than the older VS-style or Windows-style annotations), so requires the standalone Windows SDK for Windows 8 Consumer Preview or some additional fixups to use with Visual C++ 2010.*

So probably I'm not going to switch to this new library anytime soon :P

Comments | #directx #math Share

# FX Batch Compiler 1.1

22:48

Thu

17

Feb 2011

4 years ago I've coded a program to visually support batch compilation of multiple HLSL shaders using the console fxc.exe compiler from DirectX SDK. I called it **FX Batch Compiler** and it's open source, under GNU GPL license, written in C#. Now I've updated it to new version 1.1. So if you use Direct3D, check it to see if it can be useful for you. I use it sometimes in my projects.

Features:

- Write compilation scripts in a simple language by specifying parameters for fxc.exe.
- Compile multiple shaders at time.
- Compile only shaders that need rebuild checked by file modification time.
- Review success or failure, warning and error count and compiler output for every task.
- Compile single HLSL source file with different parameters and preprocessor macros.

# XNA Math and Access Violation

21:40

Wed

16

Feb 2011

XNA Math is a great math library bundled with DirectX SDK. I've written about it here: Introduction to XNA Math, XNA Math Cheat Sheet. Recently I've started coding some small raytracer using this library (especially **XMVECTOR** type) and I came across an error:

"Access violation reading location 0xffffffff"

Google didn't display many results when asked about this error in connection with "XNA Math" or "XMVECTOR", but I found a topic on our Polish gamdev forum: xnamath i dziwne crashe. Directed to other web places from there, I discovered that, just as I thought, this bug comes from misaligned address of the vector. XMVECTOR on PC is an alias for SSE __m128 type, which has to be always aligned to 16-byte boundary. Compiler seems to know about this alignment requirement and respects it whenever XMVECTOR is defined on the stack, passed as function parameter or returned from a function, but not when the vector is a member of some dynamically allocated class or struct. So this won't work:

struct Scene {

XMVECTOR dir_to_light;

};

Scene *scene = new Scene();

scene->dir_to_light = XMVector3Normalize(

XMVectorSet(1.5f, 1.f, -2.f, 0.f)); // Crash!

Adding special alignment declaration supported by Visual C++ - __declspec(align(16)) - doesn't help. it looks like operator new always aligns allocated objects to 8 bytes and there is no way to change this behavior other than redefining it to use your own custom memory allocator.

So I suppose the most simple and convenient way to walk around this problem is to use more "casual" types for storing vectors - the ones that do not use SSE and do not require alignment, like **XMFLAOT3** (which is just struct with float x, y, z). Anyway XMVECTOR is designed to optimize computations when compiler is able to place it in the CPU registers. So my solution looks like this:

struct Scene {

XMFLOAT3 dir_to_light;

};

Scene *scene = new Scene();

XMVECTOR dir_to_light = XMVector3Normalize(

XMVectorSet(1.5f, 1.f, -2.f, 0.f));

XMStoreFloat3(&scene->dir_to_light, dir_to_light);

...

XMVECTOR dir_to_light = XMLoadFloat3(&scene->dir_to_light);

XMVECTOR n_dot_l = XMVectorSaturate(XMVector3Dot(normal, dir_to_light));

Comments | #directx #math Share

# Finding Polygon of Plane-AABB Intersection

20:45

Tue

15

Feb 2011

While doing volumetric rendering according to the article Volume Rendering Techniques (Milan Ikits, Joe Kniss, Aaron Lefohn, Charles Hansen, Chapter 39 of "GPU Gems" book), I came across a problem of calculating intersection between a plane and an AABB (axis-aligned bounding box), which forms a 3- to 6-vertex polygon. The solution is actually described in the article, but here I'd like to share my implementation (using D3DX).

The solution is based on finding points of intersection between the plane and every edge of the box. So we first need a ray-to-plane intersection code. My function for this is based on: Ray-Plane Intersection.

// OutVD > 0 means ray is back-facing the plane

// returns false if there is no intersection because ray is perpedicular to plane

bool ray_to_plane(const D3DXVECTOR3 &RayOrig, const D3DXVECTOR3 &RayDir, const D3DXPLANE &Plane, float *OutT, float *OutVD)

{

*OutVD = Plane.a * RayDir.x + Plane.b * RayDir.y + Plane.c * RayDir.z;

if (*OutVD == 0.0f)

return false;

*OutT = - (Plane.a * RayOrig.x + Plane.b * RayOrig.y + Plane.c * RayOrig.z + Plane.d) / *OutVD;

return true;

}

Now having a segment A-B between two points, we can calculate ray_to_plane intersection where RayOrig=A, RayDir=B-A and we get parameter T. The segment is a subset of the infinite ray. The intersection point lies on this segment when 0 <= T <= 1. The position of this point is A+T*B. Now it's time for plane-box intersection code:

// Maximum out_point_count == 6, so out_points must point to 6-element array.

// out_point_count == 0 mean no intersection.

// out_points are not sorted.

void calc_plane_aabb_intersection_points(const D3DXPLANE &plane,

const D3DXVECTOR3 &aabb_min, const D3DXVECTOR3 &aabb_max,

D3DXVECTOR3 *out_points, unsigned &out_point_count)

{

out_point_count = 0;

float vd, t;

// Test edges along X axis, pointing right.

D3DXVECTOR3 dir = D3DXVECTOR3(aabb_max.x - aabb_min.x, 0.f, 0.f);

D3DXVECTOR3 orig = aabb_min;

if (ray_to_plane(orig, dir, plane, &t, &vd) && t >= 0.f && t <= 1.f)

out_points[out_point_count++] = orig + dir * t;

orig = D3DXVECTOR3(aabb_min.x, aabb_max.y, aabb_min.z);

if (ray_to_plane(orig, dir, plane, &t, &vd) && t >= 0.f && t <= 1.f)

out_points[out_point_count++] = orig + dir * t;

orig = D3DXVECTOR3(aabb_min.x, aabb_min.y, aabb_max.z);

if (ray_to_plane(orig, dir, plane, &t, &vd) && t >= 0.f && t <= 1.f)

out_points[out_point_count++] = orig + dir * t;

orig = D3DXVECTOR3(aabb_min.x, aabb_max.y, aabb_max.z);

if (ray_to_plane(orig, dir, plane, &t, &vd) && t >= 0.f && t <= 1.f)

out_points[out_point_count++] = orig + dir * t;

// Test edges along Y axis, pointing up.

dir = D3DXVECTOR3(0.f, aabb_max.y - aabb_min.y, 0.f);

orig = D3DXVECTOR3(aabb_min.x, aabb_min.y, aabb_min.z);

if (ray_to_plane(orig, dir, plane, &t, &vd) && t >= 0.f && t <= 1.f)

out_points[out_point_count++] = orig + dir * t;

orig = D3DXVECTOR3(aabb_max.x, aabb_min.y, aabb_min.z);

if (ray_to_plane(orig, dir, plane, &t, &vd) && t >= 0.f && t <= 1.f)

out_points[out_point_count++] = orig + dir * t;

orig = D3DXVECTOR3(aabb_min.x, aabb_min.y, aabb_max.z);

if (ray_to_plane(orig, dir, plane, &t, &vd) && t >= 0.f && t <= 1.f)

out_points[out_point_count++] = orig + dir * t;

orig = D3DXVECTOR3(aabb_max.x, aabb_min.y, aabb_max.z);

if (ray_to_plane(orig, dir, plane, &t, &vd) && t >= 0.f && t <= 1.f)

out_points[out_point_count++] = orig + dir * t;

// Test edges along Z axis, pointing forward.

dir = D3DXVECTOR3(0.f, 0.f, aabb_max.z - aabb_min.z);

orig = D3DXVECTOR3(aabb_min.x, aabb_min.y, aabb_min.z);

if (ray_to_plane(orig, dir, plane, &t, &vd) && t >= 0.f && t <= 1.f)

out_points[out_point_count++] = orig + dir * t;

orig = D3DXVECTOR3(aabb_max.x, aabb_min.y, aabb_min.z);

if (ray_to_plane(orig, dir, plane, &t, &vd) && t >= 0.f && t <= 1.f)

out_points[out_point_count++] = orig + dir * t;

orig = D3DXVECTOR3(aabb_min.x, aabb_max.y, aabb_min.z);

if (ray_to_plane(orig, dir, plane, &t, &vd) && t >= 0.f && t <= 1.f)

out_points[out_point_count++] = orig + dir * t;

orig = D3DXVECTOR3(aabb_max.x, aabb_max.y, aabb_min.z);

if (ray_to_plane(orig, dir, plane, &t, &vd) && t >= 0.f && t <= 1.f)

out_points[out_point_count++] = orig + dir * t;

}

But that's not all. Returned points are not sorted! If we don't sort them, we may in some cases end up with a mess like this:

Here comes another clever algorithm - the one for sorting vertices (counter?)clockwise. I came up with it on my own and it's a bit similar to the algorithm for finding a convex hull. We are given a set of points that all lie in a single plane and already form a convex polygon. We want to sort them clockwise "around some center point". Beginner could probably think here about calculating such center point, then for each vertex calculating and comparing some angle using atan2, of course in degrees ;)

But that's not the solution. What we need here is a way to tell whether one vector is more "to the right" then the other, relative to some reference point. Whether one vector lies on the right-hand side of the other can be easily told in 2D using the sign of a scalar returned by 2D cross-product: a.x*b.y - b.x*a.y. In 3D it's not that easy. My idea is to use 3D cross-product. It returns 3D vector, but has similar property - it is anticommutative, which means: cross(a,b) == -cross(b,a). Now if only I could tell whether the direction of the resulting vector is "right" or "opposite"... That's what the sign of dot product means! I'm just going to use dot product between the cross product result and the normal vector of the plane. Eureka! Now I have all necessary parts. I choose first vertex as a reference. I also use lambda expression from C++0x (supported in Visual C++ 2010) to more conveniently pass custom comparator to std::sort STL algorithm (otherwise I would have to write a functor). Here is the final solution:

#include <algorithm>

void sort_points(D3DXVECTOR3 *points, unsigned point_count, const D3DXPLANE &plane)

{

if (point_count == 0) return;

const D3DXVECTOR3 plane_normal = D3DXVECTOR3(plane.a, plane.b, plane.c);

const D3DXVECTOR3 origin = points[0];

std::sort(points, points + point_count, [&](const D3DXVECTOR3 &lhs, const D3DXVECTOR3 &rhs) -> bool {

D3DXVECTOR3 v;

D3DXVec3Cross(&v, &(lhs - origin), &(rhs - origin));

return D3DXVec3Dot(&v, &plane_normal) < 0;

} );

}

Comments | #directx #math Share

# MRI Rendering

19:12

Mon

14

Feb 2011

Having injured arm is not a good thing, but for this reason I had MRI (Magnetic Resonance Imaging) and got results on a CD, so I've decided to try to render them in 3D as soon as I could move my arm a bit. Here is the final result:

Read full entry | Comments | #directx #medicine #rendering Share

# DirectX SDK Size History

14:16

Wed

09

Jun 2010

I've just done something of questionable usefulness, but anyway, here it is: a sphreadsheet showing how the size of a setup file changed in each version of DirectX SDK, from Summer 2004 until freshly released June 2010.

**DirectX SDK Size History @ Google docs**

It's not suprising that generally the size is growing, from about 150 MB in 2005 until 571 MB in the most recent version. And it's just the size of the setup file. After installation, my DXSDK_Jun2010 directory has 1.22 GB. Here is more detailed analysis of what exactly takes some much space, done with great and free program called WinDirStat. As you can see, Samples subdirectory is the biggest part of it.

# Effects in DirectX 11

13:18

Sat

15

May 2010

I no longer believe Microsoft did a good job complicating new DirectX so much. Effects framework - the API that supported loading and using effect files that grouped HLSL code and render states into passes and techniques - is no longer intrinsic part of D3DX. Instead they provided source code for this library so you have to compile it by yourself!

To do this: Enter your DX SDK subdirectory "Samples\C++\Effects11", open a "Effects11_*.sln" solution file appropriate for your Visual C++ version and compile the project in both Debug and Release configuration.

Then to use effects API in your project you have to include this header: "YOUR_DX_SDK_PATH\Samples\C++\Effects11\Inc\D3dx11effect.h" and link with this lib: "YOUR_DX_SDK_PATH\Samples\C++\Effects11\Debug\D3DX11EffectsD.lib (Debug) or "YOUR_DX_SDK_PATH\Samples\C++\Effects11\Release\D3DX11Effects.lib" (Release), as well as with "d3dcompiler.lib" (in both configurations).

Here is example of how to load an effect from file. You need to first compile a source code from file or memory into a blob binary effect and then create real effect object from this blob.

// Compile effect from HLSL file into binary Blob in memory ID3D10Blob *effectBlob = 0, *errorsBlob = 0; HRESULT hr = D3DX11CompileFromFile( "Effect1.fx", 0, 0, 0, "fx_5_0", 0, 0, 0, &effectBlob, &errorsBlob, 0); assert(SUCCEEDED(hr) && effectBlob); if (errorsBlob) errorsBlob->Release();

// Create D3DX11 effect from compiled binary memory block ID3DX11Effect *g_Effect; hr = D3DX11CreateEffectFromMemory( effectBlob->GetBufferPointer(), effectBlob->GetBufferSize(), 0, g_Dev, &g_Effect); assert(SUCCEEDED(hr)); effectBlob->Release();

The effect itself is not enough. You need to retrieve object that represents "pass" to use it. So you get a technique from the effect (by index or by name) and then the pass from the technique.

ID3DX11EffectTechnique *g_EffectTechnique; // No need to be Release()-d. g_EffectTechnique = g_Effect->GetTechniqueByIndex(0); assert(g_EffectTechnique && g_EffectTechnique->IsValid()); ID3DX11EffectPass *g_EffectPass; // No need to be Release()-d. g_EffectPass = g_EffectTechnique->GetPassByIndex(0); assert(g_EffectPass && g_EffectPass->IsValid());

Now when you have this object, you can apply settings from this pass to the device context during rendering:

g_EffectPass->Apply(0, g_Ctx); g_Ctx->Draw(3, 0);

But still one problem reamins. In DirectX 11 you need to pass a pointer to the bytecode with compiled shader when creating input layout - a step that you probably cannot omit. Fortunately there is a way to access this pointer stored inside loaded effect. You just need to pass through two descriptors, just like this:

D3DX11_PASS_SHADER_DESC effectVsDesc; g_EffectPass->GetVertexShaderDesc(&effectVsDesc); D3DX11_EFFECT_SHADER_DESC effectVsDesc2; effectVsDesc.pShaderVariable->GetShaderDesc(effectVsDesc.ShaderIndex, &effectVsDesc2); const void *vsCodePtr = effectVsDesc2.pBytecode; unsigned vsCodeLen = effectVsDesc2.BytecodeLength; ID3D11InputLayout *g_InputLayout; D3D11_INPUT_ELEMENT_DESC inputDesc[] = { /* ... */ }; hr = g_Dev->CreateInputLayout( inputDesc, _countof(inputDesc), vsCodePtr, vsCodeLen, &g_InputLayout);

Luckily it looks like the effect framework doesn't add much functionality over pure HLSL shader supported by D3D11 itself, so you don't have to use it. Defining these techniques and passess is not so important after all...