In my game I have characters that have sprites that are drawn onto a off-screen canvas upon creation of the character. Now sometimes the characters have to face a different direction that usual, so I mirror them. My question is now:
what is more efficient:
Also pre-render the mirrored sprites so I can simply draw them onto
the canvas
Draw the sprites on a buffer and mirror them on it, then draw them
onto my game's canvas
Render them mirrored directly onto the canvas(for some reason always off by some pixels, prolly cause of rounding)
Related
I'm drawing an isometric grid with mouse-over hit area detection over each tile. It works but the frame rates are awful. Any idea what is bringing the frame-rates down so much? Surely, webGL is capable of attaining better FPS than this?
There are no moving sprites (only diamond-shapes PIXI.Graphics) drawn to the screen.
http://178.79.155.146/pc
Cheers,
Jordan
As a follow-up. With primitives we have to draw them to the stencil buffer each frame, then render that to the render buffer. With a sprite it is a single draw call to show the texture. If you have many sprites with the same texture we can batch them all together in a single draw call (we can't do that with Graphics).
Summary: For performance, use sprites (not WebGL primitive graphics!).
I made a speedtest to compare Snap.svg (SVG) to FabricJS (CANVAS):
http://jsbin.com/tadec/7 function dummy().
In Chrome SVG renders in 120 ms, while CANVAS renders in 1100 ms. SVG is 9x faster than CANVAS.
Fabricjs.com page says in this example that Raphael takes 225 ms and Fabric takes 97 ms (parsing: 80, rendering: 17).
I have had an impression (after reading fabricjs.com and paperjs.org) that FabricJS and more generally Canvas is faster than SVG.
My speed test claims that SVG is significantly faster than Canvas (at least Snap.svg seems to be significantly faster than FabricJS).
Why FabricJS is so slow in my test? Have I made some mistake in comparison, because I'm surprised that SVG seems to be faster than Canvas in my speed test.
EDIT: My question is two-parted: Why rendering speed is so much slower in FabricJS and why dragging speed as well?
Your benchmark is broken in my opinion, because beside measuring drawing to canvas you are measuring parsing of a huge string containing a path, over and over again. Separate this code out of the loop and you should get more reliable results.
Measurements that are provided for canvas libraries are provided for drawing, not for parsing or other pre-processing work. If you use canvas like you use SVG, then yes, it will be slower. It is not intended to be used like SVG. FabricJS provides a way to do that, but it is not optimal. One solution would be to parse path once, and then use same path over and over instead of parsing it every time.
Also, measurements are given probably for drawing a canvas, not for interaction with parts. As you say in comments, rendering may be improved, but why does dragging a shape take so much longer? Because:
maybe path is being reparsed on each redraw (not sure how FabricJS works)
because SVG can redraw only certain parts of image that you are moving, and canvas is usually redrawn completely. Why? Because you can't "erase" part of canvas where a shape used to be. So entire canvas is erased, and new positions are redrawn.
Why do then people say canvas is faster than SVG for such scenarios? Because it is if you use it properly. It will be more work, but it will work much faster.
Don't use SVG paths for drawing shapes, or use simple paths and cache them
Cache shapes which you use often into off-screen (hidden canvas) and then copy from that canvas onto visible canvas when needed
If you have multiple independant layers of an image (for example 3 layers in a game, if you have background sky which is moving, background mountains which are moving slower and a character), use multiple canvases. Put canvases one over another, draw sky on the bottom canvas, draw mountains on second canvas and draw character on top canvas. That way, when character on top canvas moves, you don't have to redraw entire background.
I hope my answer is useful for you :)
Say I have a rectangle that is 100 x 100 and I have a canvas 1000 x 1000.
As long as the rectangle's x co-ordinate is no more than 999 and no less than -100, it is true to say that some portion of the rectangle will be visibly seen on the canvas. Same goes for the rectangle's y co-ordinate.
What I would like to know is that if the rectangle's x or y co-ordinate is set so that the rectangle will not be visible on the canvas, does the internal workings of the canvas api still draw the rectangle or does it auto optimize and realise by itself that the bitmap that will be drawn on the canvas will not be seen, so therefore it doesn't attempt to draw it.
When drawing to canvas the boundaries are checked for each draw. If a pixel ends up outside the canvas it is clipped (discarded).
If not you would get a memory corruption and very soon a crash.
Canvas is designed to be very safe so you won't have poorly written Javascripts (intentional or not) crashing your browser. The same applies to colors where color values (f.ex. using a bitmap array directly) are clamped to be within the valid range.
Optimization is dependent on the implementation, but it's reasonably to assume that if the area is completely outside the boundaries of the canvas, the draw operation is rejected in full. If it is partly inside it may start the internal block copy by moving start and end cursor to represent the effective area that would be rendered visible.
The other option is to check each pixel as it is rendered, if it's inside or outside the visible boundary. This however is not optimal.
To visualize, only the gray areas would be considered, the light-blue would be ignored:
(I didn't show all possibilities but it should be easy to imagine the bottom parts etc.)
Cursor here is where the internal routine will start and stop looping through the pixels. In this case if the area to be drawn is 100x100 pixels and is drawn at -50, -50 (x,y) then the internal cursor is set to +50, +50 relative to the area being drawn and the width and height is reduced likewise.
By moving the cursor and adjusting the width and height, it doesn't have to iterate through all the pixels and therefor optimizes the copy (although, it is not quite accurate to say "all pixels", as data is not copied per pixel but mainly on block basis related to memory alignment. There are separate algorithms that deals with optimized memory copying and takes into account offset bytes (bytes that does not start or end on a "clean" memory boundary) and so forth, ie. 4 or 8 bytes are copied in one go rather than one and one byte combined with masking (AND'ing the bits)).
The boundaries apply to lines and circles etc. as well. Their effective drawing area is handled as a square area, but there are different approaches to draw lines, circles than a square of pixels, to optimize further.
See f.ex. Bresenham algorithm for lines or mid-point circle algorithm for circles or various algorithms for ellipses - I don't the specific implementation in each browser, but for these you square of the start and end coords and in some cases (as with circles and ellipses) you may have to check as you go (perhaps drawing the circle in four parts and check the part which is overlapping the boundaries on a pixel-individual basis - this is implementation specific though).
When it comes to translation that is merely a recalculation of coordinates (translate, rotation using rotation matrixes and stuff like that). The new coordinates are then checked against boundary.
Now that being said it is not sure the browsers have their own specific implementation. They might use the system's native bitmap and clipping functionality instead where possible. However, the same described above applies in this case as well.
FWIW, On IE, Chrome and FF the fully offscreen draws (non-draws?) took about 100ms less than onscreen draws for 100,000 rects.
According to the canvas spec:
"When the destination rectangle is outside the destination image (the scratch bitmap), the pixels that land outside the scratch bitmap are discarded, as if the destination was an infinite canvas whose rendering was clipped to the dimensions of the scratch bitmap."
This is not absolutely specific to your question but it's likely all "out of canvas view" operations are handled this way. So based on that, I'd say Yes, they are "optimised".
I am attempting to use an html canvas element to draw each character available in a font file to a canvas. To make this question as simple as possible, pretend only one character is drawn to a canvas. From there, I want to use Javascript to analyze the canvas and create triangle regions of the canvas that make up the entire character. The reason I need it in triangles is so that the data can later be sent to WebGL so text can be rendered and data will not be lost be scaling the text size up or down.
I am looking for some sort of algorithm to accomplish this or at least some knowledge to get me going in the right direction. If you believe I should use a different approach please tell me why, but I figured this would be the best to provide a way to modify text in many ways as well as make it possible to create 3d block text.
Here's an article on how to draw resolution independent curves with shaders
http://research.microsoft.com/en-us/um/people/cloop/loopblinn05.pdf
My understanding is instead of breaking the shapes into triangles you break them into quads with enough info sorted in the vertices to draw a portion of the curve inside each quad. In other words, as the shader draws each quad there's a formula that for each pixel can compute if that pixel is inside the curve or outside the curve.
I suggest you to start with the keyword Polygon Triangulation.
Using this methods, you can split n-Polygons into triangles like this:
These methods may only apply to figures with real (and not rounded) edges.
So, you are trying to convert a raster image into vector data?
When zoomed in, that will result in very jagged looking geometry.
Since each pixel is being treated as a square edged part of the geometry.
Couldn't you get your hands on the original vector (bezier curve) geometry for each glyph you are drawing?
Transforming that into triangle strips and fans would look smoother.
I'm trying to draw a tiled background using Javascript on an HTML5 canvas, but it's not working because shapes that intersect the edges of the canvas don't wrap around to the other side. (Just to be clear: these are static shapes--no motion in time is involved.) How can I get objects interrupted by one side of the canvas to wrap around to the other side?
Basically I'm looking for the "wraparound" effect that many video games use--most famously Asteroids; I just want that effect for a static purpose here. This page seems to be an example that shows it is possible. Note how an asteroid, say, on the right edge of the screen (whether moving or not) continues over to the left edge. Or for that matter, an object in the corner is split between all four corners. Again, no motion is necessarily involved.
Anyone have any clues how I might be able to draw, say, a square or a line that wraps around the edges? Is there perhaps some sort of option for canvas or Javascript? My google searches using obvious keywords have come up empty.
Edit
To give a little more context, I'm basing my work off the example here: Canvas as Background Image. (Also linked from here: Use <canvas> as a CSS background.) Repeating the image is no problem. The problem is getting the truncated parts of shapes to wrap around to the other side.
I'm not sure how you have the tiles set-up, however, if they are all part of a single 'wrapper' slide which has it's own x,x at say 0,0, then you could actually just draw it twice, or generate a new slide as needed. Hopefully this code will better illustrate the concept.
// Here, the 'tilegroup' is the same size of the canvas
function renderbg() {
tiles.draw(tiles.posx, tiles.posy);
if(tiles.posx < 0)
tiles.draw(canvas.width + tiles.posx, tiles.posy);
if(tiles.posx > 0)
tiles.draw(-canvas.width + tiles.posx, tiles.posy);
}
So basically, the idea here is to draw the groupings of tiles twice. Once in it's actual position, and again to fill in the gap. You still need to calculate when the entire group leaves the canvas completely, and then reset it, but hopefully this leads you in the correct direction!
You could always create your tillable image in canvas, generate a toDataUrl(), and then assign that data url as a background to something and let CSS do the tiling.. just a thought.
Edit: If you're having trouble drawing a tillable image, you could create a 3*widthx3*width canvas, draw on it as regular (assuming you grab data from the center square of data as the final result), and then see if you can't draw from subsets of the canvas to itself. Looks like you'd have to use:
var myImageData = context.getImageData(left, top, width, height);
context.putImageData(myImageData, dx, dy);
(with appropriate measurements)
https://developer.mozilla.org/En/HTML/Canvas/Pixel_manipulation_with_canvas/
Edit II: The idea was that you'd have a canvas big enough that has a center area of interest, and buffer areas around it big enough to account for any of the shapes you may draw, like so:
XXX
XCX
XXX
You could draw the shapes once to this big canvas and then just blindly draw each of the areas X around that center area to the center area (and then clear those areas out for the next drawing). So, if K is the number of shapes instead of 4*K draws, you have K + 8 draws (and then 8 clears). Obviously the practical applicability of this depends on the number of shapes and overlapping concerns, although I bet it could be tweaked. Depending upon the complexity of your shapes it may make sense to draw a shape 4 times as you originally thought, or to draw to some buffer or buffer area and then draw it's pixel data 4 times or something. I'll admit, this is some idea that just popped into my head so I might be missing something.
Edit III: And really, you could be smart about it. If you know how a set of objects are going to overlap, you should only have to draw from the buffer once. Say you got a bunch of shapes in a row that only draw to the north overlapping region. All you should need to do is draw those shapes, and then draw the north overlapping region to the south side. The hairy regions would be the corners, but I don't think they really get hairy unless the shapes are large.... sigh.. at this point I probably need to quiet down and see if there's any existing implementations of what I speak out there because I'm not sure my writing off-the-cuff is helping anybody.