I currently have a list of polygons made up of several points. The first of these is the outer polygon of the cross section and the others in shapes inside the first polygon.
I'm trying to think of a way to draw cross section lines inside the outer polygon (and not inside the inner polygons) but I'm struggling to think of a way to do this. Does anyone have any suggestions?
I'm writing in C++ using an API that lets me draw lines between points easily enough. The drawing I'm creating is in 3D, which I'm guessing will make things a bit easier.
You don't mention your OS or your development environment, so it's not clear that there may be other solutions. However, going back to basics, perhaps consider the Painter's Algorithm and don't worry about clipping or cropping your content based on existing content - just do something like this:
Draw cross section lines on the whole image.
Draw the inverse of the outer polygon with a black fill (that will remove the cross section lines that are outside the outer polygon.
Draw the inner shapes with a black fill (that will remove the cross sections lines that are inside the inner polygons).
The Wiki page shows this example:
If you're using Windows and are ok to use Direct2D (or Direct3D), there are much easier ways to do this by drawing shapes with a customised brush for filling.
Related
I have a 3D CAD-like application for which I use OpenGL wrapper library (OpenSceneGraph). For the application I am trying to come up with the best strategy on how to render thick and smooth lines in 3D.
By thick and smooth I mean:
line thickness can be more than OpenGL maximum linewidth value (it seems to be 10.f on my machine)
when composing polylines I want to avoid the look of "broken lines" (see example image below)
At the moment I render my polylines by using GL_LINE_STRIP_ADJACENCY.
I found there are many different resources on how to render nice looking lines and curves in 2D. The simplest approach that does not require much thinking is to render the line as a set of quads (GL_QUAD_STRIP). The good thing about this solution is that it solves both of my problems at the same time.
As an example, I also found this nice library that allows to achieve wide range of line and curve looks. It uses triangles for rendering.
Note: I do not seek for fancy effects like per-vertex coloring or brush-like strokes, just a 3D line segment that can have large thickness and that connects well with another line segment without any gaps between them.
The problem with those 2D approaches is that they are 2D. When I change the view point, it is obvious my line geometries are not lines but rather 2D "ribbons" lying in certain 3D planes. And I want them to look like 3D lines.
When thinking about the problem, I could only come up the the following approaches:
Render line as a set of 2D quads (triangles) and then make them to always face the camera
Use some 3D shape like cylinder to represent a line segment
I am not sure how feasible any of the two solutions are (I am beginner in OpenGL). I might have hundreds or even thousands of polylines on the scene. I am also wondering if there is a better, smarter way to approach the problem? I am open to anything and interested in the most efficient way. Thank you.
EDIT: as pointed by user #rickyviking, I didn't clarify explicitly that I am going after a 2D look (like in any CAD-like app) which would mean: the thickness of the lines does not depend on how far/near the camera is located from them.
UPDATE: thanks for answer of #rickyviking, I chose the direction to move with - geometry shaders. I still do not have a complete solution, but might post a final update and minimal code when the result is achieved, here.
I ended up using geometry shader as was suggested by one of the answers. The main idea was to convert every line segment into a triangular strip and to make sure that it always faces the camera and thickness remains the same.
I also wrote a blog post about the implementation details. If someone finds it useful, I placed the shader codes on one of my github repos (the code also provides example on how to draw thick and smooth Bezier curves using the same technique).
Here are some result screenshots (green lines are drawn using the shaders, red are by using GL_LINE_STRIP_ADJACENCY):
Note the gaps between the adjacent line segments of the red lines compared to the green ones.
Two Bezier curves (all drawn using the shaders):
First of all you need clarify yourself whether the result you're after should "look" 2D or 3D.
When you mention cylinders, they will certainly have a "3D effect" (geometries farther away thinner/smaller than geometries closer to the viewpoint), but that is not what CAD-like applications normally looks like.
I believe you're after a 2D looking result, where the width of your lines is independent from their distance from viewpoint.
When using a library like the one you mention, you should recompute the geometries every time you change your viewpoint (possibly every frame) to have them always face the screen plane.
An alternative and better performing approach would be to use the "solid wireframe" technique, here is an implementation from NVidia, which uses geometry shaders (you can find several examples on how to use them in OpenSceneGraph).
Other similar techniques are shown here: https://forum.libcinder.org/topic/smooth-thick-lines-using-geometry-shader
I don't know too much about it but one of the many interesting things about NVidia's "path rendering" SDK (which was on the face of it just another one of those nice 2D libraries you're talking about) was that it actually put a bit of effort into interoperating with 3D. See the "Eureka: 3D Path Rendering!" section in this whitepaper.
There used to be talk of it becoming a standard (non-vendor-specific) OpenGL extension but I'm not sure it ever happened.
I've used cylinders before, but that was an application that needed actual real-world sizes, varying sizes in one line and even color changing.
I'm creating a comic book editor. I want to be able to use some fairly complex customisable shapes for the speech balloons.
I can draw the tail and then draw a balloon but that means I have the outline inside the shape and I want it only around the edge.
I assumed QPainterPath::simplified() would solve the problem but it doesn't seem to do anything.
At the moment my best idea is to draw a shape with a thick outline and then draw it again with no outline but I don't think that will work for "zero width" outlines.
I can think of two possible solutions here:
Draw both the "tail" and the main "balloon" as a single shape. In this case, you'd simply draw a single shape with a single outline and a single fill.
Draw them separately, but twice. Draw an "expanded" version of the shapes in black first, and then draw the "normal" version of the shapes in white over the top of it. You wouldn't draw any "lines" at all - the "expanded" version of the fill would serve the same purpose.
The first method would allow alternative line styles to be used (dotted or wiggly lines), but the latter would allow the "outline" to be slightly offset, so that it appeared thicker around some edges and thinner around others.
It turns out QPainterPath::simplified() does work. It depends on whether I draw clockwise or anti-clockwise (I believe it works when drawn clockwise), which I presume is down to how Qt's Winding Fill works.
// create a path representing the bubble and its "tail"
QPainterPath tail = tail.shape();
tail.addPath(bubble.shape());
tail.setFillRule(Qt::WindingFill);
painter->drawPath(tail.simplified);
I'm trying to draw a 2D silhouette of an island/land of sort in C++ with OpenGL. It is just a simple island that looks something like the one here
I tried ways like drawing polygons, fill the colour black and then hard-code tons of vertex points to get the shape of the island and also to keep the edges look rough like the one in the example. But I feel that this really isn't the best way to do this because the number of vertices is just too many. It is also very difficult to tweak because it's not like I'm in Photoshop where I could just pull/add/change the points visually.
Are there any better and more clever way to draw a 2D island silhouette to get the mountain-like edges? As for the overall shape of the island, is my naive way to plant tons of points to form the polygon shape the only way?
I have just started on OpenGL and will be grateful for any suggestions. Thanks!
There are many ways to go about this here are two simple ones;
Easy way: As said in the comments, create the island in an image editor (with alpha) and draw as a quad/tris with blending enabled.
Harder way: Import a vector graphic (vector meaning points making a shape) and draw as polygons. This could get complicated for a newbie if using an existing format. Also, not as efficient as method 1, but can have a much nicer visual effect especially if you plan on zooming/scaling.
In the end it is entirely up to you how you want to implement it, but the first method is straight-forward and easy, I recommend that for a newbie (be sure to come back to it later and try method 2 though ;) ).
I want to make a 2D game in C++ using the Irrlicht engine. In this game, you will control a tiny ship in a cave of some sort. This cave will be created automatically (the game will have random levels) and will look like this:
Suppose I already have the the points of the polygon of the inside of the cave (the white part). How should I render this shape on the screen and use it for collision detection? From what I've read around different sites, I should use a triangulation algorithm to make meshes of the walls of the cave (the black part) using the polygon of the inside of the cave (the white part). Then, I can also use these meshes for collision detection. Is this really the best way to do it? Do you know if Irrlicht has some built-in functions that can help me achieve this?
Any advice will be apreciated.
Describing how to get an arbitrary polygonal shape to render using a given 3D engine is quite a lengthy process. Suffice to say that pretty much all 3D rendering is done in terms of triangles, and if you didn't use a tool to generate a model that is already composed of triangles, you'll need to generate triangles from whatever data you have there. Triangulating either the black space or the white space is probably the best way to do it, yes. Then you can build up a mesh or vertex list from that, and render those triangles that way. The triangles in the list then also double up for collision detection purposes.
I doubt Irrlicht has anything for triangulation as it's quite specific to your game design and not a general approach most people would take. (Typically they would have a tool which permits generation of the game geometry and the navigation geometry side by side.) It looks like it might be quite tricky given the shapes you have there.
One option is to use the map (image mask) directly to test for collision.
For example,
if map_points[sprite.x sprite.y] is black then
collision detected
assuming that your objects are images and they aren't real polygons.
In case you use real polygons you can have a "points sample" for every object shape,
and check the sample for collisions.
To check whether a point is inside or outside your polygon, you can simply count crossings. You know (0,0) is outside your polygon. Now draw a line from there to your test point (X,Y). If this line crosses an odd number of polygon edges (e.g. 1), it's inside the polygon . If the line crosses an even number of edges (e.g. 0 or 2), the point (X,Y) is outside the polygon. It's useful to run this algorithm on paper once to convince yourself.
I have a path made up of a list of 2D points. I want to turn these into a strip of triangles in order to render a textured line with a specified thickness (and other such things). So essentially the list of 2D points need to become a list of vertices specifying the outline of a polygon that if rendered would render the line. The problem is handling the corner joins, miters, caps etc. The resulting polygon needs to be "perfect" in the sense of no overdraw, clean joins, etc. so that it could feasibly be extruded or otherwise toyed with.
Are there any simple resources around that can provide algorithm insight, code or any more information on doing this efficiently?
I absolutely DO NOT want a full fledged 2D vector library (cairo, antigrain, OpenVG, etc.) with curves, arcs, dashes and all the bells and whistles. I've been digging in multiple source trees for OpenVG implementations and other things to find some insight, but it's all terribly convoluted.
I'm definitely willing to code it myself, but there are many degenerate cases (small segments + thick widths + sharp corners) that create all kinds of join issues. Even a little help would save me hours of trying to deal with them all.
EDIT: Here's an example of one of those degenerate cases that causes ugliness if you were simply to go from vertex to vertex. Red is the original path. The orange blocks are rectangles drawn at a specified width aligned and centered on each segment.
Oh well - I've tried to solve that problem myself. I wasted two month on a solution that tried to solve the zero overdraw problem. As you've already found out you can't deal with all degenerated cases and have zero overdraw at the same time.
You can however use a hybrid approach:
Write yourself a routine that checks if the joins can be constructed from simple geometry without problems. To do so you have to check the join-angle, the width of the line and the length of the joined line-segments (line-segments that are shorter than their width are a PITA). With some heuristics you should be able to sort out all the trivial cases.
I don't know how your average line-data looks like, but in my case more than 90% of the wide lines had no degenerated cases.
For all other lines:
You've most probably already found out that if you tolerate overdraw, generating the geometry is a lot easier. Do so, and let a polygon CSG algorithm and a tesselation algorithm do the hard job.
I've evaluated most of the available tesselation packages, and I ended up with the GLU tesselator. It was fast, robust, never crashed (unlike most other algorithms). It was free and the license allowed me to include it in a commercial program. The quality and speed of the tesselation is okay. You will not get delaunay triangulation quality, but since you just need the triangles for rendering that's not a problem.
Since I disliked the tesselator API I lifted the tesselation code from the free SGI OpenGL reference implementation, rewrote the entire front-end and added memory pools to get the number of allocations down. It took two days to do this, but it was well worth it (like factor five performance improvement). The solution ended up in a commercial OpenVG implementation btw :-)
If you're rendering with OpenGL on a PC, you may want to move the tesselation/CSG-job from the CPU to the GPU and use stencil-buffer or z-buffer tricks to remove the overdraw. That's a lot easier and may be even faster than CPU tesselation.
I just found this amazing work:
http://www.codeproject.com/Articles/226569/Drawing-polylines-by-tessellation
It seems to do exactly what you want, and its licence allows to use it even in commercial applications. Plus, the author did a truly great job to detail his method. I'll probably give it a shot at some point to replace my own not-nearly-as-perfect implementation.
A simple method off the top of my head.
Bisect the angle of each 2d Vertex, this will create a nice miter line. Then move along that line, both inward and outward, the amount of your "thickness" (or thickness divided by two?), you now have your inner and outer polygon points. Move to the next point, repeat the same process, building your new polygon points along the way. Then apply a triangualtion to get your render-ready vertexes.
I ended up having to get my hands dirty and write a small ribbonizer to solve a similar problem.
For me the issue was that I wanted fat lines in OpenGL that did not have the kinds of artifacts that I was seeing with OpenGL on the iPhone. After looking at various solutions; bezier curves and the like - I decided it was probably easiest to just make my own. There are a couple of different approaches.
One approach is to find the angle of intersection between two segments and then move along that intersection line a certain distance away from the surface and treat that as a ribbon vertex. I tried that and it did not look intuitive; the ribbon width would vary.
Another approach is to actually compute a normal to the surface of the line segments and use that to compute the ideal ribbon edge for that segment and to do actual intersection tests between ribbon segments. This worked well except that for sharp corners the ribbon line segment intersections were too far away ( if the inter-segment angle approached 180' ).
I worked around the sharp angle issue with two approaches. The Paul Bourke line intersection algorithm ( which I used in an unoptimized way ) suggested detecting if the intersection was inside of the segments. Since both segments are identical I only needed to test one of the segments for intersection. I could then arbitrate how to resolve this; either by fudging a best point between the two ends or by putting on an end cap - both approaches look good - the end cap approach may throw off the polygon front/back facing ordering for opengl.
See http://paulbourke.net/geometry/lineline2d/
See my source code here : https://gist.github.com/1474156
I'm interested in this too, since I want to perfect my mapping application's (Kosmos) drawing of roads. One workaround I used is to draw the polyline twice, once with a thicker line and once with a thinner, with a different color. But this is not really a polygon, it's just a quick way of simulating one. See some samples here: http://wiki.openstreetmap.org/wiki/Kosmos_Rendering_Help#Rendering_Options
I'm not sure if this is what you need.
I think I'd reach for a tessellation algorithm. It's true that in most case where these are used the aim is to reduce the number of vertexes to optimise rendering, but in your case you could parameterise to retain all the detail - and the possibility of optimising may come in useful.
There are numerous tessellation algorithms and code around on the web - I wrapped up a pure C on in a DLL a few years back for use with a Delphi landscape renderer, and they are not an uncommon subject for advanced graphics coding tutorials and the like.
See if Delaunay triangulation can help.
In my case I could afford to overdraw. I just drow circles with radius = width/2 centered on each of the polyline's vertices.
Artifacts are masked this way, and it is very easy to implement, if you can live with "rounded" corners and some overdrawing.
From your image it looks like that you are drawing box around line segments with FILL on and using orange color. Doing so is going to create bad overdraws for sure. So first thing to do would be not render black border and fill color can be opaque.
Why can't you use GL_LINES primitive to do what you intent to do? You can specify width, filtering, smoothness, texture anything. You can render all vertices using glDrawArrays(). I know this is not something you have in mind but as you are focusing on 2D drawing, this might be easier approach. (search for Textured lines etc.)