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

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.

# Flat Shading in DirectX 11

Fri

02

Nov 2012

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 | #rendering #directx Share

# Direct3D 11 Checklist

Mon

23

Jul 2012

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.

- Vertex Buffers:

ctx->IASetVertexBuffers(index, ...); - Index Buffer:

ctx->IASetIndexBuffer(...); - Primitive Topology:

ctx->IASetPrimitiveTopology(...); - Input Layout:

ctx->IASetInputLayout(...); - Shaders:

ctx->VSSetShader(...);

ctx->HSSetShader(...);

ctx->DSSetShader(...);

ctx->GSSetShader(...);

ctx->PSSetShader(...); - Resources for shaders:
- Sampler States:

ctx->XSSetSamplers(index, ...); - Textures:

ctx->XSSetShaderResources(index, ...); - Constant Buffers:

ctx->XSSetConstantBuffers(index, ...);

- Sampler States:
- Rasterizer State:

ctx->RSSetState(...); - Depth-Stencil State:

ctx->OMSetDepthStencilState(...); - Blend State:

ctx->OMSetBlendState(...);

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.

# Direct2D versus Direct3D

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

# DirectXMath - A First Look

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

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

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

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

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

Copyright © 2004-2020