ラベル OpenGL の投稿を表示しています。 すべての投稿を表示
ラベル OpenGL の投稿を表示しています。 すべての投稿を表示

2012年2月21日火曜日

計測プログラム

ゲームを作り込めば作り込む程だんだんパフォーマンスが悪くなるものです。 そんなときは計算処理、描画処理のループ部分に計測用プログラムを最初から組み込んでおくと、思わぬボトルネックに気付く事もあります。 せっかくですので、現在個人的に開発中の次回作で使用している計測ユーティリティを載せておきます。 Androidであればコピペして使えるプログラムなので便利ですよ。
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Logger;

public class BenchTable {
    
    private static BenchTable me = new BenchTable();
    
    private HashMap ones = new HashMap();
    private HashMap sums = new HashMap();
    
    public static BenchTable getInstance(){
        return me;
    }
    
    public void start(String key){
        One o = ones.get(key);
        if(o == null){
            o = new One();
            ones.put(key, o);
        }
        o.start = System.currentTimeMillis();
    }
    
    public void stop(String key){
        One o = ones.get(key);
        if(o == null) return;
        
        o.end = System.currentTimeMillis();
        
        Sum s = sums.get(key);
        if(s == null){
            s = new Sum();
            sums.put(key, s);
        }
        s.set(o.end - o.start);
    }
    
    public void dump(){
        Logger logger = Logger.getLogger(this.getClass().getName());
        for (Iterator it = sums.entrySet().iterator(); it.hasNext();) {
            Map.Entry entry = (Map.Entry)it.next();
            String key   = (String)entry.getKey();
            Sum value = (Sum)entry.getValue();
            logger.info("Bench : " + key
                    + " avg :" + (value.total / value.count) 
                    + " max :" + value.max
                    + " total :" + value.total
                    + " count :" + value.count
                    );
            value.reset();
        }
    }
}

class One {
    double start;
    double end;
}

class Sum{
    int count;
    double total;
    double max;
    
    void set(double t){
        count++;
        total += t;
        if(max < t)max = t;
    }
    
    void reset(){
        count = 0;
        total = 0;
        max = 0;
    }
}
BenchTableクラスでは、計測したい箇所の呼び出し回数、合計時間、最大時間、平均時間を HashTableで管理します。 使い方は下記で、気になる関数の前後にラベルを指定してstartとstopを呼び出します。 一定期間が過ぎたらdumpを呼び出せば、集めた結果を出力します。
    private int bm = 0;

    public synchronized void onCalclateObjects(){
     if(state != GameEngineState.GAME_START)return;
     
     if(bm++ > 300){
      bm=0;
         BenchTable.getInstance().dump();
     }

     BenchTable.getInstance().start("phaseCalcAvatars");
     phaseCalcAvatars();
     BenchTable.getInstance().stop("phaseCalcAvatars");
     BenchTable.getInstance().start("phaseCalcFieldItem");
     phaseCalcFieldItem();
     BenchTable.getInstance().stop("phaseCalcFieldItem");
     BenchTable.getInstance().start("phaseCalcAtacks");
     phaseCalcAtacks();
     BenchTable.getInstance().stop("phaseCalcAtacks");
     BenchTable.getInstance().start("phaseCollisionAvatars");
     phaseCollisionAvatars();
     BenchTable.getInstance().stop("phaseCollisionAvatars");
    }
出力結果はこんな感じです。
02-09 11:32:12.272: INFO/BenchTable(27115): Bench : phaseCalcAtacks avg :0.019867549668874173 max :1.0 total :6.0 count :302
02-09 11:32:12.282: INFO/BenchTable(27115): Bench : phaseCollisionAvatars avg :0.8377483443708609 max :3.0 total :253.0 count :302
02-09 11:32:12.292: INFO/BenchTable(27115): Bench : phaseCalcAvatars avg :1.1986754966887416 max :27.0 total :362.0 count :302
02-09 11:32:12.292: INFO/BenchTable(27115): Bench : phaseCalcFieldItem avg :0.10264900662251655 max :1.0 total :31.0 count :302
count :302

最後に、この計測プログラムで自分のアプリを調べたときに残念な事がわかりました。 「AndroidはJNIが遅いので、OpenGLの限界に達する前にJNIの限界でポリゴン数が限られてしまう」 Javaを使ってAndroidアプリを作ったときに3D処理にOpenGLを使うと思うのですが、おおよそ下記のような呼び出しがされます。
Javaアプリ -> OpenGL関数呼び出し -> JNI -> ネイティブOpenGL -> GPU
最近のAndroid端末のGPUはそれなりの性能のものが搭載されていると思うので、それなりのポリゴンを処理できるはずなのですが、JNIがそれほど早くないので、JavaからネイティブOpenGLAPIを呼び出す回数自体が限られてしまうのです。 なのでJavaでOpenGLの処理を書いてしまうとGPUの性能をフルに使う事が出来ない事になります。 本格的な3Dのゲームを作りたかったらC++等で作らないとダメそうですね。残念 orz

2010年6月28日月曜日

NexusOne, Droidでテクスチャがでない問題




「魔王なんて!」発売後、かなり悩まされた問題があります。特定の端末で「テクスチャが全く表示されない」という現象です。発生端末は海外の端末全てのようで、主にNexusOne, Droidで発生すると申告が来ていました。
(バグ修正にご協力頂いたGoogle Chris Pruettさん、kerieruさん、ありがとうございました。m(_ _)m)

まったく同じプログラムなのにどうしてこういうことが起きたかというと、OpenGLESの仕様が違うかららしいです。具体的には何が違うかというと、「2の累乗以外のテクスチャをサポートしているかどうか?」です。日本用の端末のDesireとXperiaはてきとうなサイズの画像ファイルを読み込んでも簡単にOpenGLのテクスチャとして使用できますが、海外の携帯は「2の累乗サイズ」でないと全く表示できません。

また、最後に悩まされたのが下記の関数です。これは海外の端末では全く機能しませんでした。


gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, tex.w, tex.h, 0, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, null);
gl.glTexSubImage2D(GL10.GL_TEXTURE_2D, 0, 0, 0, tex.w, tex.h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, bb);


どうもこの関数は引数にサイズを指定できるようで、こういう関数を使用してもいけないみたいです。うまくいったのは下記の関数をつかって2の累乗サイズの画像ファイルを読み込んだときだけでした。


GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);


この問題は実機テストがかなり大変なので、横着せずに2の累乗でテクスチャを用意するような実装を最初からした方が良さそうです。

2010年5月29日土曜日

Google Android marketへの登録準備




2ヶ月近くかけて開発していたゲームがほぼ完成したので公式サイトをオープンしました。もともとはGAEの調査をしようと始めたのですが、Googleで公開されていたAndroidのSDKがとてもよく出来ていたので、ついついゲームを作ってしまいました。
androidのアプリ開発コンテストも8月に開催されるようなので、英語訳してエントリーしてみようかとも思います。

「魔王なんてたおしちゃうから!」



ここまで作った訳ですから、android marketで販売してみようかと思います。アップロードはGoogleのアカウントや開発者としてのアカウント登録が必要のようです。

Android Market デベロッパーコンソール

アプリの登録にはGoogle Checkoutでクレジットカードを登録し、$25払う必要があるようです。アプリの売上げを受け取るには、銀行口座番号をその後登録する必要があります。これには3営業日ぐらいかかるみたいです。Googleから自分の口座に小額振り込まれるらしいので、その金額を銀行担当者に聞いて、GoogleCheckの画面に金額を入力すると、口座の確認とされるようです。面白い確認方法ですね。Googleらしいと言えばGoogleらしいです。

デベロッパーコンソールを読んでいると、コピー防止機能もあるみたいです。これは開発用端末経由での流出を防ぐためでしょうか。どちらにせよ大事なアプリであればOnにした方が良いですね。


コピー防止: コピーが防止されているアプリケーションは、Android Dev Phone では表示できません。コピー防止ツールは、アプリケーション デベロッパーに基本的な保護を提供し、ユーザー間の安易なアプリケーションの海賊版の配布を阻止します。Android Dev Phone はデベロッパーに十分な柔軟性を提供するように設計されています。この携帯電話では、携帯端末ソフトウェアのデベロッパーに、この電話のすべての機能のアクセス権が最大限提供されます。Android オープンソース プロジェクトの変更されたバージョンをインストールすることもできます。アプリケーションの無断コピーを最小限に抑えるため、Android Dev Phone には、コピーが防止されているアプリケーションの配布は行っていません。


今回作ったアプリはもう少し微調整してから販売したいので今日は公開しませんが、アプリをアップロードしたら引き続きどうなったかをレポートしたいと思います。

2010年5月28日金曜日

開発中のRPGの動画 2



かなりパフォーマンスチューニングをしました。
結局ボトルネックだったのはjavaのインスタンス生成コストとテクスチャの読み込みでした。
OpenGLに関しては出来るだけ無駄な描画を避けるのがポイントだと思います。

完成したらソースを含めて記事にまとめてみようかと思います。

2010年4月7日水曜日

Qt4 で 「手抜き」OpenGL入門


前回、UbuntuでOpenGLとQtの環境を作ることを説明した続きです。

まず、OpenGLの一番有名な床井先生の入門サイトの紹介です

GLUTによる「手抜き」OpenGL入門 和歌山大学 システム工学部 デザイン情報学科 床井浩平

このサイトではGLUTを使ったサンプルや説明がされています。OpenGLの説明自体は前述のサイトを参照していただくとして、今回はこのサイトで取り上げられているサンプルを、GLUTではなく、Qt4のQGLWidgetで実装してみます。ソースコードは下記です。


http://svn.xp-dev.com/svn/algos/algos3d/qt4sample/sample02/


コンパイルと実効は下記です

----------------
make
./sample02

----------------

実行するとQtの画面上でキューブが回転します。今回はQGLWidgetとQThreadを使います。
OpenGLのバッファの制御はQGLWidgetを使っています。ただし、これだけだとアニメーション処理ができないので、QThreadクラスを使って連続描画を行っています。

GLUTはWindowsに持っていった時に終了イベントがとれなかったり、UIも日本語対応が甘かったり意外と融通が効かないので、Qtベースでの実装も試してみると良い事があるかもしれません。


MyGLWidget.h
----------------------------

#include "qapplication.h"
#include "qthread.h"
#include "qgl.h"

#ifndef MYGLWIDGET_H_
#define MYGLWIDGET_H_

class MyGLWidget : public QGLWidget, public QThread
{
Q_OBJECT;
public:
MyGLWidget();
protected:
void initializeGL();
void resizeGL(int w, int h);
void paintGL();
void run();
double r;
};

#endif /* MYGLWIDGET_H_ */

MyGLWidget.cpp
----------------------------
#include "MyGLWidget.h"

MyGLWidget::MyGLWidget()
{
QThread::start();
}

void MyGLWidget::initializeGL()
{
glEnable(GL_DEPTH_TEST);
glClearColor( 1.0, 1.0, 1.0, 1.0 );
}

void MyGLWidget::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30.0, (double)w / (double)h, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
}

void MyGLWidget::paintGL()
{
GLdouble vertex[][3] = {
{ 0.0, 0.0, 0.0 }, /* A */
{ 1.0, 0.0, 0.0 }, /* B */
{ 1.0, 1.0, 0.0 }, /* C */
{ 0.0, 1.0, 0.0 }, /* D */
{ 0.0, 0.0, 1.0 }, /* E */
{ 1.0, 0.0, 1.0 }, /* F */
{ 1.0, 1.0, 1.0 }, /* G */
{ 0.0, 1.0, 1.0 } /* H */
};

int face[][4] = {
{ 0, 1, 2, 3 },
{ 1, 5, 6, 2 },
{ 5, 4, 7, 6 },
{ 4, 0, 3, 7 },
{ 4, 5, 1, 0 },
{ 3, 2, 6, 7 }
};
GLdouble color[][3] = {
{ 1.0, 0.0, 0.0 },
{ 0.0, 1.0, 0.0 },
{ 0.0, 0.0, 1.0 },
{ 1.0, 1.0, 0.0 },
{ 1.0, 0.0, 1.0 },
{ 0.0, 1.0, 1.0 }
};

int i,j;

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();
gluLookAt(3.0, 4.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

if(r>360)r=0;
glRotated(r, 0.0, 1.0, 0.0);
glRotated(r+=2, 1.0, 1.0, 0.0);

glBegin(GL_QUADS);
for (j = 0; j < 6; ++j) {
glColor3dv(color[j]);
for (i = 0; i < 4; ++i) {
glVertex3dv(vertex[face[j][i]]);
}
}
glEnd();
}

void MyGLWidget::run()
{
while(1){
QThread::usleep(10000);
update();
}
}

2010年4月4日日曜日

Qt4とQGLWidget


「Qt使って練習がてらオープンソースやってみない?」と誘われたのがきっかけ
でQtを調べてみたのですが、どうもこのQtライブラリはかなり整備されていて驚
きました。
どうやらQtデベロップメントフレームワークス社で開発されたC++用のオープン
ソースのアプリケーションフレームワークのようです。
クロスプラットフォーム対応を目指しているようで、Lunix, Windows, Macの
グラフィックやネットワークAPIの差を吸収してくれそうな期待が持てます。
採用実績としてはWeb ブラウザ OperaやGoogle Earthで使われているようです。

ドキュメントは下記のようです。
http://doc.trolltech.com/4.6/index.html

OpenGL関係もC++で使いやすくラッピングしているようで、デモを見るかかぎり
3Dグラフィック上に2DのGUIも載せれるようなので、ゲームの開発もなかなか
やりやすいのではないでしょうか。

http://doc.trolltech.com/4.6/demos-boxes.html


OpenGLの実装は下記のWidgetを使いつつOpenGLのAPIを組み合わせて描画するようです。
QGLWidget Class Reference:
http://doc.trolltech.com/4.6/qglwidget.html



ブラウザではちょっと厳しいアプリ開発をやるときはなかなか良さそうです。

UbuntuでQt4 + OpenGL

UbuntuにQt4ベースのOpenGL開発ライブラリを追加する。

------------------------------------------------
sudo apt-get install qt4-qmake
sudo apt-get install libqglviewer-qt4-dev
------------------------------------------------

開発ライブラリが入ったのでプロジェクトフォルダを作りそこにとりあえず
簡単な画面を出すプログラムを配置する。

------------------------------------------------
mkdir sample
cd sample
------------------------------------------------

sampleディレクトリにmain.cppというファイルを配置する。


------------------------------------------------

#include "qapplication.h"
#include "qgl.h"

int main(int argc, char *argv[])
{
QApplication window(argc, argv);
QGLWidget *mainwindow = new QGLWidget;
window.setActiveWindow(mainwindow);
mainwindow->show();
return window.exec();
}

------------------------------------------------

このmain.cppを配置した状態でqmakeを実行すると、このプログラムを認識したうえで
プロジェクトの雛形が作成される。


------------------------------------------------
qmake-qt4 -project
------------------------------------------------

出来上がったsample.proにOpenGLオプションを追記する

------------------------------------------------
QT += opengl
------------------------------------------------

下記のコマンドでMakefileを生成する

------------------------------------------------
qmake-qt4
------------------------------------------------

下記コマンドでコンパイルができる。

------------------------------------------------
make
------------------------------------------------

./sampleを実行すると真っ黒なだけのWindowsが出れば下準備は完了。

まとまったサンプルはこちら
http://svn.xp-dev.com/svn/algos/algos3d/qt4sample/sample01/