I need to draw a Polygon iteratively. for example, I want to draw a Polygon with 8 corners. I need to draw the first line with GL_LINES and then draw the second line with the same length and an angle of 135° between them, the third line has also an angle of 135° to the second line, etc.
I want to make a loop to render it but I don't know how. I have an approach, but it doesn't work properly.
the second point of line n-1 should be the first point of n and so on...
At the end, I need to get a closed Polygon. the last point of the last line should be the first point of the first line.
Use GL_LINE_LOOP, that will connect your last vertex to your first automatically:
#include <GL/glut.h>
#include <cmath>
void glPolygon( unsigned int sides )
{
if( sides < 3 ) return;
const float PI = 3.14159;
const float step = ( 2 * PI ) / static_cast< float >( sides );
glBegin( GL_LINE_LOOP );
for( unsigned int i = 0; i < sides; ++i )
{
glVertex2f( cos( i * step ), sin( i * step ) );
}
glEnd();
}
void display()
{
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double ar = glutGet( GLUT_WINDOW_WIDTH ) / (double)glutGet( GLUT_WINDOW_HEIGHT );
glOrtho( -2 * ar, 2 * ar, -2, 2, -1, 1);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glColor3ub( 255, 0, 0 );
glPolygon( 8 );
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "Polygons" );
glutDisplayFunc( display );
glutMainLoop();
return 0;
}
If you're dead-set on GL_LINES this works:
void glPolygonLines( unsigned int sides )
{
if( sides < 3 ) return;
const float PI = 3.14159f;
const float step = ( 2 * PI ) / static_cast< float >( sides );
glBegin( GL_LINES );
for( unsigned int i = 0; i < sides; ++i )
{
unsigned int cur = ( i + 0 ) % sides;
unsigned int nxt = ( i + 1 ) % sides;
glVertex2f( cos( cur * step ), sin( cur * step ) );
glVertex2f( cos( nxt * step ), sin( nxt * step ) );
}
glEnd();
}
Related
In this post the rectangle moved via mouse. I want to add a triangle and move like rectangle via mouse.
The triangle function like this:
void drawTriangle(float x,float y,float size){
glPushMatrix();
glTranslatef( x, y, 0.0f );
glScalef( size, size, 1.0f );
glBegin( GL_TRIANGLES );
glColor3ub( 255, 255, 255 );
glVertex2f( -1, 1 );
glVertex2f( 1, -1 );
glVertex2f( 1, 1 );
glEnd();
glPopMatrix();
Rectangle and triangle moved together. But I want to move it different. So what is my wrong?
You'll have to maintain an array of Shape objects and test each one for mouse collisions, as well as keep track of which Shape you're dragging:
#include <GL/glut.h>
#include <vector>
using namespace std;
struct Shape
{
float mX, mY;
float mSize;
bool mIsRectangle;
bool PointInside( const float x, const float y ) const
{
return
mX - mSize <= x && x <= mX + mSize
&&
mY - mSize <= y && y <= mY + mSize;
}
};
vector< Shape > objects;
Shape* dragging = NULL;
void mouse( int button, int state, int x, int y )
{
if( GLUT_DOWN == state )
{
dragging = NULL;
for( Shape& obj : objects )
{
if( obj.PointInside( x, y ) )
{
dragging = &obj;
glutPostRedisplay();
break;
}
}
}
else
{
dragging = NULL;
}
}
void motion( int x, int y )
{
if( dragging )
{
dragging->mX = x;
dragging->mY = y;
glutPostRedisplay();
}
}
void drawRect( float x, float y, float size )
{
glPushMatrix();
glTranslatef( x, y, 0.0f );
glScalef( size, size, 1.0f );
glBegin( GL_QUADS );
glColor3ub( 255, 255, 255 );
glVertex2f( -1, -1 );
glVertex2f( 1, -1 );
glVertex2f( 1, 1 );
glVertex2f( -1, 1 );
glEnd();
glPopMatrix();
}
void drawTriangle( float x, float y, float size )
{
glPushMatrix();
glTranslatef( x, y, 0.0f );
glScalef( size, size, 1.0f );
glBegin( GL_TRIANGLES );
glColor3ub( 255, 255, 255 );
glVertex2f( -1, 1 );
glVertex2f( 1, -1 );
glVertex2f( 1, 1 );
glEnd();
glPopMatrix();
}
void display()
{
glClearColor( 0, 0, 0, 1 );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
const double w = glutGet( GLUT_WINDOW_WIDTH );
const double h = glutGet( GLUT_WINDOW_HEIGHT );
glOrtho( 0, w, h, 0, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
for( const Shape& obj : objects )
{
if( obj.mIsRectangle )
drawRect( obj.mX, obj.mY, obj.mSize );
else
drawTriangle( obj.mX, obj.mY, obj.mSize );
}
glutSwapBuffers();
}
int main(int argc, char **argv)
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 600, 600 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMouseFunc( mouse );
glutMotionFunc( motion );
Shape temp;
temp.mSize = 50;
temp.mX = temp.mY = 100;
temp.mIsRectangle = true;
objects.push_back( temp );
temp.mX = temp.mY = 200;
temp.mIsRectangle = false;
objects.push_back( temp );
glutMainLoop();
return 0;
}
I am using the following code to implement the "zoom to mouse point" functionality in opengl in c++. Most of the code is from
OpenGL Google maps style 2D camera / zoom to mouse cursor but I had to change some include statements because of changes in the GLM (http://glm.g-truc.net/0.9.5/index.html) codebase.
#include <GL/freeglut.h>
#include <iostream>
using namespace std;
#define GLM_SWIZZLE_XYZW
#define GLM_FORCE_RADIANS
#include "glm/glm.hpp"
#include "glm/detail/setup.hpp"
#include "glm/detail/_swizzle.hpp"
#include "glm/detail/_swizzle_func.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"
glm::dvec3 Unproject( const glm::dvec3& win )
{
glm::ivec4 view;
glm::dmat4 proj, model;
glGetDoublev( GL_MODELVIEW_MATRIX, glm::value_ptr( model ) );
glGetDoublev( GL_PROJECTION_MATRIX, glm::value_ptr( proj ) );
glGetIntegerv( GL_VIEWPORT, glm::value_ptr( view ) );
glm::dvec3 world = glm::unProject( win, model, proj, view );
return world;
}
// unprojects the given window point
// and finds the ray intersection with the Z=0 plane
glm::dvec2 PlaneUnproject( const glm::dvec2& win )
{
glm::dvec3 world1 = Unproject( glm::dvec3( win, 0.01 ) );
glm::dvec3 world2 = Unproject( glm::dvec3( win, 0.99 ) );
// u is a value such that:
// 0 = world1.z + u * ( world2.z - world1.z )
double u = -world1.z / ( world2.z - world1.z );
// clamp u to reasonable values
if( u < 0 ) u = 0;
if( u > 1 ) u = 1;
return glm::swizzle< glm::X, glm::Y >( world1 + u * ( world2 - world1 ) );
}
// pixels per unit
const double ppu = 80.0;
glm::dvec2 center( 0 );
double scale = 1.0;
void ApplyCamera()
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
const double w = glutGet( GLUT_WINDOW_WIDTH ) / ppu;
const double h = glutGet( GLUT_WINDOW_HEIGHT ) / ppu;
glOrtho( -w/2, w/2, -h/2, h/2, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glScaled( scale, scale, 1.0 );
glTranslated( -center[0], -center[1], 0 );
}
glm::dvec2 centerStart( 0 );
int btn = -1;
void mouse( int button, int state, int x, int y )
{
ApplyCamera();
y = glutGet( GLUT_WINDOW_HEIGHT ) - y;
btn = button;
if( GLUT_LEFT_BUTTON == btn && GLUT_DOWN == state )
{
centerStart = PlaneUnproject( glm::dvec2( x, y ) );
}
if( GLUT_LEFT_BUTTON == btn && GLUT_UP == state )
{
btn = -1;
}
glutPostRedisplay();
}
void motion( int x, int y )
{
y = glutGet( GLUT_WINDOW_HEIGHT ) - y;
if( GLUT_LEFT_BUTTON == btn )
{
ApplyCamera();
glm::dvec2 cur = PlaneUnproject( glm::dvec2( x, y ) );
center += ( centerStart - cur );
}
glutPostRedisplay();
}
void wheel( int wheel, int direction, int x, int y )
{
y = glutGet( GLUT_WINDOW_HEIGHT ) - y;
ApplyCamera();
glm::dvec2 beforeZoom = PlaneUnproject( glm::dvec2( x, y ) );
const double scaleFactor = 0.90;
if( direction == -1 ) scale *= scaleFactor;
if( direction == 1 ) scale /= scaleFactor;
ApplyCamera();
glm::dvec2 afterZoom = PlaneUnproject( glm::dvec2( x, y ) );
center += ( beforeZoom - afterZoom );
glutPostRedisplay();
}
void display()
{
glClearColor( 0, 0, 0, 1 );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
ApplyCamera();
glBegin( GL_QUADS );
glVertex2i( -1, -1 );
glVertex2i( 1, -1 );
glVertex2i( 1, 1 );
glVertex2i( -1, 1 );
glEnd();
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 600, 600 );
glutCreateWindow( "GLUT" );
glutMouseFunc( mouse );
glutMotionFunc( motion );
glutMouseWheelFunc( wheel );
glutDisplayFunc( display );
glutMainLoop();
return 0;
}
The errors
error: 'swizzle' is not a member of 'glm'
error: 'X' is not a member of 'glm'
error: 'Y' is not a member of 'glm'
are in line
return glm::swizzle< glm::X, glm::Y >( world1 + u * ( world2 - world1 ) );
I know that glm::swizzle is obviously wrong but glm::detail::_swizzle requires 8 parameters compared to 2 earlier by glm::swizzle. What would be the new parameters be? Also, I don't know how to correct glm::X and glm::Y. Can someone please help?
Actually you don't need swizzling at all in this case since there's a dvec2 constructor that can slice off the z coordinate for you.
Change the last line of PlaneUnproject() from this:
return glm::swizzle< glm::X, glm::Y >( world1 + u * ( world2 - world1 ) );
to this:
return glm::dvec2( world1 + u * ( world2 - world1 ) );
I updated the complete code in my original answer.
Though if you really want to swizzle:
Pare down your #includes:
#define GLM_SWIZZLE
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
And change the last line of PlaneUnproject() from this:
return glm::swizzle< glm::X, glm::Y >( world1 + u * ( world2 - world1 ) );
to this:
return ( world1 + u * ( world2 - world1 ) ).xy();
In newer version of glm if you want swizzle operator you need to define GLM_FORCE_SWIZZLE before including glm. GLM_SWIZZLE is deprecated.
#define GLM_FORCE_SWIZZLE
#include "glm/glm.hpp"
Then you can use it like this:
return world1.yx();
And on some compiler you can also do it like this:
return world1.yx;
Warning: Just be aware that there is a huge performance impact if you enable it.
On Visual Studio 2013 I measure around x150 speed difference in runtime matrix multiplication.
With swizzle operations: 450 000 multiplications per second.
Without swizzle operations: 65 000 000 multiplications per second.
I believe it's pretty straightforward. Under the glm namespace there's no member known as 'swizzle'. Please check these two points :-
Just check if there is a nested namespace and refer it accordingly like glm::detail::swizzle
Else please check if the member name is swizzle or _swizzle.
Thanks!
I am trying to draw the shape shown below (in black) in OpenGL (for desktops, not mobile). I'd prefer it in 3D, but 2D would suffice as well. I will be mapping a texture to it as well. I've used triangle fans/strips for other things in the past and I imagine that's what I'd need to use here but I'm just not sure where to start on it. I've drawn the WHITE part before, but never the inverse (the black part). Any thoughts or guidance on what to use (triangle fan, triangle strip, some other odd OpenGL shape I probably didn't know existed, etc...)
Final Solution:
void draw_arch(GLfloat width, GLfloat height, GLint slices)
{
glPushMatrix();
GLfloat offset = 0.5f;
glScalef(width/2,height/(1+offset),1.0f);
glBegin(GL_QUADS);
for( unsigned int i = 0; i < slices; ++i ) {
float curAngle = ( ( i + 0 ) / (float)slices ) * 3.14159;
float nxtAngle = ( ( i + 1 ) / (float)slices ) * 3.14159;
glVertex2f( cos( curAngle ), sin( curAngle ) );
glVertex2f( cos( curAngle ), 1.0f + offset );
glVertex2f( cos( nxtAngle ), 1.0f + offset );
glVertex2f( cos( nxtAngle ), sin( nxtAngle ) );
}
glEnd();
glPopMatrix();
}
I can adjust the "offset" variable to make different looking arches, however in this application, I choose 0.5 to make it look the way I wanted it to!
Generate the top half of a circle and an offset above it and link the two with quads/triangles:
#include <GL/glut.h>
#include <cmath>
void glShape( const float height, unsigned int segs )
{
glBegin( GL_QUADS );
for( unsigned int i = 0; i < segs; ++i )
{
float curAngle = ( ( i + 0 ) / (float)segs ) * 3.14159;
float nxtAngle = ( ( i + 1 ) / (float)segs ) * 3.14159;
glVertex2f( cos( curAngle ), sin( curAngle ) );
glVertex2f( cos( curAngle ), 1 + height );
glVertex2f( cos( nxtAngle ), 1 + height );
glVertex2f( cos( nxtAngle ), sin( nxtAngle ) );
}
glEnd();
}
void display()
{
glClearColor( 0, 0, 0, 1 );
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
double ar = w / h;
glOrtho( -2 * ar, 2 * ar, -2, 2, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glColor3ub( 255, 0, 0 );
glShape( 0.1f, 20 );
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMainLoop();
return 0;
}
Probably not the minimal number of quads/triangles but it's quick and easy :)
how can drawing small circle in side big circle using algorthim of circle
each circle consist of 9 or 8 point and link each 4point to gather and link this with 4 under and so on
.................................................
........................................................
You need to generate the inner and outer points in one loop.
Give this a shot:
#include <GL/glut.h>
#include <cmath>
void Torus2d( float inner, float outer, unsigned int pts )
{
glBegin( GL_QUAD_STRIP );
for( unsigned int i = 0; i <= pts; ++i )
{
float angle = ( i / (float)pts ) * 3.14159f * 2.0f;
glVertex2f( inner * cos( angle ), inner * sin( angle ) );
glVertex2f( outer * cos( angle ), outer * sin( angle ) );
}
glEnd();
}
void display()
{
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
double ar = w / h;
glOrtho( -4 * ar, 4 * ar, -4, 4, -1, 1);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glColor3ub( 255, 0, 0 );
Torus2d( 2, 3, 20 );
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMainLoop();
return 0;
}
Find below a faster (less trigono) solution in Go (can be easily translated to c++) which was inspired by Sieglord's Abode article
func Torus(cx, cy, inner, outer float64, num_segments int) {
theta := 2 * math.Pi / float64(num_segments)
c := math.Cos(theta) //precalculate the sine and cosine
s := math.Sin(theta)
t_in := 0.0
t_out := 0.0
x_in := inner //we start at angle = 0
x_out := outer //we start at angle = 0
y_in := 0.0
y_out := 0.0
gl.Begin(gl.QUAD_STRIP)
for ii := 0; ii <= num_segments; ii++ {
gl.Vertex2f(float32(x_in+cx), float32(y_in+cy)) //output vertex inner
gl.Vertex2f(float32(x_out+cx), float32(y_out+cy)) //output vertex outer
//apply the rotation matrix
t_in = x_in
t_out = x_out
x_in = c*x_in - s*y_in
x_out = c*x_out - s*y_out
y_in = s*t_in + c*y_in
y_out = s*t_out + c*y_out
}
gl.End()
}
I've seen a similar post about this subject here, however, my question is a little bit different.
I have a 2D plot which will be comprised of circles at varying locations with varying sizes. Currently, my rendering scheme uses a display list to store a pre-drawn circle which can be actively re-sized and translated by the user using glScalef/glTranslatef. However, because I am rendering thousands of circles, the resize and drawing becomes extremely slow. Each circle can have a different radius and color so these things must be done within the loop.
What would be some things I could try to improve the speed of circle rendering when the user changes say the size of the circles? I've looked into VBO like the above link says but it was ambiguous to how much of a performance gain I would receive for this type of application where my object is constantly changing in size.
because I am rendering thousands of circles, the resize and drawing becomes extremely slow
With just vertex arrays this is getting about 60ms per frame on an Intel HD Graphics 3000 with 10,000 circles:
// g++ -O3 circles.cpp -o circles -lglut -lGL
#include <GL/glut.h>
#include <vector>
#include <iostream>
#include <cmath>
using namespace std;
// returns a GL_TRIANGLE_FAN-able buffer containing a unit circle
vector< float > glCircle( unsigned int subdivs = 20 )
{
vector< float > buf;
buf.push_back( 0 );
buf.push_back( 0 );
for( unsigned int i = 0; i <= subdivs; ++i )
{
float angle = i * ((2.0f * 3.14159f) / subdivs);
buf.push_back( cos(angle) );
buf.push_back( sin(angle) );
}
return buf;
}
struct Circle
{
Circle()
{
x = ( rand() % 200 ) - 100;
y = ( rand() % 200 ) - 100;
scale = ( rand() % 10 ) + 4;
r = rand() % 255;
g = rand() % 255;
b = rand() % 255;
a = 1;
}
float x, y;
float scale;
unsigned char r, g, b, a;
};
vector< Circle > circles;
vector< float > circleGeom;
void init()
{
srand( 0 );
for( size_t i = 0; i < 10000; ++i )
circles.push_back( Circle() );
circleGeom = glCircle( 100 );
}
void display()
{
int beg = glutGet( GLUT_ELAPSED_TIME );
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
double ar = w / h;
glOrtho( -100 * ar, 100 * ar, -100, 100, -1, 1);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 2, GL_FLOAT, 0, &circleGeom[0] );
for( size_t i = 0; i < circles.size(); ++i )
{
Circle& c = circles[i];
c.scale = ( rand() % 10 ) + 4;
glPushMatrix();
glTranslatef( c.x, c.y, 0 );
glScalef( c.scale, c.scale, 0 );
glColor3ub( c.r, c.g, c.b );
glDrawArrays( GL_TRIANGLE_FAN, 0, circleGeom.size() / 2 );
glPopMatrix();
}
glDisableClientState( GL_VERTEX_ARRAY );
glutSwapBuffers();
int end = glutGet( GLUT_ELAPSED_TIME );
double elapsed = (double)( end - beg );
cout << elapsed << "ms" << endl;
}
void timer(int extra)
{
glutPostRedisplay();
glutTimerFunc(16, timer, 0);
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 600, 600 );
glutCreateWindow( "Circles" );
init();
glutDisplayFunc( display );
glutTimerFunc(0, timer, 0);
glutMainLoop();
return 0;
}
ARB_instanced_arrays-based instancing would probably be the cleanest.
You'll have a single circle with M vertices you'll draw N times, storing your per-circle x/y position, radius, and color as vertex attributes and using glVertexAttribDivisor() appropriately.
Gets trickier if you want radius-adaptive LOD. You'll probably have to dig into geometry shaders for that.
Second using instanced arrays with glDrawElementsInstanced or glDrawArraysInstanced as a clean solution that transfers well to other types of geometry.
If you want/need to stick to OpenGL 2 (eg has to run on an iThing for example) and you only need circles, also consider point sprites. Origin of each circle is the point vertex value. Store the radius as the S value of a texture coordinate, the X value of a surface normal, whatever. Enable blending, GL_PROGRAM_POINT_SIZE, maybe point smoothing; and write a vertex shader which just sets gl_PointSize to the radius you want. Instant circles.