[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1173
  • Last Modified:

Implementing a fly-through function

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
alexhenryjames
Asked:
alexhenryjames
  • 10
  • 7
2 Solutions
 
ikeworkCommented:
Hey alexhenryjames,

easiest would be moving the camera-position for starters.

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


ike
0
 
alexhenryjamesAuthor Commented:
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
 
ikeworkCommented:
Thats the code to setup the viewport/projection. Can you show your render-function?
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
alexhenryjamesAuthor Commented:
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
 
ikeworkCommented:
That is On (left) Mouse Move as you say, I mean the function that renders your ogjects each frame.
0
 
alexhenryjamesAuthor Commented:
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
 
ikeworkCommented:
Ok I see, can you post the function that calls this Draw function?
0
 
ikeworkCommented:
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
 
alexhenryjamesAuthor Commented:

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
 
ikeworkCommented:
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
    
}

Open in new window

0
 
ikeworkCommented:
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
 
alexhenryjamesAuthor Commented:
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
 
ikeworkCommented:
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
 
ikeworkCommented:
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
 
alexhenryjamesAuthor Commented:
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
 
ikeworkCommented:
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
 
alexhenryjamesAuthor Commented:
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

Prep for the ITIL® Foundation Certification Exam

December’s Course of the Month is now available! Enroll to learn ITIL® Foundation best practices for delivering IT services effectively and efficiently.

  • 10
  • 7
Tackle projects and never again get stuck behind a technical roadblock.
Join Now