Jump to content

  • Log In with Google      Sign In   
  • Create Account

Awesome job so far everyone! Please give us your feedback on how our article efforts are going. We still need more finished articles for our May contest theme: Remake the Classics

clb

Member Since 22 May 2004
Offline Last Active Today, 12:57 PM
***--

#5024654 Standard expansion of DXTn colors?

Posted by clb on 23 January 2013 - 03:46 AM

The way how K bits wide fixed-bit-width channels with unsigned integer values [0, 2^K-1] (UNORM types) are interpreted is standard: The unsigned number k in the range [0, 2^K-1] represents the rational number k / 2^k-1.

 

This means that a 5-bit channel can represent the rationals 0/31, 1/31, 2/31, 3/31, ..., 30/31, 31/31 = 1. A 8-bit color channel can represent the rationals 0/255, 1/255, ..., 254/255, 255/255=1.

 

 

When encoding a rational represented as a floating point as an unsigned integer, we (usually) pick the integer that is nearest to the floating point number in question, since that minimizes the generated rounding error.

 

 

Converting the other way, from 5-bit integer to floating point, or 8-bit integer to floating point is lossless (but not necessarily exact), since floats have more precision. 

 

The method of "expanding bits" you specify is an optimization that does not have mathematical basis, and it introduces an error.

 

Here is a small code snippet that converts colors encoded as 5-bit UNORM to floating point and to their closest 8-bit representative, as well as directly 5-bit to 8-bit using the approximation you describe:

 

for(int c = 0; c <= 31; ++c)
{
double d = c / 31.0; // Convert 5-bit UNORM color to nearest double representation.
int u = d * 255.0; // Convert UNORM color as double to nearest 8-bit UNORM encoded representation.
int u2 = (c << 3) | (c >> 2); // Approximate conversion from 5-bit directly to 8-bit.
printf("5-bit:%3d as UNORM:%.05g Stored as 8-bit:%3d approx 5-bit->8-bit: %3d\n", c, d, u, u2);
}

 

The output for that is:

 

5-bit: 0 as UNORM:0 Stored as 8-bit: 0 approx 5-bit->8-bit: 0
5-bit: 1 as UNORM:0.032258 Stored as 8-bit: 8 approx 5-bit->8-bit: 8
5-bit: 2 as UNORM:0.064516 Stored as 8-bit: 16 approx 5-bit->8-bit: 16
5-bit: 3 as UNORM:0.096774 Stored as 8-bit: 24 approx 5-bit->8-bit: 24
5-bit: 4 as UNORM:0.12903 Stored as 8-bit: 32 approx 5-bit->8-bit: 33
5-bit: 5 as UNORM:0.16129 Stored as 8-bit: 41 approx 5-bit->8-bit: 41
5-bit: 6 as UNORM:0.19355 Stored as 8-bit: 49 approx 5-bit->8-bit: 49
5-bit: 7 as UNORM:0.22581 Stored as 8-bit: 57 approx 5-bit->8-bit: 57
5-bit: 8 as UNORM:0.25806 Stored as 8-bit: 65 approx 5-bit->8-bit: 66
5-bit: 9 as UNORM:0.29032 Stored as 8-bit: 74 approx 5-bit->8-bit: 74
5-bit: 10 as UNORM:0.32258 Stored as 8-bit: 82 approx 5-bit->8-bit: 82
5-bit: 11 as UNORM:0.35484 Stored as 8-bit: 90 approx 5-bit->8-bit: 90
5-bit: 12 as UNORM:0.3871 Stored as 8-bit: 98 approx 5-bit->8-bit: 99
5-bit: 13 as UNORM:0.41935 Stored as 8-bit:106 approx 5-bit->8-bit: 107
5-bit: 14 as UNORM:0.45161 Stored as 8-bit:115 approx 5-bit->8-bit: 115
5-bit: 15 as UNORM:0.48387 Stored as 8-bit:123 approx 5-bit->8-bit: 123
5-bit: 16 as UNORM:0.51613 Stored as 8-bit:131 approx 5-bit->8-bit: 132
5-bit: 17 as UNORM:0.54839 Stored as 8-bit:139 approx 5-bit->8-bit: 140
5-bit: 18 as UNORM:0.58065 Stored as 8-bit:148 approx 5-bit->8-bit: 148
5-bit: 19 as UNORM:0.6129 Stored as 8-bit:156 approx 5-bit->8-bit: 156
5-bit: 20 as UNORM:0.64516 Stored as 8-bit:164 approx 5-bit->8-bit: 165
5-bit: 21 as UNORM:0.67742 Stored as 8-bit:172 approx 5-bit->8-bit: 173
5-bit: 22 as UNORM:0.70968 Stored as 8-bit:180 approx 5-bit->8-bit: 181
5-bit: 23 as UNORM:0.74194 Stored as 8-bit:189 approx 5-bit->8-bit: 189
5-bit: 24 as UNORM:0.77419 Stored as 8-bit:197 approx 5-bit->8-bit: 198
5-bit: 25 as UNORM:0.80645 Stored as 8-bit:205 approx 5-bit->8-bit: 206
5-bit: 26 as UNORM:0.83871 Stored as 8-bit:213 approx 5-bit->8-bit: 214
5-bit: 27 as UNORM:0.87097 Stored as 8-bit:222 approx 5-bit->8-bit: 222
5-bit: 28 as UNORM:0.90323 Stored as 8-bit:230 approx 5-bit->8-bit: 231
5-bit: 29 as UNORM:0.93548 Stored as 8-bit:238 approx 5-bit->8-bit: 239
5-bit: 30 as UNORM:0.96774 Stored as 8-bit:246 approx 5-bit->8-bit: 247
5-bit: 31 as UNORM:1 Stored as 8-bit:255 approx 5-bit->8-bit: 255

 

I can't outright find a page from MSDN that describes this, but you can find the same interpretation from OpenGL specification pdfs where it is explained with formal rigor.




#5008557 Try Angelscript live!

Posted by clb on 08 December 2012 - 12:48 PM

Hi,

    here's something cool I wrote up this weekend. With your modern browser with WebGL enabled, visit this page: MathGeoLib live test site. It is a project consisting of a few parts:
  • Uses my native C++ graphics rendering engine gfxapi. Utilizes the emscripten compiler to deploy the application to HTML5.
  • Integrates Angelscript as the live scripting engine.
  • Uses my MathGeoLib library for scripting primitives and geometry manipulation.
  • Interop between C++ MathGeoLib classes and Angelscript is achieved using an automatic bindings generator based on juj/CodeStructure.
The application allows writing Angelscript live on a web page, and render stuff on the screen by using constructs from MathGeoLib and gfxapi. I really must congratulate Andreas Jönsson for the Angelscript project - it is a very fine piece of technology! I have previously written C++ - script bindings interop for MathGeoLib for QtScript and Javascript, and using Angelscript is the most mature, easist and convenient one of them to work with! I evaluated Python, Lua and Mono to replace my previous JavaScript-based scripting engines, but Angelscript is the king of the hill. The support for strong typing and ability to do value types with function and operator overloading is exactly what is needed for good interop and convenient games scripting, and something where the whole competition falls short :)


#5008441 C11 initializer lists not working in visual studio 2010/2012

Posted by clb on 08 December 2012 - 03:10 AM

Can one use the VC11 IDE with the GCC or other compilers?


See the vs-tool plugin in my signature if you want to try using MinGW or Clang from Visual Studio. There are also other plugins like that existing.  Note however that the plugin is very experimental at this stage, so it can/may require some hacking and tweaking activities. Here's an example of what it looks like in action: https://dl.dropbox.com/u/40949268/code/vs-mingw.png


#5008372 C11 initializer lists not working in visual studio 2010/2012

Posted by clb on 07 December 2012 - 10:55 PM

Neither the VC10 or VC11 compilers support initializer lists, see http://msdn.microsoft.com/en-us/library/vstudio/hh567368.aspx

Your choice is probably quite straightforward:
  - Rework the code not to use C++11 initializer lists, or
  - Switch to using another compiler that does support them.GCC has initializer lists since GCC 4.4: http://gcc.gnu.org/projects/cxx0x.html . Clang has support for initializer lists since Clang 3.1 http://clang.llvm.org/cxx_status.html . Intel C++ compiler advertizes partial support for initializer lists in 13.0 (I don't know what that means in practice): http://software.intel.com/en-us/articles/c0x-features-supported-by-intel-c-compiler .


#4998136 Moving a projectile from an angle.

Posted by clb on 06 November 2012 - 12:19 PM

The general update mechanism of a 2D point with constant velocity towards a given aimed angle looks something like
float newX = x + cos(angle) * velocity * deltaTime;
float newY = y + sin(angle) * velocity * deltaTime;
The angle is expressed in radians, velocity is the speed of the projectiles, and deltaTime is the amount of time that has passed since the last update.


#4996559 Sums of uniform randoms

Posted by clb on 02 November 2012 - 09:36 AM

If you only have an API that allows you to generate uniform bits (0 or 1), you can generate a random number in the range [0, N] in the following way:
int uniform(); // Returns 0 or 1 uniformly at random.

uint32_t RandomNumber(int N)
{
   uint32_t NPow2 = largest power-of-2-number smaller or equal to N.
   int i = 1;
   uint32_t result = 0;
   while(i <= NPow2)
   {
      if (uniform)
         result |= i;
      i <<= 1;
   }
   return (uint32_t)((uint64_t)result * (N+1) / (NPow2 << 1));
}

However, this is most likely not the route you want to go through, unless you somehow have a very special setup where your RNG can only supply individual random bits. That sounds rare, and instead most RNG sources are built-in to produce random integers in range [a,b] and random floats in the range [0,1] (which equals roughly 23 bits of randomness).


#4995363 which 3D engine is now available for Windows 8 Metro App?

Posted by clb on 30 October 2012 - 05:42 AM

The Unity 3D engine is advertising to have support for Windows 8 Store applications starting from Unity 4. Version 4 has not yet been released, but will apparently be out very soon.


#4990748 Link to a Game development themed math primer?

Posted by clb on 16 October 2012 - 09:10 AM

My favorite references and go-to for game maths are Christer Ericson, David Eberly, Eric Lengyel and Wolfgang Engel. Also see here. In particular, I've enjoyed Mathematics for 3D Game Programming and Computer Graphics by Eric Lengyel.


#4989027 AI for a simple shedding card game

Posted by clb on 11 October 2012 - 02:37 AM

Yeah, even with Monte Carlo, it's customary to maintain a game tree. Instead of exploring the tree fully like with traditional minimax, the tree is expanded only selectively to the areas based on the Monte Carlo simulation. When the tree search hits a leaf node (the moves after that node are not tracked by the tree), the game is continued with random play i.e. a random playout until the end is performed.


#4988730 AI for a simple shedding card game

Posted by clb on 10 October 2012 - 08:27 AM

Monte Carlo sounds an excellent approach here, but unlike in your pseudo, you need to be very smart about where you direct your playouts. Having a fixed "Do 10,000 times" loop in the code is very inefficient and wastes a lot of the playouts.

An important aspect of Monte Carlo is to construct/expand a game tree while the playouts are being played. You should never settle to just playing a fixed number of playouts at the root of the tree (or you can, but it won't be as effective). This is the machinery that causes the result to converge to the best play as you increase the number of playouts.

You'll also want to estimate the uncertainty of a certain branch. For a move M, if you play 1000 random samples and always lose, versus if you played 1000 random samples and win 50% of the time, you'll know statistically that you should probably invest more on the latter case, and never play the first move. This should guide the statistical playouts to balance the search towards uncertain branches. UCT tree search is one of the recent key advances in the field. This is also an interesting read, that gives some more references.


#4988680 Should you support Linux?

Posted by clb on 10 October 2012 - 05:42 AM

In my engine I support Win7, Win8RT, OSX, Android, iOS, Web (JS+WebGL), NaCl and NPAPI, but not linux. The reason is majorly because the number of distros is huge and after evaluating it, the build and packaging process is a pain. If you ask five different linux people what the most important distro to support is, you'll get at least five different answers. Depending on distro * distro version * kernel version * GPU card vendor combination, the support for OpenGL driver varies wildly. The system testing complexity is up the roof compared to any other platform. And most importantly, since the market segment is smaller compared to Windows and OSX and there are no good marketing channels, I can't see the point in it. If you're already a linux whiz that knows the different distros and kernels and drivers in and out, perhaps you'll be able to pull off decent support for all the combinations with a bearable/manageable pain, but for "normal" developers, I don't think it's at all worth it.

If some big player (Valve+Steam?) comes in and manages to unify the development pain (doubt it), then I'll definitely be reconsidering.


#4988080 Exiting a game by closing window.

Posted by clb on 08 October 2012 - 01:32 PM

If this is C++, you never explicitly call destructors of objects, unless you have allocated them using placement new (which I doubt in this case).

While the OS will clean up all dynamically allocated memory, it is a *very* good idea to free up all resources by calling delete for each object you new, delete[] for each array you new[], free() for everything you malloc() and so on. This is because (unless your program is very very simple) you don't know how many times different objects are allocated and removed, and you'll easily have a million memory leaks at runtime, and your app can run out of memory easily. Also, there are other types of resources that might not be automatically freed by the OS (sockets, file handles, temporary allocated disk space, pipes, mutexes, other Win32 API handles, etc.), or their release may be delayed (in particular, abandoned sockets will linger and go to unusable state for security reasons).

Some argue that calling exit(0) can be better instead of manually tearing down all application objects, but unless you're 500% sure that nothing described above applies in your case, I really really recommend avoiding it. Plus, not freeing up memory makes it impossible to debug whether you have memory leaks in the first place, e.g. you can't use the amazing VLD tool then.


#4988076 DirectX 11 States in HLSL or C++ D3DAPI?

Posted by clb on 08 October 2012 - 01:21 PM

Setting particular states is not interchangeable between HLSL and C++. This means that it's not possible to enable/disable/change e.g. culling mode or other in HLSL code, but the draw calls are rendered with whatever rasterizer state you have currently enabled when the draw call is submitted.

You should call CreateSamplerState and CreateBlendState only once for each state set you want to use at load time, and then for each frame, reuse the state objects you created.


#4986440 How to check for frame buffer support

Posted by clb on 03 October 2012 - 10:17 AM

If you are using OpenGL version 3.0 or newer, the presence of framebuffer objects (FBOs) is guaranteed. See core profile 3.0. In this case, you can just call all the functions related to FBOs (glBindRenderBuffer etc...) found in that spec. You do not need (and preferably should not) to query any extensions, what you find in that pdf are guaranteed to work.

If you are using an older OpenGL version than 3.0, you'll have to detect if there is some extension present on the system that enables similar functionality. One such extension is GL_EXT_framebuffer_object. If you detect that extension, you can call all the functions specified in that extension (glBindRenderBufferEXT etc...).

You'll find that the OpenGL 3.0 FBO docs and the GL_EXT_framebuffer_object docs are very similar (== most probably identical, except for function naming), and in fact the OpenGL 3.0 FBO feature is a result of the GL_EXT_framebuffer_object extension being "accepted" to the core.

This is very much how Khronos/OpenGL rolls. They play this game for all features in OpenGL, so it's a common OpenGL "programming pattern" to detect functionality first by checking the OpenGL version, and then by checking if one or more equivalent extensions exists. As a programmer, you'll need to be prepared to have codepaths for the "present in core" case as well as the case of each extension you want to support, in case there are functional differences.

As for how to do this check in Java/jMonkeyEngine3/lwjgl, I don't know. Try to find if there's a function for checking the OpenGL version and then if there's a function for checking for extensions.


#4986416 How much math do I need to use directx?

Posted by clb on 03 October 2012 - 09:21 AM

You don't necessarily need to know the implementation details or derivation of half of the formulas, but you will need to understand conceptually how to use the math libraries, and how to use them to compute the proper transforms.

If you do only 2D, the math involved is simpler, but not necessarily by much. It depends a lot on what you are doing.

Here are some links to test yourself:
- Do you think you can understand a math library like this and how to utilize it e.g. to specify object positions, move them around, rotate and scale them?
- Are you familiar with the Direct3D pipeline stages? A lot of the math you feed into the device revolves around that architecture.
- Does the chain of linear spaces "local -> world -> view -> clip -> screen" sound familiar, and can you understand the concepts related to this?

If you feel comfortable with these, you'll be pretty well set math-wise on developing your own 3D engine. Math-wise there's not much else than basic calculus and linear algebra involved.




PARTNERS