SFML2.6 图形模块--精灵和纹理

词汇表

大多数(如果不是全部)的您已经熟悉这两个非常常见的对象,因此让我们简要定义它们。

纹理是图片。但是我们称它为“纹理”,因为它有一个非常特定的作用:被映射到2D实体上。

精灵不过是纹理矩形。
在这里插入图片描述
好吧,这很简短,但如果你真的不明白精灵和纹理是什么,那么你可以在维基百科上找到更好的描述。

加载纹理

在创建任何精灵之前,我们需要一个有效的纹理。SFML中封装纹理的类是sf :: Texture。由于纹理的唯一作用是加载并映射到图形实体,因此几乎所有它的函数都是关于加载和更新它的。

最常见的加载纹理的方式是从磁盘上的图像文件中加载,这可以使用loadFromFile函数完成。

sf::Texture texture;
if (!texture.loadFromFile("image.png"))
{
    // error...
}

loadFromFile函数有时会无缘无故地失败。首先,请检查SFML打印到标准输出的错误消息(检查控制台)。如果消息是无法打开文件,请确保工作目录(任何文件路径将相对于其解释的目录)是您认为的那个:当您从桌面环境运行应用程序时,工作目录是可执行文件夹。但是,当您从IDE(Visual Studio,Code :: Blocks等)启动程序时,工作目录有时可能设置为项目目录。这通常可以在项目设置中轻松更改。

你也可以从内存(loadFromMemory)、自定义输入流(loadFromStream)或已经加载的图像(loadFromImage)加载图像文件。后者从sf::Image加载纹理,这是一个帮助存储和操作图像数据(修改像素、创建透明通道等)的实用程序类。sf::Image的像素留在系统内存中,这确保了对它们的操作将尽可能快,而纹理的像素驻留在视频内存中,因此检索或更新很慢,但绘制非常快。

SFML支持大多数常见的图像文件格式。完整列表可在API文档中找到。

所有这些加载函数都有一个可选参数,如果要加载图像的较小部分,则可以使用该参数。

// load a 32x32 rectangle that starts at (10, 10)
if (!texture.loadFromFile("image.png", sf::IntRect(10, 10, 32, 32)))
{
    // error...
}

IntRect类是一个表示矩形的简单实用程序类型。它的构造函数接受左上角的坐标和矩形的大小。

如果您不想从图像加载纹理,而是想直接从像素数组更新它,可以创建一个空的纹理并稍后更新它:

// create an empty 200x200 texture
if (!texture.create(200, 200))
{
    // error...
}

请注意,此时纹理的内容未定义。

要更新现有纹理的像素,您必须使用update函数。它有多个重载,用于许多种数据来源:

// update a texture from an array of pixels
sf::Uint8* pixels = new sf::Uint8[width * height * 4]; // * 4 because pixels have 4 components (RGBA)
...
texture.update(pixels);

// update a texture from a sf::Image
sf::Image image;
...
texture.update(image);

// update the texture from the current contents of the window
sf::RenderWindow window;
...
texture.update(window);

这些示例都假设源与纹理大小相同。如果不是这种情况,即如果您只想更新纹理的一部分,则可以指定要更新的子矩形的坐标。您可以参考文档以获取更多详细信息。

此外,纹理有两个属性会影响它的呈现方式。

第一个属性允许平滑纹理。平滑纹理使像素边界不太明显(但图像会更模糊),如果进行了放大,则可能是理想的选择。

texture.setSmooth(true);

在这里插入图片描述
由于平滑对纹理中相邻像素进行采样,因此可能会导致考虑选择的纹理区域外的像素的不良副作用。这可能会在精灵位于非整数坐标时发生。
第二个属性允许在单个精灵中以平铺的方式重复使用纹理。

texture.setRepeated(true);

在这里插入图片描述
只有当你的精灵被配置为显示一个比纹理大的矩形时,这个属性才能起作用。否则,这个属性不会产生任何效果。

现在我可以创建精灵了吗?

是的,你现在可以创建精灵了。

sf::Sprite sprite;
sprite.setTexture(texture);

…最后画出来。

// inside the main loop, between window.clear() and window.display()
window.draw(sprite);

如果你不想让精灵使用整个纹理,你可以设置它的纹理矩形。

sprite.setTextureRect(sf::IntRect(10, 10, 32, 32));

你可以改变精灵的颜色。你所设置的颜色会与精灵的纹理做调和(相乘)。这也可以被用来改变精灵的全局透明度(Alpha)。

sprite.setColor(sf::Color(0, 255, 0)); // green
sprite.setColor(sf::Color(255, 255, 255, 128)); // half transparent

这些精灵都使用相同的纹理,但颜色不同:
在这里插入图片描述
精灵也可以进行转换:它们有一个位置、一个方向和一个比例。

// position
sprite.setPosition(sf::Vector2f(10.f, 50.f)); // absolute position
sprite.move(sf::Vector2f(5.f, 10.f)); // offset relative to the current position

// rotation
sprite.setRotation(90.f); // absolute angle
sprite.rotate(15.f); // offset relative to the current angle

// scale
sprite.setScale(sf::Vector2f(0.5f, 2.f)); // absolute scale factor
sprite.scale(sf::Vector2f(1.5f, 3.f)); // factor relative to the current scale

默认情况下,这三个转换的原点是精灵的左上角。如果你想将原点设置为不同的点(例如精灵的中心或另一个角),你可以使用setOrigin函数。

sprite.setOrigin(sf::Vector2f(25.f, 25.f));

由于变换函数对所有SFML实体都是通用的,它们在一个单独的教程中进行了解释:变换实体

白色方块问题

你成功加载了一个纹理,正确地构建了一个精灵,但你在屏幕上看到的只是一个白色方块。发生了什么?

这是一个常见的错误。当你设置一个精灵的纹理时,精灵内部只是存储了一个指向纹理实例的指针。因此,如果纹理被销毁或移动到内存中的其他位置,精灵就会得到一个无效的纹理指针。

这个问题发生在你编写这样的函数时:

sf::Sprite loadSprite(std::string filename)
{
    sf::Texture texture;
    texture.loadFromFile(filename);

    return sf::Sprite(texture);
} // error: the texture is destroyed here

你必须正确管理纹理的生命周期,并确保它们在被任何精灵使用时都存在。

使用尽可能少的纹理的重要性

尽可能使用尽可能少的纹理是一个好策略,原因很简单:改变当前纹理是一个昂贵的操作,会占用显卡的大量资源。因此,使用许多使用相同纹理的精灵将产生最佳性能。

此外,使用单个纹理可以将静态几何体分组为单个实体(每个绘制调用只能使用一个纹理),这比绘制许多实体要快得多。批处理静态几何体涉及其他类,因此超出了本教程的范围,有关详细信息,请参见顶点数组教程。

在创建动画表或平铺集时,请尽量记住这一点:尽量使用尽可能少的纹理。

与OpenGL代码一起使用sf::Texture

如果您正在使用OpenGL而不是SFML的图形实体,则仍然可以使用sf::Texture作为OpenGL纹理对象的包装器,并将其与其他OpenGL代码一起使用。

要为绘制绑定sf::Texture(基本上是glBindTexture),可以调用bind静态函数:

sf::Texture texture;
...

// bind the texture
sf::Texture::bind(&texture);

// draw your textured OpenGL entity here...

// bind no texture
sf::Texture::bind(NULL);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值