SFML Anti-Aliasing - lines look dotted and moving objects smear - c++

Several months ago I made a Fourier Transform program using SFML 2.0. I used anti-aliasing level 8 and it looked perfectly fine. Just recently however (not quite sure when the problem began since I have not touched it in a while), it seems to have broken.
Whenever I draw a line it looks dotted and whenever something moves, it flashes between two states and it doesn't completely clear after calling window.clear(). It's not just that program however. Anytime I use any level of anti-aliasing greater than 0, even in SFML 2.5.1, the same problem occurs.
Here is the some sample code which does not work as it should on my computer:
#include <SFML/Graphics.hpp>
int main()
{
sf::Vertex line[2] =
{
sf::Vertex(sf::Vector2f(0, 0)),
sf::Vertex(sf::Vector2f(800, 0))
};
sf::ContextSettings settings;
settings.antialiasingLevel = 8.0;
sf::RenderWindow window(sf::VideoMode(800, 600), "Test", sf::Style::Close, settings);
window.setVerticalSyncEnabled(true);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
line[1].position.y += 1.0;
window.clear();
window.draw(line, 2, sf::Lines);
window.display();
}
return 0;
}
When the line finishes sweeping, it looks
like this
As this used to not be a problem, I don't think it's SFML's fault. I am using Windows 10 and my computer uses an integrated Intel UHD Graphics 620 graphics card, both of which have not changed since before the problem started happening. On a side note, I have not noticed any other programs on my computer break, only the ones I made.

Related

How is SFML so fast?

I need to draw some graphics in c++, pixel by pixel on a window. In order to do this I create a SFML window, sprite and texture. I draw my desired graphics to a uint8_t array and then update the texture and sprite with it. This process takes about 2500 us. Drawing two triangles which fill the entire window takes only 10 us. How is this massive difference possible? I've tried multithreading the pixel-by-pixel drawing, but the difference of two orders of magnitude remains. I've also tried drawing the pixels using a point-map, with no improvement. I understand that SFML uses some GPU-acceleration in the background, but simply looping and assigning the values to the pixel array already takes hundreds of microseconds.
Does anyone know of a more effective way to assign the values of pixels in a window?
Here is an example of the code I'm using to compare the speed of triangle and pixel-by-pixel drawing:
#include <SFML/Graphics.hpp>
#include <chrono>
using namespace std::chrono;
#include <iostream>
#include<cmath>
uint8_t* pixels;
int main(int, char const**)
{
const unsigned int width=1200;
const unsigned int height=1200;
sf::RenderWindow window(sf::VideoMode(width, height), "MA: Rasterization Test");
pixels = new uint8_t[width*height*4];
sf::Texture pixels_texture;
pixels_texture.create(width, height);
sf::Sprite pixels_sprite(pixels_texture);
sf::Clock clock;
sf::VertexArray triangle(sf::Triangles, 3);
triangle[0].position = sf::Vector2f(0, height);
triangle[1].position = sf::Vector2f(width, height);
triangle[2].position = sf::Vector2f(width/2, height-std::sqrt(std::pow(width,2)-std::pow(width/2,2)));
triangle[0].color = sf::Color::Red;
triangle[1].color = sf::Color::Blue;
triangle[2].color = sf::Color::Green;
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) {
window.close();
}
}
window.clear(sf::Color(255,255,255,255));
// Pixel-by-pixel
int us = duration_cast< microseconds >(system_clock::now().time_since_epoch()).count();
for(int i=0;i!=width*height*4;++i){
pixels[i]=255;
}
pixels_texture.update(pixels);
window.draw(pixels_sprite);
int duration=duration_cast< microseconds >(system_clock::now().time_since_epoch()).count()-us;
std::cout<<"Background: "<<duration<<" us\n";
// Triangle
us = duration_cast< microseconds >(system_clock::now().time_since_epoch()).count();
window.draw(triangle);
duration=duration_cast< microseconds >(system_clock::now().time_since_epoch()).count()-us;
std::cout<<"Triangle: "<<duration<<" us\n";
window.display();
}
return EXIT_SUCCESS;
}
Graphics drawing in modern devices using Graphic cards, and the speed of drawing depends on how many triangles in the data you sent to the Graphic memory. That's why just drawing two triangles is fast.
As you mentioned about multithreading, if you using OpenGL (I don't remember what SFML use, but should be the same), what you thinking you are drawing is basically send commands and data to graphic cards, so multithreading here is not very useful, the graphic card has it's own thread to do this.
If you are curious about how graphic card works, this tutorial is the
book you should read.
P.S. As you edit you question, I guess the duration 2500us vs 10us is because you for loop create a texture(even if the texture is a pure white background)(and the for loop, you probably need to start counting after the for loop), and send texture to graphic card need time, while draw triangle only send several points. Still, I suggest to read the tutorial, create a texture pixel by pixel potentially prove the miss understanding of how GPU works.

Changing the world origin in C++ SFML

I've recently gotten into SFML and as an exercise to get more comfortable (and have fun), I started translating some Coding Challenges done by Daniel Shiffman on his Youtube channel, The Coding Train. Upon attempting to translate a star field effect in SFML, I started searching for the right function in SFML that would change the world origin from the top-left of the screen to the center. The closest thing I found to this was the setOrigin function, but that only works for sprites and not the whole window/screen. If you didn't understand my description of this function, it would be the equivalent of the translate(x, y) function in Processing. Any help would be appreciated.
You need to use sf::View
https://www.sfml-dev.org/tutorials/2.5/graphics-view.php
Here is a small implementation example:
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(300, 300), "");
sf::Vector2u size = window.getSize();
sf::View view(sf::Vector2f(0, 0), sf::Vector2f(size.x, size.y));
window.setView(view);
sf::CircleShape cir(10);
cir.setOrigin(10, 10);
while(window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
if (event.type == sf::Event::Closed)
window.close();
window.clear();
window.draw(cir);
window.display();
}
return 0;
}

VertexArray of circles

I am wondering if it is possible to create a VertexArray of circles in SFML. I have looked for answers but I didn't find anything that could help. Moreover, I don't understand the part on the SFML documentation where it is written that I can create my own entities, I think this is maybe what I want to do in fact.
EDIT : I want to do that because I have to draw a lot of circles.
Thanks for helping me
While #nvoigt answer is correct, I found it useful in my implementations to work with vectors (see http://en.cppreference.com/w/cpp/container/vector for more details, look up "c++ containers", there are several types of containers to optimize read/write times).
You probably do not need it for the above described use case, but you could need it in future implementations and consider this for a good coding practice.
#include <SFML/Graphics.hpp>
#include <vector>
int main()
{
// create the window
sf::RenderWindow window(sf::VideoMode(800, 600), "My window");
// run the program as long as the window is open
while (window.isOpen())
{
// check all the window's events that were triggered since the last iteration of the loop
sf::Event event;
while (window.pollEvent(event))
{
// "close requested" event: we close the window
if (event.type == sf::Event::Closed)
window.close();
}
// clear the window with black color
window.clear(sf::Color::Black);
// initialize myvector
std::vector<sf::CircleShape> myvector;
// add 10 circles
for (int i = 0; i < 10; i++)
{
sf::CircleShape shape(50);
// draw a circle every 100 pixels
shape.setPosition(i * 100, 25);
shape.setFillColor(sf::Color(100, 250, 50));
// copy shape to vector
myvector.push_back(shape);
}
// iterate through vector
for (std::vector<sf::CircleShape>::iterator it = myvector.begin() ; it != myvector.end(); ++it)
{
// draw all circles
window.draw(*it);
}
window.display();
}
return 0;
}
sf::CircleShape is already using a vertex array (thanks to being inherited from sf::Shape). There is nothing extra you need to do.
If you have a lot of circles, try using sf::CircleShape first and only optimize when you have a real use-case that you can measure your solution against.
In addition two previous answers I will try to explain why there is no default VertexArray of circles.
By ideology of computer graphics (and SFML in our case) vertex is a smallest drawing primitive with least necessary functionality. Classical example of vertices are point, line, triange, guad, and polygone. The first four are really simple for your videocard to store and to draw. Polygon can be any geometrical figure, but it will be heavier to process, that's why e.g in 3D grapichs polygons are triangles.
Circle is a bit more complicated. For example videocard doesn't know how much points she need to draw your circle smooth enough. So, as #nvoigt answered there exists a sf::CircleShape that is being built from more primitive verticies.

SFML graphics Draw Texture in Window- Black Screen

I just tried to write a chess engine, and what is important to me is that I get a nice visual representation of the game. I tried to implement the Code in a Visual Studio project - the problem is that the program only shows me a black screen instead of the texture I loaded.
My Code is the following:
#include <SFML/Graphics.hpp>
#include <time.h>
using namespace sf;
int main(){
RenderWindow window(VideoMode(1000, 1000), "MattseChess!");
Texture t1;
t1.loadFromFile("images/board.png");
Sprite s(t1);
while (window.isOpen())
{
Event e;
while (window.pollEvent(e)) {
if (e.type == Event::Closed)
window.close();
//Draw
window.clear();
window.draw(s);
window.display();
}
}
return 0;
}
Do you have any idea of what I did wrong?
Make sure to put your drawing code outside your event loop. Otherwise you're only drawing whenever there's some event happening (such as cursor movement).
That code works. I am pretty sure you did not put your board.png into the images directory in your execution path.
Make sure this image is available:
t1.loadFromFile("images/board.png");

Slight pause/delay when moving

I've been working on this little framework for my game today and realized that moving delays when moving around. I've used SFML before and have had the same problem, but never bothered to fix it. I'm wondering if anyone has had a similar issue and has found a solution.
Here's an example of the code which is giving me the slight pause in movement:
int main(){
sf::RenderWindow window (sf::VideoMode(640, 480), "Window");
//window.setVerticalSyncEnabled(true);
sf::Texture tex;
tex.loadFromFile("Assets/Textures/player.png");
sf::Sprite s;
s.setTexture(tex);
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)){
if (event.type == sf::Event::Closed)
window.close();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
s.move(0.01f, 0.0f);
}
window.clear();
window.draw(s);
window.display();
}
}
The delay/pause/whatever I'm experience is very slight but I can notice it and it's really bugging me. Just seeing the slight break in movement when none of the values alter makes my programming mind extremely sad.
The keyboard input will have a delay just like if you hold a key in Microsoft Word. To get around this, you could create a variable and set it to true when a key is pressed.
int main(){
sf::RenderWindow window (sf::VideoMode(640, 480), "Window");
//window.setVerticalSyncEnabled(true);
sf::Texture tex;
tex.loadFromFile("Assets/Textures/player.png");
sf::Sprite s;
s.setTexture(tex);
bool moving = false;
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)){
if (event.type == sf::Event::Closed)
window.close();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
moving = true;
}
if (moving) {
s.move(0.01f, 0.0f);
}
window.clear();
window.draw(s);
window.display();
}
}
This sounds like a framerate/timing issue. One frame in a 60hz game is 16.666.. milliseconds, but on Windows at least, the system clock only has a resolution of 1ms, so your delays are going to be either 16ms or 17ms. This inaccuracy results in occasional jitter as some frames are skipped (or rendered twice, in your case, giving the appearance of a short pause) even if vsync is enabled.
If you can get manual control of frame timing, e.g. by disabling sf::RenderWindow's framerate limit and calling sf::sleep directly, one solution is to delay each frame in the sequence: 17, 17, 16, 17, 17, 16, so that the long-term average is closer to 60hz, minimizing jitter.
I have never used SFML so I can't provide any code but I hope this points you in the right direction.
You should also ensure that your monitor's refresh rate is the same as your game's framerate. SFML might already be doing this automatically.