m_elias's picture

Struggling to Understand GL.Translate & GL.Rotate

I have been reading through a couple OpenGL books and experimenting with OpenTK. According to what I read, OpenTK seems to implement the Translate and Rotate commands differently, almost backwards to what I expect. I have very little experience so I don't doubt that my understanding is just wrong but maybe someone can help me get the ol' Solar sample program transcribed for OpenTK. I have been trying to do it myself with cubes instead of spheres. Here is the source, I'm not concerned about the keyboard inputs. I am actually using a glControl in my C# forms project but any way you do it, I need to see how these examples look in OpenTK.

/*
 * Solar.c
 *
 * Program to demonstrate how to use a local
 * coordinate method to position parts of a 
 * model in relation to other model parts.
 *
 * Draws a simple solar system, with a sun, planet and moon.
 * Based on sample code from the OpenGL programming guide
 *		by Woo, Neider, Davis.  Addison-Wesley.
 *
 * Author: Samuel R. Buss
 *
 * Software accompanying the book
 *		3D Computer Graphics: A Mathematical Introduction with OpenGL,
 *		by S. Buss, Cambridge University Press, 2003.
 *
 * Software is "as-is" and carries no warranty.  It may be used without
 *   restriction, but if you modify it, please change the filenames to
 *   prevent confusion between different versions.
 * Bug reports: Sam Buss, sbuss@ucsd.edu.
 * Web page: http://math.ucsd.edu/~sbuss/MathCG
 *
 * USAGE:
 *    Press "r" key to toggle (off and on) running the animation
 *    Press "s" key to single-step animation
 *    The up arrow key and down array key control the
 *			time step used in the animation rate.  Each key
 *			press multiplies or divides the times by a factor 
 *			of two (2).
 *	  Press ESCAPE to exit.
 *
 */
 
 
#include "Solar.h"   
#include <stdlib.h> 
 
#include <GL/glut.h>	// OpenGL Graphics Utility Library
 
static GLenum spinMode = GL_TRUE;
static GLenum singleStep = GL_FALSE;
 
// These three variables control the animation's state and speed.
static float HourOfDay = 0.0;
static float DayOfYear = 0.0;
static float AnimateIncrement = 24.0;  // Time step for animation (hours)
 
// glutKeyboardFunc is called below to set this function to handle
//		all normal key presses.  
static void KeyPressFunc( unsigned char Key, int x, int y )
{
	switch ( Key ) {
	case 'R':
	case 'r':
		Key_r();
		break;
	case 's':
	case 'S':
		Key_s();
		break;
	case 27:	// Escape key
		exit(1);
	}
}
 
// glutSpecialFunc is called below to set this function to handle
//		all special key presses.  See glut.h for the names of
//		special keys.
static void SpecialKeyFunc( int Key, int x, int y )
{
	switch ( Key ) {
	case GLUT_KEY_UP:		
		Key_up();
		break;
	case GLUT_KEY_DOWN:
		Key_down();
		break;
	}
}
 
 
static void Key_r(void)
{
	if ( singleStep ) {			// If ending single step mode
		singleStep = GL_FALSE;
		spinMode = GL_TRUE;		// Restart animation
	}
	else {
		spinMode = !spinMode;	// Toggle animation on and off.
	}
}
 
static void Key_s(void)
{
	singleStep = GL_TRUE;
	spinMode = GL_TRUE;
}
 
static void Key_up(void)
{
    AnimateIncrement *= 2.0;			// Double the animation time step
}
 
static void Key_down(void)
{
    AnimateIncrement /= 2.0;			// Halve the animation time step
 
}
 
/*
 * Animate() handles the animation and the redrawing of the
 *		graphics window contents.
 */
static void Animate(void)
{
	// Clear the redering window
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    if (spinMode) {
		// Update the animation state
        HourOfDay += AnimateIncrement;
        DayOfYear += AnimateIncrement/24.0;
 
        HourOfDay = HourOfDay - ((int)(HourOfDay/24))*24;
        DayOfYear = DayOfYear - ((int)(DayOfYear/365))*365;
		}
 
	// Clear the current matrix (Modelview)
    glLoadIdentity();
 
	// Back off eight units to be able to view from the origin.
    glTranslatef ( 0.0, 0.0, -8.0 );
 
	// Rotate the plane of the elliptic
	// (rotate the model's plane about the x axis by fifteen degrees)
	glRotatef( 15.0, 1.0, 0.0, 0.0 );
 
    // Draw the sun	-- as a yellow, wireframe sphere
	glColor3f( 1.0, 1.0, 0.0 );			
    glutWireSphere( 1.0, 15, 15 );
 
    // Draw the Earth
	// First position it around the sun
	//		Use DayOfYear to determine its position
    glRotatef( 360.0*DayOfYear/365.0, 0.0, 1.0, 0.0 );
    glTranslatef( 4.0, 0.0, 0.0 );
    glPushMatrix();						// Save matrix state
	// Second, rotate the earth on its axis.
	//		Use HourOfDay to determine its rotation.
	glRotatef( 360.0*HourOfDay/24.0, 0.0, 1.0, 0.0 );
	// Third, draw the earth as a wireframe sphere.
    glColor3f( 0.2, 0.2, 1.0 );
    glutWireSphere( 0.4, 10, 10);
    glPopMatrix();						// Restore matrix state
 
	// Draw the moon.
	//	Use DayOfYear to control its rotation around the earth
   	glRotatef( 360.0*12.0*DayOfYear/365.0, 0.0, 1.0, 0.0 );
    glTranslatef( 0.7, 0.0, 0.0 );
    glColor3f( 0.3, 0.7, 0.3 );
    glutWireSphere( 0.1, 5, 5 );
 
	// Flush the pipeline, and swap the buffers
    glFlush();
    glutSwapBuffers();
 
	if ( singleStep ) {
		spinMode = GL_FALSE;
	}
 
	glutPostRedisplay();		// Request a re-draw for animation purposes
 
}
 
// Initialize OpenGL's rendering modes
void OpenGLInit(void)
{
    glShadeModel( GL_FLAT );
    glClearColor( 0.0, 0.0, 0.0, 0.0 );
    glClearDepth( 1.0 );
    glEnable( GL_DEPTH_TEST );
}
 
// ResizeWindow is called when the window is resized
static void ResizeWindow(int w, int h)
{
    float aspectRatio;
	h = (h == 0) ? 1 : h;
	w = (w == 0) ? 1 : w;
	glViewport( 0, 0, w, h );	// View port uses whole window
	aspectRatio = (float)w/(float)h;
 
	// Set up the projection view matrix (not very well!)
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    gluPerspective( 60.0, aspectRatio, 1.0, 30.0 );
 
	// Select the Modelview matrix
    glMatrixMode( GL_MODELVIEW );
}
 
 
// Main routine
// Set up OpenGL, hook up callbacks, and start the main loop
int main( int argc, char** argv )
{
	// Need to double buffer for animation
	glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
 
	// Create and position the graphics window
    glutInitWindowPosition( 0, 0 );
    glutInitWindowSize( 600, 360 );
    glutCreateWindow( "Solar System Demo" );
 
	// Initialize OpenGL.
    OpenGLInit();
 
	// Set up callback functions for key presses
	glutKeyboardFunc( KeyPressFunc );
	glutSpecialFunc( SpecialKeyFunc );
 
	// Set up the callback function for resizing windows
    glutReshapeFunc( ResizeWindow );
 
	// Callback for graphics image redrawing
    glutDisplayFunc( Animate );
 
	// Start the main loop.  glutMainLoop never returns.
	glutMainLoop(  );
 
    return(0);			// Compiler requires this to be here. (Never reached)
}

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
wolfsnipes's picture

The rendering stuff translates pretty much straight from C to C#. If this is your first OpenTK project you might want to build a basic camera and practice just viewing basic things before anything else. If not, ignore me :-)

I'm not sure if you are asking for explanation in general of OpenGL translate and rotate, or 'if OpenTK does it differently', which I don't believe it does. You might want to take a look at the official OpenGl programming guide chapter 3 here, which also has the solar system sample, but breaks down the components and describes the opengl state machine in more detail especially as pertains to model transformations. It's pretty standard that "translating then rotating is different than rotating then translating." The chapter does cover this with good examples.

Also, this earlier post might help with additional understanding: http://www.opentk.com/node/1178

Since you asked, assuming you've defined q1 q2 and q3 (will be used as spheres later on) somewhere else, here's my super quick version of the relevant code, where you would put around the end of a rendering function. I pretty much just copied and pasted into an existing project from the sample C code and renamed functions where necessary and it works fine.

IntPtr q1 = OpenTK.Graphics.Glu.NewQuadric();
IntPtr q2 = OpenTK.Graphics.Glu.NewQuadric();
IntPtr q3 = OpenTK.Graphics.Glu.NewQuadric();

 GL.Color3(Color.Yellow);
 GL.Begin(BeginMode.Quads);
 
 GL.PushMatrix();
//Draw the sun
OpenTK.Graphics.Glu.Sphere(q1, 10, 10, 10);
 
// Draw the Earth
GL.Rotate(360.0 * DayOfYear / 365.0, 0, 1.0, 0.0);
GL.Translate(40.0, 0.0, 0.0);
GL.PushMatrix();
GL.Rotate(360.0 * HourOfDay / 24.0, 0.0, 1.0, 0.0);
GL.Color3(0.2, 0.2, 1.0);
OpenTK.Graphics.Glu.Sphere(q2, 2, 10, 10);
 
GL.PopMatrix();
// Draw the moon.
// Use DayOfYear to control its rotation around the earth
GL.Rotate(360.0 * 12.0 * DayOfYear / 365.0, 0.0, 1.0, 0.0);
GL.Translate(7.0, 0.0, 0.0);
GL.Color3(0.3, 0.7, 0.3);
 
OpenTK.Graphics.Glu.Sphere(q3, 1, 10, 10);
 
GL.End();
 
 SwapBuffers();

Hope this helps,

m_elias's picture

As expected I have a lot to learn yet. My biggest frustration is translating the glut opengl tutorials to opentk. For example, when I searched for "opentk sphere", I got hits for some of the forum posts here that created a custom function for it (which I couldn't figure out), so I didn't know that OpenTK.Graphics.Glu.Sphere existed. I think my biggest issue is understanding the Modelview, Projection, Perspective and Viewport matrices and implementation. There are other seasonal work projects coming up so I think I will put this one on the back burner and hopefully when I pick it back up it all makes more sense. What I am working towards is plotting a coverage map with GPS coordinates. Something like the screen shots at these links. Thanks for taking the time to post your response.