Android Game Develop C++ #003

AndroidゲームアプリをC++で作るシリーズのパート3です。

今回はシェーダー(GLSL)を使った画像の色を変更するプログラムです。

GLSL シェーダー部分のコード

// Vertex shader, you'd typically load this from assets
static const char *vertex = R"vertex(#version 300 es
in vec4 inColor;
in vec3 inPosition;
in vec2 inUV;

out vec4 fragColor;
out vec2 fragUV;

uniform mat4 uProjection;

void main() {
    fragUV = inUV;
    fragColor = inColor;
    gl_Position = uProjection * vec4(inPosition, 1.0);
}
)vertex";

// Fragment shader, you'd typically load this from assets
static const char *fragment = R"fragment(#version 300 es
precision mediump float;

in vec4 fragColor;
in vec2 fragUV;

uniform sampler2D uTexture;

out vec4 outColor;

void main() {
    outColor = texture(uTexture, fragUV) * fragColor;
}
)fragment";

RendererクラスのCreateModel関数にColor構造体の変数を作成するところ

void Renderer::createModels() {
    std::vector <Color> colors = {
            Color(Vector4{1.0, 0.0, 0.0, 1.0}), // 0
            Color(Vector4{1.0, 0.0, 0.0, 1.0}), // 1
            Color(Vector4{1.0, 0.0, 0.0, 1.0}), // 2
            Color(Vector4{1.0, 0.0, 0.0, 1.0}) // 3
    };

    std::vector <Vertex> vertices = {
            Vertex(Vector3{1, 1, 0}, Vector2{0, 0}), // 0
            Vertex(Vector3{-1, 1, 0}, Vector2{1, 0}), // 1
            Vertex(Vector3{-1, -1, 0}, Vector2{1, 1}), // 2
            Vertex(Vector3{1, -1, 0}, Vector2{0, 1}) // 3
    };
    std::vector <Index> indices = {
            0, 1, 2, 0, 2, 3
    };

    // loads an image and assigns it to the square.
    //
    // Note: there is no texture management in this sample, so if you reuse an image be careful not
    // to load it repeatedly. Since you get a shared_ptr you can safely reuse it in many models.
    auto assetManager = app_->activity->assetManager;
    auto spAndroidRobotTexture = TextureAsset::loadAsset(assetManager, "android_robot.png");

    // Create a model and put it in the back of the render list.
    models_.emplace_back(colors, vertices, indices, spAndroidRobotTexture);
    pScene_ = new Scene1(assetManager);
}

ShaderクラスのdrawModel関数にColorを追加したところ

void Shader::drawModel(const Model &model) const {
    glVertexAttribPointer(
            color_, // attrib
            4, // elements
            GL_FLOAT, // of type float
            GL_FALSE, // don't normalize
            sizeof(Color), // stride is Vertex bytes
            model.getColorData() // pull from the start of the vertex data
    );
    glEnableVertexAttribArray(color_);

    // The position attribute is 3 floats
    glVertexAttribPointer(
            position_, // attrib
            3, // elements
            GL_FLOAT, // of type float
            GL_FALSE, // don't normalize
            sizeof(Vertex), // stride is Vertex bytes
            model.getVertexData() // pull from the start of the vertex data
    );
    glEnableVertexAttribArray(position_);

    // The uv attribute is 2 floats
    glVertexAttribPointer(
            uv_, // attrib
            2, // elements
            GL_FLOAT, // of type float
            GL_FALSE, // don't normalize
            sizeof(Vertex), // stride is Vertex bytes
            ((uint8_t *) model.getVertexData()) + sizeof(Vector3) // offset Vector3 from the start
    );
    glEnableVertexAttribArray(uv_);

    // Setup the texture
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, model.getTexture().getTextureID());

    // Draw as indexed triangles
    glDrawElements(GL_TRIANGLES, model.getIndexCount(), GL_UNSIGNED_SHORT, model.getIndexData());

    glDisableVertexAttribArray(uv_);
    glDisableVertexAttribArray(position_);
    glDisableVertexAttribArray(color_);
}

Vector4構造体を作りColor構造体も作ってModelクラスにColorを追加したところ

union Vector4 {
    struct {
        float r, g, b, a;
    };
    float idx[4];
};

union Vector3 {
    struct {
        float x, y, z;
    };
    float idx[3];
};

union Vector2 {
    struct {
        float x, y;
    };
    struct {
        float u, v;
    };
    float idx[2];
};

struct Color {
    constexpr Color(const Vector4 &inColor) : color(inColor) {}
    Vector4 color;
};

struct Vertex {
    constexpr Vertex(const Vector3 &inPosition, const Vector2 &inUV) : position(inPosition),
                                                                       uv(inUV) {}

    Vector3 position;
    Vector2 uv;
};

typedef uint16_t Index;

class Model {
public:
    inline Model(
            std::vector <Color> colors,
            std::vector <Vertex> vertices,
            std::vector <Index> indices,
            std::shared_ptr <TextureAsset> spTexture)
            : colors_(std::move(colors)),
              vertices_(std::move(vertices)),
              indices_(std::move(indices)),
              spTexture_(std::move(spTexture)) {}


    inline const Color *getColorData() const {
        return colors_.data();
    }

    inline const Vertex *getVertexData() const {
        return vertices_.data();
    }

    inline const size_t getIndexCount() const {
        return indices_.size();
    }

    inline const Index *getIndexData() const {
        return indices_.data();
    }

    inline const TextureAsset &getTexture() const {
        return *spTexture_;
    }

private:
    std::vector <Color> colors_;
    std::vector <Vertex> vertices_;
    std::vector <Index> indices_;
    std::shared_ptr <TextureAsset> spTexture_;
};

シェーダーを赤に設定して実行した結果が下の画像です

まとめ

今回はシェーダー(GLSL)を使った画像の色を変更するプログラムでした。

これが出来るようになると、ゲームプログラムの大体のことが出来るようになると思います。そのぐらい重要な部分です。

では、次のパート4で会いましょう!


投稿日

カテゴリー:

投稿者:

タグ:

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です