Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
Solved

Implementing a fly-through function

Posted on 2011-02-16
Medium Priority
1,170 Views
Last Modified: 2013-12-26
I am interested in implemeting a fly-through function for a 3D image within OpenGL for use within C#.

From MATLAB:

"
A fly-through is an effect created by moving the camera through three-dimensional space, giving the impression that you are flying along with the camera as if in an aircraft. You can fly through regions of a scene that might be otherwise obscured by objects in the scene or you can fly by a scene by keeping the camera focused on a particular point.

To accomplish these effects, move a camera along a particular path, the x-axis for example, in a series of steps. To produce a fly-through, move both the camera position and the camera target at the same time.
"

Assuming that I have a representation of an object as a set of (x, y, z) coordinates, the ability to fully rotate this object along each axis (I am using a standard TrackBall algorithm for this), what extra computations do I need to achieve a fly-though?

Initially I thought a combination of zoom and rotation would function, however a similar function within Adobe changes the camera AND the target properties simultaneously. Zoom and rotation only alters the camera parameters (x, y, z). If I could work out the relationship between the camera and the target, and map onto some OpenGL functions, that would be a starting point I think.

References:

http://www.mathworks.com/help/techdoc/visualize/f4-45695.html

http://acrobatusers.com/auc/content/tutorials/id_2100/nov2009_3dmodel.pdf
0
Question by:alexhenryjames
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

• Help others & share knowledge
• Earn cash & points
• Learn & ask questions
• 10
• 7
17 Comments

LVL 20

Expert Comment

ID: 34907278
Hey alexhenryjames,

easiest would be moving the camera-position for starters.

Can you show what functions you use to setup your camera?

ike
0

Author Comment

ID: 34907443
Hi,.

The code I am experimenting with comes from this example (MFC / OpenGL):

http://www.cse.ohio-state.edu/~crawfis/Graphics/VirtualTrackball.html. It contains the OpenGL routines I am using, in that example rotating a shape with a virtual trackball.

I think the functions you refer to are in the OnSize event within SierpinskiSolidsView.cpp:

//
// Determine the new aspect ratio
//
GLdouble gldAspect = (GLdouble) cx/ (GLdouble) cy;
//
// Reset the projection matrix with the new aspect ratio.
//
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(40.0, gldAspect, 1.001, 60.0);
glTranslatef( 0.0, 0.0, -25.0 );
//
// Set the viewport to take up the entire window.
//
glViewport(0, 0, cx, cy);
windowSize.x = cx;
windowSize.y = cy;
0

LVL 20

Expert Comment

ID: 34908173
Thats the code to setup the viewport/projection. Can you show your render-function?
0

Author Comment

ID: 34908526
Hello,

On (left) Mouse Move, we have:

<...>

curPoint = trackBallMapping( point );  // Map the mouse position to a logical sphere location.
direction = curPoint - lastPoint;
float velocity = direction.Length();
if( velocity > 0.0001 )
{
//
// Rotate about the axis that is perpendicular to the great circle connecting the mouse movements.
//
Vec3f rotAxis;
rotAxis.crossProd( lastPoint, curPoint );
rot_angle = velocity * m_ROTSCALE;
//
// We need to apply the rotation as the last transformation.
//   1. Get the current matrix and save it.
//   2. Set the matrix to the identity matrix (clear it).
//   3. Apply the trackball rotation.
//   4. Pre-multiply it by the saved matrix.
//
glGetFloatv( GL_MODELVIEW_MATRIX, (GLfloat *) objectXform );
glLoadIdentity();
glRotatef( rot_angle, rotAxis.x, rotAxis.y, rotAxis.z );
glMultMatrixf( (GLfloat *) objectXform );
//
//  If we want to see it, we need to force the system to redraw the scene.
//
Invalidate( TRUE );
}
break;

<...>

SierpinskiSolidsView.cpp
0

LVL 20

Expert Comment

ID: 34908596
That is On (left) Mouse Move as you say, I mean the function that renders your ogjects each frame.
0

Author Comment

ID: 34908694
My apologies,

In the example, the rendering is a combination of cubes and tetrahedrons:

TETRAHEDRON:

void Tetrahedron::DrawFaces(const float rotAngle )
{
Vec3f centroid;
centroid = Pts[0];
centroid += Pts[1];
centroid += Pts[2];
centroid += Pts[3];
centroid *= 0.25;
glPushMatrix();
glTranslatef( centroid.x, centroid.y, centroid.z );
glRotatef( rotAngle, 0.5, 1.0, 1.0 );
glTranslatef( -centroid.x, -centroid.y, -centroid.z );

Vec3f crossVec;
glBegin( GL_TRIANGLES );
//glColor3f( 1.0, 1.0, 1.0 );
crossVec.crossProd( Pts[0], Pts[2], Pts[1] );
glNormal3f( crossVec.x, crossVec.y, crossVec.z );
glVertex3f( Pts[0].x, Pts[0].y, Pts[0].z );
glVertex3f( Pts[2].x, Pts[2].y, Pts[2].z );
glVertex3f( Pts[1].x, Pts[1].y, Pts[1].z );

//glColor3f( 0.0, 0.0, 1.0 );
crossVec.crossProd( Pts[0], Pts[1], Pts[3] );
glNormal3f( crossVec.x, crossVec.y, crossVec.z );
glVertex3f( Pts[0].x, Pts[0].y, Pts[0].z );
glVertex3f( Pts[1].x, Pts[1].y, Pts[1].z );
glVertex3f( Pts[3].x, Pts[3].y, Pts[3].z );

//glColor3f( 1.0, 1.0, 0.0 );
crossVec.crossProd( Pts[1], Pts[2], Pts[3] );
glNormal3f( crossVec.x, crossVec.y, crossVec.z );
glVertex3f( Pts[1].x, Pts[1].y, Pts[1].z );
glVertex3f( Pts[2].x, Pts[2].y, Pts[2].z );
glVertex3f( Pts[3].x, Pts[3].y, Pts[3].z );

//glColor3f( 0.0, 1.0, 1.0 );
crossVec.crossProd( Pts[2], Pts[0], Pts[3] );
glNormal3f( crossVec.x, crossVec.y, crossVec.z );
glVertex3f( Pts[2].x, Pts[2].y, Pts[2].z );
glVertex3f( Pts[0].x, Pts[0].y, Pts[0].z );
glVertex3f( Pts[3].x, Pts[3].y, Pts[3].z );

glEnd();

glPopMatrix();

}
0

LVL 20

Expert Comment

ID: 34909219
Ok I see, can you post the function that calls this Draw function?
0

LVL 20

Expert Comment

ID: 34909422
I dont use MFC, but if I remember correctly, there was a "WM_PAINT" message, can you search for that message in your project and post the function which is called there?
0

Author Comment

ID: 34911580

Hello, draw functions below

/////////////////////////////////////////////////////////////////////////////
// CSierpinskiSolidsView drawing

void CSierpinskiSolidsView::OnDraw(CDC* pDC)
{
CSierpinskiSolidsDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);

// Make the HGLRC current.
BOOL bResult = wglMakeCurrent (pDC->m_hDC, m_hrc);
if (!bResult)
{
TRACE("wglMakeCurrent Failed %x\r\n", GetLastError() ) ;
}

//
// Draw the scene
//
glMatrixMode( GL_MODELVIEW );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

MAX_Level = pDoc->Recursion_Level;

if( Shadows )
{
//
//  Initialize the random number generator to get consistent results
//    for each frame or each pass thru with multi-pass techniques.
//
srand( 0 );
//
//  Draw the scene flattened onto the ground plane.
//
DrawShadows( pDoc );
}

//
//  Initialize the random number generator to get consistent results
//    for each frame or each pass thru with multi-pass techniques.
//
srand( 0 );

if( pDoc->Draw_Tetra )
SierpinskiGen( pDoc->BaseTetra, 0 );

if( pDoc->Draw_Sponge )
SierpinskiGenCube( pDoc->BaseCube, 0 );

glFinish();

// Swap buffers.
SwapBuffers(pDC->m_hDC) ;

//
// If we are in a self-animated mode, update the animation parameters
//    and force a redraw.
//
if( Spin )
{
rotAngle += 2.0;
Invalidate( TRUE );
}

}

void CSierpinskiSolidsView::DrawShadows( CSierpinskiSolidsDoc* pDoc )
{
//
// Set-up the transformation matrix to flatten the scene onto the ground plane.
////////////  Note, this does not work yet. ////////////////
//

glFrontFace( GL_CW );
glPushMatrix();
glScalef( 1, 1, -0.99 );
glTranslatef( 0, 0, 2.4 );

if( pDoc->Draw_Tetra )
SierpinskiGen( pDoc->BaseTetra, 0 );

if( pDoc->Draw_Sponge )
SierpinskiGenCube( pDoc->BaseCube, 0 );

glPopMatrix();
glFrontFace( GL_CCW );
//
// Draw the ground plane
//
glDisable( GL_LIGHTING );
glDisable( GL_DEPTH_TEST );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glColor4f( 0.7, 0.7, 0.7, 0.8 );
glBegin( GL_QUADS );
glVertex3f( -4.0, -4.0, -1.2 );
glVertex3f(  4.0, -4.0, -1.2 );
glVertex3f(  4.0,  4.0, -1.2 );
glVertex3f( -4.0,  4.0, -1.2 );
glEnd();
glEnable( GL_LIGHTING );
glEnable( GL_DEPTH_TEST );
glDisable( GL_BLEND );

}

void CSierpinskiSolidsView::SierpinskiGen(Tetrahedron &tetra, int level)
{
//
// If we reached the maximum recursion level,
//    stop and draw the tetrahedron.
// If animation is turned on, the rotAngle will force the
//   tetrahedron to spin.
//
if( level > MAX_Level )
tetra.DrawFaces( rotAngle*level );
//
// Otherwise, split the tetrahedron into 5 smaller tetrahedra,
//    Drawing the 4 that are on the corners.
// Logically, we split each edge into two.
// Build the tetra connecting each original vertex with the
// midpoints of the edges it shares.
//
else
{
Tetrahedron subtetra;
//
// Tetrahedron at the first vertex.
//
subtetra.Pts[0] = tetra.Pts[0];
subtetra.Pts[1] = tetra.mid[0];
subtetra.Pts[2] = tetra.mid[4];
subtetra.Pts[3] = tetra.mid[3];
//
// The Tetrahedron class contains information on the
//    edge midpoints. Bad programming here, in that this
//    class implicitly knows the ordering of the edges.
//   ------- Fix later --------
//         Add a method to Tetrahedron that subdivides itself
//           and passes back the resulting five tetrahedra.
//
subtetra.CalcMidpts();
//
// Recursively subdivide each tetra.
// Increment the level by one to note we are
//   one level further in the recursion that our
//   parent.
// Some permutation (acceleration) on the level is
//   added to force some nodes to terminate earlier
//   than others.
//
SierpinskiGen( subtetra, (level+1) );

glColor3f( 1.0, 1.0, 0.0 );
//
// Tetrahedron at the second vertex.
//
subtetra.Pts[0] = tetra.Pts[1];
subtetra.Pts[1] = tetra.mid[1];
subtetra.Pts[2] = tetra.mid[0];
subtetra.Pts[3] = tetra.mid[5];
subtetra.CalcMidpts();
SierpinskiGen( subtetra, (level+2) );

glColor3f( 0.0, 1.0, 1.0 );
//
// Tetrahedron at the third vertex.
//
subtetra.Pts[0] = tetra.Pts[2];
subtetra.Pts[1] = tetra.mid[4];
subtetra.Pts[2] = tetra.mid[1];
subtetra.Pts[3] = tetra.mid[2];
subtetra.CalcMidpts();
SierpinskiGen( subtetra, (level+3) );

glColor3f( 1.0, 0.0, 1.0 );
//
// Tetrahedron at the fourth vertex.
//
subtetra.Pts[3] = tetra.Pts[3];
subtetra.Pts[0] = tetra.mid[3];
subtetra.Pts[1] = tetra.mid[5];
subtetra.Pts[2] = tetra.mid[2];
subtetra.CalcMidpts();
SierpinskiGen( subtetra, (level+1) );

}
}
0

LVL 20

Accepted Solution

ikework earned 1200 total points
ID: 34914894
Ok, I downloaded the same project from http://www.cse.ohio-state.edu/~crawfis/Graphics/VirtualTrackball.html

All you have to do is add

1) add a glTranslatef with a modulated z-values to move into the scene, look for "// 1 new code" in the code snippet

2) make sure the application redraws the scene all the time by adding an Invalidate to the end of OnDraw, look for "// 2 new code" in the code snippet

thats it :)
``````void CSierpinskiSolidsView::OnDraw(CDC* pDC)
{
CSierpinskiSolidsDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);

// Make the HGLRC current.
BOOL bResult = wglMakeCurrent (pDC->m_hDC, m_hrc);
if (!bResult)
{
TRACE("wglMakeCurrent Failed %x\r\n", GetLastError() ) ;
}

//
// Draw the scene
//
glMatrixMode( GL_MODELVIEW );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

// 1 new code begins here
glLoadIdentity();
static float z = 10.0f;
glTranslatef(0.0f, 0.0f, z);
z += 0.1;
if(z > 25.0f) z = 10.0f;
// 1 new code ends here

MAX_Level = pDoc->Recursion_Level;

....

if( Spin )
{
rotAngle += 2.0;
Invalidate( TRUE );
}
// 2 new code begin
else
{
Invalidate( TRUE );
}
// 2 new code end

}
``````
0

LVL 20

Expert Comment

ID: 34914972
Check out this tutorial, it explains much better how to move through a 3D world and the concept of moving the world/camera:

http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=10

Have fun :)
0

Author Comment

ID: 34915509
Thanks very much; one last question, how would I integrate my mouse movement function in which I compute the desired angle of rotation and trackball projected coordinates, and then render the model, with the above, which appears to override it?
0

LVL 20

Assisted Solution

ikework earned 1200 total points
ID: 34915620
The mousefunctions shouldnt change the GL-matrices directly, they should only store the values needed to make those matrix manipulations (i.e. rot_angle and rot_axis)  in the OnDraw function.
0

LVL 20

Expert Comment

ID: 34915673
Other than that I would throw this sample program away and start over with a new clean little app, since this demo does some weird things, which make understanding an OpenGL app even harder.

If you want to learn OpenGL its better to start basic, glut and the red book are perfect for that.

The Red Book is online here:

http://www.opengl.org/documentation/red_book/
0

Author Comment

ID: 34915676
So to finish off, I should be able to rotate, zoom and perform glTranslatef on moving all of the code to the OnDraw, and maintan (x, y, z) values in between OnDraws to enable the 'camera fly' function.
0

LVL 20

Expert Comment

ID: 34915712
Yes you can, its not gonna be easy to change this demo, its not made with that in mind, so as I said, given that you are still learning OpenGL, I would not change this project, it is too hard for an unexperienced OpenGL programmer.

But certainly it can be changed in that manner, yes. Its just not what I would recommend ;)
0

Author Comment

ID: 34915735
Thanks again, I am a GUI developer (no OpenGL experience but will probably pick up a book now (F.S. Hill)) and we have a 3D developer to implement; I am just using this example to aid specification. Thanks also for the tutorial link.
0

Featured Post

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Recently, in one of the tech-blogs I usually read, I saw a post about the best-selling video games through history. The first place in the list is for the classic, extremely addictive Tetris. Well, a long time ago, in a galaxy far far away, I wasâ€¦
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
Want to learn how to record your desktop screen without having to use an outside camera. Click on this video and learn how to use the cool google extension called "Screencastify"! Step 1: Open a new google tab Step 2: Go to the left hand upper cornâ€¦
Please read the paragraph below before following the instructions in the video â€” there are important caveats in the paragraph that I did not mention in the video. If your PaperPort 12 or PaperPort 14 is failing to start, or crashing, or hanging, â€¦
Suggested Courses
Course of the Month9 days, 20 hours left to enroll

610 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.