rendering does not change with [dynamic] transformations!

I have trouble transforming objects; I just started with OpenGL, but I am NOT at all new to programming and 3D concepts (I read some up to lesson7 in the OpenGL red book online…)… I am using jGL (a java binding; you can look it up on google), since java is easy to use (unlike C++, which is the most practical, but a horrible mess)…

My problem is that I have a few rotation variables; I do something like this in display():

glPushMatrix();
glRotate3f(x, 1.0, 0.0, 0.0);
glRotate3f(y, 0.0, 1.0, 0.0);
drawSomething();
glPopMatrix();

(the values of x and y change with key presses; I know the key presses are working)

…and yet, everything is ALWAYS drawn the same!!
(I created this “glAbtractModel” class where you can fill in the abstract “draw” method…); if you replace drawSomething() with someModel.draw(), it always draws the same! However, if I explicity put those rotation commands in draw() with specific values, its works; but as soon as I try to use variables, it doesn’t.

Also, even though display lists can change OpenGL state variables, it seems that they do NOT respond to them (that is, if you store the rendering process of something in a display list, it will NOT be affected by any transformations to the ModelView Matrix); I thought that display lists stored the rendering process of something, not a FIXED [2D image] to be written to the display and depth buffer (or whatever you call the buffer that stores pixels/colors).

You can see my glAbstractModel at:

Please help me, this is SO frustrating!

Hi !

Have you debugged the code and made sure that x and y actually change, for example you may have a local x and y variable that is used instead of the x and y member variables or something like that.

If you do a transformation before rendering a displaylist the contents of the displaylist will be transformed, if they don’t you are doing something wrong.

Mikael

Any LoadMatrices call in drawSomething()

… or even glLoadIndentity ?

Are you sure that glMatrixMode is GL_MODELVIEW?

Any glPopMatrix calls in that draw function?

BTW there’s no such thing as glRotate3f, just glRotated or glRotatef unless those java bindings mess with the name. You should check the wrappers if the function name actually says 3f because there are 4 float args there.

No, I’m sure; I tested everything!

X and Y change; I tried having them as global and as local;

Yes, I push the matrix, but THEN I do the transformation and draw, then I pop the matrix.

Okay, maybe it’s not glRotate3f(); I have only been using it for less than a week (but I am an experienced programmer, and have been messing with 3D graphics/modeling for a long time).

ANYWAYS, it’s nothing stupid; if you look at the code for planet.java (I use jGL, you can look it up), it makes the day/year variables STATIC, even though they should be local.

I have tried to add interactive transformations to some other things, but they don’t work unless you do not use variables (fixed transformations).

PLEASE just have a look at my code and see if you can get it (I do not know how to signify that the rest of this is my code, but I will guess):

glAbstractModel.java:

import jgl.GL;

public abstract class glAbstractModel {
	public GL myGL;
	public float[][] points;
	public float[] transform;
	public glAbstractModel[] parts;
	private boolean set;
	private int list;

	public glAbstractModel(GL gl, float[][] pts) {
		myGL = gl;
		points = pts;
		parts = new glAbstractModel[0];
		transform = new float[16];
		myGL.glPushMatrix();
			myGL.glLoadIdentity();
			myGL.glGetFloatv(myGL.GL_MODELVIEW_MATRIX, transform);
		myGL.glPopMatrix();
		set = false;
	}

	protected abstract void draw();

	public final void render() {
		myGL.glPushMatrix();
			myGL.glMultMatrixf(transform);
			draw();
			for(int i=0; i<parts.length; i++)
				parts[i].draw();
		myGL.glPopMatrix();
	}

	public final int getList() {
		if(set)
			return list;
		list = myGL.glGenLists(1);
		myGL.glNewList(list,myGL.GL_COMPILE);
		render();
		myGL.glEndList();
		set = true;
		return list;
	}

	public final void load() {
		myGL.glLoadMatrixf(transform);
	}

	public final void set() {
		myGL.glGetFloatv(myGL.GL_MODELVIEW_MATRIX, transform);
	}

	public final void setPart(int part, glAbstractModel model) {
		parts[part] = model;
	}

	public final void addPart(glAbstractModel part) {
		int size = parts.length;
		glAbstractModel[] prts = new glAbstractModel[size+1];
		for(int i=0; i<size; i++)
			prts[i] = parts[i];
		prts[size] = part;
		parts = prts;
	}

	public final void deletePart(int part) {
		int size = parts.length-1;
		glAbstractModel[] prts = new glAbstractModel[size];
		for(int i=0; i<part; i++)
			prts[i] = parts[i];
		for(int i=part; i<size; i++)
			prts[i] = parts[i+1];
		parts = prts;
	}

	public final glAbstractModel removePart(int part) {
		glAbstractModel removed = parts[part];
		deletePart(part);
		return removed;
	}
}

=============================
test.java (a test program):

import jgl.GL;
import jgl.GLCanvas;
import java.awt.Frame;

public class test extends GLCanvas {
	public glAbstractModel model;
	public int xAngle;
	public int yAngle;

	public void myinit() {
		xAngle = yAngle = 0;

		float[] mat_specular = {1.0f, 1.0f, 1.0f, 1.0f};
		float[] mat_shininess = {50.0f};
		float[] light_position = {1.0f, 1.0f, 1.0f, 0.0f};
	
		myGL.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		myGL.glShadeModel(GL.GL_SMOOTH);
	
		myGL.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, mat_specular);
		myGL.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, mat_shininess);
		myGL.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_position);
	
		myGL.glEnable(GL.GL_LIGHTING);
		myGL.glEnable(GL.GL_LIGHT0);
		myGL.glEnable(GL.GL_DEPTH_TEST);

		model = new glAbstractModel(
			myGL,
			new float[][] {
				{ 1.0f, 1.0f, 1.0f},{ 1.0f, 1.0f,-1.0f},
				{ 1.0f,-1.0f, 1.0f},{ 1.0f,-1.0f,-1.0f},
				{-1.0f, 1.0f, 1.0f},{-1.0f, 1.0f,-1.0f},
				{-1.0f,-1.0f, 1.0f},{-1.0f,-1.0f,-1.0f}
			}
		) {
			public void draw() {
				myGL.glBegin(myGL.GL_QUAD_STRIP);
					myGL.glNormal3fv(points[0]);
					myGL.glVertex3fv(points[0]);
					myGL.glNormal3fv(points[1]);
					myGL.glVertex3fv(points[1]);
					myGL.glNormal3fv(points[3]);
					myGL.glVertex3fv(points[3]);
					myGL.glNormal3fv(points[2]);
					myGL.glVertex3fv(points[2]);
					myGL.glNormal3fv(points[6]);
					myGL.glVertex3fv(points[6]);
					myGL.glNormal3fv(points[7]);
					myGL.glVertex3fv(points[7]);
					myGL.glNormal3fv(points[5]);
					myGL.glVertex3fv(points[5]);
					myGL.glNormal3fv(points[4]);
					myGL.glVertex3fv(points[4]);
					myGL.glNormal3fv(points[0]);
					myGL.glVertex3fv(points[0]);
					myGL.glNormal3fv(points[1]);
					myGL.glVertex3fv(points[1]);
				myGL.glEnd();
				myGL.glBegin(myGL.GL_QUADS);
					myGL.glNormal3fv(points[0]);
					myGL.glVertex3fv(points[0]);
					myGL.glNormal3fv(points[2]);
					myGL.glVertex3fv(points[2]);
					myGL.glNormal3fv(points[6]);
					myGL.glVertex3fv(points[6]);
					myGL.glNormal3fv(points[4]);
					myGL.glVertex3fv(points[4]);
					myGL.glNormal3fv(points[1]);
					myGL.glVertex3fv(points[1]);
					myGL.glNormal3fv(points[3]);
					myGL.glVertex3fv(points[3]);
					myGL.glNormal3fv(points[7]);
					myGL.glVertex3fv(points[7]);
					myGL.glNormal3fv(points[5]);
					myGL.glVertex3fv(points[5]);
				myGL.glEnd();
			}
		};
		myGL.glTranslatef(0.0f, 0.0f, 2.0f);
	}

	public void display() {
		myGL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
		myGL.glPushMatrix();
			myGL.glPushMatrix();
				myGL.glLoadIdentity();
				myGL.glRotatef((float)yAngle, 0.0f, 1.0f, 0.0f);
				myGL.glRotatef((float)xAngle, 1.0f, 0.0f, 0.0f);
				model.set();
			myGL.glPopMatrix();
			model.render();
		myGL.glPopMatrix();
		myGL.glFlush();
	}

    public void myReshape (int w, int h) {
        myGL.glViewport(0, 0, w, h);
        myGL.glMatrixMode(GL.GL_PROJECTION);
        myGL.glLoadIdentity();
		if (w <= h)
		    myGL.glOrtho(
		    	-5.0f, 5.0f,
		    	-5.0f *(float)h/(float)w,
				5.0f *(float)h/(float)w,
				-5.0f, 5.0f
			);
		else
		    myGL.glOrtho(
		    	-5.0f *(float)w/(float)h,
		    	5.0f *(float)w/(float)h,
				-5.0f, 5.0f,
				-5.0f, 5.0f
			);
        myGL.glMatrixMode(GL.GL_MODELVIEW);
        myGL.glLoadIdentity();
    }

	public void keyboard(char key, int x, int y) {
		switch (key) {
			case 'x': xAngle = (xAngle+2)%360; break;
			case 'X': xAngle = (xAngle-2)%360; break;
			case 'y': yAngle = (yAngle+2)%360; break;
			case 'Y': yAngle = (yAngle-2)%360; break;
	    	case 27: System.exit(0);
	    	default: break;
		}
	}

	public void init() {
		myUT.glutInitWindowSize(500,500);
		myUT.glutInitWindowPosition(0,0);
		myUT.glutCreateWindow(this);
		myinit();
		myUT.glutDisplayFunc("display");
		myUT.glutReshapeFunc("myReshape");
		myUT.glutKeyboardFunc("keyboard");
		myUT.glutMainLoop();
	}

	public static void main (String args[]) {
		Frame mainFrame = new Frame();
		mainFrame.setSize(508,527);
		test mainCanvas = new test();
		mainCanvas.init();
		mainFrame.add(mainCanvas);
		mainFrame.setVisible(true);
    }
}

Also, I used to have an array of transformation matrices for each part instead of one main one for the whole model because I know you can transform the whole model just by transforming the modelView matrix, but I was trying different things to make it work…I might change it back

I figured that a transformation matrix is better that rotate/translate[/scale] variables, because then you can only do what you want/ anything you need to.

Anyways, ignore the code in glAbtractModel and just assume that it works; it should still draw it differently if you do some transformations before calling model.render();

NEVERMIND! I figured it out, and it is so stupid.

All through the openGL programming guide so far (ch. 8) (correct me if I am wrong), it NEVER mentioned glutPostRedisplay(), and I must have overlooked it in the example programs; I just assumed that it automatically redisplayed everything (I would never usually asume stuff like that, but I overlooked it, and it just seemed to redisplay automatically)

ANYWAYS, here is the corrected code, which I think is very good (if know java, you could use this; it is a great setup for hierchial models with movable parts; subclass it to define one specific model (you can still create as many sperate instances as you want of such a defined model, each with its parts in their own place), or you can just create an instance of the class to quickly use and define one model) (I use jGL, which looks VERY similar to GL4JAVA; they seem to be the best; java is good to use OpenGL with because it is so easy and fast to use, and OpenGL is fast by itself anyways):

/* glAbstractModel.java
 * -created by Dan Cook
 *
 * Represents an OOP 3D model for use with jGL (a great java
 * binding for OpenGL). To use glAbstractModel, create a new
 * instance of it and fill in the draw() method with commands
 * to draw the object (these should be jGL commands so that a
 * call to getList() can store the whole drawing process into
 * a display list to improve efficiency when the object is
 * rendered). The other methods are all "final" because they
 * do not need to be modified/changed.
 *
 * Call render() to render the model with all of its [movable]
 * parts. Calling addPart() or setPart() add/set a part with
 * the current transformation of GL_MODELVIEW_MATRIX (to use a
 * default transformation, call glLoadIdentity() before you add
 * or modify a part; this is done automatically for parts that
 * are specified in the constructor).
 *
 * Points are included so that you can reference the same ones;
 * that does not make much difference, but it does same memory
 * in that you do not have to redeclare every point in the draw
 * method.
 *
 * Transformation matrices (array of 16 = 4x4 matrix) are used
 * to represent the transformation of each of the movable parts;
 * the reason that each glAbstractModel does not just have its
 * own transformation is because they are only needed for the
 * movable parts and NOT for the model itself (transformation of
 * the model can be done by transforming the model/view matrix,
 * or from a specified transformation because the model is part
 * of another model). "Nonmovable parts" should be drawn as part
 * of the model because there is no need for the extra recursion
 * and GL commands where they are not neccessary.
 */

import jgl.GL;

public abstract class glAbstractModel {
	public GL myGL;
	public float[][] points;
	public glAbstractModel[] parts;
	public float[][] transform;
	private boolean set;
	private int list;

	public glAbstractModel(GL gl, float[][] pts) {
		myGL = gl;
		points = pts;
		parts = new glAbstractModel[0];
		transform = new float[0][];
		set = false;
	}

	public glAbstractModel(GL gl, float[][] pts, glAbstractModel[] prts) {
		myGL = gl;
		points = pts;
		parts = prts;
		transform = new float[parts.length][];
		resetPart(0);
		for(int i=1; i<transform.length; i++)
			transform[i] = transform[0];
		set = false;
	}

	protected abstract void draw();

	public final void render() {
		draw();
		for(int i=0; i<parts.length; i++) {
			myGL.glPushMatrix();
				myGL.glMultMatrixf(transform[i]);
				parts[i].render();
			myGL.glPopMatrix();
		}
	}

	public boolean isList() {
		return set;
	}

	public final int getList() {
		if(set)
			return list;
		list = myGL.glGenLists(1);
		myGL.glNewList(list,myGL.GL_COMPILE);
			render();
		myGL.glEndList();
		set = true;
		return list;
	}

	public final void deleteList() {
		if(set) myGL.glDeleteLists(list,1);
		set = false;
	}

	public final void deleteLists() {
		deleteList();
		for(int i=0; i<parts.length; i++)
			parts[i].deleteLists();
	}

	public final void loadPart(int part) {
		myGL.glLoadMatrixf(transform[part]);
	}

	public final void setPart(int part) {
		myGL.glGetFloatv(myGL.GL_MODELVIEW_MATRIX, transform[part]);
	}

	public final void setPart(int part, glAbstractModel model) {
		parts[part] = model;
		setPart(part);
	}

	public final void resetPart(int part) {
		myGL.glPushMatrix();
			myGL.glLoadIdentity();
			myGL.glGetFloatv(myGL.GL_MODELVIEW_MATRIX, transform[part]);
		myGL.glPopMatrix();
	}

	public final void addPart(glAbstractModel part) {
		int size = parts.length;
		glAbstractModel[] prts = new glAbstractModel[size+1];
		float[][] trnsfrm = new float[size+1][];
		for(int i=0; i<size; i++) {
			prts[i] = parts[i];
			trnsfrm[i] = transform[i];
		}
		parts = prts;
		parts[size] = part;
		transform = trnsfrm;
		resetPart(size);
	}

	public final void deletePart(int part) {
		int size = parts.length-1;
		glAbstractModel[] prts = new glAbstractModel[size];
		float[][] trnsfrm = new float[size][];
		for(int i=0; i<part; i++) {
			prts[i] = parts[i];
			trnsfrm[i] = transform[i];
		}
		for(int i=part; i<size; i++) {
			prts[i] = parts[i+1];
			trnsfrm[i] = transform[i+1];
		}
		parts = prts;
		trnsfrm = transform;
	}

	public final glAbstractModel removePart(int part) {
		glAbstractModel removed = parts[part];
		deletePart(part);
		return removed;
	}
}
/* test.java
 *
 * a simple program to test
 * the glAbstractModel class
 */

import jgl.GL;
import jgl.GLCanvas;
import java.awt.Frame;

public class test extends GLCanvas {
	public glAbstractModel model;
	public int xAngle;
	public int yAngle;

	public void myinit() {
		xAngle = 0;
		yAngle = 0;

		float[] mat_specular = {1.0f, 1.0f, 1.0f, 1.0f};
		float[] mat_shininess = {50.0f};
		float[] light_position = {1.0f, 1.0f, 1.0f, 0.0f};
	
		myGL.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		myGL.glShadeModel(GL.GL_SMOOTH);
	
		myGL.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, mat_specular);
		myGL.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, mat_shininess);
		myGL.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_position);
	
		myGL.glEnable(GL.GL_LIGHTING);
		myGL.glEnable(GL.GL_LIGHT0);
		myGL.glEnable(GL.GL_DEPTH_TEST);

		model = new glAbstractModel(
			myGL,
			new float[][] {
				{ 1.0f, 1.0f, 1.0f},{ 1.0f, 1.0f,-1.0f},
				{ 1.0f,-1.0f, 1.0f},{ 1.0f,-1.0f,-1.0f},
				{-1.0f, 1.0f, 1.0f},{-1.0f, 1.0f,-1.0f},
				{-1.0f,-1.0f, 1.0f},{-1.0f,-1.0f,-1.0f}
			}
		) {
			public void draw() {
				myGL.glBegin(myGL.GL_QUAD_STRIP);
					myGL.glNormal3fv(points[0]);
					myGL.glVertex3fv(points[0]);
					myGL.glNormal3fv(points[1]);
					myGL.glVertex3fv(points[1]);
					myGL.glNormal3fv(points[2]);
					myGL.glVertex3fv(points[2]);
					myGL.glNormal3fv(points[3]);
					myGL.glVertex3fv(points[3]);
					myGL.glNormal3fv(points[6]);
					myGL.glVertex3fv(points[6]);
					myGL.glNormal3fv(points[7]);
					myGL.glVertex3fv(points[7]);
					myGL.glNormal3fv(points[4]);
					myGL.glVertex3fv(points[4]);
					myGL.glNormal3fv(points[5]);
					myGL.glVertex3fv(points[5]);
					myGL.glNormal3fv(points[0]);
					myGL.glVertex3fv(points[0]);
					myGL.glNormal3fv(points[1]);
					myGL.glVertex3fv(points[1]);
				myGL.glEnd();
				myGL.glBegin(myGL.GL_QUADS);
					myGL.glNormal3fv(points[0]);
					myGL.glVertex3fv(points[0]);
					myGL.glNormal3fv(points[4]);
					myGL.glVertex3fv(points[4]);
					myGL.glNormal3fv(points[6]);
					myGL.glVertex3fv(points[6]);
					myGL.glNormal3fv(points[2]);
					myGL.glVertex3fv(points[2]);
					myGL.glNormal3fv(points[1]);
					myGL.glVertex3fv(points[1]);
					myGL.glNormal3fv(points[3]);
					myGL.glVertex3fv(points[3]);
					myGL.glNormal3fv(points[7]);
					myGL.glVertex3fv(points[7]);
					myGL.glNormal3fv(points[5]);
					myGL.glVertex3fv(points[5]);
				myGL.glEnd();
			}
		};
		myGL.glTranslatef(0.0f, 0.0f, 2.0f);
	}

	public void display() {
		myGL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
		myGL.glPushMatrix();
			myGL.glRotatef(xAngle, 1.0f, 0.0f, 0.0f);
			myGL.glRotatef(yAngle, 0.0f, 1.0f, 0.0f);
			model.render();
		myGL.glPopMatrix();
		myGL.glFlush();
	}

    public void myReshape (int w, int h) {
        myGL.glViewport(0, 0, w, h);
        myGL.glMatrixMode(GL.GL_PROJECTION);
        myGL.glLoadIdentity();
		if (w <= h)
		    myGL.glOrtho(
		    	-5.0f, 5.0f,
		    	-5.0f *(float)h/(float)w,
				5.0f *(float)h/(float)w,
				-5.0f, 5.0f
			);
		else
		    myGL.glOrtho(
		    	-5.0f *(float)w/(float)h,
		    	5.0f *(float)w/(float)h,
				-5.0f, 5.0f,
				-5.0f, 5.0f
			);
        myGL.glMatrixMode(GL.GL_MODELVIEW);
        myGL.glLoadIdentity();
    }

	public void keyboard(char key, int x, int y) {
		switch (key) {
			case 'x': xAngle = (xAngle+5)%360; break;
			case 'X': xAngle = (xAngle-5)%360; break;
			case 'y': yAngle = (yAngle+5)%360; break;
			case 'Y': yAngle = (yAngle-5)%360; break;
	    	case 27: System.exit(0);
	    	default: return;
		}
		myUT.glutPostRedisplay();
	}

	public void init() {
		myUT.glutInitWindowSize(500,500);
		myUT.glutInitWindowPosition(0,0);
		myUT.glutCreateWindow(this);
		myinit();
		myUT.glutDisplayFunc("display");
		myUT.glutReshapeFunc("myReshape");
		myUT.glutKeyboardFunc("keyboard");
		myUT.glutMainLoop();
	}

	public static void main (String args[]) {
		Frame mainFrame = new Frame();
		mainFrame.setSize(508,527);
		test mainCanvas = new test();
		mainCanvas.init();
		mainFrame.add(mainCanvas);
		mainFrame.setVisible(true);
    }
}