I am working on a simple project with OpenGL ES 2.0. It's gone fairly well, but I seem to have hit a spot that is seemingly poorly documented for us beginners. That being, I am trying to utilize a texture atlas. I have searched around a bit, but I can't seem to find any full code examples. Most search results lead to people giving the very basic idea of what they are and how to use them, but never a full example that I can really study.
At the moment I am just trying to load in a set of four or five images from one image atlas and apply them to a single triangle strip. I can section out a specific part of the image as I want, I just can't find any examples on applying more pieces of that image to the same triangle strip.
I don't necessarily need a full tutorial on this (I wouldn't mind one!), but if somebody could point me to some example code that does something similar I'd be quite happy. Thank you very much in advance!
A texture atlas is no different that any other image you load and render using OpenGL, the trick is to adjust the texture coordinates of each vertex of your polygon(s) to include a smaller triangle/rectangle inside that image.
In OpenGL the coordinates of an image start at (0,0) - the lower left corner and end at (1,1) - the top right corner. If you want to map only a region of the image to your polygon assign the texture coordinates by using a normalized size (0.0 - 1.0). i.e the middle point of the image would be at coordinates (0.5, 0.5).
To display a triangle strip that renders a rectangle using only the half of the image, your texture coordinates will have to be similar to this:
(0.0, 0.0) vertex at lower left corner of rectangle
(0.0, 1.0) vertex at top left corner
(0.5, 0.0) vertex at lower right corner
(0.5, 1.0) vertex at top right corner
Related
I am using OpenGL ES 2.0 (on Android) to draw simple 2D scene has few images. I have background image and some others which have alpha channel.
I would like to draw outline around non-transparent pixels in texture using only shader programs. After somewhat extensive search I failed to find example code. It looks like GLES 2.0 is still not that popular.
Can you provide some sample code or point me in right direction where I can find more information on how to do this?
There are a couple of ways of doing this depending on the a) Qaulity, and b) Speed you need. The common search terms are:
"glow outline"
"bloom"
"toon shader" or "toon shading"
"edge detection"
"silhouette extraction"
"mask"
1) The traditional approach is to use the stencil buffer and render to texture
Clear the stencil buffer (usually done once per frame)
glClear( GL_COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT )
Render to Texture
Disable Depth Writes
glDepthMask( 1 );
Disable Color Buffer Writes
glColorMask( 0, 0, 0, 0 );
Enable the Stencil buffer Set stencil to always pass and replace
glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
glStencilFunc( GL_ALWAYS, 1, 1 );
Draw object into texture
Disable stencil
Enable Color Buffer Writes
Enable Depth Writes
Do a N-pass "tap", such as 5 or 7 pass tap where you blur the texture via rendering to itself in both the vertical and horizontal direction (another option is to scale drawing the texture image up)
Switch to orthographic projection
Draw & Blend the texture image back into the framebuffer
Restore perspective projection
2) Pass along extra vertex, namely which vertices are adjacent in the proper winding order, and dynamically generate extra outline triangles.
See: http://www.gamasutra.com/view/feature/1644/sponsored_feature_inking_the_.php?print=1
3) Use cheap edge detection. In the vertex shader check the dot product of the normal with the view. If it is between:
-epsilon < 0 < epsilon
Then you have an edge.
4) Use cheap-o-rama object scaling. It doesn't work for concave objects of course but depending on your quality needs may be "good enough"
Switch to a "flat" shader
Enable Alpha Testing
Draw the model scaled up slightly
Disable Alpha Testing
Draw the model but at the normal size
References:
https://developer.valvesoftware.com/wiki/L4D_Glow_Effect
http://prideout.net/blog/?p=54
http://en.wikibooks.org/wiki/GLSL_Programming/Unity/Toon_Shading#Outlines
http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter09.html
Related SO questions:
Outline effects in OpenGL
To get the pixel shader drawing something, there needs to be geometry.
As far as I understand, you want to draw a border around these images,
but the outermost fragments generated would be image pixels in a basic implementation,
so you'd overdraw them with any border.
If you want a 'line border', you cannot do anything else than drawing the image triangles/quads (GL_TRIANGLES,GL_QUADS), and in an additional call the outline (using GL_LINES), where you may share the vertices of a single quad.
Consider, that lines can't be drawn efficiently by many GPU's)
Otherwise, see below solutions:
Solution 1:
Draw the rectangle as big as the image + border will be and adjust texture coords for the image, so that it will be placed within the rectangle appropriately.
This way, no extra geometry or draw calls are required.
Set the texture border property (single 4 component color), there will be no need to do extra fragment shader calculations, the texture unit/sampler does all the work.
Texture properties:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_BORDER)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_BORDER)
glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_BORDER_COLOR,borderColor4f)
I've never used a color border for a single channel texture, so this approach needs to be verified.
Solution 2:
Similar to 1, but with calculations in the fragment shader to check, whether the texture coords are within the border area, instead of the texture border. Without modification, the scalars of a texture coord range from 0.0 to 1.0.
Texture properties may be:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP)
The fragment color could be determined by any of these methods:
an additional border color attribute for the rectangle, where either the texel or that border color is selected then (could be a vertex attribute, but more likely an uniform or constant).
combination of the alpha texture with a second texture as background for the whole rectangle (like a picture frame) and here too, either texel is choosen.
some other math function
Of course, the color values could be mixed for image/border gradients.
EDIT:
As the number, length and position of such outline segments will vary and can even form concave shapes, you'd need to do this with a geometry shader, which is not available in ES 2.0 core. The best thing you can do is to precompute a line loop for each image on the CPU. Doing such tests in a shader is rather inefficient and even overkill, depending on image size, the hardware you actually run it on etc. If you'd draw a fixed amount of line segments and transform them using the vertex shader, you can not properly cover all cases, at least not without immense effort and GPU workload.
Should you intend to change the color values of corresponding texels, your fragment shader would need to fetch a massive and varying amount of texels for each neighbour pixel towards the texture edges as in all other implementations. Such brute force techniques are usually a replacement for recursive and iterative algos, for which the CPU is a better choice. So I suggest that you do it there by either modifying the texture or generate a second one for combination in the fragment shader.
Basically, you need to implement a path finding algo, which tries to 'get around' opaque pixels towards any edge.
Your alpha channel can be seen as a grey scale image. Look for any edge detection/drawing algorithm. For example Canny edge detector (http://en.wikipedia.org/wiki/Canny_edge_detector). Alternatively and probably much better idea if your images are not procedural is to pre-compute the edges.
If your goal is to blend various images and then apply the contour from the result of that blending, try rendering to a texture and then render again that texture over the screen and perform the edge detection algorithm.
I created one sphere using OpenGL ES20 in Android. In a perspective projection env, I animate the sphere from [-1.5, -2, -2] to [-1.5, 2, -2] . The problem is that, the sphere looks like a ellipse when it reach the frustum boundary. Indeed, it only look like a circle when it is at [0, 0, -2], the more it away from the [0,0], the more it looks like a ellipse.
Is this the standard behavior ? I thought, one sphere should look like a circle in all angles of view. Could you please help ?
You should lessen your field of view; what you show is normal and is a side effect of the slightly artificial nature of a 3d projection — a 3d projection assumes the viewer is sitting a fixed distance from the screen and that their eyes are positioned along z directly from the centre of the screen looking exactly forwards. Check out the related problems described here for a description of the same effect with a real camera.
Quite often the implicit default field of view is ninety degrees. But when you hold a phone in your hand it occupies much less than ninety degrees of your vision.
If you're using glFrustum then try specifying lesser values for left, right, top and bottom. As a quick fix, just throw a glScalef by, say, 2.0 onto your projection stack (or your ES 2 equivalent) after computing your projection matrix.
I am using textured quads to render a grid of tiles from a sprite sheet. Unfortunately when rendered, there are small gaps between the individual tiles:
Changing the texture parameters to scale the texture using GL_NEAREST rather than GL_LINEAR fixes this, but results in artifacts within the textured quad itself. Is there some way to prevent GL_LINEAR from interpolating using pixels outside of the specified UV coordinates? Any other suggestions for how to fix this?
For reference, here's the sprite sheet I am using:
Looks like a precision problem with your texture maps, are you using floats (32bit) or something smaller ? And how do you calculate the coordinates ?
Also leaving a 1 pixel border between texture sometimes helps (sometimes you always get a rounding error).
Myself I use this program http://www.texturepacker.com/ (not affiliated in any way), and you get the texture map and UV coordinates from it, you can also specify a padding around the textures and it can also extrude the last color around your texture, so even if get weird rounding probs you can always get a perfect seam.
I would check your precision and calcs first though.
I need to draw a spinning globe using opengl es in android. I think we need to draw a sphere and then apply a texture map on it. If I am correct, we cannot use the utility library glu in Opengl ES for drawing a sphere. I did find some code in objective C, but then I would have to make it work on android.
http://www.iphone4gnew.com/procedural-spheres-in-opengl-es.html
Is there any other way to do this ? I'm no sure how to approach this problem, Could you give me some inputs that would set me looking in the right direction.
Thanks
You could actually create your own sphere rendering function.
A tesselated sphere is no more then a stack of n cone segments, each approximated with m slices.
This image (courtsey of dglwiki.de) illustrates this:
(the german text translates to 'If the resolution is to low, the sphere degenerates to other symetric Bodies)
In order to construct the sphere, you'll need to specify the center point, radius, number of stacks and number of slices per stack.
The first pole of your sphere can be any point with a distance of radius from the center point. The vector from this point to the center point defines your sphere's axis of rotation (and thereby the position of the second pole)
Next, you'll need to approximate several equidistant circles of latitude on your sphere around the axis of rotation. The number of circles should be number of stacks -1. Each of these circles should have as much vertices as your desired number of slices.
Having calculated these, you have enough geometry information to construct your spheres faces.
Begin with a triangle fan originating at one of the poles using the vertices of the first circle.
Then, construct Triangle strips for each pair of neighbouring circles of latitude. The last step is to construct another triangle fan from the second pole to the last of your circles of latitude.
Using this approach, you can generate arbitrary spheres of arbitrary smoothness
In addition to what sum1 says, the link you provide to obj-C code is mostly just C, which translates quite nicely to Java/android. The technique provided is very similar to the one sum1 suggests, although the author uses only one fan at the top, then draws the entire remainder of the sphere with a single triangle strip. In addition, his globe is "laying on its side", with the fan at the "East pole" and the other point at the "west pole."
However, you can either use the link you provide as-is, or make the adjustments easily enough.
I'm new to opengl-es on android and struggling to get my head around the concept of texturing.
I am looking to produce a tilemap of various difference textures. I understand that it is better to use an atlas of all the combined textures so I don't repeatedly rebind. However I am unsure quite how to then map these textures on to my tilemap.
I understand the process of specifiying vertices and then coordinates of where on the texture map I wish to take them from (i drew a picture too!)
Click for image - curse newbies not allowed to post images :(
But my question is can I draw a triangle strip that is, in effect, longer than one "tile" but map a different area of the texture to that "tile".
So instead of drawing a triangle strip pretending to be a quad, one at a time for each tile, can I somehow draw a whole row of the tilemap (like 1,2,3,4 and cleverly shift around the texture coordinates so each "tile" is now from a different area of the texture? So for example I draw a triangle strip 4 tiles long but shift the texture coordinates so the first "tile" is the yellow of my texture the second red ... third blue... etc
If I've not explained myself too well apologies!
It might just be that this is not possible and I have to draw each one individually which seems like I've saved effort with an atlas, then had to draw them all out slowly anyway regardless. Hmm.
Sure, just adjust texture coordinates, that is how texture atlases work.