LoginSignup
8
6

More than 5 years have passed since last update.

libGDXの基礎10 シェーダを設定する

Posted at

libGDXとはWindows、Linux、Mac、Android、iPhone、HTMLに対応したクロスプラットフォームゲームライブラリです。有名なIngressでも利用されています。欧米ではわりとメジャーどころです。

シェーダとは

シェーダとはGPUのリソースを使って描画前に演算をはさめる、フィルタのようなものです。

今回のサンプルはフラグメントシェーダのみ変更してテクスチャの色を強制的に白、αはそのままという処理をしています。

通常何も考えず処理しようと思えば白いバージョンのテクスチャファイルを用意する、テクスチャのロード時にピクセル情報を白に変換して転送するなどが必要になりますが、ここは動的に描画するときに変更しているということです。

ソース

「libGDXの基礎2 ~テクスチャを表示する」と同じソースです。それにシェーダを設定しただけです。実行結果の違いを見てください。


package test.libgdx;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.scenes.scene2d.Action;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.actions.RepeatAction;
import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction;
import com.badlogic.gdx.scenes.scene2d.ui.Image;

public class MainListener9 implements ApplicationListener{

    ShaderProgram shaderProgram;

    SpriteBatch batch;
    Texture texture;

    @Override
    public void create() {
        batch = new SpriteBatch();
        texture = new Texture("enemy.png");

        //シェーダのセットアップ
        {
            String vertex = "attribute vec4 " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" //
                    + "attribute vec4 " + ShaderProgram.COLOR_ATTRIBUTE + ";\n" //
                    + "attribute vec2 " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" //
                    + "uniform mat4 u_projTrans;\n" //
                    + "varying vec4 v_color;\n" //
                    + "varying vec2 v_texCoords;\n" //
                    + "\n" //
                    + "void main()\n" //
                    + "{\n" //
                    + "   v_color = " + ShaderProgram.COLOR_ATTRIBUTE + ";\n" //
                    + "   v_color.a = v_color.a * (256.0/255.0);\n" //
                    + "   v_texCoords = " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" //
                    + "   gl_Position =  u_projTrans * " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" //
                    + "}\n";

            String fragment = "#ifdef GL_ES\n" //
                    + "#define LOWP lowp\n" //
                    + "precision mediump float;\n" //
                    + "#else\n" //
                    + "#define LOWP \n" //
                    + "#endif\n" //
                    + "varying LOWP vec4 v_color;\n" //
                    + "varying vec2 v_texCoords;\n" //
                    + "uniform sampler2D u_texture;\n" //
                    + "void main()\n"//
                    + "{\n" //
                    + "    vec4 c4 = texture2D(u_texture, v_texCoords);\n"
                    + "    gl_FragColor = v_color * vec4(1, 1, 1, c4.a);\n"
                    + "}";
            shaderProgram = new ShaderProgram(vertex, fragment);
        }
    }

    @Override
    public void resize(int w, int h) {
    }

    @Override
    public void render() {
        Gdx.gl.glClearColor(0, 0, 0.2f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);


        batch.begin();

        batch.setShader(shaderProgram);
        batch.draw(texture, 0, 0);
        batch.setShader(null);//デフォルトシェーダに戻す

        batch.end();
    }


    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }

    @Override
    public void dispose() {
    }

    //起動部分
    public static void main(String[] args) {
        new LwjglApplication(new MainListener9());
    }
}

実行

20141109-01.png

解説

ShaderProgram というクラスがシェーダを保持します。コンストラクタにバーテックスシェーダとフラグメントシェーダの文字列、またはファイルを指定することで作成できます。

直にOpenGLを使う場合はこいつのbeginendメソッドを呼び出すことで設定されます。

とはいえ、OpenGLは直には扱うことはあまりありません。アプリ開発時点では高レベルAPIなどを利用しているためです。このサンプルに限らずStageなど高レベルAPIは通常はBatchインターフェースで描画を管理します。

その場合、Batch#setShader()メソッドでShaderProgramインスタンスを渡すことで設定されます。

何もしていない場合はデフォルトシェーダが設定されています。nullを渡すことでデフォルトシェーダに戻せます。

シェーダを切り替えれるのは良いのですが、この単純なシェーダの切り替えを利用する場合、パラメータが一致しないといけません。

SpriteBatchを利用した場合、デフォルトシェーダはSpriteBatch#createDefaultShader ()で生成されます。PolygonSpriteBatchもこのメソッドを呼び出しているため、ここにあるシェーダのコードをコピーするとよいでしょう。

このサンプルのシェーダもバーテックスシェーダはそのまま、フラグメントシェーダもデフォルトシェーダを少しいじっただけのものとなっています。

このパラメータを渡しているのはSpriteBatch#setupMatrices()です。一応見ておくとよいでしょう。現時点でのバージョンのソースを載せておきます。

private void setupMatrices () {
    combinedMatrix.set(projectionMatrix).mul(transformMatrix);
    if (customShader != null) {
        customShader.setUniformMatrix("u_projTrans", combinedMatrix);
        customShader.setUniformi("u_texture", 0);
    } else {
        shader.setUniformMatrix("u_projTrans", combinedMatrix);
        shader.setUniformi("u_texture", 0);
    }
}

この辺を使う場合はソースが短いのでsetShader()も見たほうが良いです。ここでsetupMatrices()を呼んでいるのがわかります。

@Override
public void setShader (ShaderProgram shader) {
    if (drawing) {
        flush();
        if (customShader != null)
            customShader.end();
        else
            this.shader.end();
    }
    customShader = shader;
    if (drawing) {
        if (customShader != null)
            customShader.begin();
        else
            this.shader.begin();
        setupMatrices();
    }
}

何がどのタイミングで呼ばれているか、利用する場合は軽く把握しておいてください。

というわけで、シェーダをガリガリ使わないといけない用途ではBatch#setShaderを使わないほうがよい(というかつかえない)です。フィールド変数のshaderprivateですので、カスタマイズができません。

出来るだけSpriteBatchをそのまま使いたい、そういう場合はソースをまるごとコピーしたうえで別クラスとして作成するのが良いと思われます。Scen2Dで利用したい場合はStageのコンストラクタにBatchを指定することが可能ですのでそこで設定してください。

8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6