I have some rounded rectangle geometry.
ID2D1RoundedRectangleGeometry *geo; (1)
First I draw it
target->FillGeometry(geo, brush); (2)
Then I apply clipping mask using ID2D1Layer with the same geometry:
target->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), geo), nullptr); (3)
And then, with layer I make some draw over it:
target->FillGeometry(mask, anotherBrush); (4)
... another draw calls
The result:
As you can see there is a problem with edges, seems like some part of initial draw (1) is not covered by mask, although has the same geometry.
Can it be solved without resizing initial draw area or the layer area?
Specifying antialias mode at (3), changes the result a bit, but still unsatisfying:
target->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), geo, D2D1_ANTIALIAS_MODE_ALIASED), nullptr); (3)
Related
I am using GL_LINE_STRIP and glLineWidth to draw lines.
However, this leads to gaps between the single, straight segments of the strip.
I had mitigated the problem by using Catmull-Rom Splines and thus the segments where smooth enough to not notice the gaps anymore:
But now I noticed the gaps are different depending on the OpenGL implementation. Mesa introduces larger gaps than my graphic card, notice the gaps in the upper part and how the lower part with much smaller segments is noticeably darker due to more gaps:
Please note that image 1 and 2 are the same render code, the opacity is 255 in both cases, just the used opengl32.dll differs.
I then added the drawing of every joint as point:
glBegin(GL_LINE_STRIP);
for (auto p : interpolatedPoints) {
glVertex2f(p.x, p.y);
}
glEnd();
glBegin(GL_POINTS);
for (auto p : interpolatedPoints) {
glVertex2f(p.x, p.y);
}
glEnd();
This works for opacity 255 but not if I want to reduce the objects transparency. What happens then, is that the transparent point overlays the transparent line strip, thus increasing the opacity especially in areas with very short strips:
Solution 1: Polyline quadstrip
Ditching GL_LINE_STRIP altogether and triangulate the line strip ourselves seems the solution here but this looks like a larger rewrite for me - either I need a new shader or I need to calculate the triangles.
Solution 2: Blending
Wanting to avoid the rewrite, I was wondering: can blending solve the issue? Currently I use
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Is there a blending configuration which would prevent the points to add on the alpha channels of the lines? I tried some other constants here but I had no success. Please note also that the black background in the screenshots may not be black at all but contain other objects and textures which should be "correctly" overlayed by the semi-transparent line.
As a potential easy fix, you could try setting glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) and see if that helps.
If you want your lines to look nice when drawn transparently, I suggest drawing all your lines onto a separate framebuffer than the rest of your scene, reusing the same depth buffer, and with full opacity. Then draw the lines framebuffer onto the rest-of-your-scene framebuffer with partial transparency.
I have followed this gtkmm tutorial on how to draw shapes and fill them with colors (e.g. A red disc on a transparent background). I was also able, from this example, to derive another example with a red disc on a blue background.
However, what I would really need is a transparent disc with a blue background that fills everything minus the disc area, which should stay transparent.
So with cairo, the usual workflow is:
Create a surface
Draw a shape (e.g. draw a circle)
Fill the circle, so that it becomes a disc.
I would need some workflow that achieves something like this instead:
Create a surface
Draw a shape (e.g. draw a circle)
Fill the area outside the circle, so that I have a colored background with a transparent "hole" in the middle.
I have done some research on this on the web but all examples seem to assume that we want to fill the inner region of a shape (which I must admit is more typical).
How could I do this?
P.S. I have added the C tag because I don't mind if you prefer to use C (or even Python).
Draw your circle and draw a rectangle containing all the visible area. Set the cairo fill rule to even/odd. Fill. Done.
cairo_save(cr); // Save the state
cairo_arc(cr, 42, 42, 21, 0, 2*M_PI); // Draw circle
cairo_rectangle(cr, 0, 0, width, height); // Rectangle containing everything
cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
cairo_fill(cr);
cairo_restore(cr); // Restore default fill rule (optional; pairs with save above)
IMHO, The function of 'Draw outside the circle' is complex to the graphic framework. It may also be ambiguous if you draw more than one circle filled outside.
As graphic shapes drawn later are placed 'on' the ones drawn former. What is needed is that draw a rectangle to fill the entire graphic context before drawing other shapes. This is defined as clear with the background color in some frameworks.
the workflow would seem like:
1. Create the surface.
2. Draw the background colored with what outside the circle.
3. Draw the circle filled with a specific color, e.g. white.
As a result, the circle would cover the background.
If insist on draw the circle first, please search Flood Fill Algorithm, which is used to draw on images. However, it is needless and costly to achieve the screen pixels and play such algorithms when drawing on screen.
I find
Example Application: Creating a Clock with Cairo in the later section of the book you provide.
That seems help.
I have found some code that will allow me to draw a rounded rectangle in OpenGL immediate mode (here).
What I would like to do it decrease the alpha, the further away from the centre of the rectangle - as would find under a Windows/Mac window or dialog for example where a shadow is drawn.
Can somebody point me to an example on how to do this?
This is relatively easy to do with geometry.
Create the vertices for two rounded rectangles: an inner one and an outer one. Assign an alpha of 1 to the inner rectangle, and an alpha of 0 to the outer rectangle. Triangulate both the inner rectangle and the space between the two rectangles. Unless you specifically ask otherwise, the alpha will be interpolated smoothly between the inner rectangle and the outer rectangle.
Something like this:
You may have better results using a texture and slicing the rectangle into 9 parts—this may give you better output with simpler geometry and simpler code, depending on your application.
I'm hoping to draw a plane in OpenGL, using C++, with a hole in the center, much like the green of a golf course for example.
I was wondering what the easiest way to achieve this is?
It's fairly simple to draw a circle and a plane (tutorials all over google will show this for those curious), but I was wondering if there is a boolean subtraction technique like you can get when modelling in 3Ds Max or similar software? Where you create both objects, then take the intersection/union etc to leave a new object/shape? In this case subtract the circle from the plane, creating a hole.
Another way I thought of doing it is giving the circle alpha values and making it transparent, but then of course it still leaves the planes surface visible anyway.
Any help or points in the right direction?
I would avoid messing around with transparency, blending mode, and the like. Just create a mesh with the shape you need and draw it. Remember OpenGL is for graphics, not modelling.
There are a couple ways you could do this. The first way is the one you already stated which is to draw the circle as transparent. The caveat is that you must draw the circle first before you draw the plane so that the alpha blending will blend the circle with the background. Then when you render the plane the parts that are covered by the circle will be discarded in the depth test.
The second method you could try is with texture mapping. You could create a texture that is basically a mask with everything set to opaque white except the circle portion which is set to have an alpha value of 0. In your shader you would then multiply your fragment color by this mask texture color so that the portions where the circle is located are now transparent.
Both of these methods would work with shapes other than a circle as well.
I suggest the stencil buffer. Use the stencil buffer to mark the area where you want the hole to be by masking the color and depth buffers and drawing only to the stencil buffer, then unmask your color and depth, avoid drawing to the stencil buffer, and draw your plane with a stencil function telling OpenGL to discard all pixels where the stencil buffer "markings" are.
Since GL_LINE_SMOOTH is not hardware accelerated, nor supported on all GFX cards, how do you draw smooth lines in 2D mode, which would look as good as with GL_LINE_SMOOTH ?
Edit2: My current solution is to draw a line from 2 quads, which fade to zero transparency from edges and the colors in between those 2 quads would be the line color. it works good enough for basic smooth lines rendering and doesnt use texturing and thus is very fast to render.
So, you want smooth lines without:
line smoothing.
full-screen antialiasing.
shaders.
Alright.
Your best bet is to use Valve's Alpha-Tested Magnification technique. The basic idea, for your needs, is to create a texture that represents the distance from the line, with the center of the texture being a distance of 1.0. This could probably be a 1D texture.
Then using the techniques described in the paper (many of which work with fixed-function, including the antialiased version), draw a quad that represents your lines. Obviously you'll need alpha blending (and thus it isn't order-independent). You use your line width to control the distance at which it becomes the appropriate color, thus allowing you to make narrow or wide lines.
Doing this with shaders is virtually identical to the above, except without the texture. Instead of accessing a distance texture, the distance is passed and interpolated from the vertex shader. For the left-edge of the quad, the vertex shader passes 0. For the right edge, it passes 1. You multiply this by 2, subtract 1, and take the absolute value.
That's your distance from the line (the line being the center of the quad). Then just use that distance exactly as Valve's algorithm does.
Turning on full-screen anti-aliasing and using a quad would be my first choice.
Currently I am using 2 or 3 quads to do this, it is the simpliest way to do it.
If line thickness <= 1px, then you need only 2 quads.
If line thickness > 1px, then you need to add third quad in the middle.
The fading edge quads thickness must not change if the line thickness >= 1px.
In the image below you can see the quads with blue borders. White color means full opacity and black color means zero opacity (=fully transparent).