yoyaのメモ

2011/05/22(Sun) [phpopengl] スクリーンショット(2)

[] スクリーンショット(2)

3D っぽくないという声が多かったので、球を表示してみました。

glMaterialfv(GL_FRONT, GL_DIFFUSE, $color);
glTranslatef($position[0], $position[1], $position[2]);
glutSolidSphere(0.08, 16, 10);

f:id:yoya:20110523021222g:image

見た目面白いのが出来ると楽しい。

PHP なのでコンパイルの煩わしさもないし。

オリジナルは↑これです。

2011/05/19(Thu) [phpopengl] スクリーンショット

[]スクリーンショット

OpenGL for PHP で表示中の画像を落とすルーチンをまとめました。

で、

↑ これに画像保存のルーチンを挟んで、更に GIF アニメにしてみました。

f:id:yoya:20110519203414g:image

(3D っぽくないけど、一応 OpenGLAPI で描画したものです)


直接見ると背景が青いのに glReadPixels で画像に落とすと赤くなる。何か足りないかしら。

glutGet

画像に落とすのに、開いてるウィンドウのサイズを調べる必要がありますが、 glutGet を読んでみたら NULL しか返しませんでした。動くようにしました。

Get 系はあまり動かないかも。

とりあえず世の中の色んなサンプルを移植してみて、動かないと気づいた物から対応していきますが、もし、動かしてほしい関数がある人がいたら連絡下さい。

優先します。

[]glReadPixels の binding 変更

phpopengl の glReadPixels APIPHP っぽくしました。red, green, blue [,alpha] の hash のリストを返します。メモリ沢山使いますけど。

f:id:yoya:20110520013126g:image

色を替えてみました。

やっぱり 3D っぽくないけど地面に着地してる所に気付いてもらえるといいな。

2011/01/12(Wed) [phpopengl] glReadPixels はオフスクリーンで動かない?

[]glReadPixels はオフスクリーンで動かない?

OpenGL をバックエンドで使う為にディスプレイ表示せずに画像ファイルだけ生成しようと、glReadPixels の PHP バインディングを実装したのですが、どうやら、ディスプレイ表示抜きで使うのは無理そう。

glReadPixelsはVRAMに書き込まれたデータをメモリ上へ取得
するAPIです.それゆえ,VRAMに書き込まれないと各ピクセルの
データを取得できないので,オフスクリーンバッファを用いて
描画するときにはglReadPixelsは使用できません.

何かの環境(多分、MacOSX)で display の callback を外したらウィンドウを開かず glReadPixels を使えた記憶があるのですが、

Debian Linux で試すとウィンドウが表示されます。

OS 毎にオフスクリーンで画像生成する方法があるようですが、

とりあえずウィンドウを開かずに描画出来れば我慢できそうなので、

そこから攻めてみようかと思います。

(パフォーマンスの観点でもメリットがあるかもしれないし)

続き

2010/12/08(Wed) [phpopengl] glReadPixels GL_RGBAで動きました

[] glReadPixels GL_RGBAで動きました

こんな感じで動きました。

v_pixels_len = (int)Z_LVAL_P(width) * Z_LVAL_P(height)* sizeof(long);
v_pixels = emalloc(v_pixels_len);
glReadPixels((int)Z_LVAL_P(x),(int)Z_LVAL_P(y),(int)Z_LVAL_P(width),(int)Z_LVAL_P(height),(int)Z_LVAL_P(format),(int)Z_LVAL_P(type),v_pixels);
long_array_to_php_array(v_pixels, v_pixels_len, pixels);
  • 第7引数を参照渡しとして指定する
  • 第7引数を元にバッファを作るのをやめて、渡されたサイズを元に emalloc する
  • (C側の)glReadPixel の結果を第7引数に埋め込む。

glReadPixelsの使い方 (暫定)

$pixels = array(); // 空配列を渡す
glReadPixels(0, 0, $width, $height, GL_RGBA, GL_UNSIGNED_BYTE, $pixels);
  • 画像ファイル保存

GD で画像を生成する為にピクセルデータを構築するのは、signed long を RGBA として解釈するので、ちょっと面倒だけど。

以下ので出来ました。

    // GD でキャンバスを作る
$im = imagecreatetruecolor($width, $height);
$i = 0;
// pixels 配列を R, G, B, A(無視) の順で解釈してイメージを作成
for ($y = $height ; $y >= 0; $y--) {
    for ($x = 0; $x < $width ; $x++) {
        $rgb = $pixels[$i];
        if ($rgb < 0) {
            $rgb += 4294967296; // integer => float
        }
        $blue  = $rgb % 0x100 ; $rgb /= 0x100;
        $green = $rgb % 0x100 ; $rgb /= 0x100;
        $red   = $rgb % 0x100 ; $rgb /= 0x100;
        $color = imagecolorallocate($im, $red, $green, $blue);
        imagesetpixel($im, $x, $y, $color); // pixel を埋めていく
        $i ++;
    }
}
imagepng($im, "output.png"); // PNG ファイルとして保存!!!

PHP の integer は 0x80000000 以上の正の値を扱えないので、

その場合は float に格上げして、ビット演算をあきらめて mod で処理してます。(unpack 使えって話ですね。すみません)

課題

PHP で無理やりバイト処理は心臓に悪いので、

array(array('red'=>..., 'green'=>..., 'blue'=>..., 'alpha'=>...))

の形式で返した方が良いと思いました。

メモリ使いすぎる問題は、それ以前に(パフォーマンス的に) PHP

こんなループ処理する事自体間違えてるので、extension の C 側の

ルーチンで全部処理するのが正しいですね。

yglImagePNG($filename); みたいにバッファ吸出し&画像出力を

C 言語側で閉じて処理する新規 function を作ってみよう。

2010/12/07(Tue) [phpopengl] glReadPixels調査 (2)

[] glReadPixels調査 (2)

glReadPixels に渡すバッファが足りないのは

使い方を間違えていたからでした。

あらかじめ必要な要素数の array を用意しないと seg.fault

するのは、前回説明した通りですが、

$pixels = array($width * $height);

で実験していて、これは間違いで、

$pixels = array_fill(0, $width * $height, 0);

です。

一応、これで落ちなくはなったけど。。。

値を受け取れない

PHP_FUNCTION(glreadpixels)
{
        <略>
    v_pixels = php_array_to_long_array(pixels);
    glReadPixels((int)Z_LVAL_P(x),(int)Z_LVAL_P(y),(int)Z_LVAL_P(width),(int)Z_LVAL_P(height),(int)Z_LVAL_P(format),(int)Z_LVAL_P(type),v_pixels);
}

なので、何も値が返ってきません。

実験

まず、引数を参照渡しにします。

ZEND_BEGIN_ARG_INFO_EX(force_ref_seventh_arg, 1, 0, 7)
    ZEND_ARG_INFO(0, arg1)
    ZEND_ARG_INFO(0, arg2)
    ZEND_ARG_INFO(0, arg3)
    ZEND_ARG_INFO(0, arg4)
    ZEND_ARG_INFO(0, arg5)
    ZEND_ARG_INFO(0, arg6)
    ZEND_ARG_INFO(1, arg7)
ZEND_END_ARG_INFO()
function_entry opengl_functions[] = {
    <略>
    PHP_FE(glreadpixels,force_ref_seventh_arg)

PHP_FUNCTION(glreadpixels) の 最後に、

        long_array_to_php_array(v_pixels, (int)Z_LVAL_P(width) * Z_LVAL_P(height)* 4 /*U_LONG size*/, pixels);
}

の一行を追加してみたけど、何も変わる様子無いです。

long_array_to_php_array の処理は予想通りだったので、

Zend API の使い方に何か問題があるのかも。

そもそも論

そもそもこういう配列の使い方すると、メモリがすぐ溢れるので、

PHP の array で値を受け取るのは実用的じゃないよね。

結局のところ、PHP カンファレンスで使った glReadPixels_yoya が現実的な気がします。