8月 08

おはようございます、Selphyです。
前回のエントリーでは、テクスチャーを使った簡単なサンプルを説明しました。

最後のサンプルでは、カルーセルの基本形を作ります。

RS内で使用している型やメソッドなどについては、RenderScriptのReference に記載されているので、そちらをご覧ください。

完成形のスクリーンショット

完成したアプリのスクリーンショット

ファイル構成

今までは RSHelloWorld を使っていましたが、新しいプロジェクトを作成します。

完成したアプリのスクリーンショット

コード

MainActivity.javaMainTextureView.javamain.xmlは前回のプロジェクトと大きく変わっていません。
プロジェクトが変わったことによるパッケージ名の修正程度なので省きます。

  • SampleScript.java
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    protected SampleScript(RenderScriptGL rs, Resources res) {
        script = new ScriptC_SampleScript(rs, res, R.raw.samplescript);
       
        // 構造体の初期化
        //  構造体内部にrs_allocationがあるので、そこにテクスチャーを設定する。
        ScriptField_RS_Droid droids = new ScriptField_RS_Droid(rs, MODEL_COUNT, Allocation.USAGE_GRAPHICS_TEXTURE);
        for (int i=0; i<MODEL_COUNT; i++) {
            ScriptField_RS_Droid.Item droid = new ScriptField_RS_Droid.Item();
            droid.texture = Allocation.createFromBitmap(rs, BitmapFactory.decodeResource(res, textureIds[i]));
            droids.set(droid, i, true);
        }
        script.bind_gDroids(droids);
       
        // ProgramStore
        //  Alpha値を有効にする。
        progStoreBlendAlpha = ProgramStore.BLEND_ALPHA_DEPTH_TEST(rs);
        script.set_gProgStoreBlendAlpha(progStoreBlendAlpha);
       
        // テクスチャー用のFragment
        //  Samplerを設定してテクスチャーのジャギーを目立たなくする。
        ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(rs);
        texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
        progFragmentTexture = texBuilder.create();
        progFragmentTexture.bindSampler(Sampler.CLAMP_LINEAR(rs), 0);
        script.set_gProgFragmentTexture(progFragmentTexture);
       
        // Raster
        //  テクスチャーの表裏を描画する。
        script.set_gCullNone(ProgramRaster.CULL_NONE(rs));
       
        rs.bindRootScript(script);
    }

    Step3で構造体を扱ったので、ここでは復習のためにテクスチャーを構造体で用意しました。
    コード内にコメントもあるので、特に説明はありません。
    また、実際には、タッチイベントを RS に通知するためのメソッドもありますが、いままでのサンプルコードと同じ部分なので省いています。

  • SampleScript.rs
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    int32_t root() {
        rsgClearColor(0.0f, 0.0f, 0.0f, 1.0f);      // RGBA
        rsgClearDepth(1.0f);
       
        // プロジェクション設定
        rs_matrix4x4 proj;
        rsMatrixLoadPerspective(&proj, 30.0f, (float) rsgGetWidth() / (float) rsgGetHeight(), 0.01f, 1000.0f);
        rsgProgramVertexLoadProjectionMatrix(&proj);
       
        rsgBindProgramStore(gProgStoreBlendAlpha);
        rsgBindProgramFragment(gProgFragmentTexture);
       
        // モデル座標の回転を計算
        if (gSwipePoint.x != 0) {
            gRotX += gSwipePoint.x * 0.5f;
            gSwipePoint.xy = 0;
            if (gRotX > 360 || gRotX < -360)
                gRotX %= 360;
        }
       
        // モデル座標
        rs_matrix4x4 matrix;
        rsMatrixLoadIdentity(&matrix);
        rsMatrixLoadTranslate(&matrix, 0, 0, -500);
        rsMatrixRotate(&matrix, 30, 1, 0, 0);
        rsMatrixRotate(&matrix, gRotX, 0, 1, 0);
        rsgProgramVertexLoadModelMatrix(&matrix);
       
        float x, y, z, minX, minY, maxX, maxY;
       
        rsgBindProgramRaster(gCullNone);
       
        // テクスチャー描画
        for (int32_t i=0; i<MODEL_COUNT; i++) {
            RS_Droid_t droid = gDroids[i];
            float rad = VALUE_DOUBLE_PI * (float) i / (float) MODEL_COUNT;
            x = 50 * sin(rad);
            y = 0;
            z = 50 * cos(rad);
           
            minX = z * sin(rad - VALUE_DOUBLE_PI) + x * cos(rad - VALUE_DOUBLE_PI) - 25;
            maxX = minX + 50;
            minY = y - 25;
            maxY = minY + 50;
            z = z * cos(rad - VALUE_DOUBLE_PI) - x * sin(rad - VALUE_DOUBLE_PI);
           
            rsgBindTexture(gProgFragmentTexture, 0, droid.texture);
            rsgDrawQuadTexCoords(minX, maxY, z, 0.f, 0.f,
                                 minX, minY, z, 0.f, 1.f,
                                 maxX, minY, z, 1.f, 1.f,
                                 maxX, maxY, z, 1.f, 0.f);  
        }
       
        // 20fps
        return 50;
    }

     プロジェクションでは、3Dモデルが描画される際のパースペクティブに関わる値を設定しています。
    どういうことかというと、3Dモデルをカメラで撮影して、その映像が描画されているとすると、カメラの視野角、アスペクト比、どこまで遠くまで撮影できるかという設定です。
     モデル座標については、 rsgProgramVertexLoadModelMatrix というメソッド名だったのでモデル座標ということにしましたが、このサンプルでは、ワールド座標として扱っています。
    これが何かというと、3Dモデルが描画される空間の座標系だと思ってください。
     最後にテクスチャーを描画するための座標が出てきますが、今回のサンプルでは、個々のテクスチャーをモデルとして扱っているので、テクスチャーの描画座標がモデル座標という感覚で扱っています。
     このあたりの知識は3D描画の基本なので、詳細な説明は省きます。

サンプルでは、モデルが常に同一方向を向き、x軸方向のスワイプにのみ動くようにしました。
2自由度でモデルを動かしたい場合には、クォータニオンによる計算をおすすめします。
常に正面を向かせたい場合、テクスチャーの描画座標を三角関数で計算してください。
また、モデルの動きに慣性を与えるとUXが向上するので試してみてください。

サンプルは Google Code で公開しています。

このエントリーの内容について
クリエイティブ・コモンズ・ライセンス
RSHelloWorld by Selphy, Kiroru Inc. is licensed under a Creative Commons 表示 – 非営利 – 継承 3.0 非移植 License.



Posted by selphy

Comments are closed.

preload preload preload