Drawing a concave polygon in OpenGL - ios

I have a concave polygon I need to draw in OpenGL.
The polygon is defined as a list of points which form its exterior ring, and a list of lists-of-points that define its interior rings (exclusion zones).
I can already deal with the exclusion zones, so a solution for how to draw a polygon without interior rings will be good too.
A solution with Boost.Geometry will be good, as I already use it heavily in my application.
I need this to work on the iPhone, namely OpenGL ES (the older version with fixed pipeline).
How can I do that?

Try OpenGL's tessellation facilities. You can use it to convert a complex polygon into a set of triangles, which you can render directly.
EDIT (in response to comment): OpenGL ES doesn't support tessellation functions. In this case, and if the polygon is static data, you could generate the tessellation offline using OpenGL on your desktop or notebook computer.
If the shape is dynamic, then you are out of luck with OpenGL ES. However, there are numerous libraries (e.g., CGAL) that will perform the same function.

It's a bit complicated, and resource-costly method, but any concave polygon can be drawn with the following steps (note this methos works surely on flat polygons, but I also assume you try to draw on flat surface, or in 2D orthogonal mode):
enable stencil test, use glStencilFunc(GL_ALWAYS,1,0xFFFF)
disable color mask to oprevent unwanted draws: glColorMask(0,0,0,0)
I think you have the vertices in an array of double, or in other form (strongly recommended as this method draws the same polygon multiple times, but using glList or glBegin-glEnd can be used as well)
set glStencilOp(GL_KEEP,GL_KEEP,GL_INCR)
draw the polygon as GL_TRIANGLE_FAN
Now on the stencil layer, you have bits set >0 where triangles of polygon were drawn. The trick is, that all the valid polygon area is filled with values having mod2=1, this is because the triangle fan drawing sweeps along polygon surface, and if the selected triangle has area outside the polygon, it will be drawn twice (once at the current sequence, then on next drawings when valid areas are drawn) This can happens many times, but in all cases, pixels outside the polygon are drawn even times, pixels inside are drawn odd times.
Some exceptions can happen, when order of pixels cause outside areas not to be drawn again. To filter these cases, the reverse directioned vertex array must be drawn (all these cases work properly when order is switched):
- set glStencilFunc(GL.GL_EQUAL,1,1) to prevent these errors happen in reverse direction (Can draw only areas inside the polygon drawn at first time, so errors happening in the other direction won't apperar, logically this generates the intersectoin of the two half-solution)
- draw polygon in reverse order, keeping glStencilFunc to increase sweeped pixel values
Now we have a correct stencil layer with pixel_value%2=1 where the pixel is truly inside the polygon. The last step is to draw the polygon itself:
- set glColorMask(1,1,1,1) to draw visible polygon
- keep glStencilFunc(GL_EQUAL,1,1) to draw the correct pixels
- draw polygon in the same mode (vertex arrays etc.), or if you draw without lighting/texturing, a single whole-screen-rectangle can be also drawn (faster than drawing all the vertices, and only the valid polygon pixels will be set)
If everything goes well, the polygon is correctly drawn, make sure that after this function you reset the stencil usage (stencil test) and/or clear stencil buffer if you also use it for another purpose.

Check out glues, which has tessellation functions that can handle concave polygons.

I wrote a java classe for a small graphical library that do exacly what you are looking for, you can check it here :
https://github.com/DzzD/TiGL/blob/main/android/src/fr/dzzd/tigl/PolygonTriangulate.java
It receive as input two float arrays (vertices & uvs) and return the same vertices and uvs reordered and ready to be drawn as a list of triangles.
If you want to exclude a zone (or many) you can simply connect your two polygones (the main one + the hole) in one by connecting them by a vertex, you will end with only one polygone that can be triangulate like any other with the same function.
Like this :
To better understand zoomed it will look like :
Finally it is just a single polygon.

Related

WebGL: Draw different geometric primitives within same draw call?

I have a WebGL scene that wants to draw both point and line primitives, and am wondering: Is it possible to draw multiple WebGL primitives inside a single draw call?
My hunch is this is not possible, but WebGL is constantly surprising me with tricks one can do to accomplish strange edge cases, and searching has not let me confirm whether this is possible or not.
I'd be grateful for any insight others can offer on this question.
You can't draw WebGL lines, points, and triangles in the same draw call. You can generate points and lines from triangles and then just draw triangles in one draw call that happens to have triangles that make points and triangles that draw lines and triangles that draw other stuff all one draw call.
Not a good example but for fun here's a vertex shader than generates points and lines from triangles on the fly.
There's also this for an example of making lines from triangles
How creative you want to get with your shaders vs doing things on the CPU is up to you but it's common to draw lines with triangles as the previous article points out since WebGL lines can generally only be a single pixel thick.
It's also common to draw points with triangles since
WebGL is only required to support points of size 1
By drawing with triangles that limit is removed
WebGL points are always aligned with the screen
Triangle based points are far more flexible. You can rotate the point for example and or orient them in 3D. Here's a bunch of points made from triangles
Triangle based points can be scaled in 3D with no extra work
In other words a triangle based point in 3d space will scale with distance from the camera using standard 3D math. A WebGL point requires you to compute the size the point should be so you can set gl_PointSize and so requires extra work if you want it to scale with the scene.
It's not common to mix points, lines, and triangles in a single draw call but it's not impossible by any means.

Polygon(Quad) to Square Cells

I am really having a problem with this.
I have a polygon (a quad) which can be any shape. When my mouse is inside the polygon I need to find the x,y values of where my mouse is (inside the quad) as though the poygon were are perfect square. Further explanation; I have a 32x32 texture applied to the polygon and I need to know the x,y of the texture that the mouse is over.
I have some code that works for most shapes but which breaks if TR.Y is less than TL.y for instance.
I have some pretty simple code that tests whether the cursor is inside the polygon (via two triangle tests). But I cannot figure out how to use this to generate an x,y of a virtual square projection.
This problem is killing me. What is the name of operation i am trying to perform? Does anyone know of an explanation where the equations are presented in code form (any kind of code) (rather than just mathematical notation?). Any kind of help would be so appreciated.
I am on the verge of doing a 2nd render with specially formatted textures (each pixel having a unique value) so that I can just colour test to get an approximate x,y match (and precision is something that can be compromised here without causing too much trouble) - but then I will have to work around the DX Lib's attempt to blend and smooth the special texture as it is warped to fill the quad)
**Edit: Code that works for many quad shapes
It depends on method - how the texture is drawn at this quad.
If it uses perspective transform Square=>Quad, you have to use matrix of inverse transform Quad=>Square. Short article
For linear interpolation approach see this page

Texture getting stretched across faces of a cuboid in Open Inventor

I am trying to write a little script to apply texture to rectangular cuboids. To accomplish this, I run through the scenegraph, and wherever I find the SoIndexedFaceSet Nodes, I insert a SoTexture2 Node before that. I put my image file in the SoTexture2 Node. The problem I am facing is that the texture is applied correctly to 2 of the faces(say face1 and face2), in the Y-Z plane, but for the other 4 planes, it just stretches the texture at the boundaries of the two faces(1 and 2).
It looks something like this.
The front is how it should look, but as you can see, on the other two faces, it just extrapolates the corner values of the front face. Any ideas why this is happening and any way to avoid this?
Yep, assuming that you did not specify texture coordinates for your SoIndexedFaceSet, that is exactly the expected behavior.
If Open Inventor sees that you have applied a texture image to a geometry and did not specify texture coordinates, it will automatically compute some texture coordinates. Of course it's not possible to guess how you wanted the texture to be applied. So it computes the bounding box then computes texture coordinates that stretch the texture across the largest extent of the geometry (XY, YZ or XZ). If the geometry is a cuboid you can see the effect clearly as in your image. This behavior can be useful, especially as a quick approximation.
What you need to make this work the way you want, is to explicitly assign texture coordinates to the geometry such that the texture is mapped separately to each face. In Open Inventor you can actually still share the vertices between faces because you are allowed to specify different vertex indices and texture coordinate indices (of course this is only more convenient for the application because OpenGL doesn't support this and Open Inventor has to re-shuffle the data internally). If you applied the same texture to an SoCube node you would see that the texture is mapped separately to each face as expected. That's because SoCube defines texture coordinates for each face.

iOS Metal line width

I would like to set the width of a line that I'm drawing in Metal. I can set the size of a point with point_size as explained here:
https://developer.apple.com/library/prerelease/ios/documentation/Metal/Reference/MTLRenderCommandEncoder_Ref/index.html
But, I'm not sure how it works with lines.
Short answer would be there is no way to control line width in the same way as a point size in Metal. Even in OpenGL graphics API, the function to do this (which used to exist as gllinewidth function) is now deprecated.
An option would be to draw the line as a quad (a box), with two triangles. This would let you control the width of the line.
If you want to stick to the line primitive itself, for some particular reason, the equivalent OpenGL question has been asked on StackOverflow already as seen here. The shader can be simple translated to Metal shading API.
If you're dead set on using lines instead of drawing a 2D box with two rectangles you can draw multiple lines next to each other. You can do that by drawing the same two vertices multiple times with one drawPrimitives call, just increase the instanceCount to simulate the thickness and then in your vertex shader function you could use your vertex_id and a modulus operation or some other type of logic to translate the position of the line to simulate thickness. This will probably be a lot easier than trying to do something fancy in a fragment shader.
If you are drawing multiple lines, multiply your instanceCount by the thickness you want and adjust your vertex shader function logic to place those additional lines next to each other.
I experimented with this and found this to be a pretty cumbersome process. As you need additional math to position the extra lines to thicken correctly. For example if you're drawing a horizontal line and want to increase thickness by two you'd want to modify the y value, but if it's vertical you'd want to modify the x. Drawing at an angle gets more complicated. You'll also run into issues trying to match lengths with widths if you're attempting to draw shapes.
I think it's much better to just draw two triangles to make a rectangle to fake a line. The math will be much easier and simpler to understand.
In Geometry, Euclid's lines do not have any width, they only have length, the width they get during drawing is simply for representation. So while I think lines may be good for debugging and development, like for displaying vectors or creating a grid to see scale, they're not what you want if you're trying to style them to present them to users. In that case it's the wrong tool for the job.

XNA Drawing a series of squares

I am trying to draw a series of squares in XNA. I am looking at all these articles about TriangleStrips and DynamicVertexBuffers. But, not sure where to begin.
Current step
I am able to draw 1 square using VertexPositionColor, TriangleList and indices. Now I want to draw a series of squares with varying colors.
End Goal
Something to keep in mind is the number of such squares that I would like to be able to draw, eventually. If we assume a 5px width, on a 1920x1080 screen, we can calculate the number of squares to be (1920 * 1080) / 25 = 82944.
Any pointers on how to accomplish this would be great!
Generally, you can draw more squares in the same way you draw the first one. However, there will be a significant loss in performance.
Instead, you can add all triangles to one vertex buffer / index buffer. You already are able to draw two triangles as a triangle list. You should be able to easily adjust this routine to draw more than two triangles. Just add the according vertices and indices to the buffers and modify the draw call.
If you need vertices at the same position with different colors, you need to add two vertices to the buffer.
This way, the performance loss is very little, because you draw everything with only one draw call. Although the amount of triangles should be no problem for most graphic cards, some smaller or older ones can get into trouble. If so, you should consider changing your drawing strategy. Maybe it is not even necessary to draw that much triangles. But you can think about that, if the resulting performance is too low...
If you don't care about 3D, just 2D - you can use SpriteBatch to draw squares/rectangles on the screen. This will handle batching all the vertex/index buffer management for you.

Resources