Giving 2D structures 3D depth [duplicate] - opengl

This question already has an answer here:
Closed 12 years ago.
Possible Duplicate:
How to give a 2D structure 3D depth
Hello everyone,
I posted this same question yesterday. I would like to have uploaded images showing my program output but due to spamming protection I am informed I need 10 reputation "points". I could send images of my output under different projection matrices to anyone willing.
I am beginning to learn OpenGL as part of a molecular modeling project, and currently I am trying to render 7 helices that will be arranged spatially close to each other and will move, tilt, rotate and interact with each other in certain ways.
My question is how to give the 2D scene 3-Dimensional depth so that the geometric structures look like true helices in three dimensions?
I have tried playing around with projection matrices (gluPerspective, glFrustum) without much luck, as well as using the glDepthRange function. As I understand from textbook/website references, when rendering a 3D scene it is appropriate to use a (perspective) projection matrix that has a vanishing point (either gluPerspective or glFrustum) to create the illusion of 3 dimensions on a 2D surface (the screen)
I include my code for rendering the helices, but for simplicity I insert the code for rendering one helix (the other 6 helices are exactly the same except for their translation matrix and the color function parameters) as well as the reshape handler.
This is the output ![enter image description here][1] I get when I run my program with an orthographic projection (glOrtho) and it looks as a 2D projection of helices (curved lines drawn in three dimensions). This is my output (![enter image description here][2]) when I use a perspective projection (glFrustum in my case). It does not appear as if I am looking at my helices in 3D!!
Perhaps the glFrustum parameters are wrong?
//GLOBALS
GLfloat x, y, z;
GLfloat c = 1.5f; //helical pitch
GLfloat theta; //constant angle between tangent and x-axis
thetarad = theta/(Pi/180.0); //angle converted from degrees to radians
GLfloat r = 7.0f; //radius
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST); /* enable depth testing */
glDepthFunc(GL_LESS); /* make sure the right depth function is used */
/*CALLED TO DRAW HELICES*/
void RenderHelix() {
/**** WHITE HELIX ****/
glColor3f(1.0,1.0,1.0);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(-30.f, 100.f, 0.f); //Move Position
glRotatef(90.0, 0.0, 0.0, 0.0);
glBegin(GL_LINE_STRIP);
for(theta = 0; theta <= 360; ++theta) { /* Also can use: for(theta = 0; theta <= 2*Pi; ++rad) */
x = r*(cosf(theta));
y = r*(sinf(theta));
z = c*theta;
glVertex3f(x,y,z);
}
glEnd();
glScalef(1.0,1.0,12.0); //Stretch or contract the helix
glPopMatrix();
/* Code for Other 6 Helices */
.............
glutSwapBuffers();
}
void Reshape(GLint w, GLint h) {
if(h==0)
h=1;
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
GLfloat aspectratio = (GLfloat)w/(GLfloat)h;
if(w<=h)
//glOrtho(-100,100,-100/aspectratio,100/aspectratio, -50.0,310.0);
//glOrtho(-100,100,-100/aspectratio,100/aspectratio, 0.0001,1000000.0); //CLIPPING FAILSAFE TEST
//gluPerspective(122.0,(GLfloat)w/(GLfloat)h,10.0,50.0);
glFrustum(-10.f,10.f, -100.f/aspectratio, 100.f/aspectratio, 1.0f, 15.0f);
else
//glOrtho(-100*aspectratio,100*aspectratio,-100,100,-50.0,310.0);
//glOrtho(-100*aspectratio,100*aspectratio,-100,100,0.0001,1000000.0); //CLIPPING FAILSAFE TEST
//gluPerspective(122.0,(GLfloat)w/(GLfloat)h,10.0,50.0);
glFrustum(-10.f*aspectratio,10.f*aspectratio,-10.f,10.f, 1.0f,15.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

The usual reason that simple 3d applications don't "look 3d" is because you need to set up a lighting system. Lighting is a major source of depth cues to your brain.
Here's a good tutorial on adding lighting to an OpenGL program:
http://www.cse.msu.edu/~cse872/tutorial3.html
EDIT: For more context, here's the relevant chapter from the classic OpenGL Red Book:
http://fly.cc.fer.hr/~unreal/theredbook/chapter06.html
Notice the screenshot near the top, showing the same sphere render both with and without lighting.

I agree it's difficult if you can't post your images (and it may not be trivial then).
If your code is open source you are likely to get help for molecular modelling from the Blue Obelisk Community (http://blueobelisk.shapado.com/ is a SE-type site for answering these questions).
There used to be a lot of GL used in our community but I'm not sure I know a good code which which you could hack to get some idea of the best things to do. The leading graphics tools are Jmol (where the gfx were largely handwritten and very good) and Avogadro which uses Qt.
But if you ask for examples of open source GL moelcular graphics you'll probably get help.
And of course you'll probably get complementary help here

Related

OpenGL C++ - Solar System

I've finished building a solar system using OpenGL and C++. One of the features in this system is having camera positions on each planet pointing to the north which moves based on the planet transformation. The camera positions are: One at the top, one a little behind the planet and the last one is far away from the planet. There are some other features but I don't have any issues with them.
So, the issue I am having is that some planets seem to be trembling for some reason while rotating around their centers. If I increase the speed of spinning the planet will stop trembling or the trembling becomes unnoticeable. The entire solar system is fully based on real textures and proportional space calculations and it has multiple camera positions as mentioned earlier.
Here is some code that might help understanding what I am trying to achieve:
//Caculate the earth postion
GLfloat UranusPos[3] = {Uranus_distance*DistanceScaler * cos(-uranus * M_PI / 180), 0, Uranus_distance*DistanceScaler * sin(-uranus * M_PI / 180)};
//Caculate the Camera Position
GLfloat cameraPos[3] = {Uranus_distance*DistanceScaler * cos(-uranus * M_PI / 180), (5*SizeScaler), Uranus_distance*DistanceScaler * sin(-uranus * M_PI / 180)};
//Setup the camear on the top of the moon pointing
gluLookAt(cameraPos[0], cameraPos[1], cameraPos[2], UranusPos[0], UranusPos[1], UranusPos[2]-(6*SizeScaler), 0, 0, -1);
SetPointLight(GL_LIGHT1,0.0,0.0,0.0,1,1,.9);
//SetMaterial(1,1,1,.2);
//Saturn Object
// Uranus Planet
UranusObject( UranusSize * SizeScaler, Uranus_distance*DistanceScaler, uranusumbrielmoonSize*SizeScaler, uranusumbrielmoonDistance*DistanceScaler, uranustitaniamoonSize*SizeScaler, uranustitaniamoonDistance*DistanceScaler, uranusoberonmoonSize*SizeScaler, uranusoberonmoonDistance*DistanceScaler);
The following is the planet function I am calling to draw the object inside the display function:
void UranusObject(float UranusSize, float UranusLocation, float UmbrielSize, float UmbrielLocation, float TitaniaSize, float TitaniaLocation, float OberonSize, float OberonLocation)
{
glEnable(GL_TEXTURE_2D);
glPushMatrix();
glBindTexture( GL_TEXTURE_2D, Uranus_Tex);
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glRotatef( uranus, 0.0, 1.0, 0.0 );
glTranslatef( UranusLocation, 0.0, 0.0 );
glDisable( GL_LIGHTING );
glColor3f( 0.58, 0.29, 0.04 );
DoRasterString( 0., 5., 0., " Uranus" );
glEnable( GL_LIGHTING );
glPushMatrix();
// Venus Spinning
glRotatef( uranusSpin, 0., 1.0, 0.0 );
MjbSphere(UranusSize,50,50);
glPopMatrix();
glDisable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_2D);
glPushMatrix();
glBindTexture( GL_TEXTURE_2D, Umbriel_Tex);
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glDisable(GL_LIGHTING);
if (LinesEnabled)
{
glPushMatrix();
gluLookAt( 0.0000001, 0., 0., 0., 0., 0., 0., 0., .000000001 );
DrawCircle(0.0, 0.0, UmbrielLocation, 1000);
glPopMatrix();
}
glEnable( GL_LIGHTING );
glColor3f(1.,1.,1.);
glRotatef( uranusumbrielmoon, 0.0, 1.0, 0.0 );
glTranslatef( UmbrielLocation, 0.0, 0.0 );
MjbSphere(UmbrielSize,50,50);
glPopMatrix();
glDisable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_2D);
glPushMatrix();
glBindTexture( GL_TEXTURE_2D, Titania_Tex);
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glDisable(GL_LIGHTING);
if (LinesEnabled)
{
glPushMatrix();
gluLookAt( 0.0000001, 0., 0., 0., 0., 0., 0., 0., .000000001 );
DrawCircle(0.0, 0.0, TitaniaLocation, 1000);
glPopMatrix();
}
glEnable( GL_LIGHTING );
glColor3f(1.,1.,1.);
glRotatef( uranustitaniamoon, 0.0, 1.0, 0.0 );
glTranslatef( TitaniaLocation, 0.0, 0.0 );
MjbSphere(TitaniaSize,50,50);
glPopMatrix();
glDisable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_2D);
glPushMatrix();
glBindTexture( GL_TEXTURE_2D, Oberon_Tex);
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glDisable(GL_LIGHTING);
if (LinesEnabled)
{
glPushMatrix();
gluLookAt( 0.0000001, 0., 0., 0., 0., 0., 0., 0., .000000001 );
DrawCircle(0.0, 0.0, OberonLocation, 1000);
glPopMatrix();
}
glEnable( GL_LIGHTING );
glColor3f(1.,1.,1.);
glRotatef( uranusoberonmoon, 0.0, 1.0, 0.0 );
glTranslatef( OberonLocation, 0.0, 0.0 );
MjbSphere(OberonSize,50,50);
glPopMatrix();
glDisable(GL_TEXTURE_2D);
glPopMatrix();
glDisable(GL_TEXTURE_2D);
}
Finally, the following code is for the transformation calculations used for solar animation:
uranus += 0.0119 * TimeControl;
if( uranus > 360.0 )
uranus -= 360.0;
// Clockwise Rotation
uranusSpin -= 2.39 * TimeControl;
if( uranusSpin <= -360.0 )
uranusSpin = 0.0;
Note: the problem happens only with 4 planets only.
I really appreciate any idea that could solve the problem.
First of all take a look at:
Is it possible to make realistic n-body solar system simulation in matter of size and mass?
Now to your problem. I am too lazy to go through your code but you most likely hit the floating point accuracy barrier and or have accumulating errors during rotating. My bet is that the error is bigger further away from the sun (outer planets and more in the ecliptic plane). If that is so then it is obvious. So how to remedy that?
floating point accuracy
while rendering you are transforming vertexes by transform matrix. For reasonable ranges is this OK but if you Vertex is very far from (0,0,0) then the matrix multiplication is not that precise. This means when you convert back to camera space the Vertex coordinate is jumping around. To avoid this you need to translate your vertexes to camera origin before feeding it to OpenGL.
So just subtract camera position from each Vertex (before loading them to OpenGL!!!) you have and then render them with camera with position (0,0,0). This way you get rid of the jumping and even wrong interpolation of primitives. see
ray and ellipsoid intersection accuracy improvement
If your object is still too big (this is not the case for Solar system) then you can stack up more frustums together and render each with separate camera shifted by some step so you get in range.
Use 64 bit floats where you can, but be aware GPU implementations does not support 64-bit interpolators so fragment shader is feed by 32-bit floats instead.
accumulating errors in transform matrix
If you have some "static" matrix and apply countless operations on it like rotation, translation Then it will lose its precision after while. This is recognizable by changing scale (axises are not unit size anymore) and adding skew (axises are not perpendicular to each other anymore) with time it gets worse and worse.
To remedy that You can keep counter of operations per matrix and if hit some treshold perform matrix normalization. This is simple just extraxt all the axises vectors, make them perpendicular again, set them back to their original size and write them back to your matrix. With basic vector math knowledge is this easy just exploit cross product (which gives you perpendicular vector). I use Z axis as view direction so I keep Z axis direction as is and correct the X,Y axises directions. The size is easy just divide each vector by its size and you are unit again (or very close to it). for more info see:
Understanding 4x4 homogenous transform matrices
[Edit1] What is going on
Have a look at your code for single planet without the rendering stuff:
// you are missing glMatrixMode(GL_????) here !!! what if has been changed?
glPushMatrix();
// rotate to match dayly rotation axis?
glRotatef( uranus, 0.0, 1.0, 0.0 );
// translate to Uranus avg year rotation radius
glTranslatef( UranusLocation, 0.0, 0.0 );
glPushMatrix();
// rotate Uranus to actual position (year rotation)
glRotatef( uranusSpin, 0., 1.0, 0.0 );
// render sphere
MjbSphere(UranusSize,50,50);
glPopMatrix();
// moons
glPopMatrix();
So what you are doing is this. Let assume you are using ModelView matrix and you are instructing OpenGL to do this operation on it:
ModelView = ModelView * glRotatef(uranus,0.0,1.0,0.0) * glTranslatef(UranusLocation,0.0,0.0) * glRotatef(uranusSpin,0.,1.0, 0.0);
So what is wrong with this? For small scenes nothing but you are using proportional sizes so:
UranusLocation=2870480859811.71 [m]
UranusSize = 25559000 [m]
So that means the glVertex magnitudes are ~25559000 and after applying transforms ~2870480859811.71+25559000. Now there are few problems with these values.
First any glRotation call applies sin and cos coefficients to the 2870480859811.71 Lets assume we have error of sin,cos around 0.000001 that means the final position after result has position error in it:
error=2870480859811.71*0.000001=2870480.85981171
The OpenGL sin,cos implementation has probably higher precision but not by much. Anyway if you are comparing it to planet radius
2870480.85981171/25559000=0.112308 -> 11%
You get that the jumping error is around 11% of the planet size. That is huge. The implication from this is that the jumping is the bigger the further away from Sun and more Visible for smaller Planets (as our perception is usually relative not absolute).
You can try to boost this by using double precision (glRotated) but that does not mean it would solve the problem (some drivers does not have double precision implementation of sin,cos).
If you want to get rid of these problems you have follow the bullet #1 or do the rotations on your own on at least doubles and feed only the final matrix to OpenGL. So first the #1 approach. Translation of matrix is just +/- operation (also encoded as multiplication) but no un-precise coefficients are present so you are using full precision of used variable. Anyway I would use glTranslated just to be sure. So we need to make sure the rotations does not use big values inside OpenGL. So try this:
// compute planet position
double x,y,z;
x=UranusLocation*cos(uranusSpin*M_PI/180.0);
y=0.0;
z=UranusLocation*sin(uranusSpin*M_PI/180.0);
// rotate to match dayly rotation axis?
glRotated( uranus, 0.0, 1.0, 0.0 );
// translate to Uranus to actual position (year rotation)
glTranslated(x,y,z);
// render sphere
MjbSphere(UranusSize,50,50);
This affects the daily rotation speed as the daily and Year rotations angles are not adding up, but you are not implementing the daily rotation yet anyway. If this does not help then we need to use camera local coordinates to avoid having big values send to OpenGL:
// compute planet position
double x,y,z;
x=UranusLocation*cos(uranusSpin*M_PI/180.0);
y=0.0;
z=UranusLocation*sin(uranusSpin*M_PI/180.0);
// here change/compute camera position to (original_camera_position-(x,y,z))
// rotate to match dayly rotation axis?
glRotated( uranus, 0.0, 1.0, 0.0 );
// render sphere
MjbSphere(UranusSize,50,50);
Hope I matched your coordinate system if not just swap axises or negate them (x,y,z).
It is much better to have own precise matrix math at disposal and compute the glTranslate,glRotate on CPU side with high precision and use only the resultant matrix in OpenGL. see the Understanding 4x4 homogenous transform matrices link above how to do that.
I can not give you an exact answer based on what you have shown. I can not compile and run your current code and test it with numbers and the debugger. What I can do is give you some advise that ought to help you out.
From what I can tell based on the code that you did supply you are creating your Planet objects via a function call. So I can rationalize that you are doing this for every planet. If that is the case then if you take a notice at your full code base you will see that everyone of these functions besides their names, and the numbers that are used are basically copies of themselves or duplicate code. This is where you need a more versatile structure.
Here are some important things to consider in your construct.
Create a full 3D Motion camera class & a separate Player Class
The Camera Class will allow you to look up, down, left & right by (restrained angles) - Via Mouse Controls
The Player Class will have the camera object attached to it at camera_eye_level, lookAtDirection that is perpendicular to the upVector. The player class will be able to move freely forward, backward, up, down turn left & turn right via keyboard controls. This gives you flexibility.
Note: If You are doing by scale and your planets are considerably far apart, make your player's linear speed rate higher so that you move faster towards the object covering more distance.
Create a base Geometry class
Derived Geometry Classes: Box, Flat Grid, Cylinder, Sphere, Pyramid, Cone
These classes will hold a finite container of Vector3s(Vertices),
a container of Vector3(Indices), a container of Vector2(Texture Coords),
a container of Vector4(Material - Color with Alpha), and a container
of Vector3(Normals).
The base class will probably only hold an unsigned int (ID value) and or a std::string (Name Identifier) and an Enum Value of Type Geometry that is being created
Each Derived class will have a constructor on required parameters, the size of the 3 dimensions (don't need to worry about Texture & Color Information Here that will come later)
Create a Material Class
Create a base Light class
Derived Types: Directional, Point & Spot
Create A Texture Class
Create A Texture Transform Class - This Will Allow you to apply transformations directly on the texture that is attached to your Geometry To give the effect that an object is moving, when only the texture transform is.
Example: Geometry Type Box( 2,1,4 ) Texture Applied "conveyor_belt1.png" this way you don't have to change the box's transform and move all the vertices, texcoords, and normals on each render pass, you can just simply make the texture move in place. Less computationally expensive
Create Node Class - Base class for all nodes that will belong to a Scene Graph
Types of Nodes for SceneGraph - ShapeNode(Geometry), LightNode, TransformNode(contains vector & matrix information for Translation, Rotation & Scaling),
The combination of the Node Classes and The SceneGraph will create a tree like structure such as this:
// This would be an example of text file that you would read in to parse the data
// and it will construct the scene graph for you, as well as rending it.
// Amb = Ambient, Dif = Diffuse - The Materials Work With Lighting & Shading and will blend with which ever texture is applied
// Items needed to construct
// Objects
Grid geoid_1 Name_plane Wid_5 Dep_5 divx_10 divz_10
Sphere geoid_2 name_uranus radius_20
Sphere geoid_3 name_earth radius_1
Sphere geoid_4 name_earth_moon radius_0.3
// Materials
Material matID_1 Amb_1,1,1,1 Dif_1,1,1,1 // (white fully opaque)
// Textures
Texture texID_1 fileFromTexture_"assets\textures\Uranus.png"
Texture texID_2 fileFromTexture_"assets\textures\Earth.png"
Texture texID_3 fileFromTexture "assets\textures\EarthMoon.png"
// Lights (Directional, Point, & Spot Types)
Transform Trans_0,0,0 // This is the center of the World Space and has to be a
+Shape geoID_1 matID_1 // Applies flat grid to root node to create your horizontal plane
+Transform Trans_10,2,10000 // Nest a transform node that is relative to the root; this will allow you to rotate, translate and scale every object that is attached and nested below this node. Any Nodes Higher in the branch will not be affected
++Shape geoID_2 matID_1 texID_1
+Transform Trans_10,1.5,200 // This node has 1 '+' so it is nested under the root and not Uranus
++Shape geoID_3 matID_1 tex1ID_2
+++Transform Trans_10,1.5,201 // This node is nested under the Earth's Transform Node and will belong to the Earth's Moon.
+++Shape geoID_4 matID_1 textID_3
END // End Of File To Parse
With this kind of construct, you would be able to translate, rotate and scale objects independently of each other, or by a hierarchy. For example: And as for the moons of Uranus you can apply the same technique as I showed with the Earth and its moon. Each moon would have its own transform but those transforms would be nested under the planets transforms where the planets transforms would be nested to the root or even the Sun's transform if you added one in. (Sun = Light Source) it would have several light nodes attached. (I've already done this before with the Sun - Earth & Moon and had the objects rotate accordingly.
You have a Model of a Jeep but you have 4 different models to render to make the full object in your game. 1 Body, 2 Front Wheels, 3 Back Wheels & 4 Steering Wheel. With this construct a graph my look like this
Model modID_1 modelFromFile_"Assets/Models/jeep_base.mod"
Model modID_2 modelFromFile_"Assets/Models/jeep_front_wheel.mod"
Model modID_3 modelFromFile_"Assets/Models/jeep_rear_wheel.mod"
Model modID_4 modelFromFile_"Assets/Models/jeep_steering.mod"
Material matID_1 Amb_1_1_1_1 Diff_1_1_1_1
Texture texID_1 textureFromFile_"Assets/Textures/jeep1_.png"
TextureTransform texTransID_1 name_front
TextureTransform texTransID_2 name_back
TextureTransform texTransID_3 name_steering
+Transform_0,0,0 name_root
++Transform_0,0.1,1 name_jeep
+++Shape modID_1 matID_1 texID_1 texCoord_0,0, size_75,40
+++Transform_0.1,0.101,1 name_jeepFrontWheel
+++Shape modID_2 matID_1 texID_1 texCoord_80,45 size_8,8
+++Transform_-0.1,-0.101,1 name_jeepBackWheel
+++Shape modID_3 matID_1 texID_2 texCoord_80,45 size_8,8
+++Transform_0.07,0.05,-0.02 name_jeepSteering
+++Shape modID_4 matID_1 texID_2 texCoord_80,55 size_10,10
END
Then in your code you can grab the transform nodes that belongs to jeep and when you translate it across the screen all the jeeps parts move together as one object, yet independently all tires can rotate front & back using the texture transforms, and your fronts can turn left and right by is own node transform by a constrained degree, also your steering can turn the same direction as the wheels using the texture transform, but may rotate less or more, depending on the characteristics of this particular vehicle and how it will handle within the scene or game.
With this type of system; the process is a bit harder to construct, but once it is working it allows for a simple automation of generating a scene graph. The down side to this is text file is easy to read at the human level but parsing a text file is much harder than parsing a binary file. The main reason for that is your function that belongs to your Scene class to parse and create all of these different nodes (All Geometry(Shapes), All (Lights), Material Texture and Transform Nodes.
The reason for having the Geometry and Lights having a base class is when you create a ShapeNode or a LightNode that is attached or nested to a TransformNode it can accept any derived type from the base class. This way you don't have to code your scene graph construction and parser to accept every type of geometry and light, you can have it accept any geometry and light, but to tell it what type it is.
Now you can make this a bit easier by creating a parser that works reads in binary files. The plus side is, it is easier to write the parser as long as you know the structure of the file, how much data to read in, and the expected type of data at the current read location. The down side is you can not read or set this up manually as I demonstrated above with a human readable text file. However going with this method would require you to have a decent Hex Editor Program that allows for file template types. such as 010 Editor this way you can add your own template to your file structure and when you read in the binary file with the applied template, you can then see if the values are correct and the fields have the appropriate data type and values.
In truth the best advice I can give you is this: The construct above is still good to follow, but may not be the best, it is a good starting point. But what you are learning right now on OpenGL appears to be OpenGL v1.0 which is basically outdated and deprecated. You should scrap all that you have learned from this relic of an API and begin to learn on modern OpenGL any version that is higher than 3.3. From there you can then learn to build and write shaders in GLSL and it will simplify a lot of things for you once you have your frame work up and working. Then once you get that up and working, instead of rendering everything to the screen from the CPU and rendering it from the GPU instead is much more efficient. Once you have that in place then consider looking into the concept of Batch Rendering. Batch Rendering will allow you to control how many buckets there are and how many vertices each bucket will contain. This batch process prevents the bottle neck between the rate of I/O from the CPU over the BUS to the GPU since GPUs do computation much faster than your CPU. Then with your scene graph you will not have to worry about creating lights, creating materials and applying them for all of these will be done in your fragment shader (GLSL) or what is called pixel shader (DirectX). All of your vertices and index information will be passed into the vertex Shader. Then it is just a matter of linking your shaders to an openGL program.
If you would like to see and learn about everything I have described above then visit the community that I've been a member of since 2007-08 at www.MarekKnows.com and join our community. He has several video tutorial series to learn from.

Draw oval with sphere in Opengl

I want to draw an oval by projection the sphere on the screen (like rasterize). Here is my code but it doesn't show anything on the screen. Should I use more functions to initialize the projection? Is this way possible to draw oval on screen by using sphere?
GLfloat xRotated, yRotated, zRotated;
GLdouble radius=1;
void display(void);
void reshape(int x, int y);
int main (int argc, char **argv)
{
glutInit(&argc, argv);
glutInitWindowSize(800,800);
glutCreateWindow("OVAL");
zRotated = 30.0;
xRotated=43;
yRotated=50;
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
void display(void)
{
glMatrixMode(GL_PROJECTION);
glOrtho(0.1, 1.0, 0.1, 1.0, -1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0,0.0,-5.0);
glColor3f(0.9, 0.3, 0.2);
glRotatef(xRotated,1.0,0.0,0.0);
glRotatef(yRotated,0.0,1.0,0.0);
glRotatef(zRotated,0.0,0.0,1.0);
glScalef(1.0,1.0,1.0);glutSolidSphere(radius,20,20);
glFlush();
}
void reshape(int x, int y)
{
if (y == 0 || x == 0) return;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(39.0,(GLdouble)x/(GLdouble)y,0.6,21.0);
glMatrixMode(GL_MODELVIEW);
glViewport(0,0,x,y);
}
You are drawing a sphere compltely outside of the viewing volume, so it should be no surprise that it can't be seen.
There are a couple of issues with your code:
All OpenGL matrix functions besides glLoadIndentity and glLoadMatrix always post-multiply a matrix to the current top element of the current matrix stack. In your display function, you call glOrtho without resetting the projection matrix to identity before. This will result in totally weird - and different - results if the display callback is called more than once.
You should add a call to glLoadIdentity() right before calling glOrtho.
You set up the model view transformations so that the sphere's center will always end up at (0,0,-5) in eye space. However, you set a projectiom matrix which defines a viewing volume which goes from z=1 (near plane) to z=-1 (far plane) in eye space, so your spehre is actually behind the far plane.
There are several ways this could be fixed. Changing the viewing frustum by modifying the parameters of glOrtho might be the easisest. You could for example try (-2, 2, -2, 2, 1, 10) to be able to see the sphere.
It is not really clear what
I want to draw an oval by projection the sphere on the screen (like rasterize).
exactly means. If you just want the sphere to be distorted to an ellipsoid, you could just apply some non-uniform scaling. This in principle could be done in the projection matrix (if no other objects are to be shown), but this would make much more sense to apply it to the model matrix of the sphere - you already have the glScale call there, you could try something like glScalef(1.0f, 0.5f, 1.0f);.
Also note that the ortho parameters I suggested previously will result in some distortion if your viewport is not exactly square. In a real world, one wants to incorporate the aspect ratio of the viewport into the projection matrix.
If you want to see the sphere deformed as by a perspective projection, you would have to skip the glOrtho altogheter and switch to a perspective projection matrix.
The code you are using is totally outdated. The OpenGL matrix stack has been deprecated in OpenGL 3.0 (2008) and is not available in core profiles of modern OpenGL. The same applies for builtin vertex attributes like glColor or immediate mode drawing and client-side vertex arrays. As a result, GLUT's drawing functions can also not be used with modern GL any more.
If you really intend learning OpenGL nowadays, I stronly advise you to ignore this old cruft and star learning the modern way.

OpenGL: Generating ellipse in code [duplicate]

This question already has an answer here:
OpenGL stretched shapes - aspect ratio
(1 answer)
Closed 7 years ago.
I have been trying to generate an ellipse using OpenGL and I have a feeling I have got something very wrong. I am trying to use an ellipse generating code but for simplicity, I have set the length of the major and minor axes equal. This should give me a circle but somehow that is not what is rendered with OpenGL and I am not sure what is wrong.
So the code is as follows:
glPushAttrib(GL_CURRENT_BIT);
glColor3f(1.0f, 0.0f, 0.0f);
glLineWidth(2.0);
// Draw center
glBegin(GL_POINTS);
glVertex2d(0, 0);
glEnd();
glBegin(GL_LINE_LOOP);
// This should generate a circle
for (GLfloat i = 0; i < 360; i++)
{
float x = cos(i*M_PI/180.f) * 0.5; // keep the axes radius same
float y = sin(i*M_PI/180.f) * 0.5;
glVertex2f(x, y);
}
glEnd();
glPopAttrib();
This should generate a circle as far as I can think. However. I get something like the attached image, which is not a circle. I am not sure what I am doing wrong.
It is a circle in clip space. Note that the horizontal extent is half the screen's width and the vertical extent is half the screen's height. The viewport transformation that maps clip space (-1 to 1 on both axes) to screen space basically performs a scaling and translation, which causes the deformation of the circle.
To prevent this from happening, you need to set up an appropriate projection transform, e.g. with glOrtho.

OpenGL switching between ortho and perspective

I have a tile engine using orthographic projection in immediate mode and I'm just trying to draw a 3d cube on top of my tile scene, in hopes that I can eventually incorporate 3d models into my engine instead of just sprites / textured quads. I would also like to make the tiles 3d for that slight bit of extra eye candy.. Hopefully I can eventually convert this to use modern OpenGL so I can take advantage of those extra features. Not on the top of my priority list at the moment. So on to the question.
I'm initializing OpenGL with this:
void initGL()
{
glDisable(GL_DEPTH_TEST);
glViewport( 0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
//Initialize Projection Matrix
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
//Initialize Modelview Matrix
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glOrtho(0,SCREEN_WIDTH,SCREEN_HEIGHT,0,0,1);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
//...setting some various other attributes, omitted for brevity...
glEnable(GL_TEXTURE_2D);
glClearColor( 0, 0, 0, 0 );
}
I have a function for drawing a cube that works.
void draw_cube()
{
/* position object */
glRotatef(30.0F, 1.0F, 0.0F, 0.0F);
glRotatef(30.0F, 0.0F, 1.0F, 0.0F);
/* draw six faces of a cube */
glBegin(GL_QUADS);
...vertices... (removed for brevity)
glEnd();
}
I made 2 functions for setting the 2d and 3d projection modes.
void set3d()
{
glEnable(GL_DEPTH_TEST);
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(0,SCREEN_WIDTH,0,SCREEN_HEIGHT, 0,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void set2d()
{
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,SCREEN_WIDTH,SCREEN_HEIGHT,0,0,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
For the sake of completeness, some pseudocode of my textured quad drawing..
pushmatrix();
translate();
rotate();
-translate();
glbegin();
...vertices
glend();
popmatrix();
So far I have managed to get the cube to draw on top of the tiles, but it disappears after approximately 1 second to never be seen again until I run the program again.
Basically what I'm doing in the main loop is this:
move objects around, process collisions, etc.
set2d();
draw textured quads, lines, text, etc. in 2d mode.
set3d();
draw_cube();
My question is: Why is the cube disappearing, and are there any errors in my set2d() and set3d() functions?
You have quite a few problems in this code, too many to list in comments in fact.
Your projection matrices are changing the handedness of your post-projected coordinate space, which will affect polygon winding.
Stick to a single handedness, unless you want to reverse the direction used for front- / back-facing polygon facets (glFrontFace (...)) - it is CCW by default, but you will have to change it to CW when you use set3d (...) to maintain consistent behavior.
This problem arises because you have the Y-axis going different directions
The behavior your are describing, where the object appears briefly and then disappears is indicative of an issue with your matrix stack.
Are you calling initGL (...) more than once in your software? You will run into a stack overflow if you do this enough times since you needlessly push the current matrix onto the stack and never pop it off.
You cannot use 0.0 for zNear with a perspective projection matrix, this will result in wonky math during the perspective divide step that comes after transformation to clip-space; the depth buffer will not work correctly.
In fact, glFrustum (...) will generate a GL_INVALID_VALUE error and do exactly nothing if you pass a value ≤ 0.0 for zNear. On a related note, gluPerspective (...) will not do this since it is not actually part of OpenGL, but it is equally invalid behavior to pass such a value to gluPerspective (...).

Drawing hour marks of a clock using OpenGL

here is my code:
void drawClock(void)
{
glClearColor(1.0,1.0,1.0,1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(0.0,0.0,0.0);
for(int i=0; i<12; i++){
glRotatef(30,0,0,1);
glTranslatef(5.2,0.0,0.0);
glutWireCube(2.0);
}
glFlush();
}
Here is my reshape function (without it I don't see anything, although I'm not sure how it really works)
void changeSize(int w, int h) {
// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if(h == 0) h = 1;
float ratio = 1.0* w / h;
// Reset the coordinate system before modifying
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set the viewport to be the entire window
glViewport(0, 0, w, h);
// Set the correct perspective.
gluPerspective(45,ratio,1,1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,0.0,70.0,
0.0,0.0,-1.0,
0.0f,1.0f,0.0f);
}
So I am trying to draw the hour marks of a clock using wire cubes of size 2.0, and each of these cubes must be 5.2 units away from the center. This is for an assignment, I know it is probably very simple but I just can't manage to make it work properly. My problem is that the cubes appear in 3D, but I want them to appear in 2D, as in I would only see one face. Also, the circle is not centered, I do not understand why. I know I am supposed to use pushMatrix and popMatrix but no matter how I use it it doesn't work.
3d Problem
gluPerspective makes a perspective projection. To accomplish what you need you should apply an orthographic projection instead.
The best way to do this with your current code is to us glOrtho to provide a left, right, bottom, top, far,near box within which everything will 'appear' 2D. Try the code below in place of gluPerspective.
glOrtho(10.0f,-10.0f,10.0f,-10.0f,10.0f,-10.0f,10.0f);
Position problem
I'm not so sure about the transformation as I've not used immediate mode for a while. Note the order of operations makes a difference.
As for the push/pop of matrices, it is basically a stack of 4x4 matrices detailing the transformations. I'm sure it works along the lines of
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslate(x,y,z);// Where x,y,z is the starting point of your clock
for(int i=0; i<12; i++){
glPushMatrix();
glRotatef(i * 30,0,0,1);
glTranslatef(5.2,0.0,0.0);
glutWireCube(2.0);
glPopMatrix();
}