How to define order when drawing 2D triangles in OpenGL ES 1.1? - ios

I'm drawing triangles with only x and y coordinates per vertex:
glVertexPointer(2, GL_FLOAT, 0, vertices);
Sometimes when I draw a triangle over another triangle they seem to be coplanar and the surface jerks because they share the exact same surface in space.
Is there a way of saying "OpenGL, I want that you draw this triangle on top of whatever is below it" without using 3D coordinates, or do I have to enable depth test and use 3D coordinates to control a Z-index?

If you want to render the triangle just on top of whatever was in the framebuffer before, you can just disable the depth test entirely. But if you need some custom ordering different from draw order, then you won't get around adding additional depth information (in the form of a 3rd z-coordinate). There is no way to say to OpenGL "render the following stuff but with the z-coordinate collectively set to some value". You can either say "render the follwing stuff on top of whatever is there" or "render the following stuff on whatever depth results from its transformed vertices".

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.

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 OpenGL ES to draw a mesh wireframe

I have a human model in an .OBJ file I want to display as a mesh with triangles. No textures. I want also to be able to move, scale, and rotate in 3D.
The first and working option is to project the vertices to 2D using the maths manually and then draw them with Quartz 2D. This works, for I know the underlying math concepts for perspective projection.
However I would like to use OpenGL ES for that method, but I am not sure how to draw the triangles.
For example, the code in - (void)drawRect:(CGRect)rect is:
glClearColor(1,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
GLKBaseEffect *effect = [[GLKBaseEffect alloc] init];
[effect prepareToDraw];
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
Now what? I have an array of vertex positions (3 floats per vertex) and an array of triangle indices, so I tried this:
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, numVertices,pVertices);
glDrawElements(GL_TRIANGLES, numTriangles, GL_UNSIGNED_INT,pTriangles);
but this doesn't show anything. I saw from a sample the usage of glEnableVertexAttribArray(GLKVertexAttribPosition) and glDrawArrays but I 'm not sure how to use them.
I also understand that rendering a wireframe is not possible with ES? So I have to apply color attributes to the vertices. That's ok, but before that the triangles have to be displayed first.
The first thing I'd ask is: where are your vertices? OpenGL (ES) draws in a coordinate space that extends from (-1, -1, -1) to (1, 1, 1), so you probably want to transform your points with a projection matrix to get them into that space. To learn about projection matrices and more of the basics of OpenGL ES 2.0 on iOS, I'd suggest finding a book or a tutorial. This one's not bad, and here's another that's specific to GLKit.
Drawing with OpenGL in drawRect: is probably not something you want to be doing. If you're already using GLKit, why not use GLKView? There's good example code to get you started if you create a new Xcode project with the "OpenGL Game" template.
Once you get up to speed with GL you'll find that the function glPolygonMode typically used for wireframe drawing on desktop OpenGL doesn't exist in OpenGL ES. Depending on how your vertex data is organized, though, you might be able to get a decent wireframe with GL_LINES or GL_LINE_LOOP. Or since you're using GLKit, you can skip wireframe and set up some lights and shading pretty easily with GLKBaseEffect.

OpenGL ES Fill Effect

How to create a fill effect? I have an irregular closed shape created using:
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
(.......)
glVertexPointer(2, GL_FLOAT, 0, vertexBuffer);
glDrawArrays(GL_POINTS, 0, vertexCount);
(.......)
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
Now I would like to have an "fill/paint bucket" effect like in photoshop. The background inside the shape is white (for example) and by clicking inside the shape I want to change the color to red or green.
Can somebody give me some hints, please.
So you render a set of points and want OpenGL to "magically" fill the enclosed region. That's not possible. OpenGL doesn't realize that these points enclose some region. You don't even draw a line strip, it's just a set of points. Even a human has to put in a reasonable effort of thinking to see that the points "enclose" a region, let aside a computer, or just a simple interface for drawing points, lines and triangles onto the screen.
Instead of drawing points, just draw a polygon (use GL_POLYGON or GL_TRIANGLE_FAN instead of GL_POINTS). But if the enclosed region is non-convex that won't work in all cases. What you always have to realize is, that OpenGL is nothing more than a drawing API. It just draws points, lines and triangles to screen. Yes, with fancy effects, but all in all it just draws simple primitives. It doesn't manage any underlying graphics scene or something. The moment a primitive (like a single point, line or triangle) has been drawn, OpenGL doesn't remember it anymore.
What you want to achieve (given you at least change the point set to a line loop that really encloses a region), is not to be achieved by simple means. In the simplest case you need some kind of flood fill algorithm that fills the region you enclosed by the lines. But for this you don't profit from OpenGL in any way, as this requires you to analyse the image on the CPU and set individual pixels. And neither can shaders do this in a simple (or any?) way.

Drawing a concave polygon in OpenGL

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.

Resources