I'm trying to draw triangle in C using opengl but without standard opengl functions for drawing triangles and lines. (I use ubuntu.)
I used Bresenham line drawing algoritm. I suppose, that the code of this algorithm itself is fine, because it draws tringle but it look like on following picture.
And I need to make it look like this
In the line drawing algorithm I draw the line pixel by pixel using following function:
void setPixel(int x, int y) {
glBegin(GL_POINTS);
glVertex2i(x,y);
glEnd();
glFlush();
}
Could you help me with the following? :
Why aren't the lines smooth?
Why is there a space between pixels?
Why aren't the lines thinner?
You may want to change point size with
glPointSize(1.0f); // or similar value
before glBegin call.
As stated by #Nemanja Boric, points aren't simple pixels.
One does usually draw such squares using glBegin(GL_QUADS), since the point size is limited.
If this is not a line drawing exercise, use glBegin(GL_LINE_LOOP);
glEnable(GL_LINE_SMOOTH); for smooth lines
glLineWidth(); to adjust the line width. However, with GL_LINE_SMOOTH enabled, the line looks thinner because of antialiasing.
First of all, do not use point primitives to represent pixels. If you have anti-aliasing enabled (GL_MULTISAMPLE or the older GL_POINT_SMOOTH), then they are not actually rectangular in nature.
Since you are using an older version of OpenGL here, you still have direct access to raster functions. That is, you can skip primitive assembly and draw relative to glRasterPos2i (...). glWindowPos2i (...) will even skip coordinate transform and let you draw directly in window coordinates without messing with projection/modelview matrices (assuming you have an OpenGL 1.4+ implementation).
Here is how you could accomplish the same thing as in your sample code:
void setPixel(int x, int y) {
const GLubyte color [] = { 255, 255, 255, 255 };
glWindowPos2i (x, y);
glDrawPixels (1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
glFlush();
}
If you don't have access to glWindowPos2i, then use an orthographic projection matrix equal to your window's dimensions and an identity modelview matrix and replace glWindowPos2i (...) with glRasterPos2i (...).
Neither solution will be high-performance, but at least you will not have to worry about things like point size, depth tests, etc.
Related
I am making a function for drawing a circle in 2d space.
For this, I have identified 2 approaches:
go through all the possible pixels and run them through a formula that will return a value that shows whether the pixel coordinates are inside the circle, outside (bonus: or intersecting it)
get all the circle pixels (basically draw the circle)
I tried to look at some math sources, but I have met with some problems:
in the second approach, the resolution at which I am incrementing the angle matters, so if it is too little, or radius is too small, there will be unnecessary duplication. On the other hand, if the angle gets incremented by more, or radius is too large, there will be gaps.
The formula I was using is:
struct vec2{int x; int y;};
void get_circle(int x, int y, int r, int angle, struct vec2 *coordinates) {
coordiantes->x = x + r * cos(angle);
coordinates->y = y + r * sin(angle);
}
This is obviously a bit much to run a lot of times.
I also want to make some kind of primitive anti-aliasing, so if I can get a value where a pixel only intersects the circle line by a half, it would be drawn as a half-pixel.
My final goal is to draw a nice circle with a line that can be thick. The thickness can be achieved with the area approach where I fill all pixels in a circle area, and then I remove pixels in the inner circle. Or it can be several iterations of the circle. I didn't write the array part of the computation, but yes, I would like each pixel identified. If we take a pixel as a rectangle, then I would like no pixel to be drawn if the theoretical circle goes through <33% of the surface, half-pixel 33-66, and full if >66%.
Please advise. I need some approach that will be computationally efficient.
First, "most efficient" depends on quite a few things. For most modern OpenGL systems you can usually get away with just computing points around the circumference using sine and cosine (and an appropriate aspect scale) with the native floating-point type, then plotting the points using any decent polyline algorithm.
Once you have things working, profile.
If profiling shows your algorithm to be holding things up (and compared to other normal and common computations, it shouldn't be), only then should you spend time and effort on trickier (read: more complicated) stuff, like the Midpoint Circle Algorithm to generate points to send to your polyline.
Also, don't forget to memoize into a sprite or texture or pixmap or whatever is appropriate for your hardware/software IFF profiling shows a worthwhile improvement.
I need to use Cairo to make geometric formulas move through the screen.
How does one "move" objects (like circles) in Cairo? I did try cairo_translate(cr, x, y) function but it seems to change the referential for all the objects and I don't know how to produce de "movement". In other frameworks I would increment the x value and change the speed with an appropriate clock() function to control FPS's, then I would paint the drawing area background and draw the object with new coordinates.
But I don't know how to produce this with Cairo and all documentation I can find does not mention how this is done.
This is the code I have:
genRandVector(numOfBalls);
/* creates big ball */
cairo_set_line_width(cr, 5);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_arc(cr, balls_MAP[0].x, balls_MAP[0].y, CONF.big_rad, 0, 2 * M_PI);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 0.9, 0.9, 0.9);
cairo_fill(cr);
/* creates other balls */
int i;
cairo_close_path(cr);
cairo_set_source_rgb(cr, 0, 0, 0);
for(i = 1; i < numOfBalls; i++) {
cairo_arc(cr, balls_MAP[i].x, balls_MAP[i].y, CONF.small_rad, 0, 2 * M_PI);
cairo_stroke_preserve(cr);
cairo_fill(cr);
cairo_close_path(cr);
}
And my circles are still. I would like to make all of them move randomly. I just don't know how to make them "move".
cairo doesn't animate things, and it doesn't have the concept of objects. Using cairo is more like using a paintbrush on a canvas: once you draw something onto the canvas, it's stuck there and you can't refer to it to change its properties at all, let alone move it around.
Therefore, to animate things drawn with cairo, you have to wipe the part of the canvas that's being animated and draw it again. How to do that depends on what toolkit you are using to display your graphics.
From the tags, I assume you are using GTK+. There are several methods of GtkWidget, such as gtk_widget_queue_draw() and gtk_widget_queue_draw_area(), that will schedule a redraw of your widget. Call this in a g_timeout_add() handler to schedule your animation. You'll get a drawing signal (the same one you're using already) for the portion of the GtkWidget that you chose to redraw (which you can get from within the draw handler with cairo_clip_extents()). Since the relevant portion of the canvas will be blanked already when you enter the draw handler, you can just start drawing your next frame.
You may wish to consider using a dedicated animation framework instead if your needs are sufficiently complicated. Clutter is one specifically designed to be used with GTK+, but there are also others.
I'm trying to understand Cairo framework; but I don't know how to put more than one shape into the drawing area. All codes/tutorials I've seen are either too advanced or do not relate to this issue.
This is my code to draw a circle (I'm using C and gtk+3.0):
void draw(GtkWidget *this, cairo_t *cr, gpointer data) {
cairo_set_line_width(cr, 5);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_translate(cr, prog.width/2, prog.height/2);
cairo_arc(cr, 0, 0, 50, 0, 2 * M_PI);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 0.9, 0.9, 0.9);
cairo_fill(cr);
}
I understand all but one thing: cairo_t *cr. From what I've been searching cr is a Context, but didn't quite grasped an intuitive idea of what it is about (maybe my question lies on this understanding?).
So, if I needed more circles near this one, how could I create them?
My try was using cairo_move_to(cr, x, y) and draw another shape but obviously it didn't work.
Thanks!
Yes, cairo_t is the type of a cairo context.
To draw on cairo, you set drawing parameters, a source which defines the color or image that gets drawn, and a path that specifies the shape that gets drawn, and then you call cairo_stroke() or cairo_fill() to do the actual drawing. After calling those, the path is reset (unless you use the _preserve versions of the functions), but everything else stays the same.
So to draw again, you just need to add more setup and drawing function calls after the first one.
cairo_move_to() does not actually move anything. What cairo_move_to() does is change the position of the "current point" of the path. Path components you add later, such as cairo_line_to(), will start at the current point and then set the current point to their end point.
In your case, you can draw multiple circles by adding a cairo_move_to() after the last line of your draw handler and then repeating the steps you used to draw the first circle.
cairo_arc() is different because you specify the center of the arc as the second and third arguments. To draw an arc somewhere else, you need to change those two arguments. (The current point does play a role in cairo_arc(); you'll need to see the documentation for information.)
The cairo documentation is the best place to start learning about cairo; it has lots of tutorials and samples.
By (5, 5) I mean exactly the fifth row and fifth column.
I found it very hard to draw things using screen coordinates, all the coordinates in OpenGL is relative, and usually ranging from -1.0 to 1.0. Why it is so serious to prevent programmers from using screen coordinates / window coordinates?
The simplest way is probably to set the projection to match the pixel dimensions of the rendering space via glOrtho. Then vertices can be in pixel coordinates. The downside is that resizing the window could cause problems and you're mostly wasting the accelerated transforms.
Assuming a window that is 640x480:
// You can reverse the 0,480 arguments depending on you Y-axis
// direction preference
glOrtho(0, 640, 0, 480, -1, 1);
Frame buffer objects and textures are another avenue but you'll have to create your own rasterization routines (draw line, circle, bitmap, etc). There are problaby libs for this.
#dandan78 OpenGL is not a Vector Graphics renderer. Is a Rasterizer. And in a more precise way is a Standard described by means of a C language interface. A rasterizer, maps objects represented in 3D coordinated spaces (a car, a tree, a sphere, a dragon) into 2D coordinated spaces (say a plane, your app window or your display), these 2d coordinates belong to a discrete coordinated plane. The counter rendering method of rasterization is Ray Tracing.
Vector graphics is a way to represent by means of mathematical functions a set of curves, lines or similar geometrical primitives, in a nondiscrete way. So Vector graphics is in the "model representation" field rather than "rendering" field.
You can just change the "camera" to make 3D coordinates match screen coordinates by setting the modelview matrix to identity and the projection to an orthographic projection (see my answer on this question). Then you can just draw a single point primitive at the required screen coordinates.
You can also set the raster position with glWindowPos (which works in screen coordinates, unlike glRasterPos) and then just use glDrawPixels to draw a 1x1 pixel image.
glEnable( GL_SCISSOR_TEST );
glScissor( 5, 5, 1, 1 ); /// position of pixel
glClearColor( 1.0f, 1.0f, 1.0f, 0.0f ); /// color of pixel
glClear( GL_COLOR_BUFFER_BIT );
glDisable( GL_SCISSOR_TEST );
By changing last 2 arguments of glScissor you can also draw pixel perfect rectangle.
I did a bit of 3D programming several years back and, while I'm far from an expert, I think you are overlooking a very important difference between classical bitmapped DrawPixel(x, y) graphics and the type of graphics done with Direct3D and OpenGL.
Back in the days before 3D, computer graphics was mostly about bitmaps, which is to say collections of colored dots. These dots had a 1:1 relationship with the pixels on your monitor.
However, that had numerous drawbacks, including making 3D very difficult and requiring bitmaps of different sizes for different display resolutions.
In OpenGL/D3D, you are dealing with vector graphics. Lines are defined by points in a 3-dimensional coordinate space, shapes are defined by lines and so on. Surfaces can have textures, lights can be added, as can various types of lighting effects etc. This entire scene, or a part of it, can then be viewed through a virtual camera.
What you 'see' though this virtual camera is a projection of the scene onto a 2D surface. We're still dealing with vector graphics at this point. However, since computer displays consist of discrete pixels, this vector image has to be rasterized, which transforms the vector into a bitmap with actual pixels.
To summarize, you can't use screen/window coordinates because OpenGL is based on vector graphics.
I know I'm very late to the party, but just in case someone has this question in the future. I converted screen coordinates to OpenGL matrix coordinates using these:
double converterX (double x, int window_width) {
return 2 * (x / window_width) - 1;
}
double converterY (double y, int window_height) {
return -2 * (y / window_height) + 1;
}
Which are basically re-scaling methods.
I'm writing a 2D game using OpenGL. When I want to blit part of a texture as a sprite I use glTexCoord2f(u, v) to specify the UV co-ordinates, with u and v calculated like this:
GLfloat u = (GLfloat)xpos_in_texture/(GLfloat)width_of_texture;
GLfloat v = (GLfloat)ypos_in_texture/(GLfloat)height_of_texture;
This works perfectly most of the time, except when I use glScale to zoom the game in or out. Then floating point rounding errors cause some pixels to be drawn one to the right of or one below the intended rectangle within the texture.
What can be done about this? At the moment I'm subtracting an 'epsilon' value from the right and bottom edges of the rectangle, and it seems to work but this seems like a horrible kludge. Are there any better solutions?
Your issue is most likely not coming from rounding errors, but a misunderstanding on how OpenGL maps texels to pixels. If you notice off-by-one errors, it's probably because your UVs, your vertex positions or your projection matrix/viewport pair are not aligned to where they ought to be.
To simplify, I'll just talk about 1D, and be assuming you use a projection and a viewport that map X,Y coordinates to the equivalent pixel location (i.e. a glOrtho(0,width,0,height,zmin,zmax) and a glViewport(0,width,0,height).
Say you want to draw 5 texels (starting at 0 for simplicity) of your 64-wide texture showing on the 10 pixels (scale of 2) of your screen starting at pixel 20.
To get there, draw the triangle with X coordinates 20 and 30, and U (of the UV pair) of 10/64 and 15/64. The rasterization of OpenGL will generate 10 pixels to shade, with X coordinates 20.5, 21.5, ... 29.5. Note that the positions are not full integers. OpenGL rasterizes in the middle of the pixel.
Likewise, it will generate U coordinates of 10.25/64, 10.75/64, 11.25/64, 11.75/64 ... 14.25/64, 14.75/64. Note again that texel coordinates, brought back to texel positions in the texture space, are not full integers. OpenGL samples from the middle of texel locations, so this is fine.
How the samplers use these UVs to generate texel values depend on filtering modes, but be it nearest or linear, the pixels should be contained solely inside the texels of interest (0.25 with a size of 0.5 should only use color from 0 to 0.5, which is all inside the first texel).
In general, if you follow the general principles I laid out, you should never see artifacts.
Use Ortho and Viewport of exactly your frame buffer size
Use positions of X, X+width exactly
Use UVs that correspond to exactly the texels you want (if you want the 10 texels starting from the texel 0, use U=0 to U=10.
If you ever have a -1 somewhere in your math, it's likely not correct (for position or UVs).
To get back to your example, it's unclear how you link the uvs you compute to positions (since you don't show the position computation).
It's also unclear how you got xpos_in_texture (you should explain how you computed them for the corners of your sprite). My guess is that you computed that wrong.
A bit late, but for posterity I was having the same problem, with the pixels from adjacent regions of a texture atlas bleeding into sprites/tiles when scaling or zooming the view. I had my glOrtho, glViewport, etc dimensions all set correctly, then I realized the problem was I was scaling the view before translating the camera, which meant that even though I was snapping to integer pixels pre-zoom, after the zoom it would align to a fraction of a pixel and introduce the texel problem.
So if your code looks something like this, where camera.zoom is a non-integer (i.e. 0.75):
glScalef(camera.zoom, camera.zoom, 1.0f);
glTranslatef(camera.x, camera.y, 0.0f);
You'll want to make sure the result of the translation after scaling aligns to whole pixels on the screen, so you can do something like:
glScalef(camera.zoom, camera.zoom, 1.0f);
glTranslatef(
floor(camera.x * camera.zoom) / camera.zoom,
floor(camera.y * camera.zoom) / camera.zoom,
0.0f);
Do the division as a double, round the result down yourself to the desired level of precision, then cast it to GLFloat.
Your xpos/ypos must be based on 0 to (width or height) - 1 and then:
GLfloat u = (GLfloat)xpos_in_texture/(GLfloat)(width_of_texture - 1);
GLfloat v = (GLfloat)ypos_in_texture/(GLfloat)(height_of_texture - 1);