SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

スマホアプリ開発の最新トレンド! ぜったい外せない位置情報活用術

OpenGLを使った地図描画エンジンの作り方(3)

スマホアプリ開発の最新トレンド! ぜったい外せない位置情報活用術 番外編

色の変更

 前回までのサンプルでは、北海道のポリライン情報に対して色情報を固定の状態で描画を行いました。オーソドックスな方法の場合、ポリラインなどに対して色情報を与えるには、頂点ごとに色を指定して描画を行いますが、地図エンジンではスタイルの切り替えを行うため、この方法は採用していません。代わりにシェーダに対して色を指定する方法で行います。変更点は以下になります。

Shader(変更)
public class Shader {

    public static byte ID_MAX = 0;
    public static final byte ID_VuColor= ID_MAX++;
    protected int[] mShaderParameter = null;

    /**
     * 頂点シェーダプログラム
     */
    private final String VSHADER_SOURCE =
            "precision highp float;" +
            "attribute vec4 a_Position;\n" +
            "uniform mat4 u_ViewMatrix;\n" +
            "uniform mat4 u_ProjMatrix;\n" +
            "varying vec4 v_Color;\n" +
            "void main() {\n" +
            "  gl_Position = u_ProjMatrix * u_ViewMatrix * a_Position;\n" +
            "  gl_PointSize = 16.0;" +
            "}\n";
    
    /**
     * フラグメントシェーダプログラム
     */
    private final String FSHADER_SOURCE =
            "precision highp float;" +
            "uniform vec4 u_Color;" +
            "void main() {\n" +
//          "  gl_FragColor = vec4(1.0,1.0,1.0,1.0);\n" +
            "  gl_FragColor = u_Color;\n" +
            "}\n";

    /**
     * コンストラクタ
     */
    public Shader() {
        mShaderParameter = new int[ID_MAX];
    }
    
    /**
     * シェーダープログラムを読み込みコンパイルします。
     * @return
     */
    public int initShaders() {
        int program = createProgram();
        GLES20.glUseProgram(program);
        return program;
    }
    
    /**
     * プログラムオブジェクトを作成します。
     * @return
     */
    public int createProgram() {
        // シェーダオブジェクトを作成する
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, this.VSHADER_SOURCE);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, this.FSHADER_SOURCE);
        
        // プログラムオブジェクトを作成する
        int program = GLES20.glCreateProgram();
        if (program == 0) {
            throw new RuntimeException("failed to create program");
        }
        
        // シェーダオブジェクトを設定する
        GLES20.glAttachShader(program, vertexShader);
        GLES20.glAttachShader(program, fragmentShader);

        // プログラムオブジェクトをリンクする
        GLES20.glLinkProgram(program);

        // リンク結果をチェックする
        int[] linked = new int[1];
        GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linked, 0);
        if (linked[0] != GLES20.GL_TRUE) {
            String error = GLES20.glGetProgramInfoLog(program);
            throw new RuntimeException("failed to link program: " + error);
        }

        // 値のパイプを設定
        setShaderParamaterId(ID_VuColor, GLES20.glGetUniformLocation(program, "u_Color"));

        return program;
    }
    
    /**
     * シェーダを読み込みます。
     * @param type
     * @param source
     * @return
     */
    public int loadShader(int type, String source) {
        // シェーダオブジェクトを作成する
        int shader = GLES20.glCreateShader(type);
        if (shader == 0) {
            throw new RuntimeException("unable to create shader");
        }
        // シェーダのプログラムを設定する
        GLES20.glShaderSource(shader, source);
        // シェーダをコンパイルする
        GLES20.glCompileShader(shader);
        // コンパイル結果を検査する
        int[] compiled = new int[1];
        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
        if (compiled[0] != GLES20.GL_TRUE) {
            String error = GLES20.glGetShaderInfoLog(shader);
            throw new RuntimeException("failed to compile shader: " + error);
        }
        return shader;
    }

    /**
     * パイプ配列を設定する
     * @param id
     * @param value
     */
    public void setShaderParamaterId(byte id, int value) {
        mShaderParameter[id] = value;
    }

    /**
     * 指定のパイプを返す
     * @param id
     * @return
     */
    public int getShaderParameterId(byte id) {
        return mShaderParameter[id];
    }
}

 ※追加・変更箇所は太字にしています。

GL20MyRender(変更)
省略

    @Override
    public void onDrawFrame(GL10 arg0) {
        synchronized (mFrontModelViewMatrix) {
            mFrontModelViewMatrix.copy(mBackModelViewMatrix);
            mFrontProjectionMatrix.copy(mBackProjectionMatrix);
        }
        //行列をセット
        GLES20.glUniformMatrix4fv(muViewMatrix, 1, false, mBackModelViewMatrix.matrix, 0);
        GLES20.glUniformMatrix4fv(muProjMatrix, 1, false, mBackProjectionMatrix.matrix, 0);
        
        //背景色を設定します。
        GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f); //海色を指定
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

        //線を描画
        drawLine(mAPosition,2.0f,0.0f,0.0f,0.0f,1.0f);
    }

    /**
     * ポリラインを描画する
     * @param pos
     */
    public void drawLine(int pos,float width,float r,float g,float b,float a) {
        //線の色を設定します
        GLES20.glUniform4f(mShader.getShaderParameterId(Shader.ID_VuColor),r,g,b,a);

        //線幅を設定します
        GLES20.glLineWidth(width);
        
        //頂点バッファを設定します
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexId);
        GLES20.glVertexAttribPointer(pos, 3, GLES20.GL_FLOAT, false, FSIZE*3, 0);
        
        //描画
        GLES20.glDrawArrays(GLES20.GL_LINE_STRIP, 0, mNumVertices);
    }

省略

 ※追加・変更箇所は太字にしています。

 下記図5のように表示されたでしょうか。見やすいように背景色の変更も行っています。

 フラグメントシェーダ部分の「gl_FragColor」に対して、GL20MyRender内から「GLES20.glUniform4f(mShader.getShaderParameterId(Shader.ID_VuColor),r,g,b,a);」で色を渡しています。前回までのサンプルは、シェーダ内で色を固定にしていましたが、今回のサンプルのようにシェーダに対して外からインプットできるようにすることで、その時々のスタイルにあわせた色に変更が可能です。基礎的な方法ではありますが、いろいろと応用ができますので参考にしてください。

図5(色の変更後)
図5(色の変更後)

 シェーダを応用すると、より効率的な方法で描画することが可能になります。ぜひいろいろトライしてみてください。それでは、つぎにシェーダを少し応用して破線を描いてみたいと思います。

次のページ
破線について

この記事は参考になりましたか?

スマホアプリ開発の最新トレンド! ぜったい外せない位置情報活用術連載記事一覧

もっと読む

この記事の著者

冨川 修広(ヤフー株式会社)(トミカワ ノブヒロ(ヤフーカブシキカイシャ))

2008年ヤフー入社。地図に関するシステム全般の設計・開発を担当。フルリニューアルしたAndroid版Yahoo!地図アプリでは、プロダクトマネージャとしてプロジェクト全体を統括。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/7686 2014/03/26 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー