Draw only portions of the circle visible to the user

Started by
16 comments, last by Khatharr 8 years, 3 months ago

I have a basic output of a circle, of which I want to optimize by only drawing angle ranges that are visible. For me this should hopefully improve performance, as I currently am getting serious performance loss drawing very large circles and need to reduce the amount of output to keep it efficient.

My current draw code:


function draw(){
  ctx.clearRect(0,0,canvas.width,canvas.height);

  ctx.save();  
    ctx.translate(camera.x,camera.y);
    ctx.beginPath();
    ctx.arc(pos.x,pos.y,radius,0,2*Math.PI);
    ctx.stroke();
  ctx.restore();
  
  requestAnimationFrame(draw);
}

draw();

I only need to calculate the perimeter of the circle not the inner body of it, so if the edge of the circle is off screen it would not draw a circle.

This is a visual example of what I refer to:

Ko7Xz.jpg

There are certain situations that have to be taking into account for calculating the angles. The size of the radius, the origin position of the circle and position of the camera. I initially tried comparing radius size versus (canvas width/2) but soon realized that was incorrect math logic. And so, i have no idea how i would approach the issue.

What is the best way to achieve this in JavaScript?

EDIT: added basic javascript code example: https://jsfiddle.net/44tawd81/ you can click and drag the circle.

Advertisement

Did you try a simple approach where you draw a circle in 4 or more pieces? Clipping should then kill the parts that are not visible.

Well i tried two semi circles, which was actually required in order for me to draw objects with the right depth perception and ordering for sprites. But could not work out the maths.

I was thinking much simpler, like


ctx.beginPath();
ctx.arc(pos.x,pos.y,radius, 0, Math.PI / 2);
ctx.stroke();

ctx.beginPath();
ctx.arc(pos.x,pos.y,radius, Math.PI / 2, Math.PI);
ctx.stroke();

ctx.beginPath();
ctx.arc(pos.x,pos.y,radius, Math.PI, 3 * Math.PI / 2);
ctx.stroke();

ctx.beginPath();
ctx.arc(pos.x,pos.y,radius, 3 * Math.PI / 2, 2 * Math.PI);
ctx.stroke();

I don't know enough Javascript to know whether the above is actually allowed, but I hope you get the idea.

The engine can perhaps not skip drawing a circle that is partially visible, only (parts of a) circle that is completely invisible.

By splitting it in 4 parts, you are giving the engine an option to skip drawing some parts.

This is all quite highly speculative though, but it seems simple enough to just try and see.

I can draw sectors easily, it was the maths on determining if it should be skipped i was struggling with.

How about just clipping ?

@Crossbones, i am not 100% sure on how the JavaScript engine works. If i have a clip which is smaller than my circle, does the browser still process the entire circle or just whats relevant to the clip ? There is woeful documentation on techy stuff like that.

Also, i would still have to call the function to draw the circle which surely it would be more efficient if i skipped the call entirely, if for example the circle was bigger than the entire output and so you never saw the perimeter?

Be sure to profile where the time is being spent. Too often, people are "sure" that the problem is in a section of code and it turns out they're wrong.

Also, even if you can't figure out the math, you can try to draw partial circles just to see if it speeds things up. The arc function might turn out to be even slower than the circle function and if so, you'll need to think of a different way to solve it. One possibility is you could have a circle sprite, and draw it scaled appropriately. Again, this may or may not be faster. Time it! :)

Maybe you can limit the size of the circles. Why do you need such overly large circles? Maybe we can help come up with a better solution to your problem?

- Eck

EckTech Games - Games and Unity Assets I'm working on
Still Flying - My GameDev journal
The Shilwulf Dynasty - Campaign notes for my Rogue Trader RPG

Be sure to profile where the time is being spent. Too often, people are "sure" that the problem is in a section of code and it turns out they're wrong.

Also, even if you can't figure out the math, you can try to draw partial circles just to see if it speeds things up. The arc function might turn out to be even slower than the circle function and if so, you'll need to think of a different way to solve it. One possibility is you could have a circle sprite, and draw it scaled appropriately. Again, this may or may not be faster. Time it! smile.png

Maybe you can limit the size of the circles. Why do you need such overly large circles? Maybe we can help come up with a better solution to your problem?

- Eck

I don't think there is a circle function i believe arc is the one.

I did do a cpu profile, and 80% of process goes to the "stroke" function which deals with giving the circle its perimeter line. The circles are large because it's a solar system i am trying to make, although not fully to scale, it is rather large none the less ;)

Did you try just not drawing circles bigger than some X? While the image is obviously broken then, it should give you a big boost in performance if you are correct.

That is, you can do simple experiments to check your own conclusions, before going in and properly fix it.

This topic is closed to new replies.

Advertisement