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で会いましょう!
コメントを残す