TOP > プログラミング関連 > SFML非公式翻訳トップ > 【非公式翻訳】SFML2.4チュートリアル > グラフィックスモジュール > スプライトとテクスチャ

[原文(公式)]

◆◆ スプライトとテクスチャ ◆◆
SFML2.4 非公式日本語翻訳
ことば を おぼえよう
やっほー、もうみんな、「テクスチャ」「スプライト」っていう2つの言葉は聞いたことあるよね?
じゃあどんな意味なのか、わかるかな?
「テクスチャ」って なぁに?
画像です。でも、どうして「テクスチャ」って呼ぶのかな?
それはですね、「2Dの物体に貼り付ける」っていう特別な役割があるからだよ。

「スプライト」って、なぁに?
テクスチャが貼り付けられた四角形、のことだよ。



わかったかな?
まだよくわかんないっていうお友達は、wikipedia先生にきいてみてね。
テクスチャをロードする
つまり、スプライトを作る前に、テクスチャが必要ってことだね。
SFML でテクスチャを扱うためのクラスは、sf::Texture だよ。そのまんまだね。 テクスチャの役割は「画像を読み込んで」「何かに貼り付ける」ことだから、 このクラスのほとんどのメソッドは、読み込みと更新に関するものだよ。

さて、画像ファイルをハードディスクから読み込んでテクスチャにするには loadFromFile関数を使うよ。
sf::Texture texture;
if (!texture.loadFromFile("image.png"))
{
    // error...
}
この loadFromFile関数なんだけど、ときどき、よくわかんない理由で失敗してしまいます。 そんなときは、まず、エラーメッセージをチェックせよ。コンソールに出力されてます。 さて、なんて言ってるでしょう? 「unable to open file」? そんなときは、カレントディレクトリを確認だ。 カレントディレクトリっていうのは、キミのアプリケーションがファイルを読み込むときの、 相対パスの出発点になるフォルダのことです。 さて、キミの思ってる通りのフォルダかな? アプリケーションをデスクトップ環境で起動しているときは、 そのアプリケーションが置いてあるフォルダがカレントディレクトリなのだけど、 IDE(Visual Studio とか、Code::Blocksとか)から起動してるときは、 そのプロジェクトのフォルダになってるかも。プロジェクトの設定でカンタンに変更できるはず。
テクスチャはメモリから読み込むこともできます ( loadFromMemory関数 )。
ストリームから読み込むこともできます (loadFromStream関数)。
読み込み済みの画像を元に作ることもできます (loadFromImage関数)。

最後のやつについておはなしするよ。

読み込み済みの画像っていうのは、つまり、 sf::Image ってことです。 画像データをメモリ上に保存して取り扱うためのお助けクラスです(ピクセルを操作したり、透過色を設定したり……)。 メモリ上にデータを持ってる状態だから、処理はすごく速いよー。 これとは正反対に、ビデオメモリ上にあるテクスチャのピクセルはアクセスするのも更新するのも遅いんだ。描画はすごく早いのだけどね。

SFML で扱える画像のフォーマットなんだけど、 だいたいみんなが知ってるフォーマットは、使えるようになってるよ。 APIドキュメントに一覧が載ってるから、よかったら見てみてね。

じゃあ次に、画像の一部だけをロードするやり方だよ。 今までお話してきたローディングの関数には引数がもう1つあって、そこに値を指定するよ。
// 座標(10, 10) から サイズ32x32 の矩形を読み込む
if (!texture.loadFromFile("image.png", sf::IntRect(10, 10, 32, 32)))
{
    // error...
}
おや、また新しいお友達ですね。sf::IntRectちゃん。
この子は四角形を表すシンプルなユーティリティクラスだよ。コンストラクタに左上の座標と、四角形のサイズを入れてあげてね。

テクスチャを画像から直接作成するんじゃなくて、ピクセルのリストで作ることもできます。 その場合、まずは空のテクスチャを作って、そのあとで更新するよ。
// サイズ 200x200 の 空のテクスチャを生成
if (!texture.create(200, 200))
{
    // error...
}
この時点では、まだテクスチャの中身は作成されてません。
sf::Textureクラスの update関数にピクセルのリストを指定しよう。 update関数はピクセルのリスト以外にも、いろんな種類のものを、テクスチャを更新する材料として、引数に受け取れるようになってます。
// テクスチャを更新:ピクセルのリストを使って
// 「* 4」してるのは、色の要素が4つ(RGBA)だから
sf::Uint8* pixels = new sf::Uint8[width * height * 4];
...
texture.update(pixels);

// テクスチャを更新:画像を使って
sf::Image image;
...
texture.update(image);

// テクスチャを更新:ウィンドウに表示されてる内容を使って。
sf::RenderWindow window;
...
texture.update(window);
上のサンプルでは、テクスチャを更新する材料は「そのテクスチャと同じサイズなのだ!」と勝手に仮定されてます。 もし同じサイズじゃない場合、たとえばテクスチャの一部分だけ更新したいとか、 そういうときは、更新したい部分の矩形の座標を指定することができるよ。詳しくは、APIドキュメントを見てね。

最後にもう1つ。
テクスチャには設定項目が2つあって、どんなふうに描画されるのかを変更できるんだ。

1つ目の設定項目は、テクスチャをスムーズに描画するかどうか、の設定だよ。 スムーズに描画すると、ピクセルの粒がぼやけて、見分けにくくなるんだ。拡大して表示するときに、違いが目立つよ。
texture.setSmooth(true);

スムーズ表示の機能はピクセルさんたちに、あれこれと口出しをするってことだから、 ときどき、見た目がおかしくなってしまうこともあるよ。 どんなときにそうなるかっていうと、スプライトを、整数じゃない座標に表示しているとき、だよ。
2つ目の設定項目は、リピート表示です。
1つのスプライトの中で、同じテクスチャをたくさん並べた感じにするよ。
texture.setRepeated(true);
この設定は、スプライトの方がテクスチャより大きい場合だけ効果があるよ。
よーし、じゃあ、スプライトを作ってみようかな
作ろう作ろうー!
sf::Sprite sprite;
sprite.setTexture (texture);
そんでもって、描画だ!
// メインループの中、window.clear() と window.display()の間に書く
window.draw (sprite);
矩形を指定して、スプライトの中に、テクスチャを一部分だけ表示することもできます。
sprite.setTextureRect (sf::IntRect (10, 10, 32, 32) );
スプライトの色も指定できます。
このとき、テクスチャの色と乗算合成されて表示されるよ。 透明度(アルファ値)も設定できます。
sprite.setColor (sf::Color (0, 255, 0) ); // 緑
sprite.setColor (sf::Color (255, 255, 255, 128) ); // 半透明
このスプライトは、みんな同じテクスチャで、色の設定だけ変えてます。

表示する位置、向き、倍率も設定できるよ。
// 位置
sprite.setPosition(sf::Vector2f(10, 50)); // 絶対位置
sprite.move(sf::Vector2f(5, 10)); // 相対位置(移動)

// rotation
sprite.setRotation(90); // 絶対角度
sprite.rotate(15); // 相対角度(回転)

// scale
sprite.setScale(sf::Vector2f(0.5f, 2.f)); // 絶対倍率
sprite.scale(sf::Vector2f(1.5f, 3.f)); // 相対倍率(拡大)
デフォルトでは、スプライトの左上の点が、位置や回転や拡大の基準点になってます(中心点、または原点)。
左上じゃなくて、真ん中とかの方がいいかもしれないですよね。 setOrigin関数で変更できるよー。
sprite.setOrigin(sf::Vector2f(25, 25));
こういう、移動や回転などの操作は SFML の他の物体でも同じやり方です。 なので、別のチュートリアルにまとめてあります。
大変! スプライトが まっしろだよ!
テクスチャ作成成功! スプライトもちゃんと作ったよ。 だけど……画面にはまっしろな四角形が出るだけ。なんでなんで!

それはね、よくあるミステイクなの。
スプライトにテクスチャを設定したとき、スプライトが内部で保持しているのは、 そのテクスチャへの「ポインタ」なの。 だから、テクスチャの本体が削除されたり、メモリ上の別の場所に移動したりしたら、 スプライトはテクスチャを見失ってしまうの。

この失敗は、こんなふうにコードを書くと起きるよ。
sf::Sprite loadSprite (std::string filename)
{
    sf::Texture texture;
    texture.loadFromFile (filename);

    return sf::Sprite (texture);
} // 関数が終了する時点で、テクスチャが破棄されてしまう
スプライトに使われる間、テクスチャが有効なままでいてくれるように、 テクスチャがいつ生成されていつ破棄されるのか、ライフタイムをしっかり管理するようにしようね。
テクスチャはできるだけ少ない枚数にしよう
理由はカンタンだよ。
テクスチャを切り替えるのはグラフィックカードさんにとって、すごく疲れるお仕事なんだ。 同じテクスチャのままで、たくさんのスプライトを使う方が、カードさんは高速に動いてくれるよ。

たとえば、アニメーションシートやタイルセットを作るとき、このこと(テクスチャを少なめにする)を覚えておこう!

ちなみに、1枚のテクスチャだけを使うようにすると、スタティックジオメトリをグループ化して、 1つの物体にできるんだ。そうすると、1回の draw関数で1枚のテクスチャしか使わなくてすむから、 たくさんの物体を1つずつ別々に描画するよりも早く処理できるよ。
スタティックジオメトリをグループ化するおはなしをするには、他のクラスのお話もしなきゃいけなくなって、 今日のおはなしのテーマを越えてしまうから、詳しくは頂点リストの日におはなしするね。

OpenGL のコードで sf::Texture を使う
SFML のグラフィックスモジュールじゃなくて OpenGL を使うときにも、sf::Textureさんは活躍してくれるよ。 OpenGL のテクスチャのラッパーになって、他の OpenGL のデータと仲良くできるよ。

描画のために sf::Textureを使うには( glBindTexture と基本的に同じ )、スタティック関数の bind を使ってね。
sf::Texture texture;
...

// バインド
sf::Texture::bind (&texture);

// ……テクスチャを貼った OpenGLの物体を描画……

// バインドを解除
sf::Texture::bind (NULL);