Stencil buffer clear values not 0? - opengl-es

Ive been trying to understand / debug a problem to do with the stencil buffer. I probably dont understand how it works versus how I think it works. Essentially I have a scene where I render all my solid objects and assign them a stencil value of 1. I then go through the same scene again, but the second time I render only the transparent objects and give them a stencil value of 2. In the final step I have a screen quad that draws the scene to a texture. I want to use the stencil buffer to only draw the final quad where the stencil bits were set to 1 or 2. So in code:
// First enable the stencil buffer
gl.enable( gl.STENCIL_TEST );
gl.clearStencil( 0 );
gl.clear(gl.STENCIL_BUFFER_BIT); // presumably this clears the buffer to 0?
// ...for the solid meshes
gl.stencilFunc( gl.ALWAYS, 1, 0xffffffff ); // Always pass the stencil
gl.stencilOp( gl.REPLACE, gl.REPLACE, gl.REPLACE ); // Replace the stencil value with ref=1
// ...for the transparent meshes
gl.stencilFunc( gl.ALWAYS, 2, 0xffffffff ); // Always pass the stencil
gl.stencilOp( gl.REPLACE, gl.REPLACE, gl.REPLACE ); // Replace the stencil value with ref=2
// ...for the final screen quad
gl.stencilFunc( gl.GEQUAL, 1, 0xffffffff ); // Only draw the bits higher than 1 (so 1 and 2 should be included)
gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP); // Dont touch the stencil values in the buffer
However this never seems to work. From my tests it seems as though the stencil values are set to 0xffffffff before I assign them values. This makes the GEQUAL test pointless as the buffer values are greater than 0.
I created a JS fiddle to demo what I mean. I draw a small square and assign its values to 4. Then draw a bigger square and test for gequal to 5. I would have thought that the bigger square would always fail. However it always passes. When I test using gl.stencilFunc( gl.GEQUAL, 4, 0xffffffff ); I see the correct small square only. But when I test gl.stencilFunc( gl.GEQUAL, 0xffffff, 0xffffffff ); then it also looks correct. This to me says that the stencil buffer is not set to 0?
http://jsfiddle.net/90af0rov/
Im really confused and would appreciate any pointers on this <:(

You are getting the GEQUAL operation the wrong way around in stencilFunc.
See the documentation here: https://www.opengl.org/sdk/docs/man2/xhtml/glStencilFunc.xml
GL_GEQUAL
Passes if ( ref & mask ) >= ( stencil & mask ).
So in your code example, it will only draw when ref (which is 1) is greater equal to the value currently in the stencil buffer. If you change it to:
gl.stencilFunc( gl.LESS, 0, 0xffffffff );
Then it should fix it, as it will now pass if the ref of zero is less than the value in the stencil buffer. You could also use NOTEQUAL instead of LESS in this case.

Related

How to use the DXGI flip model in a Direct2D windowed app?

I have a Win32 non-game windowed app that uses a Direct2D device context/HWND render target to draw a window. Currently it uses a DXGI swap chain with the DXGI_SWAP_EFFECT_DISCARD swap effect.
Microsoft recommends using the new flip model swap effects, either DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL or DXGI_SWAP_EFFECT_FLIP_DISCARD. I'm interested in using them primarily because they would allow me to specify a list of dirty rects when calling Present1(), which should improve performance/power usage.
Simply changing the SwapEffect to either of the new flip model values produces a weird (but actually expected) result of drawing a black window each second frame, with artifacts of the previous frames visible onscreen.
So the question is: is it possible to use the new flip model swap effects in this situation, and if yes, how should things be set up?
Given that the app needs to draw the dirty rects into an otherwise valid buffer, it seems that a correct approach would involve maintaining two buffers with essentially the same content (one to draw into, and one to give to the DWM for composition), so not sure if it would be possible to achieve any performance gains this way in an app that doesn't redraw each frame completely. But perhaps I'm missing something important.
The swap chain is currently set up as follows:
swapChainDesc.Width = ...;
swapChainDesc.Height = ...;
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapChainDesc.Stereo = false;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
swapChainDesc.Flags = 0;
EDIT 1
It turns out that DXGI_SWAP_EFFECT_DISCARD forces BufferCount to 1, so my initial value of 2 was somewhat misleading, as only one buffer is used. Source (3rd comment).
Also the docs for DXGI_SWAP_EFFECT say that UWP apps are forced into the flip model, so this should be a solvable problem.
There are two good ways to do it.
The first way is a little heavier on energy usage. You can draw your contents into an intermediate buffer/render texture, and copy it to swapchain just before every present. That way you can only actually render the parts that changed in your intermediate buffer, and not care about what the state of the swapchain is.
The second way is more complicated, but can yield optimal energy usage. Instead of using intermediate buffer and drawing only what changes since the last frame there, you draw directly into the swapchain buffer. For this to work correctly, you need to redraw not what changes between current and last frame, but between current and (current - BufferCount) frame. For instance:
Frame 1 - you draw a green rectancle at (200 x 200) with dimensions of (150 x 150). The dirty region is entire frame because it's the first frame.
Frame 2 - you draw a blue rectangle at (250 x 250) with dimensions of (50 x 50). The dirty region is (250, 250, 300, 300).
Frame 3 - you draw a red rectangle at (225 x 225) with dimensions of (50 x 50). The dirty region is (225, 225, 50, 50).
If your buffer count is 2, that means when you draw frame 3, you need to not only redraw the dirty region of (225, 225, 50, 50), but also the dirty region of (250, 250, 300, 300).

OpenGL transparency in texture when render with stencil buffer

The question has been updated thanks to the comments.
Screenshot of how textures overlap
To draw 2 points with brush texture using the stencil buffer to avoid textures transparency overlap, the following code is used:
glEnable(GL_STENCIL_TEST.gluint)
glClear(GL_STENCIL_BUFFER_BIT.gluint | GL_DEPTH_BUFFER_BIT.gluint)
glStencilOp(GL_KEEP.gluint, GL_KEEP.gluint, GL_REPLACE.gluint)
glStencilFunc(GL_ALWAYS.gluint, 1, 1)
glStencilMask(1)
glDrawArrays(GL_POINTS.gluint, 0, 1)
glStencilFunc(GL_NOTEQUAL.gluint, 1, 1)
glStencilMask(1)
glDrawArrays(GL_POINTS.gluint, 1, 1)
glDisable(GL_STENCIL_TEST.gluint)
And stencil buffer works, however, each point fill a full rectangle in the stencil buffer, but a texture image has transparency. So maybe texture used in the wrong way?
The texture is loaded like this
glGenTextures(1, &gl_id)
glBindTexture(GL_TEXTURE_2D.gluint, gl_id)
glTexParameteri(GL_TEXTURE_2D.gluint, GL_TEXTURE_MIN_FILTER.gluint, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D.gluint, 0, GL_RGBA, gl_width.int32, gl_height.int32, 0, GL_RGBA.gluint, GL_UNSIGNED_BYTE.gluint, gl_data)
Blending set as
glEnable(GL_BLEND.gluint)
glBlendFunc(GL_ONE.gluint, GL_ONE_MINUS_SRC_ALPHA.gluint)
Could you please advice where to look in order to fill 1s in stencil buffer by exactly not transparent area of brush image?
I recommend to discard the transparent parts of the texture in the fragment shader. A fragment can be completely skipped in the fragment shader by the discard keyword.
See Fragment Shader - Special operations.
Use a small threshold and discard a fragment, if the alpha channel of the texture color is below the threshold:
vec4 texture_color = .....;
float threshold = 0.01;
if ( texture_color.a < threshold )
discard;
An other possibility would be to use an Alpha test. This would be only available in OpenGL compatibility profile, but not in core profile or OpenGL ES.
See Khronos OpenGL-Refpages glAlphaFunc:
The alpha test discards fragments depending on the outcome of a comparison between an incoming fragment's alpha value and a constant reference value.
With the following alpha test, the fragments whos alpha channel is below the threshold are discarded:
float threshold = 0.01;
glAlphaFunc(GL_GEQUAL, threshold);
glEnable(GL_ALPHA_TEST)

Give 2d image customization to produce real view

Is it possible to add image/text on the 2d image so that it gives a real view.For example as present in : http://www.zazzle.com/make_your_own_iphone_5_case-179092402149274498.
These views are orthographic and isometric views and they can be reproduced using affine transformations in canvas, as they are also parallelograms.
First you will need to make masks for the different cases. These needs to be drawn in the same orientation as the case in the "photo". Use solid pixels (any color will do, it won't show in later step) where you want the custom graphics to show, transparent pixels anywhere else (anti-aliased pixels are fine).
Then draw in the mask in the canvas, select composite mode "source-in" to replace non-transparent pixels and finally, select blending mode "multiply" and draw the case "photo" on top to mix in shadows and highlights. The latter step is what will give the illusion of the image having depth.
For the isometric views, calculate the skew angle (or use trial and error if you're not sure if the image is accurate - this is as a rule-of-thumb usually tan(60°), ie. transform(1, 0, Math.tan(60/180*Math.PI), 1, 0, 0)), then do the same process as above. Just remember only apply transformation when drawing the custom image, mask and top layer must be drawn without transformations.
The orthographic side views can be generated using scaling for the x-axis. Depending on which angle, add a stripe for the side of the case.
Example of steps
var img = new Image(),
cust = new Image(),
count = 2,
ctx = document.querySelector("canvas").getContext("2d");
img.onload = cust.onload = comp;
img.src = "http://i.stack.imgur.com/je0Jh.png";
cust.src = "http://i.stack.imgur.com/uRPDt.png";
function comp() {
if (--count) return;
// draw in mask
ctx.drawImage(img, 0, 0);
// comp. mode source-in
ctx.globalCompositeOperation = "source-in";
// draw in custom graphics
ctx.drawImage(cust, 0, 0, ctx.canvas.width, ctx.canvas.height);
// blend mode multiply
ctx.globalCompositeOperation = "multiply";
// draw in original case multiplied (does not work in IE)
ctx.drawImage(img, 0, 0);
}
<canvas with=263 height=505></canvas>
The quality largely depends on the quality of the mask - I made a very quick-n-dirty version here as you can see (your case image can also act as the mask btw).
The steps are the same for the isometric view with the exception of the skew transform. Multiply does not work in IE, you can use alpha here instead or make a separate mask containing only shadows etc.
That being said: remember that this is not the image sent to production. This will just show a representation of the final result. What is used is the image, image position and size. These data is then used to build an unmasked flat print-template which is used to make the phone-case.

Masking with glBlendFunc, without frame buffers

I'm hoping this is possible to do without using frame buffers or shaders, just by straight up using the glBlendFunc or glBlendFuncSeparate.
I'm rendering my scene normally with my standard blend mode:
glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
Ontop of that scene, I want to draw a texture which is masked by some other texture. These are drawn at arbitrary positions (not necessarily rectangular, not necessarily the same size / position as each other).
The order is; render the masked texture, then the mask texture.
The masked texture is a regular image, with alpha.
The mask texture either black RGBA(0, 0, 0, 255), or transparent RGBA(0, 0, 0, 0)
I want anything that the black does NOT touch, to be invisible. Basically, the final result should be:
RGBA(masked.r, masked.g, masked.b, masked.a * mask.a)
Below are images of the ordering, to explain what I mean. I'm really looking for a solution to avoid having to use a different shader or stick things onto a framebuffer. If it absolutely isn't possible, please let me know.
I'll explain why this isn't possible. Masking with blending requires three passes because it has three parts: the destination, the source, and the mask. No matter what you do, you must blend the source and the mask into a framebuffer and THEN render to destination.
The stencil buffer, however, is built into the default window framebuffer, provided you tell OpenGL to provide for it (like you would a depth buffer), and appears to do exactly what you want. As a GLUT call, it would look like this to initialize the stencil buffer in your window along with the alpha-enabled color and depth buffers, in a double-buffered window:
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_ALPHA | GLUT_DEPTH | GLUT_STENCIL);
The stencil buffer is able to do exactly what you need - you can draw a shape in it, and selectively tell it to either discard or keep pixels inside that shape. Here's an example of how to use it, modified from the the OpenGL Red Book:
GLdouble dRadius = 0.1; // Initial radius of spiral
GLdouble dAngle; // Looping variable
// Use 0 for clear stencil, enable stencil test
glClearStencil(0);
glEnable(GL_STENCIL_TEST);
// Clear stencil buffer
glClear(GL_STENCIL_BUFFER_BIT);
// All drawing commands fail the stencil test, and are not
// drawn, but increment the value in the stencil buffer.
// glStencilFunc takes three arguments: the stencil function, the reference value, and the mask value. Whenever the stencil function is tested (for example GL_LESS), both the reference and the stencil value being tested from the buffer is bitwise ANDed with the mask: GL_LESS returns true if (ref & mask) < (stencil & mask).
glStencilFunc(GL_NEVER, 0x0, 0x0);
// glStencilOp takes three arguments: the stencil operation to call when the stencil test fails, the stencil operation to call when the stencil test passes but the depth test fails, and the stenciloperation to call when the stencil test passes AND the depth test passes (or depth test is disabled or no depth buffer is allocated).
glStencilOp(GL_INCR, GL_INCR, GL_INCR);
// Spiral pattern will create stencil pattern
// Draw the spiral pattern with white lines. We
// make the lines white to demonstrate that the
// stencil function prevents them from being drawn
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_LINE_STRIP);
for(dAngle = 0; dAngle < 400.0; dAngle += 0.1)
{
glVertex2d(dRadius * cos(dAngle), dRadius * sin(dAngle));
dRadius *= 1.002;
}
glEnd();
// Now, allow drawing, except where the stencil pattern is 0x1
// and do not make any further changes to the stencil buffer
glStencilFunc(GL_NOTEQUAL, 0x1, 0x1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
// Now draw red square
glColor3f(0.0f, 1.0f, 0.0f);
glRectf(0, 0, 200, 200);
The output of this drawing code is a red square, with a spiral across it, starting at (1, 1). The spiral is made up of discarded pixels, and as such will be the same color as the cleared color buffer. If you were to use this code for your purposes, you would draw the square where you wanted your texture to be where the spiral code is written, and then use GL_EQUAL as the stencil function, drawing your masked texture where the red square is drawn. More information on the stencil buffer can be found here.

glDrawPixels() with 0.375 translation

I've noticed some strange behaviour with glDrawPixels() when using a 0.375 translation. This is my GL initialization:
width = 640; height = 480;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity( );
glOrtho(0, width, height, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity( );
glTranslatef(0.375, 0.375, 0.0);
Now I want to draw a 640x30 pixel buffer to the very last 30 rows of my GL window. Hence, I do the following:
glRasterPos2i(0, 480);
glDrawPixels(640, 30, GL_RGBA, GL_UNSIGNED_BYTE, pixelbuffer);
Unfortunately, nothing gets drawn using this code. glGetError() also returns 0. The interesting thing is that as soon as I remove the call to glTranslatef(0.375, 0.375, 0.0) everything works fine!
So could somebody explain to me why this 0.375 translation on both axes confuses glDrawPixels()? Is this somehow rounded to 1.0 internally making my call to glDrawPixels() suddenly want to draw beyond the context's boundaries and thus it gets clipped by OpenGL? This is the only explanation I can think of but I don't understand why OpenGL should round a 0.375 translation to 1.0... it should be rounded down to 0.0 instead, shouldn't it?
The point (0,480) actually straddles one of your clipping planes given your projection matrix. Your sub-pixel shift hack pushes the point beyond the breaking point and the raster position is clipped. In GL, glRasterPos (...) will invalidate all following raster operations as long as the initial position is clipped (which in this case, it is).
You could try glRasterPos2i (0, 479). This is altogether more meaningful given the dimensions of your window anyway. You could also drop the whole charade and use glWindowPos2i (...) instead of relying on your projection and modelview matrices to position the raster coordinate in window-space.
I can't answer your question on why glTranslatef stops glDrawPixels from working, but I can tell you that isn't the way to select where to draw. Check the man page for glDrawPixels for a bit more info. It will tell you about glRasterPos and glWindowPos

Resources