I. 概要
今日も OpenGLES を学び続けましょう
今日は、以前のブログ投稿「OpenGLES: GLSurfaceView による Android カメラ プレビューの実装」に基づいて 、OpenGLES を使用してカメラの4 正方形グリッド フィルターと9 正方形グリッド フィルターを実装します。
2. 四方格子
まず、いくつかの用語を定義します。
- 前回のブログ投稿で実装された通常のカメラ プレビューは「Big Palace Grid」と呼ばれています。
- 今回実装する必要があるのは「4マスグリッド」+「フィルター」です。
- 四方格子のそれぞれの小さな正方形は「リトル・パレス・グリッド」と呼ばれます。
- 小さなグリッド領域内の点は次のように記録されます: (min_x, min_y)
- 小さな宮殿のグリッドの原点は次のように記録されます: (min_origin_x, min_origin_y)
- 大きなグリッド領域内の点は次のように記録されます: (max_x, max_y)
大きな宮殿グリッドの原点は (0,0) であり、特別なマークは必要ありません
まず4 つの正方形のグリッドを実装する方法を見て、次にフィルターを追加する方法を見てみましょう。
小さなグリッド(min_x, min_y) は、大きなグリッド(max_x, max_y)の配下にあり、(max_x, max_y) の1/4 の部分領域
にすぎません。, min_y) を (max_x, max_y) に対応させる
図から簡単にわかります。
1.大きなグリッドは、 x 軸と y 軸 (min_origin_x, min_origin_y) に沿って反対方向に (0,, 0) まで移動する小さなグリッドと同等であり、長さと幅を 2 倍することも考慮できます
。逆方向:
2.小さなグリッドこれは、大きな宮殿グリッドの長さと幅を 2 で割って、x 軸と y 軸に沿って正の方向に (min_origin_x, min_origin_y) まで移動することに相当します。
「右上隅の小さな宮殿のグリッド」を例として取り上げます。
1.大きなグリッドは、右上隅の小さなグリッドをx 軸と y 軸に沿って反対方向に (0.5, 0.5) から (0, 0) に移動し、長さと幅を 2 倍に拡大することと同じです。 。
または
2.右上隅の小さなグリッドは、大きなグリッドの長さと幅を 1/2 に縮小し、x 軸と y 軸の正の方向に沿って (0.5, 0.5) まで移動します。
私たちが行う必要があるのは、テクスチャ サンプリング座標内の一部の座標(小さなグリッド) をすべての座標(大きなグリッド)にマッピングする方法です。
したがって、私たちが求めたいのは上記の「1.」の対応関係であり、その逆の「2.」はプロセスをより鮮明に理解するためのものです。
この方法によれば、どんなに複雑なグリッド分割であっても、小さなグリッドが「大きなグリッド」にどのように重なるかを平行移動や拡大縮小によって推測することができれば、対応関係を見つけることができます。
したがって、「小さな宮殿のグリッド」を「大きな宮殿のグリッド」に変換する式は次のようになります。
max_x = (min_x - min_origin_x) *2
max_y = (min_y - min_origin_y) *2
(min_origin_x, min_origin_y) は、実現する「いくつかのグリッド」のうちの「いくつか」によってさらに定式化できますが、これは難しいことではありませんので、推定は行いません。
3. フィルター
フラグメント シェーダーで、テクスチャ サンプラーとテクスチャ座標からテクスチャを作成します
作成されたテクスチャは、実際には、組み込み変数に割り当てられたカラー値のベクトルです。
これが、テクスチャ サンプラーとテクスチャ座標を使用する必要がある理由です。これは、テクスチャ サンプラーがテクスチャ座標に基づいてこの座標点のカラー値を取得するのと同じです。すべてのカラー値がカラフルな画像を形成します。これがテクスチャです。。
カラー値のRGB コンポーネントは、カラー ベクトルを通じて取得できます。
次に、色に対してさまざまな「フィルター」効果を作成できます。
以下は白黒フィルターのコードです。
//黑白
void blackAndWhite(inout vec4 color){
float threshold = 0.5;
float mean = (color.r + color.g + color.b) / 3.0;
color.r = color.g = color.b = mean >= threshold ? 1.0 : 0.0;
}
コード リテラルを通じて直接理解できます。
テクスチャ座標点によってサンプリングされたカラー値の 3 つのコンポーネント (r、g、b) の平均値が >0.5 の場合は白の値が割り当てられ、それ以外の場合は黒が割り当てられます。
以下は、 4 正方形グリッドの白黒、グレースケール、反転、および元の画像のリアルタイム フィルター シェーダー コードの最終実装です。
わかりやすい言葉なので、いちいち説明はしません。
#version 300 es
#extension GL_OES_EGL_image_external_essl3 : require
precision mediump float;
in vec2 texCoord;//纹理坐标,图片当中的坐标点
out vec4 outColor;
uniform samplerExternalOES s_texture;//图片,采样器
//黑白
void blackAndWhite(inout vec4 color){
float threshold = 0.5;
float mean = (color.r + color.g + color.b) / 3.0;
color.r = color.g = color.b = mean >= threshold ? 1.0 : 0.0;
}
//灰度
void grey(inout vec4 color){
float weightMean = color.r * 0.3 + color.g * 0.59 + color.b * 0.11;
color.r = color.g = color.b = weightMean;
}
//反向
void reverse(inout vec4 color){
color.r = 1.0 - color.r;
color.g = 1.0 - color.g;
color.b = 1.0 - color.b;
}
void main(){
float x = texCoord.x;
float y = texCoord.y;
//四宫格滤镜
if (x <= 0.5 && y <= 0.5){
x = x * 2.0;
y = y * 2.0;
outColor = texture(s_texture, vec2(x, y));
reverse(outColor);
} else if (x <= 0.5 && y >= 0.5){
x = x * 2.0;
y = (y-0.5) * 2.0;
outColor = texture(s_texture, vec2(x, y));
blackAndWhite(outColor);
} else if (x>0.5 && y > 0.5){
x = (x-0.5) * 2.0;
y = (y-0.5) * 2.0;
outColor = texture(s_texture, vec2(x, y));
grey(outColor);
} else if (x>0.5 && y < 0.5){
x = (x-0.5) * 2.0;
y = y * 2.0;
outColor = texture(s_texture, vec2(x, y));
}
}
実現効果:
4. 9マスグリッドフィルター
これまでブログを読んで自分で 4 マス グリッド フィルターを実装した場合、9 マス グリッド フィルターは当然のことです。
9マスグリッドのサンプルコードでは、1つずつ実装を計算するのではなく、xとyの範囲を等分して実装しました。
そのため、フィルター効果をいちいち追加するのではなく、九公歌の実現に重点を置きました。
前回の記事で述べたように、小さいグリッドと大きいグリッドの対応が分かれば、 「グリッドが何個」という「数」に基づいてシェーダーコードをさらに合理化し、ループステートメントを使用してグリッドを分割することができます。 。
コードの実装は単なる形式にすぎず、一度原理を完全に理解すると、そこから逸脱することはできません。
以下は Jiugongge シェーダー コードです。
#version 300 es
#extension GL_OES_EGL_image_external_essl3 : require
precision mediump float;
in vec2 texCoord;//纹理坐标,图片当中的坐标点
out vec4 outColor;
uniform samplerExternalOES s_texture;//图片,采样器
void main(){
float x = texCoord.x;
float y = texCoord.y;
//九宫格滤镜
float x = texCoord.x;
float y = texCoord.y;
if (x < 1.0 / 3.0) {
x = x * 3.0;
} else if (x < 2.0 / 3.0) {
x = (x - 1.0 / 3.0) * 3.0;
} else {
x = (x - 2.0 / 3.0) * 3.0;
}
if (y <= 1.0 / 3.0) {
y = y * 3.0;
} else if (y < 2.0 / 3.0) {
y = (y - 1.0 / 3.0) * 3.0;
} else {
y = (y - 2.0 / 3.0) * 3.0;
}
outColor = texture(s_texture, vec2(x, y));
}
実現効果: