スプライトとGUIの表示

基本事項

二通りの表示方法がある。

  1. フレーム毎に逐次表示する方法。
  2. GUIEnvironmentに登録する方法。
    フレーム毎に個々に描画処理を記述しなくても、一度登録した物を自動的に表示する。

フレーム毎に逐次表示

1.の方法を取る場合、endScene()の前に、下記のような描画処理を挿入する。
irrDriver->draw2DImage(irrDriver->getTexture("irrlichtlogo2.png"), 
  core::position2d<s32>(400, 400), // 表示先の位置
  core::rect<s32>(0, 0, 128, 128),       // 元画像中の表示する範囲
  NULL,                            // クリッピングなし
  video::SColor(255,255,255,255),  // 色(暗くしたい場合は小さくする)
  true                             // アルファチャネル有効
);

これは、座標(400,400)を左上としてirrlichtlogo2.pngを表示する例である。irrlichtlogo2.pngは128x128の画像なので、(0, 0, 128, 128)は全域を表示するという意味になる。

拡大縮小ありの場合は、下記のようにする。

irrDriver->draw2DImage(irrDriver->getTexture("irrlichtlogo2.png"),
  core::rect<s32>(400, 400, 480, 480), // 表示先の範囲
  core::rect<s32>(0, 0, 128, 128),     // 元画像中の表示する範囲
  NULL,                                // クリッピングなし
  NULL,                                // 暗くしたい場合は、4頂点の色をSColorへのポインタで指定
  true                                 // アルファチャネル有効
  );

上記の場合、(400, 400)の位置を左上として幅80高さ80で表示する。

GUIEnvironmentに登録する場合

GUIEnvironmentに登録して表示する場合、前提として、各フレームでIGUIEnvironment::drawAll()を呼び出している必要がある。登録されたものを描画するのがdrawAll()関数だからである。無い場合は、SceneManagerのdrawAll()呼び出し以降、かつendScene()よりも前に下記の呼び出しを挿入すること。

pIrrDevice->getGUIEnvironment()->drawAll();

(イメージを表示する場合の例)
下記を実行すると、以後この画像を表示し続ける。

gui::IGUIEnvironment* ge = pIrrDevice->getGUIEnvironment();
gui::IGUIImage* gi = ge->addImage(
  pIrrDevice->getVideoDriver()->getTexture("irrlichtlogo2.png"),
  core::position2d<s32>(10,20)); // スクリーン座標のx=10,y=20に表示

消したいときは、gi->remove() で削除する。drop()ではない。

イメージの回転表示

Irrlichtのビルボード機能、スプライト機能には、回転機能が存在しない。このため、そういうことがしたいのならプリミティブを直接操作する必要がある。
このために作成したユーティリティ関数を下記に示す。

using namespace irr;
using namespace irr::core;

template <class T>
class CMatrix2 {
public:
    T M[4];
    void transformVect(irr::core::vector2d<T> &v) {
        irr::core::vector2d<T> r;
        r.X = v.X * M[0] + v.Y * M[1];
        r.Y = v.X * M[2] + v.Y * M[3];
        v = r;
    }
};

enum enumDRAWBillBoard_Coord {
    EDBC_WORLD =  0,
    EDBC_CAMERA = 1
};

void DrawRotatedBillboard(IrrlichtDevice* pDevice, scene::ICameraSceneNode* pCamera,
        video::ITexture* pTexture, core::vector3df vpos, core::dimension2d<f32> size,
        double rot, enumDRAWBillBoard_Coord edbc, bool bScale) {

    scene::ISceneManager* smgr = pDevice->getSceneManager();
 	video::IVideoDriver* pDriver = pDevice->getVideoDriver();

    vector3df v1, v2;

    if(edbc == EDBC_WORLD) {
        pCamera->getViewMatrix().transformVect(v1, vpos);
        if(v1.Z <= 0) return;
    }
    else
        v1 = vpos;

    pCamera->getProjectionMatrix().transformVect(v2, v1);
    if(v2.Z <= 0) return;

    vector2df rvscr(v2.X / v2.Z, v2.Y / v2.Z);

    CMatrix2<float> mtx;
    mtx.M[0] = (float)cos(rot);  mtx.M[1] = (float)-sin(rot);
    mtx.M[2] = -mtx.M[1];        mtx.M[3] = mtx.M[0];

    dimension2d<u32> d2Screen = pDriver->getCurrentRenderTargetSize();

    rect<s32> rvp = pDriver->getViewPort();

    float H = float(v2.Z * tan(pCamera->getFOV() / 2));
    float r = bScale ? rvp.getHeight() / 2 / H : 1.0f;
    dimension2d<f32> ssize(size.Width * r , size.Height * r);

    position2d<float> center(d2Screen.Width  / 2 + rvscr.X * d2Screen.Width  / 2,
                             d2Screen.Height / 2 - rvscr.Y * d2Screen.Height / 2);

    position2d<float> p2d[4];
    p2d[0].X = - ssize.Width / 2;
    p2d[0].Y = - ssize.Height / 2;
    p2d[1].X =   ssize.Width / 2;
    p2d[1].Y = - ssize.Height / 2;
    p2d[2].X =   ssize.Width / 2;
    p2d[2].Y =   ssize.Height / 2;
    p2d[3].X = - ssize.Width / 2;
    p2d[3].Y =   ssize.Height / 2;

    video::S3DVertex vert[4];

    for(int i = 0; i < 4; i ++) {
        mtx.transformVect(p2d[i]); // To rotate billboard
        p2d[i].X *= d2Screen.Width / rvp.getWidth();
        p2d[i].Y *= d2Screen.Height / rvp.getHeight();
        p2d[i] += center;
        vert[i].Pos.X = p2d[i].X;
        vert[i].Pos.Y = p2d[i].Y;
        vert[i].Color = video::SColor(255, 255, 255, 255);
    }
    float xmin = p2d[0].X;
    float xmax = p2d[0].X;
    float ymin = p2d[0].Y;
    float ymax = p2d[0].Y;

    for(int i = 1; i < 4; i ++) {
        if(p2d[i].X > xmax) xmax = p2d[i].X;
        if(p2d[i].X < xmin) xmin = p2d[i].X;
        if(p2d[i].Y > ymax) ymax = p2d[i].Y;
        if(p2d[i].Y < ymin) ymin = p2d[i].Y;
    }

    if(xmin > d2Screen.Width || ymin > d2Screen.Height ||
       xmax < 0 || ymax < 0)
       return; // Totally out of viewport

    vert[1].TCoords.X = 1;
    vert[2].TCoords.X = 1;
    vert[2].TCoords.Y = 1;
    vert[3].TCoords.Y = 1;

    u16 index[] = { 0, 1, 2, 2, 3, 0};

    video::SMaterial mat;
    mat.Lighting = false;
    mat.TextureLayer[0].Texture = pTexture;
    mat.setFlag(video::EMF_ZBUFFER, false);
    mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
    pDriver->setMaterial(mat);
    pDriver->draw2DVertexPrimitiveList(vert, 4, index, 2, video::EVT_STANDARD);
}

このように、標準で存在しない物については、上記のようにプリミティブ描画関数draw2DVertexPrimitiveList等を直接操作して描画する必要がある。


Copyright by MUTATE Systems 2018
管理者宛メール