All Blog Entries

All blog entries, ordered from most recent. Entry count: 1198.

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

Pages: > 1 ... 45 46 47 48 49 ... 150 >

# 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:

Comments | #directx Share

# 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:

 

 

 

Comments | #directx #medicine #rendering Share

# PolyJam - Global Game Jam 2011 in Warsaw

Tue
18
Jan 2011

Global Game Jam is a worldwide initiative to organize a 48-hour game development competition in many different locations, at the same time. For more information, read the extensive GGJ Wiki. This year it takes place on January 28-30. In Poland there are even 3 registered places. KrakJam takes place at AGH University in Kraków. It is organized second time, by Koshmaar and the "Shader" scientific group.

For the first time the competition will also be held in Warsaw. It's called PolyJam and it's organized by "Polygon" scientific group at Warsaw University of Technology. Here is the list of PolyJam jammers. I invite everyone who is interested in game development (not only programming, but also graphics, sound, game design and other disciplines) to register.

I'm going to participate, yet I'm not quite sure how the atmosphere of such event looks like. What's the best approach to creating games at such competitions? Is it making a simple 2D game from scratch using some simple C++ framework, using some middleware like Unity, or maybe developing a web game in JavaScript of Flash?

Comments | #competitions #events #ggj Share

# New jEdit Launcher - How to Install

Mon
17
Jan 2011

Writing programs in some managed technologies like Java or .NET instead of native C/C++ has many disadvantages. First and the most obvious one is smaller efficiency and greater memory consumption. That's why, for example, I prefer uTorrent over Azureus as BitTorrent client. Second flaw is harder access to native system API. That's why my friend Przemek created libraries for accessing new Windows 7 taskbar features from Java, Python and Qt code and sells them as his startup Strix Code.

Finally it's sometimes harder to integrate such programs with system shell. With .NET it's not the case because it creates EXE files so they can work as normal programs and even system services (I'm not sure about shell extensions and device drivers). With Java it's more difficult because there program is a JAR file. As jEdit is still my favourite text editor (second after Visual C++ of course), I was looking for a way to integrate it with Windows so it was my default editor for TXT and other text files. Recently I've found New jEdit Launcher - a package that serves this purpose very well, but unfortunately it's quite hard to setup. So in case you also use jEdit and look for a way to do it, here are the steps, checked under Windows XP as well as 7:

  1. Unpack New jEdit Launcher to some directory. Windows 7 causes lots of problems with Program Files so I prefer some other places, let's say "h:\Program_Files\New jEdit Launcher".
  2. Run command prompt ("cmd.exe"). On Windows 7 you must do it as Administrator, so open Start menu, type "cmd", right-click on the black "cmd.exe" icon and select "Run as administrator".
  3. From the command prompt, enter the "bin" subdirectory of New jEdit Launcher like this:
    > h:
    > cd "\Program_Files\New jEdit Launcher\bin"
  4. Call the magic command to register DLL file:
    > regsvr32 jeditext.dll
  5. Now launch registery editor through Start > Run > "regedit" and create entries as decribed in "New jEdit Launcher\README.html" documentation in "Installing" section.
  6. Second bunch of required registry entries (described in "Configuration" section) can be entered more conveniently, through "New jEdit Launcher\config\launcher.reg" file. Open this file in some text editor (Notepad or... jEdit :) and fix the paths to your Java JRE and jEdit directories. Enter path to "javaw.exe" not "java.exe" as the "Java Executable", because you don't want system console to be shown along with jEdit window. Values "jEdit Target" and "jEdit Working Directory" must point to the place where you have jEdit installed. Don't forget that all backslashes in these paths must be doubled, like "h:\\Program_Files\\jEdit 4.3.2\jedit.jar"!!!
  7. Now run this "launcher.reg" file through double-clicking on it. After confirming the warning/question, the registry entries should be created.
  8. Check if it works by running "New jEdit Launcher\bin\jedit.exe" file. jEdit should be started if it wasn't already running.
  9. You can create a shortcut to this "jedit.exe" file in your Start menu. This way you have a shortcut to jEdit with pretty icon instead of default Java one, as when linking directly to the "jedit.jar" file.
  10. Associate TXT and possibly other file types (extensions) with this "jedit.exe" program. It's done differently in Windows XP and 7 but generally you can find the appropriate configuration window it in the Control Panel. This way all text files will be opened by jEdit and they also (unfortunately) get jEdit icon.

Comments | #windows Share

# Origami - Super Spike Ball

Sat
08
Jan 2011

As the Spike Ball Heaven website shows, an origami module with four tabs and four pockets invented by Rona Gurkewitz and Bennett Arnstein can be assembled into three sizes of spike balls - Spike Ball (from 12 pieces), Super Spike Ball (from 24 pieces) and Super Duper Spike Ball (from 54 pieces). Recently I've made the Super Spike Ball - it's the one on left left. I don't plan to try the third size anytime soon :)

Comments | #origami Share

# Process Class Deadlocks on Long Lines when Redirecting Output

Fri
07
Jan 2011

To run a console process programatically from your program and capture its output is very difficult to do right. There are so many possible problems! Not only you have to pass correct command line parameters and escape them if they contain special characters like space, care about working directory and maybe even environmental variables. You must also handle different possible behavior of the program. For example, it can freeze indefinitely, so you better do some timeout when waiting for it to exit. It may ask for additional console input and wait for it. It may print some information on both of its outputs - "standard output" and "standard error". They are all asynchronous and you better capture these data because if a buffer fills up, the program will hang waiting until you consume this output to allow it to post more. You also have to read these buffers to the end after program exited because there may still be some bytes remaining.

I do it in C# and I was hoping I already did it all right... Until today. I wanted to run "mysqldump" and capture its output to store a MySQL database table in memory and then import it on another machine. But when exporting a table with large binary data in its BLOB fields, my program hung. My code was like this:

using System.Text;
using System.Diagnostics;
using System.Threading;

class ConsoleCommand
{
  public void Execute(string fileName, string arguments, int timeout, string standardInputData)
  {
    using (Process process = new Process())
    {
      process.StartInfo.FileName = fileName;
      process.StartInfo.Arguments = arguments;
      process.StartInfo.RedirectStandardInput = true;
      process.StartInfo.RedirectStandardOutput = true;
      process.StartInfo.RedirectStandardError = true;
      process.StartInfo.UseShellExecute = false;
      process.StartInfo.CreateNoWindow = true;
      process.OutputDataReceived += new DataReceivedEventHandler(StandardOutputHandler);
      process.ErrorDataReceived += new DataReceivedEventHandler(StandardErrorHandler);
      process.Start();
 
      process.BeginOutputReadLine();
      process.BeginErrorReadLine();
 
      if (standardInputData != null)
      {
        process.StandardInput.Write(standardInputData);
        process.StandardInput.Close();
      }
 
      if (!process.WaitForExit(timeout))
        throw new Exception("Process execution timeout.");
      m_StandardOutputEvent.WaitOne();
      m_StandardErrorEvent.WaitOne();
 
      m_ExitCode = process.ExitCode;
    }
  }

  public int ExitCode { get { return m_ExitCode; } }
  public string StandardOutputData { get { return m_StandardOutputData.ToString(); } }
  public string StandardErrorData { get { return m_StandardErrorData.ToString(); } }

  private void StandardOutputHandler(object process, DataReceivedEventArgs e)
  {
    if (e.Data == null)
      m_StandardOutputEvent.Set();
    else
      m_StandardOutputData.AppendLine(e.Data);
  }

  private void StandardErrorHandler(object process, DataReceivedEventArgs e)
  {
    if (e.Data == null)
      m_StandardErrorEvent.Set();
    else
      m_StandardErrorData.AppendLine(e.Data);
  }

  private int m_ExitCode;
  private StringBuilder m_StandardOutputData = new StringBuilder();
  private StringBuilder m_StandardErrorData = new StringBuilder();
  private ManualResetEvent m_StandardOutputEvent = new ManualResetEvent(false);
  private ManualResetEvent m_StandardErrorEvent = new ManualResetEvent(false);
}

I couldn't find any solution on the Internet. That's why I write about it here - maybe some day someone (you?) who has same problem finds this article on Google. I know it must have something in common with binary data on the output, so I coded a small program that printed all possible ASCII characters. It worked. So there was not the problem with characters codes, but with the length of the data. The delegate associated with OutputDataReceived and ErrorDataReceived is designed to handle text lines. I suppose there is an internal buffer somewhere inside .NET that splits the text into lines. If there is a lot of data (more than 1 MB) in a single line (binary data without end-of-line character), the buffer fills up, neither OutputDataReceived delegate is called, nor the console program is able to print more output and everything just deadlocks :(

The only solution I know at the moment is not to use these OutputDataReceived and ErrorDataReceived events, but to poll for output data synchronously like this:

class ConsoleCommand
{
  public void Execute(string fileName, string arguments, int timeout, string standardInputData)
  {
    using (Process process = new Process())
    {
      process.StartInfo.FileName = fileName;
      process.StartInfo.Arguments = arguments;
      process.StartInfo.RedirectStandardInput = true;
      process.StartInfo.RedirectStandardOutput = true;
      process.StartInfo.RedirectStandardError = true;
      process.StartInfo.UseShellExecute = false;
      process.StartInfo.CreateNoWindow = true;
      process.Start();

      if (standardInputData != null)
      {
        process.StandardInput.Write(standardInputData);
        process.StandardInput.Close();
      }

      DateTime end_time = DateTime.Now + TimeSpan.FromMilliseconds((double)timeout);
      bool process_exit = false, output_end = false, error_end = false;
      for (;;)
      {
        if (!output_end)
        {
          if (process.StandardOutput.EndOfStream)
            output_end = true;
          else
            m_StandardOutputData.Append(process.StandardOutput.ReadToEnd());
        }

        if (!error_end)
        {
          if (process.StandardError.EndOfStream)
            error_end = true;
          else
            m_StandardErrorData.Append(process.StandardError.ReadToEnd());
        }

        if (!process_exit)
          process_exit = process.WaitForExit(0);

        if (DateTime.Now > end_time)
        {
          process.Close();
          throw new Exception("Process execution timeout.");
        }

        if (process_exit && output_end && error_end)
          break;

        System.Threading.Thread.Yield();
      }

      m_ExitCode = process.ExitCode;
    }
  }

  public int ExitCode { get { return m_ExitCode; } }
  public string StandardOutputData { get { return m_StandardOutputData.ToString(); } }
  public string StandardErrorData { get { return m_StandardErrorData.ToString(); } }

  private int m_ExitCode;
  private StringBuilder m_StandardOutputData = new StringBuilder();
  private StringBuilder m_StandardErrorData = new StringBuilder();
}

Comments | #.net Share

Pages: > 1 ... 45 46 47 48 49 ... 150 >

[Download] [Dropbox] [pub] [Mirror] [Privacy policy]
Copyright © 2004-2026