I am trying to draw a line of specific width using libgdx shape renderer. I followed this link
The problem is if i specify more line width i.e more than 9 it does not show increased width. More than 9 either i specify 20 or 100 pixels it will have the same result as 9
shapeRenderer.begin(ShapeType.Line);
shapeRenderer.line(50, 70, 0, 50, 200, 0, Color.BLUE, Color.RED);
int lineWidth = 20; // pixels
Gdx.gl10.glLineWidth(lineWidth / camera.zoom);
shapeRenderer.end();
Thanks
Shakeel
To query the range of supported widths and the size difference between
supported widths within the range, call glGet with arguments
GL_ALIASED_LINE_WIDTH_RANGE, GL_SMOOTH_LINE_WIDTH_RANGE, and
GL_SMOOTH_LINE_WIDTH_GRANULARITY.
Reference
To avoid device specific behavior, I use a quad instead. Draw a 1x1 square from a small texture and then position, scale (depending on the width and height of the line you wanted to draw), color, and rotate it.
You should use ShapaRenderer.rectLine. You can see a more detailed answer here
Use this
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
instead of shapeRenderer.begin(ShapeType.Line);
Replace 10 with line width you want
Gdx.gl.glLineWidth(10 / camera.zoom);
Related
I'm developing a simple a graphical editor for my flash-based app. In my editor there's a posibility of scaling, range of scaling is big (maximum scale is 16.0, minimum scale is 0.001 and default scale is 0.2). So it's quite possible that a user can draw a line with thickness 0.1 or 300.0, and it looks that line possible thickness (in Graphics.lineStyle()) has upper border. As I found out from livedocs maximum value is 255. So if thickness is greater then 255.0 there'is drawn a line of thickness 255.0. Whether mentioned upper border exists and how big is it. Here're my questions:
Right now I'm drawing lines with drawPath() or lineTo() methods. Natural walkarround if thickness is greater then 255.0 is to draw a rectange instead of segment and two circles on the ends of segment (instead of lineTo()). Or even to draw two thin segments and two half-circles and fill interior. Maybe there's more elegant/quick solution?
Another question is if the thickness of line is big but less then 255.0 (e.g. 100.0), what is faster drawing a line with lineTo() or drawing two thin segments and two half-circles and fill interior?
And finally, maybe someone knows a good article/book where I can read what's inside all methods of flash.display.Graphics class (or even not flash specific article/book on graphics)?
Any thoughts are appreciated. Thank you in advance!
I agree with f-a that putting the line in a container would probably be better and more efficient than drawing a rectangle and extra circles.
I don't think that the math would be too difficult to work out. For efficiency you should probably only do this if the line style is going to be over 255.
To setup the display object to hold your line I would start by halving the width of your line (the length can stay the same). Then create a new sprite and draw the line in the sprite at half size (e.g. if you wanted 300, just draw it at 150). It would be most simple to just start at (0,0) and draw the segment straight so that all of your transformations can be applied to the new sprite.
From here you can just double the scaleY of the sprite to get the desired line weight. It should keep the same length and the ends should also be rounded correctly.
Hope this helped out!
A cool resource for working with the graphics class is Flash and Math. This site has several cool effects and working examples and source code.
http://www.flashandmath.com/
DisplayObject.getBounds in actionscript returns the bounds of the object with the strokes included. The left, top, width, height properties of a SymbolInstance in JSFL don't seem to include the strokes. That's the only way I've found to get the bounds of a symbol from JSFL. Is there another way?
You are looking for the Edge object on a Shape. The Edge has a Stroke object that has a thickness property.
// This will show the selected shape's first edge's thickness:
fl.trace(fl.getDocumentDOM().selection[0].edges[0].stroke.thickness );
You will have to loop over all the shapes and all of their edges to determine final bounds (if you are confident that all the edges have the same thickness, just check one).
Strokes have 0 width to JSFL, when it comes to getting the bounds of an object.
The only method I can think of is to edit the symbol, select the shape, and either
1.) get the stroke size and add 1/2 of its value to your calculation, or
2.) convert the stroke to a fill (unreliable for complex outlines)
If you only wish to include the strokes but exact sizing is not crucial, you can just arbitrarily add some pixels to the result of getBounds.
I'm drawing line graphs on a canvas. The lines draw fine. The graph is scaled, every segment is drawn, color are ok, etc. My only problem is visually the line width varies. It's almost like the nib of a caligraphy pen. If the stroke is upward the line is thin, if the stroke is horizontal, the line is thicker.
My line thickness is constant, and my strokeStyle is set to black. I don't see any other properties of the canvas that affect such a varying line width but there must be.
Javascript:
var badCanvas = document.getElementById("badCanvas"),
goodCanvas = document.getElementById("goodCanvas"),
bCtx = badCanvas.getContext("2d"),
gCtx = goodCanvas.getContext("2d");
badCanvas.width = goodCanvas.width = badCanvas.height = goodCanvas.height = 300;
// Line example where the lines are blurry weird ect.
// Horizontal
bCtx.beginPath();
bCtx.moveTo(10,10);
bCtx.lineTo(200,10);
bCtx.stroke();
//Verticle
bCtx.beginPath();
bCtx.moveTo(30,30);
bCtx.lineTo(30,200);
bCtx.stroke();
// Proper way to draw them so they are "clear"
//Horizontal
gCtx.beginPath();
gCtx.moveTo(10.5,10.5);
gCtx.lineTo(200.5,10.5);
gCtx.stroke();
//Verticle
gCtx.beginPath();
gCtx.moveTo(30.5,30);
gCtx.lineTo(30.5,200);
gCtx.stroke();
// Change the line width
bCtx.lineWidth = 4;
gCtx.lineWidth = 4;
// Line example where the lines are blurry weird ect.
// Horizontal
bCtx.beginPath();
bCtx.moveTo(10,20.5);
bCtx.lineTo(200,20.5);
bCtx.stroke();
//Verticle
bCtx.beginPath()
bCtx.moveTo(50.5,30);
bCtx.lineTo(50.5,200);
bCtx.stroke();
// Proper way to draw them so they are "clear"
//Horizontal
gCtx.beginPath();
gCtx.moveTo(10,20);
gCtx.lineTo(200,20);
gCtx.stroke();
//Verticle
gCtx.beginPath();
gCtx.moveTo(50,30);
gCtx.lineTo(50,200);
gCtx.stroke();
HTML:
<h2>BadCanvas</h2>
<canvas id="badCanvas"></canvas>
<h2>Good Canvas</h2>
<canvas id="goodCanvas"></canvas>
CSS:
canvas{border:1px solid blue;}
Live Demo
My live demo basically just recreates what the MDN says. For even stroke widths you can use integers for coordinates, for odd stroke widths you want to use .5 to get crisp lines that fill the pixels correctly.
From MDN Article
If you consider a path from (3,1) to (3,5) with a line thickness of
1.0, you end up with the situation in the second image. The actual
area to be filled (dark blue) only extends halfway into the pixels on
either side of the path. An approximation of this has to be rendered,
which means that those pixels being only partially shaded, and results
in the entire area (the light blue and dark blue) being filled in with
a color only half as dark as the actual stroke color. This is what
happens with the 1.0 width line in the previous example code.
To fix this, you have to be very precise in your path creation.
Knowing that a 1.0 width line will extend half a unit to either side
of the path, creating the path from (3.5,1) to (3.5,5) results in the
situation in the third image — the 1.0 line width ends up completely
and precisely filling a single pixel vertical line.
If linewidth is an odd number, just add 0.5 to x or y.
I just solved a problem of a similar nature. It involved a bug in a For loop.
PROBLEM: I had created a for loop to create a series of connected line segments and noticed that the line was thick to start but thinned out significantly by the final segment (no gradients were explicitly used).
FIRST, DEAD END THOUGHT: At first I assumed it was the above pixel issue, but the problem persisted even after forcing all the segments to remain at a constant level.
OBSERVATION: I noticed that I made a newbie's mistake -- I only used a single "ctx.beginPath()" and "ctx.moveTo(posX,posY)" PRIOR to the For loop and a single "ctx.stroke()" AFTER the For loop and the loop itself wrapped a single ctx.lineTo().
SOLUTION: Once I moved all methods (.beginPath(), .moveTo(), .lineTo() and .stroke()) together into the For loop so they would all be hit on each iteration, the problem went away. My connected line had the desired uniform thickness.
Try lineCap = "round" and lineJoin = "round". See "Line Styles" in this PDF to see what these parameters do.
Edit 17-July-2015: Great cheat sheet, but the link is dead. As far as I can tell, there's a copy of it at http://www.cheat-sheets.org/saved-copy/HTML5_Canvas_Cheat_Sheet.pdf.
In Flash, pixels are calculated using twips, or twentieth of a pixel. Consequently, every position is always in multiples of 0.05. I haven't seen this mentioned in the HTML Canvas spec and am unable to trace the cursor position on Canvas. Does anyone know the accuracy of its pixel calculations?
Edit for clarification:
I'm referring more to Zeno's paradox which says in order to move something from point A to point B, it must first move to a point halfway between the two. And then halfway again, ad infinitum.
So if I want to move on the x axis from point 0 to 100 at 0.5:
At frame 1: 50
Frame 2: 75
Frame 3: 87.5
Then: 93.75, 96.875, 98.4375... etc.
So at what step does the Canvas actually round-up to the next pixel?
I'm unsure what you mean by accuracy of slicing.
Pixels on the Canvas can be drawn to a little less than 0.10, after which they make barely any visible impact.
Of course, if you scale, you can draw things that are 0.00125 pixels, and so on. But they won't be visible if you unscale.
http://jsfiddle.net/GvVD9/
(That first square block on the top-left is a pixel)
Accuracy of the mouse is an entirely different thing, in no way related to the canvas spec.
EDIT:
Well, we can sorta demonstrate that. We can draw a bunch of pixels with y values approaching 100 and see how they compare to a red pixel drawn with the y value 100.
http://jsfiddle.net/GvVD9/46/
Every single horizontally separated piece is just a single 1 by 1 pixel rect using the drawRect command.
50
75
87.5
93.75 // first black pixel you see in image
96.875
98.4375
99.21875
99.609375
99.8046875
99.90234375
99.951171875
99.9755859375
99.98779296875
99.993896484375
99.9969482421875 // last black pixel you see in image
I'm using the AS3 drawRoundRect function as in the following snippet:
g.lineStyle(1, 0x808080, 1, true);
g.drawRoundRect(0, 0, 100, 24, 12, 12);
As you can see, pixel hinting is on.
The problem I'm having is corners being anti-aliased way too much, they are way too blurry and not even symmetrical on the above snippet. Frankly, the drawRoundRect function draws the ugliest rounded rectangles that I've ever seen.
Is there a way to make AS3 draw more crisp rectangles?
Thanks!
:)
fills are rendered much better than lines. as you can see here:
const thickness:Number = 1;
g.beginFill(0x080808);
g.drawRoundRect(0, 0, 100, 24, 12);
g.drawRoundRect(thickness, thickness, 100 - 2 * thickness, 24 - 2 * thickness, 12 - thickness);
g.endFill();
g.lineStyle(thickness, 0x080808, 1, true);
g.drawRoundRect(0, 50, 100, 24, 12);
well, it is not SOOOOOOOOOOO unincredibly better ... :-S ... but at least its symetric ... and the smudges on the corners are more like little beads ... :-D
greetz
back2dos
I've had similar problems in the past. It usually came down to one of the movieclips along the display path not being on an even pixel. Flash then tries to render fractional pixels, which it can't do, which caused distortion and blurriness.
So, make sure all your movieclips/sprites are on an even pixel (I know you're drawing the rect on even pixels, but if the displayobject it belongs to, or any of its parents aren't on an even pixel, it would be causing the problem).
I've had the same deal, as well. One hacky trick you could try is to apply a minor blur filter to the parenting object.
It looks like you're using the drawRoundRect method of the Graphics class.
If the object you're working with is a UIComponent, you could try using the drawRoundRect method of UIComponent. It takes an Object for the cornerRadius value, rather than setting ellipse width and height values. I'm not 100% sure that the cornerRadius value isn't converted into ellipse width and height, but it seems like it'd be something to try.
Also, you could try the GraphicsUtil class's drawRoundRectComplex. It takes a Number for each corner's radius. Again, not completely sure that it doesn't eventually use the same underlying mechanics as drawRoundRect.
When you using drawRoundRect set X to be half of thickness, and then thickness will be on rounded pixel. In this your case try:
g.lineStyle(1, 0x808080, 1, true);
g.drawRoundRect(0.5, 0.5, 99, 23, 12, 12);