gpt4 book ai didi

c++ - 如何使用像素完美缩放/移动修复 SFML 中顶点数组中的垂直伪影线?

转载 作者:行者123 更新时间:2023-11-30 04:48:01 25 4
gpt4 key购买 nike

我一直在开发一款仅使用 SFML 和 C++ 的 2D 俯视游戏,该游戏有一个拼贴图。当放大和缩小或以不同的缩放级别移动渲染 View 时,我无法消除垂直线工件的瓦片 map 。我在下面附上了问题的图片;以红色圈出。

Problem with gap between squares

[编辑]

有很多因素导致这个错误不一致。如果我只使用一个图 block 中的 tile_atlas,则不会出现人工制品。如果我将每个纹理映射到一个图 block ,也就是不使用顶点数组;我没有看到任何伪影,但在屏幕上的图 block 数量相同的情况下,速度要慢 10 倍到 15 倍。我已经尝试找到不会导致伪像的缩放级别,并且有一些。但级别几乎是随机的,放大和缩小时,不平滑和不连贯。

我尝试了很多教程和论坛“修复”,但都没有完全奏效。我已经完全重写了底层 tile 引擎 4 次,但无济于事。

https://en.sfml-dev.org/forums/index.php?topic=15747.0

主题=14504

主题=5952

主题=13637.15

https://www.sfml-dev.org/tutorials/2.5/graphics-view.php

https://www.binpress.com/creating-city-building-game-with-sfml/

https://www.sfml-dev.org/tutorials/2.5/graphics-vertex-array.php

[编辑]

我已经阅读了 Terreria 缩放问题,修复了制作超大纹理然后缩放的问题,或者多个纹理,每个缩放级别一个。似乎详尽无遗。我正在寻找一种正确实现缩放的编程方式。

这是我最后一次修复代码的帖子,否则我将需要更改语言。

我认为主要问题来自程序的放大/缩小功能。我已经尝试了很多变化/尝试让它工作 +0.5f 偏移,+0.375f 偏移,不是像素完美

if (sf::Keyboard::isKeyPressed(sf::Keyboard::E))
{
float zoom_in = 0.995f;

float nz = last_sq * zoom_in;
nz = std::floor(nz);
float now = nz / last_sq;
if (nz <= 10)
continue;
last_sq = nz;

std::cout << now << std::endl;

cam.zoom(now);
}


if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
cam.move(0.f, -0.02f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::floor(x);
y = std::floor(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}

这是完整的代码。

main.cpp


#include "chunk_map.h"
#include "tile_atlas.h"
#include <vector>
//#include "main.h"
#include "map.h"
#include <iostream>

#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/View.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Window/Keyboard.hpp>

#include "animation_handler.h"

int main(int argc, char* argv[])
{
sf::RenderWindow app(sf::VideoMode(600, 600), "Tilemap Example");
// Hard set fps to monitor refresh rate.

// textures to load.
/*text_mgr.loadTexture("grass", "grass.png");
text_mgr.loadTexture("high_grass", "high_grass.png");

Animation staticAnim(0, 0, 1.0f);
tileAtlas["grass"] = Tile(32, 1, text_mgr.getRef("grass"),{ staticAnim },
TileType::GRASS, 50, 0, 1);

tileAtlas["high_grass"] = Tile(32, 1, text_mgr.getRef("high_grass"),{ staticAnim },
TileType::HIGH_GRASS, 100, 0, 1);*/

//Map map;

//map.load(50, 50, tileAtlas);

#ifdef NDEBUG
app.setVerticalSyncEnabled(true);
std::cout << "#################\n";
#endif // DEBUG
//app.setVerticalSyncEnabled(true);
sf::View cam = app.getDefaultView();

tile_atlas atlas = tile_atlas();

std::vector<chunk_map> map;

for (int x = 0; x < 5; x++)
{
for (int y = 0; y < 5; y++)
{
map.push_back(chunk_map());
map.back().set_texture(atlas.get_atlas());
map.back().set_position(10 * x, 10 * y, 10 * (x + 1), 10 * (y + 1));
map.back().load_tiles();
}
}

sf::Clock clock;
int checked = 0;
int last_sq = 600;

while (app.isOpen())
{
//sf::Time elapsed = clock.restart();
//float dt = elapsed.asSeconds();

sf::Event eve;
while (app.pollEvent(eve))
if (eve.type == sf::Event::Closed)
app.close();


if (sf::Keyboard::isKeyPressed(sf::Keyboard::P))
std::cout << "view x: " << cam.getSize().x << "\tview y: " << cam.getSize().y << std::endl;


if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q))
{
float zoom_out = 1.005f;

float nz = last_sq * zoom_out;
nz = std::ceil(nz);
float now = nz / last_sq;
last_sq = nz;

std::cout << now << std::endl;

cam.zoom(now);
//float x = cam.getCenter().x;
//float y = cam.getCenter().y;
//x = std::floor(x);
//y = std::floor(y);
////std::cout << "x: " << x << "\ty: " << y << std::endl;
//cam.setCenter(x, y);
}


if (sf::Keyboard::isKeyPressed(sf::Keyboard::E))
{
float zoom_in = 0.995f;

float nz = last_sq * zoom_in;
nz = std::floor(nz);
float now = nz / last_sq;
if (nz <= 10)
continue;
last_sq = nz;

std::cout << now << std::endl;

cam.zoom(now);
//float x = cam.getCenter().x;
//float y = cam.getCenter().y;
//x = std::floor(x);
//y = std::floor(y);
////std::cout << "x: " << x << "\ty: " << y << std::endl;
//cam.setCenter(x, y);
}


if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
cam.move(0.f, -0.02f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::floor(x);
y = std::floor(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}


if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
{
cam.move(-0.02f, 0.f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::floor(x);
y = std::floor(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}


if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
{
cam.move(0.f, 0.02f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::ceil(x);
y = std::ceil(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}


if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
{
cam.move(0.02f, 0.f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::ceil(x);
y = std::ceil(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}


if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
sf::Time elapsed = clock.getElapsedTime();
float t = elapsed.asSeconds();
int time = std::floor(t);

if (checked < time)
{
checked = time;

cam.move(0.01f, 0.f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::ceil(x);
y = std::ceil(y);
std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
}


if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
app.close();

app.setView(cam);

#ifdef _DEBUG
app.clear();
#endif // DEBUG
//map.draw(app, dt);

for (int i = 0; i < 25; i++)
{
app.draw(map.at(i));
}

app.display();
}
}

block 映射.h

#pragma once


#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/Graphics/VertexArray.hpp>
#include <vector>


class chunk_map : public sf::Drawable
{
private:
//change values of these to match your needs and improve performance
enum { tilesize = 32, chunksize = 32};

//tile size float
float tile_size_float = 32.0f;

// Draw chunk
virtual void draw(sf::RenderTarget& target, sf::RenderStates states)const;

// texture for chunk
sf::Texture m_texture;

// chunk dimensions
int tiles_per_chunk_x;
int tiles_per_chunk_y;

//start x and y and ending x and y scaled to tile size. a.k.a.
// 1,1 = tile 1,1. 10,10, equals tile 10,10
int chunk_start_x;
int chunk_start_y;

int chunk_end_x;
int chunk_end_y;

// Vertex array of positions of tiles in chunk
std::vector<std::vector<sf::VertexArray> > m_chunks;

// Append tiles.
void append_tile(int gx, int gy, sf::VertexArray& garr);

public:
chunk_map();
~chunk_map();
void load_tiles();


void set_texture(sf::Texture);
void set_position(int chunk_start_x, int chunk_start_y,
int chunk_end_x, int chunk_end_y);

};


block map .cpp

#include "chunk_map.h"

#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/System/Vector2.hpp>
#include <SFML/Graphics/Vertex.hpp>

chunk_map::chunk_map()
{
}

chunk_map::~chunk_map()
{
}


void chunk_map::load_tiles()
{
/*

Tile loading this is were the tiles are added to the Quadrantics of the tilemap.
this is the entire chunk_map loop

*/
if ((chunk_end_x * chunk_end_y) == 0)//empty map - possibly forgotten to fill data struct
{
//to stop displaying at all after failed loading:
tiles_per_chunk_x = 0;
tiles_per_chunk_y = 0;
m_chunks.clear();
return;
}

chunk_map::tiles_per_chunk_x = (chunk_end_x / chunksize) + 1;
chunk_map::tiles_per_chunk_y = (chunk_end_y / chunksize) + 1;
m_chunks.assign(tiles_per_chunk_x, std::vector<sf::VertexArray>(tiles_per_chunk_y, sf::VertexArray(sf::Quads)));//ready up empty 2d arrays
for (int iy = chunk_start_y; iy < chunk_end_y; ++iy)
{
for (int ix = chunk_start_x; ix < chunk_end_x; ++ix)
{
append_tile(ix, iy, m_chunks[ix / chunksize][iy / chunksize]);
}
}
}


void chunk_map::append_tile(int gx, int gy, sf::VertexArray& garr)
{
/*

This is the specific tile vertex, broken from the other function to decrease complexitity.

*/

int tile_selection_index_x = rand() % 2;
int tile_selection_index_y = 0;

float f_tx = tile_selection_index_x * tile_size_float;
float f_ty = tile_selection_index_y * tile_size_float;


sf::Vertex ver;

//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float, gy * tile_size_float);
//texture in position of text atlas
//top left corner
//ver.texCoords = sf::Vector2f( 0.f, 0.f);
ver.texCoords = sf::Vector2f(f_tx, f_ty);
garr.append(ver);

//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float + tile_size_float, gy * tile_size_float);
//texture in position of text atlas
//top right corner
//ver.texCoords = sf::Vector2f( tile_size_float, 0.f);
ver.texCoords = sf::Vector2f(f_tx + tile_size_float, f_ty);
garr.append(ver);

//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float + tile_size_float, gy * tile_size_float + tile_size_float);
//texture in position of text atlas
//bottom right corner
//ver.texCoords = sf::Vector2f( tile_size_float, tile_size_float);
ver.texCoords = sf::Vector2f(f_tx + tile_size_float, f_ty + tile_size_float);
garr.append(ver);

//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float, gy * tile_size_float + tile_size_float);
//texture in position of text atlas
//bottom left corner
//ver.texCoords = sf::Vector2f( 0.f, tile_size_float);
ver.texCoords = sf::Vector2f(f_tx, f_ty + tile_size_float);
garr.append(ver);
}


void chunk_map::set_texture(sf::Texture t)
{
/*

Sets the texture data for this chunk map from the texture atlas.

*/

m_texture = t;

// TODO test this feature
// Attempt to optimize tearing on zooming to a different view.
//m_texture.setSmooth(true);
}


void chunk_map::set_position(int chunk_start_x, int chunk_start_y,
int chunk_end_x, int chunk_end_y)
{
/*

Initialize the accordinates of the start of the chunk_map to the end.

*/
chunk_map::chunk_start_x = chunk_start_x;
chunk_map::chunk_start_y = chunk_start_y;

chunk_map::chunk_end_x = chunk_end_x;
chunk_map::chunk_end_y = chunk_end_y;
}


void chunk_map::draw(sf::RenderTarget& target, sf::RenderStates states)const
{
/*

The actual draw call to this specific chunk_map

*/


// position variables for this draw.
int left = 0;
int right = 0;
int top = 0;
int bottom = 0;


//get top left point of view
sf::Vector2f temp = target.getView().getCenter() - (target.getView().getSize() / 2.f);


//get top left point of view
left = static_cast<int>(temp.x / (chunksize * tilesize));
top = static_cast<int>(temp.y / (chunksize * tilesize));


//get bottom right point of view
temp += target.getView().getSize();
right = 1 + static_cast<int>(temp.x / (chunksize * tilesize));
bottom = 1 + static_cast<int>(temp.y / (chunksize * tilesize));


//clamp these to fit into array bounds:
left = std::max(0, std::min(left, tiles_per_chunk_x));
top = std::max(0, std::min(top, tiles_per_chunk_y));
right = std::max(0, std::min(right, tiles_per_chunk_x));
bottom = std::max(0, std::min(bottom, tiles_per_chunk_y));


//set texture and draw visible chunks:
states.texture = &m_texture;



for (int ix = left; ix < right; ++ix)
{
for (int iy = top; iy < bottom; ++iy)
{
target.draw(m_chunks[ix][iy], states);
}
}
}

tile_atlas.h

#pragma once
#include <SFML/Graphics/Texture.hpp>
class tile_atlas
{
private:
sf::Texture atlas_texture;
public:
tile_atlas();
~tile_atlas();
sf::Texture& get_atlas();
};

tile_atlas.cpp

#include "tile_atlas.h"
#include <iostream>
#include <string>


tile_atlas::tile_atlas()
{
std::string file_string = "tilemap_test.png";
if (!atlas_texture.loadFromFile(file_string))
{
std::cout << "Failed loading file: " << file_string << std::endl;
exit(1);
}
}

tile_atlas::~tile_atlas()
{
}

sf::Texture& tile_atlas::get_atlas()
{
return atlas_texture;
}

我正在尝试修复此代码以移除垂直伪影,因此无论移动 View 或放大/缩小,上图都将始终看起来像这样。

tilemap as expected



[答案代码]

使用@Mario 的回答,这是我编写的代码(在 main.cpp 的底部),它完全修复了工件。这是一个显示示例的好链接。 https://www.sfml-dev.org/tutorials/2.5/graphics-draw.php#off-screen-drawing

    #ifdef _DEBUG
app.clear();
#endif // DEBUG
//map.draw(app, dt);


/*-----------------------------------------------------------*/
// Draw the texture
//rt.clear();

rt.draw(map.at(0));
rt.display();
if (cam.getSize().x < 500)
{
rt.setSmooth(false);
}
else
{
rt.setSmooth(true);
}
//// get the target texture (where the stuff has been drawn)
const sf::Texture& texture = rt.getTexture();

sf::Sprite sprite(texture);

app.draw(sprite);

//app.draw(map.at(0));

/*-----------------------------------------------------------*/

app.display();

最佳答案

简单但有效:

在不缩放到渲染纹理的情况下按 1:1 渲染像素,然后将其放大。

确定正确的位置、缩放等可能有点棘手,但可以做到。

关于c++ - 如何使用像素完美缩放/移动修复 SFML 中顶点数组中的垂直伪影线?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55997965/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com