2014年10月17日金曜日

UMGのプロパティバインディングとスライダーを使ってみた

UMGのブループリントに変数を追加し,UMGのコンポーネントと連動させることができるようなので,それを利用してテキストボックスとスライダーを連動させてみた.

Widgetブループリントの生成


ここでは,SampleWidgetBPというWidgetブループリントを作成し,Editable Text BoxとSliderを配置し,それぞれValueTextとValueSliderという名前にしてみた.

変数の追加


次に,グラフからプロパティとして利用するFloatの変数Valueを追加しておく.

ValueTextのテキストの取得と設定に関する設定

まず,テキストボックスに変数Valueの値を取得して変換して設定するようにする.


更に,テキストボックスが編集された場合にValueに値を設定し,Sliderの値も変更するようにする.(Sliderには設定しなくてもできる気もする)



ValueSliderの値の取得と設定


ValueTextと同様に,詳細のValueを変数Valueを参照するようにしたり,値が変化した際にValueに設定するようにしている.




Widgetの表示


最後に,レベルブループリントなどからWidgetを生成して,Add to Viewportで画面に出せば,Sliderの変化に合わせてテキストボックスの値が変わり,テキストボックスの変更に合わせてスライダーが移動するUIが完成する.


最後に

SliderにプロパティとしてValueを設定しているところをバインディングに変更すれば,Sliderに値を設定する部分は不要かもしれないが・・・眠いのでまた明日にしよう.

2014年10月15日水曜日

Unreal Motion Graphics (UMG)でプログレスバーを表示してみた

UMGでプログレスバーを作ってみました.

UMGを有効にするには,メニューの編集からエディタの設定を選びます.

実験的,の項目からUMGにチェックを入れ,エディタを再起動します

コンテンツブラウザから新規のアセットを追加します.右クリックメニューからユーザーインターフェースの中のWidgetブループリントを選びます.

できたブループリントのファイルをダブルクリックして開くと,UMGのエディタになるので,適当にプログレスバーを配置し,名前をProgressに変更しておきます.終わったらコンパイルしておきます.

レベルブループリントを開き,追加したブループリントの名前のオブジェクトの変数を作ります.(この図では手抜きでデフォルトの名前のまま).そして,Begin Playイベント時にCreateWidgetを利用して作成したWidgetを生成します.CreateWidgetに作成したブループリントを指定すると,Widgetが生成できます.CreateWidgetが返すのはUserWidget型のオブジェクトなので,キャストを挟んで変数に設定します.

このWidgetから線をひっぱり,Add to Viewportを呼び出すと,画面に表示されます.

Progressと名付けたfloat型の変数を追加しておき,Begin Playイベント時に0で初期化しておきます.

Tickイベントで毎フレーム0.001ずつProgressの値を増やします.ただし,100を超えないようにします.

最後に,Widget変数から線をひっぱりGet Progressと打つと,プログレスバーのオブジェクトが取得できます.そこから更に線をひっぱると,Set Percentというものがあるので,そこに変数Progressの値を設定します.

これをコンパイルして再生すると,プログレスバーが徐々に進んでいきます.

他のUIもいろいろ触ってみたくなってきました.

2014年10月13日月曜日

glLoadGenを使う場合の注意点

OpenGL 4 Shading Language Cookbook, 2nd Editionを読んでいて,いきなり躓いた.

第一章で導入するglLoadGenが,ダウンロードできる最新版だと上手く動かない.
こちらに書いてあるように問題があるので,こちらを参照して手元のものを書き直すか,Mercurialを使って最新版をダウンロードする必要がある.

次に,Windows上で実行した場合,何故かバージョン指定を"(ダブルクオーテーション)で囲む必要があった.
(PowerShellを使っているせいか?)

この点を修正すると,ようやく動かすことができた.

2014年10月7日火曜日

WebGLによるPVRテクスチャの利用

DDSの読み込みを作った勢いで,iOSのWebGL向けにPVRテクスチャを読み込む処理を書いてみた.

動作サンプルはこちら
iOS 8以降で確認できます.

// 拡張機能の取得
var ct = gl.getExtension("WEBKIT_WEBGL_compressed_texture_pvrtc");

// FCCを32bit符号付き整数に変換する
function FourCCToInt32(value){
    return (value.charCodeAt(0) << 0) +
        (value.charCodeAt(1) << 8) +
        (value.charCodeAt(2) << 16) +
        (value.charCodeAt(3) << 24);
}

// 32bit符号付き整数をFCCに変換する
function Int32ToFourCC(value){
    return String.fromCharCode(
        (value >> 0) & 0xff,
        (value >> 8) & 0xff,
        (value >> 16) & 0xff,
        (value >> 24) & 0xff
    );
}

// XMLHttpRequestの生成
var XHR = new XMLHttpRequest();

// 読み込むファイルの指定
XHR.open('GET', './sample4.pvr');

// 読み込み完了時の処理
XHR.addEventListener('load', function(){
    // iOS Developer Libraryより
    // PVRTextureLoaderを参照
    // https://developer.apple.com/library/ios/samplecode/PVRTextureLoader/Introduction/Intro.html
    var header = new Uint32Array(XHR.response, 0, 13);
    var tag = Int32ToFourCC(header[11]);

    if(tag != "PVR!"){
        alert("PVRフォーマットではありません.");
        return ;
    }

    var hasAlpha = header[10] != 0 ? true : false;
    var PVR_TEXTURE_FLAG_TYPE_MASK = 0xff;
    var PVR_TEXTURE_FLAG_TYPE_PVRTC_2 = 24;
    var PVR_TEXTURE_FLAG_TYPE_PVRTC_4 = 25;

    var height = header[1];
    var width  = header[2];

    var format = 0;
    var blockSize = 0;
    var blockWidth = 0;
    var blockHeight = 0;
    // 1ピクセルあたりのビット数
    var bpp = 0;
    switch(header[4] & PVR_TEXTURE_FLAG_TYPE_MASK){
    case PVR_TEXTURE_FLAG_TYPE_PVRTC_2:
        if(hasAlpha){
            format = ct.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
        }else{
            format = ct.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
        }
        blockSize = 8 * 4;
        blockWidth = width / 8;
        blockHeight = height / 4;
        bpp = 2;
        break;
    case PVR_TEXTURE_FLAG_TYPE_PVRTC_4:
        if(hasAlpha){
            format = ct.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
        }else{
            format = ct.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
        }
        blockSize = 4 * 4;
        blockWidth = width / 4;
        blockHeight = height / 4;
        bpp = 4;
        break;
    default:
        alert("未知のフォーマットです.\n");
        return ;
    }

    // 最低限のサイズはあるものとする
    blockWidth = Math.max(2, blockWidth);
    blockHeight = Math.max(2, blockHeight);

    var size = blockWidth * blockHeight * ((blockSize * bpp) / 8);
    var buffer = new Uint8Array(XHR.response, 13 * 4, size);

    // 圧縮テクスチャを渡す
    gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, buffer);

    // テクスチャのパラメータを設定
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

    // テクスチャを設定して有効化
    gl.uniform1i(gl.getUniformLocation(program, 'texture'), texture);
    gl.activeTexture(gl.TEXTURE0);

    // 描画開始
    draw();
});
// バイト配列として結果が帰ってくるようにする
XHR.responseType = 'arraybuffer';

// 読み込み開始
XHR.send();

処理としてはDDSを読み込む場合とほとんど変わらず,違いというと,取得する拡張機能の名前が違うことと,受け取ったバイト列をフォーマットに合わせる部分.

このコード書くの,何が大変だったかってpvrのテクスチャを生成するのが手間だったのと,iOSでチェックするためのデバッグが面倒だった.Safariを使ってiOS上で見ているウェブページをデバッグする機能が無かったら大変だった.

2014年10月6日月曜日

PVR形式のテクスチャの作り方

忘れそうなのでメモ.

xcrun -sdk iphoneos texturetool [-m] -e PVRTC --bits-per-pixel-4 -o outputfile -f PVR inputfile
# -m でミップマップ生成
# --bits-per-pixel-2も

2014年10月2日木曜日

WebGLでDDSテクスチャを表示する

WebGLでDDSテクスチャを表示する方法,調べても日本語ではあまり情報がなかったのでまとめておく.
通常のテクスチャの表示方法については,wgld.orgを参考にする.

まず,現状ではDDSのテクスチャを読み込むには,WebGLのコンテキストからgetExtension()を利用して,拡張機能を取得して利用する必要がある.
// var gl; // WebGLのレンダリングコンテキスト

// Chromeでの拡張機能の取得
var ct = gl.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc');
// FireFoxでの拡張機能の取得
// var ct = gl.getExtension('MOZ_WEBGL_compressed_texture_s3tc');
ブラウザによって取得のために渡す文字列が違うが,取得した後は同じように扱える.このctは,compressedTexImage2Dに渡すフォーマットに関する定数を持ったオブジェクトになっている.
今のところ,次の4つの定数が含まれている.

  • COMPRESSED_RGBA_S3TC_DXT1_EXT
  • COMPRESSED_RGBA_S3TC_DXT3_EXT
  • COMPRESSED_RGBA_S3TC_DXT5_EXT
  • COMPRESSED_RGB_S3TC_DXT1_EXT

テクスチャにデータを渡す準備ができたら,テクスチャのデータをXMLHttpRequestを利用して読み込む.
var XHR = new XMLHttpRequest();
XHR.open('GET', テクスチャのパス);

XHR.addEventListener('load', onLoad, false);

// ロード結果のフォーマットの指定
XHR.responseType = 'arraybuffer';

// 実際の読み込み
XHR.send();

これで,読み込み終わったタイミングでonLoadが呼び出されるので,DDSのテクスチャの解析を行う.

DDSファイルは,Microsoftのドキュメントにあるように,4文字を32bit整数にまとめたFOURCCと,その後に続くヘッダから始まる.

まず,FOURCCと32bit整数を相互に変換する機能が必要なので,関数を作っておく.
// FCCを32bit符号付き整数に変換する
function FourCCToInt32(value){
    return (value.charCodeAt(0) << 0) +
        (value.charCodeAt(1) << 8) +
        (value.charCodeAt(2) << 16) +
        (value.charCodeAt(3) << 24);
}

// 32bit符号付き整数をFCCに変換する
function Int32ToFourCC(value){
    return String.fromCharCode(
        (value >> 0) & 0xff,
        (value >> 8) & 0xff,
        (value >> 16) & 0xff,
        (value >> 24) & 0xff
    );
}


XHRの読み込み結果からマジックナンバーおよびヘッダ(31個の32bit整数で出来ている)を読み込み,ヘッダから必要な情報を取り出し,compressedTexImage2Dに渡す.
function onLoad()
{
    var header = new Int32Array(XHR.response, 0, 32);

    // マジックナンバーのチェック
    if(header[0] !== FourCCToInt32('DDS ')){
        return ;
    }

        // ブロックのバイトサイズ
    var blockBytes;
    // フォーマット
    var format;

    // DDS_PIXELFORMATのdwFourCCを確認し,1ブロックのサイズと
    // フォーマットを確認する
    var FOURCC_DXT1 = FourCCToInt32('DXT1');
    var FOURCC_DXT3 = FourCCToInt32('DXT3');
    var FOURCC_DXT5 = FourCCToInt32('DXT5');
    switch(header[21]){
    case FOURCC_DXT1:
        blockBytes = 8;
        format = ct.COMPRESSED_RGBA_S3TC_DXT1_EXT;
        break;
    case FOURCC_DXT3:
        blockBytes = 16;
        format = ct.COMPRESSED_RGBA_S3TC_DXT3_EXT;
        break;
    case FOURCC_DXT5:
        blockBytes = 16;
        format = ct.COMPRESSED_RGBA_S3TC_DXT5_EXT;
        break;
    }

    // DDS_HEADERのdwHeightを取得 (マジックナンバー分に注意)
    var height = header[3];

    // DDS_HEADERのdwWidthを取得 (マジックナンバー分に注意)
    var width  = header[4];

    // DDS_HEADERのdwSizeを取得し,マジックナンバー分を足して,テクスチャデータの
    // 先頭を求める
    var offset = header[1] + 4;

    // 今のテクスチャのバイトサイズを求める
    var length = Math.max(4, width) / 4 * Math.max(4, height) / 4 * blockBytes;

    // バッファを生成する
    var buffer = new Uint8Array(XHR.response, offset, length);

    // 圧縮テクスチャを渡す
    gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, buffer);

    // 本来はミップマップのために,サイズを変えながら残りのデータを読み込むが省略

    // テクスチャのパラメータを設定
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

    // テクスチャを設定して有効化
    gl.uniform1i(gl.getUniformLocation(program, 'texture'), texture);
    gl.activeTexture(gl.TEXTURE0);

    // 実際の描画
    draw();
}

実際に動作するサンプルを用意してみた.とりあえず適当に丸を書いただけのテクスチャなのでおもしろみは無い.

サンプル

他の拡張機能についても,そのうち調べてみよう.