SFML community forums

Help => Graphics => Topic started by: Avonclese on July 15, 2016, 04:12:33 pm

Title: Sprite alignment with shrunk view
Post by: Avonclese on July 15, 2016, 04:12:33 pm
Hello!

I thought I would ask a quick question to see if there is an alternative solution to my problem.

In a nutshell:

Game is isometric, contains objects which fit together per-pixel to create seamless walls/tilemaps/environments etc.
Native game resolution is 800x600 (an arbitrary value for the purposes of this discussion).
Users can change the resolution to suit their device, and my code uses sf::View to scale everything nicely.

The problem is that when the user goes above or below the native resolution, View seems to scale each object individually? So as the picture shows, these 2 wall objects no longer appear seamless when the user sets their resolution to 640x480.

My only successful solution so far is to render everything to an off-screen texture, where things draw perfectly in native resolution, and then draw that to the window.  Looks perfect but the entire process is CPU/GPU consuming to perform every frame, so I'm looking for alternatives.

FYI:
 - the 2 wall objects are being drawn in a single call via vertex array
 - texture smoothing on or off has absolutely no impact on the image
Title: Re: Sprite alignment with shrunk view
Post by: Laurent on July 15, 2016, 04:17:55 pm
Quote
Looks perfect but the entire process is CPU/GPU consuming to perform every frame, so I'm looking for alternatives.
I wouldn't say that, since it is just an extra sprite to draw. Or maybe you're making it more complicated than needed?
Title: Re: Sprite alignment with shrunk view
Post by: Avonclese on July 16, 2016, 03:25:47 am
It's possible I am over-complicating it, I'm not an expert so I may be missing something obvious! If you don't mind looking, here is a quick snippet of my canvas (offscreen texture) code I use to achieve the desired results. You say it's just an extra sprite to draw, but I thought it was a lot more?

//Clear the canvas
canvas.clear(Color::Black);                             //equivalent to drawing an entire window of pixels?

//Here I would draw all my things - normally to the window but needs to be the canvas now.  No change between techniques.
canvas.draw(stuff);

//Display the canvas
canvas.display();                                       //seems to be taxing to the framerate?

//Window clear, draw canvas sprite, and display
window.clear(Color::Black);                             //equivalent to drawing an entire window of pixels?
window.draw(canvas_sprite);                             //draws an entire window of pixels
window.display();                                       //as above
 

In a normal renderwindow-only setup, I just have the last 3 lines (except drawing objects instead of the canvas sprite), achieving ~500fps.  With the canvas code it drops to 250fps, even with no object drawing (only 2 tiny objects so I'm not surprised). So is the canvas process alone adding 3 extra full window pixel fills for the gpu, I think?  I was expecting some performance hit, but not this much.

I'm not particularly upset with the outcome, I'm mainly curious if I missed something obvious?
Title: Re: Sprite alignment with shrunk view
Post by: DarkRoku12 on July 16, 2016, 06:53:40 am
The performance hit vary depending on your graphic card.

But think that, the more pixel you draw, the more time it will take.

500 fps = 1/500 = 0.002 render time per frame.
250 fps = 1/250 = 0.004 render time per frame.

More info here. (https://www.mvps.org/directx/articles/fps_versus_frame_time.htm)

Only its take twice of render time to complete each frame.

But remember to test performance on release mode and all optimizations enabled in you compiler.

But if you read the sfml view's (http://www.sfml-dev.org/tutorials/2.3/graphics-view.php) tutorial carefully you can solve your problem without having to use a RenderTexture.
Title: Re: Sprite alignment with shrunk view
Post by: Avonclese on July 16, 2016, 08:10:58 am
Thanks DarkRoku for the link about FPSvsTime, I have a much better understanding of that now. Great resource!

I have read the view tutorial very carefully (I even spotted the incorrect values in the code examples) I'm not sure what I have missed? :(

I want the user to see the exact same amount of the world at ANY resolution.
I set my View size to 800x600.  I call this my native resolution and will never change because I only want them to see 800x600 of the world, ever.
So when I play the game in windowed 640x480 it will take my larger View size and squash it into the window.
Likewise if they set the resolution to 1920x1080, thanks to View it will stretch the 800x600 size into the window (yes the aspect ratio will be wrong).

This is a great system and works perfectly, until I add my isometric objects. When it stretches or squashes...I get the artifacting in the picture of my original post.
How can I solve this using only Views?
Title: Re: Sprite alignment with shrunk view
Post by: Jesper Juhl on July 16, 2016, 08:42:04 am
How about drawing to a 800x600 rendertexture first. Then when everything in the frame is drawn, draw the rendertexture to the screen using the view.
Title: Re: Sprite alignment with shrunk view
Post by: DarkRoku12 on July 16, 2016, 08:51:06 pm
The trick is.

If your window is smaller than your view's size: Things affected by the view will seems to be smaller. (zoom out)
If your window is bigger than your view's size: Things affected by the view will seems to be bigger. (zoom in)
If your window is the same size than your view's size: no zoom.

If you want to zoom in the view, without change the view size.
Use the zoom method:
float zoom = 2.0f ;
view.zoom( 1.0f / zoom ) // Zoom in.
view.zoom( zoom ) // Zoom out.
 

Anothers views methods here (http://www.sfml-dev.org/documentation/2.3/classsf_1_1View.php#ac95b636eafab3922b7e8304fb6c00d7d).
Title: Re: Sprite alignment with shrunk view
Post by: Avonclese on July 17, 2016, 04:27:02 am
Jesper, yes in my original post I described that my current solution is to use a RenderTexture. Visually it's perfect but I was concerned about the performance hit, I think it's not a big issue now :)

DarkRoku I have experimented with zooming but I wasn't able to find a solution that solves my issue :(  Thank you for your help I really appreciate it!

If anyone is curious I thought I would share my very small basic example to illustrate my problem. Hit Q to switch between window only and rendertexture.  If anyone if bored enough to check it out I'm always open for feedback. Thanks everyone!

//in main.cpp
#include <SFML/Graphics.hpp>

//program entry point and loops
int main(int argc, char* args[]){
    //view setup
    sf::Vector2f native_res={800,600};
    sf::View view;
    view.setSize(native_res);
    view.setCenter(native_res.x/2,native_res.y/2);

    //window setup
    sf::Vector2f user_res={640,480};
    sf::RenderWindow window(sf::VideoMode(user_res.x, user_res.y),"View testing",sf::Style::Titlebar|sf::Style::Close);

    //apply view with zoom here??
    //float zoom=native_res.x/user_res.x; //assumes matching ratios
    //view.zoom(zoom);

    //apply view
    window.setView(view);

    //textures
    sf::Texture walltex;
    sf::Texture backingtex;
    walltex.loadFromFile("wall.png");
    backingtex.loadFromFile("backing.png");
    walltex.setSmooth(true);
    backingtex.setSmooth(true);

    //sprites
    sf::Sprite backing(backingtex);
    sf::Sprite wall1(walltex);
    sf::Sprite wall2(walltex);
    wall1.setPosition(100,100);
    wall2.setPosition(132,116);

    //off-screen canvas via rendertexture
    sf::RenderTexture canvas;
    canvas.create(native_res.x,native_res.y);
    canvas.setSmooth(true);
    sf::Sprite canvas_sprite(canvas.getTexture());

    //loop
    bool drawcanvas=true;
    while(window.isOpen()){
        //sole event check for closing window
        sf::Event event;
        while(window.pollEvent(event)){
            if(event.type==sf::Event::Closed){
                window.close();
            }
            if(event.type==sf::Event::KeyPressed){
                if(event.key.code==sf::Keyboard::Q){
                    drawcanvas=!drawcanvas;
                }
            }
        }
        if(drawcanvas==true){
            //WINDOW ONLY DRAWS
            window.clear(sf::Color::Black);
            window.draw(backing);
            window.draw(wall1);
            window.draw(wall2);
            window.display();
        } else {
            canvas.clear(sf::Color::Black);
            canvas.draw(backing);
            canvas.draw(wall1);
            canvas.draw(wall2);
            canvas.display();
            window.clear(sf::Color::Black);
            window.draw(canvas_sprite);
            window.display();
        }
    }
    return 0;
}
 
Title: Re: Sprite alignment with shrunk view
Post by: DarkRoku12 on July 17, 2016, 06:14:54 am
I tested your code, probably its a openGL related theme.
Zoom its not perfect, even less when things are too shorts.

But if the RenderTexture phase does not affect the gameplay don't worry if yes, enable and option to eliminate it, like you did in the example.