Speedy2D icon indicating copy to clipboard operation
Speedy2D copied to clipboard

Add support for Translate

Open Revertron opened this issue 4 years ago • 4 comments

Another very needed function is translate(x,y) like in other canvases: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/translate

It would be great to have it in Speedy :)

Revertron avatar Mar 29 '21 22:03 Revertron

Thanks for the suggestion!

This is something I've thought about, and it might be best to leave it to the library user to do this themselves. I can see three options for implementing this:

  • For every vertex, we could send the current translation offset to the GPU as an attribute. This would require a lot of extra bandwidth + data on the GPU, and I think this would be slower than just doing the addition on the CPU side.
  • We could send the current translation offset to the GPU once as a uniform. Unfortunately this means we'd need to start a new draw call every time the offset changes, which would lead to very poor performance.
  • The addition could be done internally on the CPU every time a vertex is added. Adding an API for this would force the addition to be done on every frame, which would be slower than the current API when translation isn't required. The current API sends the float values directly to the GPU unmodified, which means there's no performance overhead and the API user can implement translation however they like (e.g. cache the values, not translate at all, etc)

So I think the options above aren't great for performance. In general I'd also like to avoid adding APIs that create "global state", i.e. a drawing API call in speedy2d should ideally behave the same way regardless of which APIs were called before it.

If anyone has any better ideas for how this could be implemented, please let me know!

QuantumBadger avatar Mar 31 '21 21:03 QuantumBadger

Thanks for the rely!

Forgive me, but I didn't really get this: Unfortunately this means we'd need to start a new draw call every time the offset changes, which would lead to very poor performance.

Does camera move in OpenGL require an extra work on GPU?

Revertron avatar Mar 31 '21 21:03 Revertron

No problem!

Does camera move in OpenGL require an extra work on GPU?

It depends on how the camera is implemented :) The second option above is if it were implemented using uniform values.

For a typical video game, the camera is in one position for the entire frame. I.e. at the start of the frame, the camera position is sent to the GPU, and every triangle in the frame is translated by the same amount. This is good for performance.

However, if we add a translate() API to Speedy2D in the way that most canvases support, then the camera position could change multiple times per frame. E.g. you could do:

graphics.translate(100, 100);
graphics.draw_circle((0, 0), 10.0, Color::BLUE);

graphics.translate(200, 200);
graphics.draw_circle((0, 0), 10.0, Color::BLUE);

graphics.translate(300, 300);
graphics.draw_circle((0, 0), 10.0, Color::BLUE);

Because the camera position changes in the middle of the frame, we need to "interrupt" the drawing of the frame to upload the new position to the GPU. Basically, without translate() we'd be able to draw all three circles with a single command. With translate(), we need to send three separate draw commands to the GPU, with a different camera position every time, which is very slow.

In pseudocode, this is the current situation:

opengl.set_camera(0, 0);
opengl.draw([shape1, shape2, shape3, ...]); // All at once, very fast

And this is if we add translate() using uniforms:

opengl.set_camera(100, 100);
opengl.draw([shape1]);
opengl.set_camera(200, 200);
opengl.draw([shape2]);
opengl.set_camera(300, 300);
opengl.draw([shape3]);

Hope that makes sense :)

QuantumBadger avatar Mar 31 '21 22:03 QuantumBadger

Some more details on why having multiple draw calls is expensive: https://stackoverflow.com/questions/4853856/why-are-draw-calls-expensive

QuantumBadger avatar Mar 31 '21 22:03 QuantumBadger