Anamorphic distortion of a tracked user.

Hey everyone!

Im doing a project where im tracking a users position (head tracking) through 360 degrees using a webcam array. I am currently obtaining the users real world XYZ co-ordinates and wish to apply these into an OpenGL program that will present the user with a view of a 3D object based on their current perspective.

The outcome I am aiming for is much like this video: http://vimeo.com/10776715

I have managed to create the tracking side of this up to the point where I have co-ordinates to be used. at this point now i am a little stuck as to how best to approach the rendering and display of the objects. I have just started trying to learn OpenGL (GLUT +GLTools) for C++ but there is soo much to it.

could anyone with experience help me figure out the steps involved in the way this is displayed?

i know it has something to do with perspective distortion (like those street chalk paintings) but have no contextual idea of how this is done within OpenGL.

Hope someone can help me to realise this!

thanks
Khaled

Use this :
http://www.opengl.org/sdk/docs/man/xhtml/glFrustum.xml
This allow to perform “off-axis rendering”, search these terms.

EDIT: to hand-wave explain how it can be used in your case:

  • consider the screen on which the 3d is displayed as an infinite plane, P
  • the view center C will in fact be the point of P which is nearest to the user eyes
  • then the real screen will be a window (top-bottom-left-right of glFrustum), with coordinates relative to this center C

For the exact math, read the glFrustum documentation

I’m a bit uncertain as to what you mean.

my understanding from this is there is an infinite plane which the objects are placed onto. The centre of this plane should be the closest point of the physical monitor based on the captured XYZ co-ordinates of the user. then from this co ordinate use glfrustum to determine the viewable area?

here is an illustration of my understanding of what you said:

Also would i be using orthographic or perspective projection?

I’m self learning OpenGL. A lot is still not making a whole lot of sense to me but i am determined to nail it.

thanks for the help so far :slight_smile:

-Khaled

Not really, the infinite plane is just the projection plane. Objects can be anywhere in 3D. And point C can also be out of the physical screen, if user is “very aside” from the screen.

look at this : stereo off-axis

now imagine the eye separation is larger than screen width …
going for mighty ascii art … viewed from above, always a right angle between user-C line and P plane, V is the vision cone (in fact some distorted pyramid) going from user eye to the 4 edges of screen :



 +_._. . . . . . . . + C point
user \_____        |_. right angle
   \__     \____     .
      \__       \____.
         \_   V      + left frustum edge
           \__       | 
              \__    | physical screen
                 \__ |
                    \+ right frustum edge
                     .
                     .
                     .
                  infinite plane P


So with regards to the glFrustum function:


void glFrustum(	GLdouble  	left,
 	        GLdouble  	right,
 	        GLdouble  	bottom,
 	        GLdouble  	top,
 	        GLdouble  	nearVal,
 	        GLdouble  	farVal);

Left, right, bottom and top are XYZ co-ordinates that should be set once to coincide with the outer edge of the physical monitor?

and then near and far clipping planes determine what is in the viewing volume.

I think this might be a little too advanced for me currently, I might need to learn to walk before i can run.

I understand what needs to be done theoretically, but putting it into the context is proving a little more complex than i had first imagined.

-Khaled

Ive spent some time looking into this and the GlFrustum function, however i cant seem to find the place where to create/adjust this matrix to allow for the off-axis projection. Im trying to use a sample application to help for me to better understand how this all works but cant seem to find anything. I have been learning OpenGL through the superbible book but it doesnt seem to cover projection matrices in much detail.

Could anyone help to explain this in terms i might understand.

thanks

ok so after reading a few journals on off-axis projection it seems that i need to create an asymmetric viewing frustum. This is starting to make more practical sense to me however I think the confusion is coming due to me using GLEW and GLtools etc. Can anyone break down the methods to create an asymmetric viewing frustum.

thanks

double scale = horizontal distance between user and C point
double left = horizontal distance between C and left screen edge, positive if on the right, negative otherwise
double right = horizontal distance between C and right screen edge, positive if on the right, negative otherwise
double bottom, top = same idea, on vertical axis

then glFrustum(left/scale, right/scale, bottom/scale, top/scale, nearClip, farClip);

Done.

The code I wish to attempt to apply this to is below (taken from the superbible 5 sample code). I am truly struggling to apply this transformation. I (think) I understand the theory behind the application and know that this will also be required if I decide to create a stereoscopic version however I just cannot get my head around how or where to implement it. I’m almost ready to admit defeat with this one, however it is truly not an option for me.


// SphereWorld.cpp
// OpenGL SuperBible
// New and improved (performance) sphere world
// Program by Richard S. Wright Jr.

#include <GLTools.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>

#include <math.h>
#include <stdio.h>

#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif




GLShaderManager		shaderManager;			// Shader Manager
GLMatrixStack		modelViewMatrix;		// Modelview Matrix
GLMatrixStack		projectionMatrix;		// Projection Matrix
GLFrustum			viewFrustum;			// View Frustum
GLGeometryTransform	transformPipeline;		// Geometry Transform Pipeline

GLTriangleBatch		torusBatch;
GLBatch				floorBatch;

        
//////////////////////////////////////////////////////////////////
// This function does any needed initialization on the rendering
// context. 
void SetupRC()
    {
	// Initialze Shader Manager
	shaderManager.InitializeStockShaders();
	
	glEnable(GL_DEPTH_TEST);
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	
	// This makes a torus
	gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);
	
    	
	floorBatch.Begin(GL_LINES, 324);
    for(GLfloat x = -20.0; x <= 20.0f; x+= 0.5) {
        floorBatch.Vertex3f(x, -0.55f, 20.0f);
        floorBatch.Vertex3f(x, -0.55f, -20.0f);
        
        floorBatch.Vertex3f(20.0f, -0.55f, x);
        floorBatch.Vertex3f(-20.0f, -0.55f, x);
        }
    floorBatch.End();    
    }


///////////////////////////////////////////////////
// Screen changes size or is initialized
void ChangeSize(int nWidth, int nHeight)
    {
	glViewport(0, 0, nWidth, nHeight);
	
    // Create the projection matrix, and load it on the projection matrix stack
	viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);
	projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    // Set the transformation pipeline to use the two matrix stacks 
	transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    }

        
// Called to draw scene
void RenderScene(void)
	{
    // Color values
    static GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f};
    static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };

    // Time Based animation
	static CStopWatch	rotTimer;
	float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
	
	// Clear the color and depth buffers
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
    
    // Save the current modelview matrix (the identity matrix)
	modelViewMatrix.PushMatrix();	
		
	// Draw the ground
	shaderManager.UseStockShader(GLT_SHADER_FLAT,
								 transformPipeline.GetModelViewProjectionMatrix(),
								 vFloorColor);	
	floorBatch.Draw();

    // Draw the spinning Torus
    modelViewMatrix.Translate(0.0f, 0.0f, -2.5f);
    modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),
                                vTorusColor);
    torusBatch.Draw();

	// Restore the previous modelview matrix (the identity matrix)
	modelViewMatrix.PopMatrix();
        
    // Do the buffer Swap
    glutSwapBuffers();
        
    // Tell GLUT to do it again
    glutPostRedisplay();
    }


int main(int argc, char* argv[])
    {
	gltSetWorkingDirectory(argv[0]);
		
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800,600);
  
    glutCreateWindow("OpenGL SphereWorld");
 
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s
", glewGetErrorString(err));
        return 1;
        }
        

    SetupRC();
    glutMainLoop();    
    return 0;
    }

I hate being such a newbie at this but I really need the contextual explanation.

anyone able to help me with this??

I’m really struggling with this and time isnt on my side either, any help would really be great!

kinda would be nice to get a reply to this…

Anyone??

Just load a projection matrix initialized with the values defined in http://www.opengl.org/sdk/docs/man/xhtml/glFrustum.xml

Here in your code :

   // Create the projection matrix, and load it on the projection matrix stack
   M3DMatrix44f myOffAxisCustomMatrix;
   m3dLoadIdentity44(myOffAxisCustomMatrix);
   myOffAxisCustomMatrix[0]=(2.0 * nearVal ) / ( right - left );
   // etc for each matrix element that differ from identity
   // ...
   projectionMatrix.LoadMatrix(myOffAxisCustomMatrix);

It would be easier to help if you :

  1. at least showed your progress and efforts on this
  2. explained precisely what you have trouble with

Thanks for the help ZbuffeR,

Its a very confusing concept for me so i figured if i could see it working then it would help me to understand how to properly implement.

ive looked over what youve posted, and am starting to understand (i think) how this all works.

I know that the glFrustum defines the parameters of the clipping planes for the window. so

glFrustum(-100, 100, -100, 100, 1, 100)

Now i know that would define a 200x200 clipping area, this is then used to create a projection matrix which is used to multiply the current projection matrix. What i dont know is how to put this into the code terms. from what you have above…

myOffAxisCustomMatrix[0]=(2.0 * nearVal ) / ( right - left );

I would assume i could define the frustum in this line but im clueless as to how this all works.

Im struggling a little with being precise because precision generally requires understanding, something i currently am lacking :(.

thanks for the help so far

OK so i seem to be an absolute tool, or im missing something very vital with all of this. Ive read book after book and practically every article and journal i can find about projection matrices and off axis projection and asymmetric viewing frustum.

I am at a total loss with this. Could someone show some compassion and help me to break this all down.

i got sample code and application to help me to understand the frustum here:

http://www.songho.ca/opengl/gl_transform.html

I can see how the glfrustum works. but anytime i have a go implementing anything into my sample code i get a black screen or a black screen with a green line in.

I am in the beginners section and really want to break through and nail this.

Ok, I’ll give it a go.

First, put all your theories and assumptions aside for now. I think they’re tripping you up.

Now, let’s define a 90x90 degree “symmetric” perspective frustum so you can see what’s in front of the eyepoint, and you can verify that you’ve at least got a respectable viewing matrix active:

glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glFrustum( -1, 1, -1, 1, 1, 10000 );
glMatrixMode( GL_MODELVIEW );

And make sure you defined your viewing matrix (gluLookAt) to put the objects at least 1 unit or greater distance in front of the eyepoint (just because we defined our near clip 1 meter distant from the eye).

Now how do we know that’s a 90x90 degree symmetric frustum? Well, L=-R and B=-T, so it’s symmetric. And to the 90x90… Eyepoint is at 0,0,0 in EYE-SPACE. The last “1” says the plane of the screen (i.e. near clip plane) is 1 unit down the -Z axis in a plane perpendicular to this axis. And the first -1,1 pair says the screen is 2 units wide. Well, that forms a 45/45/90 triangle [ (0,0,0)-(1,0,-1),(-1,0,-1) ], with the 90 degrees at the eye. So, it is.

Can you see your objects in front of the eye? Anywhere within 90 degrees of straight forward and you will, as long as they’re between 1 and 10,000 units in front of the eye.

Now let’s skew this symmetric perspective frustum to an “assymetric” perspective frustum (i.e. off-axis perspective frustum) very slowly, gradually skewing it to look off to the left in eye-space. Iteratively try these instead:

glFrustum( -1.01, 0.99, -1, 1, 1, 1000000 );
glFrustum( -1.02, 0.98, -1, 1, 1, 1000000 );
glFrustum( -1.05, 0.95, -1, 1, 1, 1000000 );
glFrustum( -1.1, 0.9, -1, 1, 1, 1000000 );

Do you still see your objects? Congrats! You’re doing off-axis perspective and you can still see the scene. They should be gradually shifting right in the frustum, as your frustum skews off toward the left in eye-space.

Now are you gonna do this incremental stuff in your code? No, of course not. You’re going to define where in the real-world your “screen” is and compute viewing and frustum parameters to give you that slice into the world.