Cinder + threaded OpenNI Skeletontracking

Here is some stuff I’ve put together that does Skeletontracking via OpenNI on a separate thread in cinder.
This is based on some code that was posted by Sector9 on the cinder forums, and which is based on the example code that comes with the Nite module.

For some reason my skeleton is offset by some seemingly random number. I’m not sure what’s causing that if someone could take a look

In order to get this to work, you’ll need to get OpenNI working on it’s own first.
I recommend following these steps,

PostADay-Round2#4 – Cinder Kinect OpenNI – Playing and seeking a .oni file

I’ve been using the Kinect for the past two weeks. It’s an amazing device, very fun to code for.
To be honest, the Kinect really provides a webcam image, and a depth map… That’s really all it adds to the mix. While that’s a lot – people (by that i mean gadget blogs, non-coder blogs) seem to think that you can just plug this thing and you will get instant Minority Report.

That’s not how it works, in fact the REAL magic of the kinect is the OpenNI drivers provided by Primesense. Primesense are the people who created the technology which microsoft has licensed. Their OpenNI drivers provide the amazing skeleton tracking / user tracking / hand tracking / gesture tracking stuff that people associate with the Kinect.

When trying to create something using the Kinect it can be somewhat annoying having to get up, calibrate it with the proper use, and then start moving around to test a variable you changed. For that reason, the OpenNI library provides a way to record, and also create files which it calls “.oni”

The easiest way to create your own .oni file, is to record one with the NIViewer sample project. However just as useful if that’s too annoying, is the skeleton.oni file provided by primesense.

These files can actually then be played by the the library, and you can even seek within them to skip around to the interesting parts you want to test.

Here’s how to play back a .oni file, it’s actually very simple. This file makes some assumptions but i’ll explain those later.

void CinderRibbons::setupWithOniFile( std::string filepath ) {
  nRetVal = skeleton->mContext.OpenFileRecording( filepath.c_str() );
		// File opened
		CHECK_RC(nRetVal, "Open File Recording", true);
		// Get recording 'player'
		nRetVal = skeleton->mContext.FindExistingNode(XN_NODE_TYPE_PLAYER, skeleton->mPlayer);
		CHECK_RC(nRetVal, "Find player generator", true);
void CinderRibbons::seekToFrame( XnUInt32 seekPosition )
	CinderOpenNISkeleton *skeleton = CINDERSKELETON;
	XnStatus nRetVal = XN_STATUS_OK;
    // Make sure we're ready
	if(!openNIThread || !skeleton->mDepthGenerator)
	const XnChar*	nodeName		= skeleton->mDepthGenerator.GetName();
	XnUInt32		currentFrame	= 0;
	XnUInt32		totalFames		= 0;
	nRetVal = skeleton->mPlayer.TellFrame(nodeName, currentFrame);
	CHECK_RC(nRetVal, "Getting CURRENT frame", false);
	nRetVal = skeleton->mPlayer.GetNumFrames(nodeName, totalFames);
	CHECK_RC(nRetVal, "Getting TOTAL frames", false);
	// Stop the thread before trying to seek
    // We'll be offset currentFrame and passing this value to the seek funciton which takes a relative position
    XnUInt32        seekAbsolutePos = -currentFrame + seekPosition;
    // Seek
	nRetVal = skeleton->mPlayer.SeekToFrame(nodeName, seekAbsolutePosition, XN_PLAYER_SEEK_CUR);
	CHECK_RC(nRetVal, "Seeking to frame", false);
	// Update the data now that we're at the new position
	skeleton->mDepthGenerator.GetMetaData( skeleton->mDepthMD );
	skeleton->mUserGenerator.GetUserPixels(0, skeleton->mSceneMD);
	// Restart the thread...
	// Thread count stays the same - but there is a race condition on a nanoscale
	// Had some problems, will have to look into later - for now we're creating a new thread.
	openNIThread = new OpenNIThreadRunner();
	// Output debug
	app::console() << "Seeked to frame" << currentFrame+seekPosition << std::endl;

PostADay-Round2#3 – Wheres that file!?

Here’s a small tip I started using. When coding in C++ it can be tricky to figure out where a file is, relative to the application so there is an urge to simply load the file using an absolute path. It’s really a problem later on if you use a second computer, or time passes or you’re working on this project within a team.

Probably there’s a better trick, but what I do is load the program, pause it, then use the xcode console window (cmd+r) and type, ‘pwd’ and ‘cd’ right in there then browse to the by pressing file – since it starts off in the application you know if you can get to it then you can load it correctly.

PostADay-Round2#3 – List of xcode / GCC preprocessor macros

Here is a list of preprocessor defined macros when compiling in Xcode.
Xcode defines a few other macros as well, if anyone knows how to get those to output please share!

So useful!

terminal:$ gcc -dM -E - < /dev/null
#define __DBL_MIN_EXP__ (-1021)
#define __FLT_MIN__ 1.17549435e-38F
#define __DEC64_DEN__ 0.000000000000001E-383DD
#define __CHAR_BIT__ 8
#define __WCHAR_MAX__ 2147483647
#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
#define __FLT_EVAL_METHOD__ 0
#define __DBL_MIN_10_EXP__ (-307)
#define __FINITE_MATH_ONLY__ 0
#define __DEC64_MAX_EXP__ 384
#define __SHRT_MAX__ 32767
#define __LDBL_MAX__ 1.18973149535723176502e+4932L
#define __APPLE_CC__ 5664
#define __UINTMAX_TYPE__ long unsigned int
#define __DEC32_EPSILON__ 1E-6DF
#define __block __attribute__((__blocks__(byref)))
#define __SCHAR_MAX__ 127
#define __USER_LABEL_PREFIX__ _
#define __STDC_HOSTED__ 1
#define __DEC64_MIN_EXP__ (-383)
#define __DBL_DIG__ 15
#define __FLT_EPSILON__ 1.19209290e-7F
#define __LDBL_MIN__ 3.36210314311209350626e-4932L
#define __DEC32_MAX__ 9.999999E96DF
#define __strong
#define __APPLE__ 1
#define __DECIMAL_DIG__ 21
#define __LDBL_HAS_QUIET_NAN__ 1
#define __DYNAMIC__ 1
#define __GNUC__ 4
#define __MMX__ 1
#define __FLT_HAS_DENORM__ 1
#define __DBL_MAX__ 1.7976931348623157e+308
#define __DBL_HAS_INFINITY__ 1
#define __DEC32_MIN_EXP__ (-95)
#define __LDBL_HAS_DENORM__ 1
#define __DEC32_MIN__ 1E-95DF
#define __weak __attribute__((objc_gc(weak)))
#define __DBL_MAX_EXP__ 1024
#define __DEC128_EPSILON__ 1E-33DL
#define __SSE2_MATH__ 1
#define __amd64 1
#define __tune_core2__ 1
#define __LONG_LONG_MAX__ 9223372036854775807LL
#define __GXX_ABI_VERSION 1002
#define __FLT_MIN_EXP__ (-125)
#define __x86_64 1
#define __DBL_MIN__ 2.2250738585072014e-308
#define __LP64__ 1
#define __DBL_HAS_QUIET_NAN__ 1
#define __DEC128_MIN__ 1E-6143DL
#define __DBL_HAS_DENORM__ 1
#define __NO_INLINE__ 1
#define __DEC_EVAL_METHOD__ 2
#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL
#define __FLT_MANT_DIG__ 24
#define __VERSION__ "4.2.1 (Apple Inc. build 5664)"
#define __DEC64_EPSILON__ 1E-15DD
#define __DEC128_MIN_EXP__ (-6143)
#define __SIZE_TYPE__ long unsigned int
#define __DEC32_DEN__ 0.000001E-95DF
#define __FLT_RADIX__ 2
#define __LDBL_EPSILON__ 1.08420217248550443401e-19L
#define __SSE_MATH__ 1
#define __k8 1
#define __LDBL_DIG__ 18
#define __x86_64__ 1
#define __FLT_HAS_QUIET_NAN__ 1
#define __FLT_MAX_10_EXP__ 38
#define __LONG_MAX__ 9223372036854775807L
#define __FLT_HAS_INFINITY__ 1
#define __DEC64_MAX__ 9.999999999999999E384DD
#define __DEC64_MANT_DIG__ 16
#define __DEC32_MAX_EXP__ 96
#define __DEC128_DEN__ 0.000000000000000000000000000000001E-6143DL
#define __LITTLE_ENDIAN__ 1
#define __LDBL_MANT_DIG__ 64
#define __DEC32_MANT_DIG__ 7
#define __k8__ 1
#define __WCHAR_TYPE__ int
#define __pic__ 2
#define __FLT_DIG__ 6
#define __INT_MAX__ 2147483647
#define __FLT_MAX_EXP__ 128
#define __BLOCKS__ 1
#define __DBL_MANT_DIG__ 53
#define __DEC64_MIN__ 1E-383DD
#define __WINT_TYPE__ int
#define __SSE__ 1
#define __LDBL_MIN_EXP__ (-16381)
#define __MACH__ 1
#define __amd64__ 1
#define __LDBL_MAX_EXP__ 16384
#define __SSP__ 1
#define __LDBL_MAX_10_EXP__ 4932
#define __DBL_EPSILON__ 2.2204460492503131e-16
#define _LP64 1
#define __GNUC_PATCHLEVEL__ 1
#define __LDBL_HAS_INFINITY__ 1
#define __INTMAX_MAX__ 9223372036854775807L
#define __FLT_DENORM_MIN__ 1.40129846e-45F
#define __PIC__ 2
#define __FLT_MAX__ 3.40282347e+38F
#define __SSE2__ 1
#define __FLT_MIN_10_EXP__ (-37)
#define __INTMAX_TYPE__ long int
#define __DEC128_MAX_EXP__ 6144
#define __GNUC_MINOR__ 2
#define __DBL_MAX_10_EXP__ 308
#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L
#define __STDC__ 1
#define __PTRDIFF_TYPE__ long int
#define __DEC128_MANT_DIG__ 34
#define __LDBL_MIN_10_EXP__ (-4931)
#define __GNUC_GNU_INLINE__ 1
#define __SSE3__ 1

PostADay-Round2#2 – Cinder/C++ Boid class port

It’s weird porting something that was written into, c++ ported to AS3, back to C++. However If you’ve ever tried to find the C++ version of a boids class. They’re all too complicated for my needs, and i really like the way @soulwire ‘s version works so I started porting it into C++. Based largely on my iOS port of the same class.



BoidTrailTest from mario gonzalez on Vimeo.

Basic Usage



float boidMaxSpeed = 100;
float boidMaxForce = 25;
// Create
_boid = new Boid( boidMaxSpeed, boidMaxForce );
_boid-&gt;setPosition( _target.x, _target.y, _target.z );
// Set wander properties
_boid-&gt;setWanderRadius( 75.0f );
_boid-&gt;setWanderMaxTurningSpeed( M_PI / 32 ); // 
_boid-&gt;setWanderLookAheadDistance( 300 );


_boid->wander( 0.3f );
_boid->seek( _mousePositionXYZ, 0.8f );

PostADay-Round2#1 – Calculating surface normals in C++

Given a quad, this is how you can calculate the normals for each face.
This works for triangles, as well as quad.

Loop through each face, and pass in 3 verticies. If you have a quad ABCD pass in ABD. For example for the front facing face on this cube, I would pass in, v2, v3, v0

// cube ///////////////////////////////////////////////////////////////////////
//    v6----- v5
//   /|      /|
//  v1------v0|
//  | |     | |
//  | |v7---|-|v4
//  |/      |/
//  v2------v3

This is in C++ which supports operator overloading, so keep that in mind, when you see p2-p1, its doing: (p2.x-p1.x; p2.y-p1.y; p2.z-p1.z; )

Vec3f RibbonMesh::calcNormal( const Vec3f &p1, const Vec3f &p2, const Vec3f &p3 )
    Vec3f V1= (p2 - p1);
    Vec3f V2 = (p3 - p1);
    Vec3f surfaceNormal;
    surfaceNormal.x = (V1.y*V2.z) - (V1.z-V2.y);
    surfaceNormal.y = - ( (V2.z * V1.x) - (V2.x * V1.z) );
    surfaceNormal.z = (V1.x-V2.y) - (V1.y-V2.x);
    // Dont forget to normalize if needed
    return surfaceNormal;

PostADay – Round2

I think i’m going to start writing one post per day, it was pretty fun experience last time, although i only made it about 2 weeks in.
This time I’m going to simply aim for 1 post per day, for 1 week.

As a programmer, I feel that I’m learning stuff everyday. If it wasn’t, then i wouldn’t be coding!
So it should be fairly easy to share one of those things each day.

Let’s see how i do