Edit: Made a whole guide out of it:
To share an example of what I’m doing:
extends Sprite2D
var DevScreenHeight:float = 648.0 # Default viewport height
var Scale:float = 1 # Size Multiplier
var Window_Size:Vector2i
func _ready() -> void:
Window_Size = get_viewport().size # Set window size variable to viewport size.
scalesvg("res://icon.svg") # Import an image from SVG
anchor_bottom_center() # Set initial position to the bottom of the screen.
func _process(delta: float) -> void:
if Window_Size != get_viewport().size: # If window size has changed
Window_Size = get_viewport().size # Update window size variable
scalesvg("res://icon.svg") # Rescale the image
anchor_bottom_center() # Set position to bottom again
func scalesvg(path_to_svg: String) -> void:
var SVG: PackedByteArray = FileAccess.get_file_as_bytes(path_to_svg) # Load SVG to buffer
var Bitmap: Image = Image.new()
var DesiredScale: float = Window_Size.y / DevScreenHeight # Set scale according to window height relative to the default viewport height
Bitmap.load_svg_from_buffer(SVG, DesiredScale * Scale) # Scale SVG and convert from buffer to bitmap
texture = ImageTexture.create_from_image(Bitmap) # Apply the bitmap as a texture
func anchor_bottom_center() -> void:
position = Vector2(0,get_viewport().size.y * 0.5 - texture.get_height() * 0.5) # Calculates the coordinate for the bottom center of the screen and offset it by the height of the bitmap
Result:
Default window size:
Fullscreen window size:
You can’t tell a difference from the thumbnails (but if you open them you’ll notice the fullscreen one is upscaled by quite a lot with no quality loss) because what i’ve done is taken advantage of the properties of SVG to scale the image losslessly, e.g. this sample game (if you can call it that) would be exactly the same quality visually on a 720p and 2160p display; similar to adobe flash (or just any vector graphics) games.
In the general purpose sense, this technique would be fantastic to use for UIs no matter if you’re making a 2D or 3D game.
But I’m hoping to take it further than that.
The biggest downside is that this isn’t particularly cheap. So when things need to be rescaled it may stutter quite heftily although it odesn’t in my case but that’s probably because I only have one, actually let me test it…
I tried with 50 sprites, it never stuttered while dragging and resizing the window but fps did dip down to 70 at worst (if i have just one it doesn’t make any sort of dent, for comparison).
Notably the bigger the resulting bitmap/texture is going to be after the scaling, the more expensive the process gets (and the cost increase is sorta exponential in that regard. For instance if I scale just one texture by 100 (that’s 12800x12800 resolution, obscenely huge) the process takes a few whole seconds, but if i scale it by 10 (1280x1280) it still only takes a matter of milliseconds, but the fps dips down to 50-60 and there are some microstutters (e.g. one sprite scaled by 10 is a little more expensive to scale than 50 sprites scaled by 1).
I think it’s a perfectly acceptable price though because we only need to do this sort of scaling whenever the sprites are first loaded and again when the window size changes (which could be accompanied by a loading screen).
Although it would be quite a lot more ideal if this scaling process could be offloaded to other threads than the game thread.