This semester, I am taking a Computer Graphics course at school, and our first assignment is to create a concave/convex illusion.
This is an example of what I am supposed to create:
Concave/Convex Circle Illusion
I've tried to work this problem out myself, however I keep getting stuck. I know how to create the gray background, and I know how to create a circle. What I dont know how to do is to make the circle look like the picture. I know how to fill it with a solid color, I just dont know how to fill it with multiple colors and fade it like in the picture.
So here is my C++ code which we run in Visual Studio 15.
#include <cstdlib>
#include <glut.h>
#include <math.h>
const double p = 3.14159/180;
void circle(float r){
glColor3f(1.0,0.0,0.0);
glBegin(GL_LINE_LOOP);
for (int i=100; i <= 460; i++){
double degree = p*i;
double x = cos(degree) * r;
double y = sin(degree) * r;
glVertex2d(x,y);
}
glEnd();
}
/*
//This circle function was my attempt at creating the illusion shown in the picture above.
//I tried to break up the circle into separate pieces and make them each a different color,
//but unfortunately it didnt come out like the picture above.
void circle (float radius){
glColor3f(0.0,0.0,0.0); // black
glBegin(GL_POLYGON);
glVertex2i(21,21);
glVertex2i(25,19);
glVertex2i(28,17);
glVertex2i(32,16);
glVertex2i(36,17);
glVertex2i(40,19);
glVertex2i(43,21);
glEnd();
glColor3f(0.329412,0.329412,0.329412); // dim grey
glBegin(GL_POLYGON);
glVertex2i(21,21);
glVertex2i(19,25);
glVertex2i(17,30);
glVertex2i(48,30);
glVertex2i(46,25);
glVertex2i(43,21);
glEnd();
glColor3f(0.752941,0.752941,0.752941); // grey
glBegin(GL_POLYGON);
glVertex2i(17,30);
glVertex2i(16,35);
glVertex2i(15,40);
glVertex2i(50,40);
glVertex2i(49,35);
glVertex2i(48,30);
glEnd();
glColor3f(0.650024,0.650024,0.650024); // light grey
glBegin(GL_POLYGON);
glVertex2i(15,40);
glVertex2i(16,45);
glVertex2i(17,50);
glVertex2i(48,50);
glVertex2i(49,45);
glVertex2i(50,40);
glEnd();
glColor3f(0.8,0.8,0.8); // very light grey
glBegin(GL_POLYGON);
glVertex2i(17,50);
glVertex2i(20,55);
glVertex2i(45,55);
glVertex2i(48,50);
glEnd();
glColor3f(1.0,1.0,1.0); // white
glBegin(GL_POLYGON);
glVertex2i(20,55);
glVertex2i(23,58);
glVertex2i(25,60);
glVertex2i(28,62);
glVertex2i(32,63);
glVertex2i(36,62);
glVertex2i(40,60);
glVertex2i(43,58);
glVertex2i(45,55);
glEnd();
}
*/
void display(void){
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.658824,0.658824,0.658824);
glBegin(GL_POLYGON); //Creates the gray background
glVertex2i(10,10);
glVertex2i(390, 10);
glVertex2i(390,290);
glVertex2i(10,290);
glEnd();
circle(30);
glFlush();
}
void main(int argc, char** argv){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(400, 300);
glutInitWindowPosition(200,100);
glutCreateWindow("Project 1");
glClearColor(0.0,0.0,0.0,0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,400.0,0.0,300.0);
glutDisplayFunc(display);
glutMainLoop();
}
So Ive got the majority of the code down, I just cant figure out the coloring of the circle.
Any advice/help that can make the outcome of my code look like the example picture above would be greatly appreciated.
Thanks!
Drawing by glBegin/glEnd sequences is deprecated since several years.
Read about Fixed Function Pipeline and see Vertex Specification and Shader for a state of the art way of rendering.
But, the effect of the picture is achieved by a simple gray color gradient. The background is gray and inside the circle is a linear color gradient from white to black.
glClear, clear the framebuffer by the color which is set by glClearColor.
Set a gray clear color to create a gray background:
glClearColor( 0.5f, 0.5f, 0.5f, 1.0f );
glClear(GL_COLOR_BUFFER_BIT);
To create a color gradient, you have to set the color attribute by glColor3d, before you set the vertex coordinate by glVertex2d. The color is interpolated between the vertices. Use the primitive type GL_TRIANGLE_FAN to create a filled polygon:
const double p = 3.14159/180;
void circle(float r, bool flip ){
glBegin(GL_TRIANGLE_FAN);
glColor3d( 0.5, 0.5, 0.5 );
glVertex2d( 0.0, 0.0 );
for (int i=0; i <= 360; i++)
{
double degree = p*i;
double c = cos( degree );
double s = sin( degree );
double col = s * 0.5 + 0.5;
if ( flip )
col = 1.0 - col;
glColor3d( col, col, col );
glVertex2d( c*r, s*r );
}
glEnd();
}
The draw function may look like this:
void display(void){
glClearColor( 0.5f, 0.5f, 0.5f, 1.0f );
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
for ( int x = 0; x < 2; ++ x )
{
for ( int y = 0; y < 2; ++ y)
{
glPushMatrix();
glTranslated( 120.0 + 160.0*x, 100.0+100*y, 0.0f );
circle(30, x > 0);
glPopMatrix();
}
}
glFlush();
}
Preview:
Related
I want to draw tow circles with the same radii but exclude the overlapped area when drawing.
I want to draw or set dots on gray area.
I implement the mathematical aspect behind it and here is my code:
void draw_venn(){
float radian_to_degree_theta=2 * 3.14 / 360,
r = 0.5,
distance=0.3,
theta=0.0,
theta2=0.0,
xR=0.0,
yR=0.0,
xG=0.0,
yG=0.0,
sum_radii=0,
dis=0.0;
sum_radii=r+r;
for (r = 0.5; r >=0; r-=0.001)
{
for (float degree = 0; degree < 361; degree+=0.1)
{
theta =degree*radian_to_degree_theta;
xR=r*cos(theta)+distance;
yR=r*sin(theta);
xG=r*cos(theta)-distance;
yG=r*sin(theta);
dis=sqrt(pow(xR-xG,2) + pow(yR-yG,2));
if (dis <= sum_radii)
{
set_point(xR,yR,0.1,1,0,0);
set_point(xG,yG,0.1,0,1,0);
}
}
}
}
void set_point(float x,float y,float size,float R,float G,float B){
glPointSize(size);
glBegin (GL_POINTS);
glColor3f (R, G, B);
glVertex2f(x, y);
glEnd ();
}
void draw(void)
{
glClearColor (1, 1, 1, 0);
glClear (GL_COLOR_BUFFER_BIT);
glPushMatrix();
draw_ven();
glPopMatrix ();
glFlush();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE);
glutInitWindowSize(1400, 1400);
glutInitWindowPosition(700, 500);
glutCreateWindow("GL Sample");
glutDisplayFunc(draw);
glutMainLoop();
return 0;
}
and here is the result:
How can I find if a point is inside the overlapping area?
I reviewed and tested out your code. Trigonometry can get a bit tricky. Following is the "draw_venn" function with some refinements to produce an overlap effect.
void draw_venn()
{
float radian_to_degree_theta=2 * 3.141 / 360,
r = 0.5,
distance=0.3,
theta=0.0,
theta2 = 0.0,
xR=0.0,
yR=0.0,
xG=0.0,
yG=0.0,
dis=0.0;
glPointSize(1);
glColor3f(1,0,0);
glBegin(GL_POINTS);
for (r = 0.5; r >=0; r-=0.001)
{
for (float degree = 0; degree < 361; degree+=0.1)
{
theta =degree*radian_to_degree_theta;
theta2 = (180.0 - degree) * radian_to_degree_theta;
xR=r*cos(theta2)+distance;
yR=r*sin(theta2);
xG=r*cos(theta)-distance;
yG=r*sin(theta);
dis = sqrt(pow((distance - xG), 2) + pow(yG, 2));
if (dis < 0.5)
{
set_point(xR,yR,0.1,0,0,1); /* Color the overlap blue */
set_point(xG,yG,0.1,0,0,1); /* This works due to symmetry */
}
else
{
set_point(xR,yR,0.1,1,0,0); /* Set the symmetrical circle colors */
set_point(xG,yG,0.1,0,1,0);
}
}
}
glEnd();
}
Pointing out the two significant revisions, first I derive a mirror image value for "theta" and place that into variable "theta2". That is used to draw the red circle. This assures that the circle images are being built in equal but opposite directions so that the coordinates are symmetrical. Second, I revised the formula for checking if the green image coordinates fall within the red circle's outermost radius. Using the Pythagorean theorem calculation for the hypotenuse, the formula determines if the hypotenuse value is smaller than the outermost radius length (0.5). If it is smaller make that point for the green circle blue, and since the circle points are being built and colored symmetrically, also make the corresponding point for the red circle blue.
The result of those revisions is a Venn Diagram showing an overlap.
I hope that helps and gives you a springboard to proceed.
Regards.
Add 8bit Stencil Buffer to your context
I do it by setting up pixelformat like this:
PIXELFORMATDESCRIPTOR pfd;
ZeroMemory( &pfd, sizeof( pfd ) ); // set the pixel format for the DC
pfd.nSize = sizeof( pfd );
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
SetPixelFormat(hdc,ChoosePixelFormat(hdc, &pfd),&pfd);
Enable and Clear Stencil with 0 and setup it for incrementation
Disable color and depth output
Render circles
Enable color and depth output
Set up Stencil test to not equal 2
You can also use equal to 1 in case you overlap more than just 2 objects
Render circles
Disable Stencil test
I see it like this:
//---------------------------------------------------------------------------
void glCircle(float x,float y,float r)
{
int e;
float a,da=2.0*M_PI/72.0;
glBegin(GL_TRIANGLE_FAN);
glVertex2f(x,y);
for (e=1,a=0.0;e;a+=da)
{
if (a>=2.0*M_PI) { e=0; a=0.0; }
glVertex2f(x+(r*sin(a)),y+(r*cos(a)));
}
glEnd();
}
//---------------------------------------------------------------------------
void gl_draw()
{
glClearColor(1.0,1.0,1.0,1.0);
glClear(GL_COLOR_BUFFER_BIT);
float aspect=float(xs)/float(ys); //xs,ys is screen resolution
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glScalef(1.0,aspect,1.0);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
// turn off color,depth
glStencilMask(0xFF);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
// clear stencil and setup it for increment
glEnable(GL_STENCIL_TEST);
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
glStencilFunc(GL_ALWAYS,1,0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
// render stencil
glCircle(-0.3,0.0,0.6);
glCircle(+0.3,0.0,0.6);
// turn on color,depth
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
// render screen (where Stencil is not 2)
glStencilFunc(GL_NOTEQUAL,2,0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glColor3f(1.0,0.0,0.0); glCircle(-0.3,0.0,0.6);
glColor3f(0.0,1.0,0.0); glCircle(+0.3,0.0,0.6);
glDisable(GL_STENCIL_TEST);
glFlush();
SwapBuffers(hdc);
}
//---------------------------------------------------------------------------
And output:
In case you also want to know if pixel is inside both circles you can use:
GLint a;
glReadPixels(X,ys-1-Y,1,1,GL_STENCIL_INDEX,GL_INT,&a);
if (a==2); // X,Y is inside both circles
else; // X,Y is not inside both circles
In case You insist on rendering the stuff pixel by pixel then do it at least properly As your current approach is horibly slow for many reasons... For example you can do this like this:
glClearColor(1.0,1.0,1.0,1.0);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glTranslatef(-1.0,-1.0,0.0);
glScalef(2.0/xs,2.0/ys,1.0);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
int x0=(4*xs)/10,y0=ys/2,r0=xs/4; // circle0
int x1=(6*xs)/10,y1=ys/2,r1=xs/4; // circle1
int x,y,xx0,xx1,yy0,yy1,rr0=r0*r0,rr1=r1*r1;
glBegin(GL_POINTS);
glColor3f(1.0,0.0,0.0);
for (x=-r0;x<=r0;x++){ xx0=x; xx0*=xx0; xx1=x+x0-x1; xx1*=xx1;
for (y=-r0;y<=r0;y++){ yy0=y; yy0*=yy0; yy1=y+y0-y1; yy1*=yy1;
if (xx0+yy0<=rr0)
if (xx1+yy1>=rr1)
glVertex2i(x0+x,y0+y); }}
glColor3f(0.0,1.0,0.0);
for (x=-r1;x<=r1;x++){ xx1=x; xx1*=xx1; xx0=x+x1-x0; xx0*=xx0;
for (y=-r1;y<=r1;y++){ yy1=y; yy1*=yy1; yy0=y+y1-y0; yy0*=yy0;
if (xx1+yy1<=rr1)
if (xx0+yy0>=rr0)
glVertex2i(x1+x,y1+y); }}
glEnd();
glFlush();
SwapBuffers(hdc);
Where xs,ys is GL screen resolution.
See related:
I have an OpenGL Tessellated Sphere and I want to cut a cylindrical hole in it
OpenGL 3D-raypicking with high poly meshes
Is there a more efficient way of texturing a circle?
I am trying to draw two 2D diamonds facing each other.
So I drew the first diamond then I drew the second diamond after using:
glTranslated(0, -150, 0);
so it can appear exactly under my first diamond .
However, I ran into a problem that I couldn't flip the second diamond so it could look like a mirror.
Here is what i am trying to do:
I searched online for solutions and they all mentioned that I should
use
glScalef(1.0f,-1.0f,1.0f);
but each time I use it the drawing disappears.
The function
glRotatef(angle,x,y,z);
caught my attention but i couldn't use it properly resulting in wrong direction.
Here is how my image looks like right now without glRotate():
So I think I need the proper technique to use any of these functions.
Note: I am using many line loops and vertices to draw.
#include <windows.h> // For MS Windows
#include <GL/glut.h> // (or others, depending on the system in use)
void init(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0); // Set display-window color to
white.
glMatrixMode(GL_PROJECTION); // Set projection parameters.
gluOrtho2D(0.0, 400.0, 0.0, 400.0);
}
void drawDiamond()
{
glBegin(GL_LINE_LOOP);
glVertex2f(125, 350);
glVertex2f(245, 350);
glVertex2f(290, 300);
glVertex2f(182, 200);
glVertex2f(75, 300);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2f(109, 333);
glVertex2f(138, 350);
glVertex2f(159, 337);
glVertex2f(123, 300);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2f(109, 333);
glVertex2f(123, 300);
glVertex2f(154, 225);
glVertex2f(92, 300);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2f(290, 300);
glVertex2f(75, 300);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2f(123, 300);
glVertex2f(159, 337);
glVertex2f(154, 300);
glVertex2f(171, 225);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2f(181, 300);
glVertex2f(159, 337);
glVertex2f(181, 350);
glVertex2f(209, 337);
glVertex2f(181, 300);
glVertex2f(171, 225);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2f(181, 300);
glVertex2f(209, 337);
glVertex2f(219, 300);
glVertex2f(195, 225);
glVertex2f(181, 300);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2f(209, 337);
glVertex2f(243, 300);
glVertex2f(195, 225);
glVertex2f(219, 300);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2f(209, 337);
glVertex2f(229, 350);
glVertex2f(260, 333);
glVertex2f(243, 300);
glVertex2f(209, 337);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2f(260, 333);
glVertex2f(278, 300);
glVertex2f(210, 225);
glVertex2f(243, 300);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2f(195, 225);
glVertex2f(182, 200);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2f(171, 225);
glVertex2f(182, 200);
glEnd();
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT); // Clear display window.
glColor3f(0.0, 0.0, 0.0); // Set line segment color to blue.
// your code goes here
drawDiamond();
glTranslatef(0.0f, -150, 0.0f);
drawDiamond();
glFlush(); // Process all OpenGL routines as quickly as possible.
}
void main(int argc, char** argv)
{
glutInit(&argc, argv); // Initialize GLUT.
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // Set display mode.
glutInitWindowPosition(50, 100); // Set top-left display-window
position.
glutInitWindowSize(400, 400); // Set display-window width and
height.
glutCreateWindow("Diamond Project"); // Create display window.
init(); // Execute initialization procedure.
glutDisplayFunc(display); // Send graphics to display window.
glutMainLoop(); // Display everything and wait.
}
What you want to do is to mirror (flip) the object around an axis, which is parallel to the X-axis, and goes through the bottom bounding of the object (diamond).
To do so, the bottom Y coordinate (bottomY) has to be found and the object has to be translated in the opposite direction. Note the bottom of the model coordinates (vertices) and not the bottom of final coordinates on the viewport:
float bottomY = 200.0f;
glTranslatef( 0.0f, -bottomY , 0.0f );
At next the object has to be flipped. This can either be done by
glRotatef(180.0f, 1.0f, 0.0f, 0.0f);
or by
glScalef(1.0f, -1.0f, 0.0f)
Note, both operations result in the same transformation matrix, because cos(90°) = cos(-90°), sin(90°) = -sin(90°).
Then the bottomY translation has to be reversed:
glTranslatef( 0.0f, bottomY, 0.0f );
But note that the OpenGL fixed function pipeline stack operates in the the reverse order, because the current matrix is multiplied by the matrix which is specified by the new operation.
Translation: See the documentation of glTranslate:
glTranslate produces a translation by x y z . The current matrix (see glMatrixMode) is multiplied by this translation matrix, with the product replacing the current matrix.
Rotation: See the documentation of glRotate:
glRotate produces a rotation of angle degrees around the vector x y z . The current matrix (see glMatrixMode) is multiplied by a rotation matrix with the product replacing the current matrix.
Scaling: See the documentation of glScale:
glScaleproduces a nonuniform scaling along the x, y, and z axes. The three parameters indicate the desired scale factor along each of the three axes.
The current matrix (see glMatrixMode) is multiplied by this scale matrix.
This means the the following should do what you want:
float bottomY = 200.0f;
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
drawDiamond();
glTranslatef( 0.0f, bottomY , 0.0f );
glRotatef( 180.0f, 1.0f, 0.0f, 0.0f );
glTranslatef( 0.0f, -bottomY , 0.0f );
drawDiamond();
and is the same as:
glTranslatef( 0.0f, bottomY , 0.0f );
glScalef( 1.0f, -1.0f, 1.0f );
glTranslatef( 0.0f, -bottomY , 0.0f );
Depending on how your vertices are setup and depending on if you have Back Face Culling enabled you might have to change your diamond or (model's) center point to be the bottom tip from there you can then simply rotate about the X axis provided that you declared that as the Horizontal Axis. To do so shouldn't be all that hard. It would look something like:
glRotatef( 180.0f, 1, 0, 0 );
provided you are rotating in degrees as opposed to radians.
For each vertex (I'm assuming that you use immediate mode for designating vertices), you can glVertex2i(myVertex.x, symmetryLine - myVertex.y, 0) where myVertex are the x and y values you previously used, and symmetryLine the value you wish to mirror against. Best way would be to use a negative glScale though. Your diamond is rotationally symmetric glRotate also works but you know, not a very elegant way to do it.
I am a beginner in OpenGl and I am struggling a bit with setting up the glOrtho camera to match the window size so that I can draw a line using the window's coordinates. For example, if I want to draw a line from coordinates 0,10 (x,y) to 600,10. I managed to draw the line (which will be a "Separator" from the viewport and a toolbar with buttons) in my current set up but it was by "try end error" approach and the coordinates that I needed to put don't make any sense to me. When I tried to draw a line using the above-mentioned coordinates, the line simply did not show up. What I need to change in the glOrtho set up in order to work with these (1000x600) screen size and draw my vertices and not these:
glVertex3f(-2.0, 11.0, 0.0);
glVertex3f(20.0, 11.0, 0.0);
Note, my current window size is 1000x600 (width/height)
This is the line (on the top that crosses the whole screen):
This is my OGWindow class that handles all of the drawing:
void OGWindow::MyReSizeGLScene(int fwidth, int fheight)
{
// Store window size in class variables so it can be accessed in myDrawGLScene() if necessary
wWidth = fwidth;
wHeight = fheight;
// Calculate aspect ration of the OpenGL window
aspect_ratio = (float) fwidth / fheight;
// Set camera so it can see a square area of space running from 0 to 10
// in both X and Y directions, plus a bit of space around it.
Ymin = -1;
Ymax = 12;
Xmin = -1;
// Choose Xmax so that the aspect ration of the projection
// = the aspect ratio of the viewport
Xmax = (aspect_ratio * (Ymax -Ymin)) + Xmin;
glMatrixMode(GL_PROJECTION); // Select The Projection Stack
glLoadIdentity();
glOrtho(Xmin, Xmax, Ymin, Ymax, -1.0, 1.0);
glViewport(0, 0, wWidth, wHeight); // Viewport fills the window
}
void OGWindow::myDrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the drawing area
OGWindow::myDrawModel();
drawToolbar();
glutSwapBuffers(); // Needed if we're running an animation
glFlush();
}
void OGWindow::myDrawModel(GLvoid)
{
switch ( squareColour ) {
case RED:
glColor3f(1.0, 0.0, 0.0);
break;
case BLUE:
glColor3f(0.0, 0.0, 1.0);
break;
}
glBegin( GL_QUADS );
glVertex3f( squareX, squareY, 0.0 ); // Coordinates of bottom-left corner of square
glVertex3f( squareX + squareWidth, squareY, 0.0 );
glVertex3f( squareX + squareWidth, squareY + squareHeight, 0.0 );
glVertex3f( squareX, squareY + squareHeight, 0.0 );
glEnd();
}
// Convert from screen coords returned by mouse
// to world coordinates.
// Return result in worldX, worldY
void OGWindow::screen2World(int screenX, int screenY, double & worldX, double & worldY)
{
// Dimensions of rectangle viewed by camera projection
double projWidth = Xmax -Xmin;
double projHeight = Ymax - Ymin;
// Screen coords with origin at bottom left
int screenLeft = screenX;
int screenUp = wHeight - screenY;
worldX = Xmin + screenLeft * projWidth / wWidth ;
worldY = Ymin + screenUp * projHeight / wHeight ;
}
//Method to draw the toolbar separator line
void OGWindow::drawToolbar(GLvoid) {
//draw toolbar line separator
glColor3f(0.0,0.0,0.0);
glBegin(GL_LINES);
glVertex3f(-2.0, 11.0, 0.0);
glVertex3f(20.0, 11.0, 0.0);
glEnd();
//draw create button
glPushMatrix();
glTranslatef(2.0, 10.0, 0.0);
glutSolidCube(2.0);
glPopMatrix();
}
This is my main class where I am ivoking the methods from OGWindow:
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize( 1000, 600 );
glutInitWindowPosition(0, 0);
glutCreateWindow("OpenGL Demo");
glEnable(GL_DEPTH_TEST); // enable the depth buffer test
glutDisplayFunc(DrawGLScene);
glutReshapeFunc(ReSizeGLScene);
glutMouseFunc(mouseClick);
glutMotionFunc(mouseMotion);
glutPassiveMotionFunc(mousePassiveMotion);
glutIdleFunc(Idle);
theWindow.initGL();
glutMainLoop();
}
Check out the documentation of glOrtho function. As you see, there are 6 parameters: left, right, bottom, top, near, far. You made mistake by setting window width to top instead of bottom parameter. Here's proper use of function:
glOrtho (0, 1000, 600, 0, -1.0, 1.0)
So, first your ortho settings. If you want your camera to match the screen dimensions, glOrtho has to use the same dimensions.
// This will anchor the camera to the center of the screen
// Camera will be centered on (0,0)
glOrtho( -screenWidth/2.f, screenWidth/2.f, -screenHeight/2.f, screenHeight/2.f, -1, 1 );
// This will anchor the camera to the lower left corner of the screen
// Camera will be centered on (screenWidth/2, screenHeight/2)
glOrtho( 0, screenWidth, 0, screenHeight, -1, 1 );
Try both and see the difference. Although if you are making some sort of editor, where your camera doesn't move, you may be looking for the second ortho setup.
Second, you only ever use (apparently) the GL_PROJECTION matrix mode. You must use this mode to set the camera projection and GL_MODELVIEW to apply transforms to the camera or the objects.
So when you call resize and don't change the matrix mode back to GL_MODELVIEW, you'll be applying translations to the projection matrix.
If you did forget to initialize the modelview matrix it may contain garbage values and yield unexpected results.
In OpenGL's fixed pipeline, by default, specifying vertex coordinates using glVertex3f is equivalent to specifying a location between -1.0 and +1.0 in screen space. Therefore, given a set of 4 perfectly adjacent screen-space vertices using GL_TRIANGLE_STRIP (or even GL_QUADS), and unless your window is already perfectly square, you will always render a rectangle instead of a perfect square...
Knowing the width, height and aspect ratio of a window, is there some way to correct this?
I have tried multiplying the vertex coordinates by the aspect ratio, which unfortunately seemed to achieve the same visual effect.
Here's the full source code I'm currently using:
#include "main.h"
#pragma comment(lib, "glut32.lib")
int g_width = 800;
int g_height = 600;
int g_aspectRatio = double(g_width) / double(g_height);
bool g_bInitialized = false;
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(0, 0);
glutInitWindowSize(g_width, g_height);
glutCreateWindow("OpenGL Test App");
glutDisplayFunc(onRender);
glutReshapeFunc(onSize);
glutIdleFunc(onRender);
glutMainLoop();
return 0;
}
void onInit()
{
glFrontFace(GL_CW);
}
void onRender()
{
if(!g_bInitialized)
onInit();
static float angle = 0.0f;
const float p = 0.5f * g_aspectRatio;
glLoadIdentity();
gluLookAt(
0.0f, 0.0f, 10.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f
);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glScalef(1, -1, 1); // Flip the Y-axis
glRotatef(angle, 0.0f, 1.0f, 0.0f);
glBegin(GL_TRIANGLE_STRIP);
{
glColor4f(1.0, 0.0, 0.0, 1.0); // Red
glVertex3f(-p, -p, 0.0); // Top-Left
glColor4f(0.0, 1.0, 0.0, 1.0); // Green
glVertex3f(p, -p, 0.0); // Top-Right
glColor4f(0.0, 0.0, 1.0, 1.0); // Blue
glVertex3f(-p, p, 0.0); // Bottom-Left
glColor4f(1.0, 1.0, 0.0, 1.0); // Yellow
glVertex3f(p, p, 0.0); // Bottom-Left
}
glEnd();
angle += 0.6f;
glutSwapBuffers();
}
void onSize(int w, int h)
{
g_width = max(w, 1);
g_height = max(h, 1);
g_aspectRatio = double(g_width) / double(g_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h);
gluPerspective(45, g_aspectRatio, 1, 1000);
glMatrixMode(GL_MODELVIEW);
}
EDIT:
This has been solved... In the above code, I had defined g_aspectRatio as an int instead of a floating-point value. Therefore, it's value was always 1...
In my (old) experience, that's just why you have an aspect ratio argument to gluPerspective().
The manual page says:
In general, the aspect ratio in gluPerspective should match
the aspect ratio of the associated viewport. For example, aspect = 2.0
means the viewer's angle of view is twice as wide in x as it is in y.
If the viewport is twice as wide as it is tall, it displays the image
without distortion.
Check your g_aspectRatio value.
by default, specifying vertex coordinates using glVertex3f is equivalent to specifying a location between -1.0 and +1.0 in screen space
Wrong. Coordinates passed to OpenGL through glVertex or a glVertexPointer vertex array are in model space. The transformation to screen space happens by transforming into view space by the modelview matrix and from view space to clip space by the projection matrix. Then clipping is applied and the perspective divide applied to reach normalized coordinate space.
Hence the value range for glVertex can be whatever you like it to be. By applying the right projection matrix you get your view space to be in [-aspect; aspect]×[-1, 1] if you like that.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-aspect, aspect, -1, 1, -1, 1);
I have a code where I want to draw a bowl and two cones at a time.
But, it is showing only those cones, not showing the ball.
#include <GL/glut.h>
#include <stdlib.h>
#include <Math.h> // Needed for sin, cos
#define PI 3.14159265f
GLfloat ballRadius = 0.5f; // Radius of the bouncing ball
GLfloat ballX = 0.0f; // Ball's center (x, y) position
GLfloat ballY = 0.0f;
GLfloat ballXMax, ballXMin, ballYMax, ballYMin; // Ball's center (x, y) bounds
GLfloat xSpeed = 0.02f; // Ball's speed in x and y directions
GLfloat ySpeed = 0.007f;
int refreshMillis = 30; // Refresh period in milliseconds
static void resize(int width, int height)
{
const float ar = (float) width / (float) height;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
}
static void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// This is ball's code that is not being drawn.
***glTranslatef(ballX, ballY, 0.0f); // Translate to (xPos, yPos)
// Use triangular segments to form a circle
glBegin(GL_TRIANGLE_FAN);
glColor3f(1.0f, 0.0f, 0.0f); // Blue
glVertex2f(0.0f, 0.0f); // Center of circle
int numSegments = 100;
GLfloat angle;
for (int i = 0; i <= numSegments; i++) { // Last vertex same as first vertex
angle = i * 2.0f * PI / numSegments; // 360 deg for all segments
glVertex2f(cos(angle) * ballRadius, sin(angle) * ballRadius);
}
glEnd();***
//End of ball code
glColor3d(0,1,0);
glPushMatrix();
glTranslated(-1.0,0.5,-6);
glRotated(65, -1.0, 0.0, 0.0);
glutSolidCone(1, 2, 70, 50);
glPopMatrix();
glPushMatrix();
glTranslated(0.0,-1.5,-6);
glRotated(65, -1.0, 3.0, 0.0);
glutWireCone(1,2, 16, 16);
glPopMatrix();
glutSwapBuffers();
}
/* Program entry point */
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(740,580);
glutInitWindowPosition(10,10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Programming Techniques - 3D Cones");
glutReshapeFunc(resize);
glutDisplayFunc(display);
glClearColor(1,1,1,1);
glutMainLoop();
return EXIT_SUCCESS;
}
The reason you don't see the circle is that it's clipped against the near plane. With glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0); you specify that the near plane is at z = -2, and the far plane at z = -100. Anything outside these values are clipped. But by using glVertex2, your z values for the circle vertices are 0, so all of them are clipped. You can fix it by calling glTranslatef(ballX, ballY, -10.0f); instead.
A couple more pointers:
Always reset the matrix mode to GL_MODELVIEW (e.g. in your resize() function). You don't have to, but it's a good convention.
Always glPush/PopMatrix() before modifying the matrix stack (e.g. when translating the circle).
glColor3f(1.0f, 0.0f, 0.0f); // Blue? ;)