Skip to main content
gamedev.net
🔒 Locked 🤖 Godot

glScaled

Started by iSina 21 replies 4.4k views
Original Post
iSina
iSina
Greetings, What I am doing isnt exactly a game but more of a molecular modelling program. I was planning only to include calculations and give output to known molecular visualization toolsi but however the form I have chosen to represent molecules are quite different from standard ones. So I will have to add my openGL extension. However among the load of other codes I have to write, I dont have time to extensively go over openGL books, so I am trying to string together pieces of codes I find around. The code is in perl, but it is almost the same as c or c++ except the $ sign which is a declaration of a variable like saying int Right now I have a question about glScaled: Suppose at some part of the program I want to plot N number of ellipsoids (where N is given) for (1..N){ # Here some code read changing variables for $x, $y, $z, $xdir, $ydir, $zdir values # glBegin (GL_QUADS); glLoadIdentity(); glScaled($x, $y, $z); my $newQuad = gluNewQuadric (); gluSphere($newQuad,1, 32, 16); glEnd ; glTranslatef($xdir, $ydir, $zdir); } What I want the program to do is to read some coordinate and radius information about a set of ellipsoids and plot them on screen one after the other. Each one has a specific scaling value. However when I use glScaled in that form, the scaling amount add up, so if at the first cycle it is glScaled(2,2,2) and in the second cycle it is glScaled (3,3,3) it acts as if glScaled(6,6,6). I know using glScaled isnt just as straight forward as this since it changes the scales of all the objects plotted after its call, but I havent been able to fix it. Thanks for the help...
jouley
jouley
You can either undo the scale after drawing the shape by scaling by 1/$x, etc...:
glLoadIdentity();// while loopingglScaled($x, $y, $z);//draw a shapeglScaled(1.0/$x, 1.0/$y, 1.0/$z);glTranslatef($xdir, $ydir, $zdir);


...or use the gl matrix stack:

glLoadIdentity();// while loopingglPushMatrix();glScaled($x, $y, $z);//draw a shapeglPopMatrix();glTranslatef($xdir, $ydir, $zdir);
Sneftel
Sneftel
You really need to get to know the mathematical effect of the different transformation commands-- that is, the ramifications of the fact that they cause an internal matrix to be postmultiplied by a different matrix, and what the effect of different orders of operations is. The OpenGL redbook has a great description of this stuff, but unfortunately only in the 3rd and later editions (opengl 1.3 and later, so it's not in the online version. You should also get to know the matrix stack (glPushMatrix and glPopMatrix), although this is somewhat a different thing.
swiftcoder
swiftcoder
You have two choices, either:
a) scale by the reciprocal value after drawing each object (which will reset the scale)
or, b) glPushMatrix() before scaling, and glPopMatrix() after drawing (which will save and restore the matrix before the scale)
Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
Lord_Evil
Lord_Evil
I'd recommend option b) the matrix stack. Lots of multiplications (adding transformations and their inverse to cancel them out) will slowly introduce errors due to numerical instability/floating point precision issues.
If I was helpful, feel free to rate me up ;)If I wasn't and you feel to rate me down, please let me know why!
iSina
iSina
I was trying to rescale the scales back to its original value as you said, I will also try what you have recommended. I am quite aware of linear algebra as I had to really use construct amount of transformation operators (like those that would take an ellipsoid into unit circle and those that would rotate vectors around arbitrary axis). I am not however aware of the internal workings of openGL, and I dont think I will have enough time soon to see through it. However I will look through the book you mentioned. The graphics extension I am planning for now is very simple (I could write in matlab like in a day but I want it to be a part of my own program not a side script).

I will update this topic if I am stuck anywhere else, thanks alot for the help,
iSina
iSina
I am trying to use push and pop matrix way in this manner (I just put in 1.1 instead of varying scale amounts). So the size of the sphere should remain the same right? But its size increases and infact after the second sphere, it takes the form of an ellipsoid although the scaling is homogenous...(there is a picture after the code)

sub DrawGLScene {


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

glTranslatef(-1.5, 0.0, -6.0);


for (1..5){
glPushMatrix();
glScaled(1.1,1.1,1.1);

glBegin (GL_QUADS);
my $newQuad = gluNewQuadric ();
gluSphere($newQuad,1, 32, 16);
glEnd ;

glPopMatrix();
glTranslatef(3.0, 0.0, 0.0);

}


glutSwapBuffers;
}

http://img136.imageshack.us/img136/2268/spheredq6.jpg
Lord_Evil
Lord_Evil
It's also the order of the calls that matter. Your translation inside the loop influences the scaling. Put it inside the glPushMatrix/glPopMatrix pair and use glTranslatef(i * 3.0, 0.0, 0.0f) instead.
If I was helpful, feel free to rate me up ;)If I wasn't and you feel to rate me down, please let me know why!
iSina
iSina
When I put translation between push and pop, only a single sphere appears (they are not translated but all are put on top of each other) I suppose the translation goes wrong? And also what is the purpose of i* and f, they are not defined on perl like that I think because it gives an error..
Lord_Evil
Lord_Evil
Ah sorry, the f comes from my habit on using float literals which are declared as 0.0f (instead 0.0 which would be double).

The i was meant to be the counter variable of the loop, didn't pay attention to the fact that you don't declare it. What I meant is that you could increase the translation distance by 3 every time you loop, i.e. in C++
for(int i = 0; i < 5; i++){ ... glTranslatef(i * 3.0, 0.0, 0.0); //i.e. first iteration translate by 0, second by 3 etc. ...}
If I was helpful, feel free to rate me up ;)If I wasn't and you feel to rate me down, please let me know why!
iSina
iSina
When I put translate between pop and push it still does not work, I still coundt figure what I am doing wrong, I guess I will have to start reading a book on openGL though my intentions are quite simple this queue type of processing needs more attention I suppose :

sub DrawGLScene {	my $newQuad;    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);      glLoadIdentity();	    glTranslatef(-1.5, 0.0, -6.0);     		for (my $i=1; $i<5; $i++){				glPushMatrix();				glScaled(1.1, 1.1, 1.1);				glBegin (GL_QUADS);				$newQuad = gluNewQuadric ();					gluSphere($newQuad,0.5, 32, 16);		glEnd ;				glPopMatrix();						glPushMatrix();			glTranslatef($i*1.4,$i*1.4,$i*1.4); # with or without the $i		glPopMatrix();						}    glutSwapBuffers;}


[Edited by - iSina on July 18, 2008 10:08:37 AM]
jouley
jouley
Quote:
Original post by iSina
When I put translate between pop and push it still does not work

You'll want to put it between the push and pop that encompass your drawing. Really, you should take the time to read up on the matrix stack. When you push a matrix onto the stack, it saves a copy of the current matrix and all later calls modify a new one. Popping a matrix gets rid of this new one and restores the previous one. So:
glPushMatrix( );glTranslate/Rotate/Scale( );// NOTHING DRAWNglPopMatrix( );
... is one giant noop. It makes a copy of a matrix, fiddles with a new one, throws this new one away, and restores the copy. The basic flow should look like this:
for (my $i=1; $i<5; $i++){	glPushMatrix();		        // transform (scale/translate/rotate) here        // then, draw (glBegin/End, gluSphere, etc.)	glPopMatrix();}
At the end of each iteration of the loop, you'll wind up back where you started in terms of transformations. So, you apply the next shape's scaling and translation within the single push/pop pair, draw it, and start over.

You'll want to look into it more, but here's a start.
iSina
iSina
Yeah I just realized it was stupid to put in a seperate push pop and I tried to put it in the same place as scale. I did it now it works, thanks.
iSina
iSina
Here comes my second question, suppose I denoted the page up key so that when it is pressed the camera zooms out. I am doing it like this:

glutSpecialFunc(\&cbSpecialKeyPressed);

is the part for calling key pressed function. And in that function page up is like

sub cbSpecialKeyPressed{  my $key = shift;  if ($key == GLUT_KEY_PAGE_UP)  {   $Z_Off -= 1;   DrawGLScene();  }....}


And I added a seperate glTranslate function that translates in the z axis $Z_off. So each time someone presses (or keeps pressing) page up, the scene is redrawn with a rotated model. That rather seems cumbersome. Although my model is going to be very simple, I wonder if there is a more elegant way of doing it. Also what is the call if I want to change GLUT_KEY_PAGE_UP to mouse buttons or mouse movements? Is it done in the same way?

Thanks

iSina
iSina
And one more, I have set the color

glColor4f(0.2,0.8,0.6,.95);


and the light as

glLightfv_p(GL_LIGHT1, GL_POSITION, @Light_Position);
glLightfv_p(GL_LIGHT1, GL_AMBIENT, @Light_Ambient);
glLightfv_p(GL_LIGHT1, GL_DIFFUSE, @Light_Diffuse);
glEnable(GL_LIGHT1);
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);

where arrays are (those starting with @)

my @Light_Ambient = ( 0.0, 0.0, 0.0, 0.0 );
my @Light_Diffuse = ( 0.0, 0.0, 0.0, 0.0 );
my @Light_Position = ( 0.0, 0.0, 0.0, 0.0 );

But no light seems to be set. Do I need to put a texture on these ellipsoids? Here is a screen shot:

lightfc4.jpg
jouley
jouley
Quote:
Original post by iSina
But no light seems to be set. Do I need to put a texture on these ellipsoids?

You don't need a texture, but the first thing you should do is glEnable(GL_LIGHTING) [smile]. If that doesn't do the trick, I'll look into it deeper.

As for your previous question, why do you get (or expect, I'm not sure which) a "rotated model?" As of yet, I haven't seen any rotating in your code. So, I'm not really sure what the problem is, but your approach seems reasonable, and not too cumbersome. You'd have to change the message handling for reacting to mouse movements, but the approach would be the same.
iSina
iSina
I have added the rotation in response to the key later on, it is not in the previous ones I have added.

I have added the glEnable(GL_LIGHTING), but there is still no shades of light on the surface of the ellipsoids.

iSina
iSina
Quote:
As of yet, I haven't seen any rotating in your code. So, I'm not really sure what the problem is, but your approach seems reasonable, .


The reason I am saying this is because my main intention is just to rotate the camera, and to do that I am reinitializing the whole model. I am not sure how camera works internally in openGL but if rotating camera just means rotating the model in fact, then there is no choice. But I really want that button to do is to rotate the camera not the whole model (as I said, if there is anything like a camera)

jouley
jouley
Quote:
Original post by iSina
my @Light_Ambient = ( 0.0, 0.0, 0.0, 0.0 );
my @Light_Diffuse = ( 0.0, 0.0, 0.0, 0.0 );
my @Light_Position = ( 0.0, 0.0, 0.0, 0.0 );

Whoops, I should have caught this - you'll want to set the ambient and diffuse terms to something other than black. Start with white for diffuse and maybe a light gray for the ambient, just to see. From there, you can play around and set it how you think it looks best.

Also, your position needs some tinkering. For a "headlight" style light, set it to (0.0, 0.0, 1.0, 0.0). That'll be directional straight down the Z axis.

For more on these things, check out this.

You may want to try this all on GL_LIGHT0, as it has most of its default states set in a sane manner, unless you're already using it for something. Also, if things don't work like they should, it's always a good idea to use glGetError.
jouley
jouley
Quote:
Original post by iSina
Quote:
As of yet, I haven't seen any rotating in your code. So, I'm not really sure what the problem is, but your approach seems reasonable, .


The reason I am saying this is because my main intention is just to rotate the camera, and to do that I am reinitializing the whole model. I am not sure how camera works internally in openGL but if rotating camera just means rotating the model in fact, then there is no choice. But I really want that button to do is to rotate the camera not the whole model (as I said, if there is anything like a camera)

Gotcha. See here for a start on how things work, particularly section 9.011.

I'm unsure of what you mean by "reinitializing the whole model." Do you reload the model and compute new vertex positions based on your desired rotation? If so, that's definitely overkill. If, however, you're using a glRotate call before rendering, then that's a perfectly fine way to do things. Rotating the "camera" vs. rotating the model is a tricky thing to understand, but they will give different results, especially if there are other things in your scene being rendered.

So: If glRotate gives you the effect you're after, use it. If you can't quite get it, post all of the relevant code and the desired effect, i.e. "I want this model to spin, but for the one next to it to stay still," or "I want the camera to revolve around both models," or "I want both models to spin in place." Knowing what you're looking to do will be helpful when offering advice.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.