OpenGL.Shader:志兄はあなたにフィルターの生放送クライアント(5)フィルターの紹介を書くことを教えます:コントラスト、露出、モザイク
11982 ワード
OpenGL.Shader:志兄はあなたにフィルターを書いてクライアントを生中継することを教えます(5)
前章では、nv 21ストリームをレンダリングするときにフィルタのシームレスな切り替えを行う方法について説明しました.この章の内容は前章に続き、コントラスト、露光、モザイクの3つのフィルタの特効を紹介し、フィルタ効果を動的に調整する方法について説明します.くだらないことは言わないで、show the code!
フィルター1:コントラスト
頂点シェーダはベースクラスGpuBaseFilterを使用します.NO_FILTER_VERTEX_SHADER、1波のメタシェーダを分析して、コントラストの原理を発見するのは難しくありません:
textureColor.rgb−vec 3(0.5)は二分整列に用いられ、量子化と理解される.contrastはコントラスト因子である.コントラストを乗算して、異なる色の値のレベル範囲を拡大します.(経験範囲は0~4に抑える)
明らかにこのcontrastは動的に調整できるので、前章の内容の設計方法を思い出して、GpuFilterRenderでsetAdjustEffect(float percent)を追跡しても、renderOnDrawで呼び出されていることを発見するのは難しくありません.一部のコードは以下の通りです.
トレースを続けると、ActivityによってSeekbarが呼び出され、CfeSchedulerが呼び出されることがわかります.adjustFilterValue(value,max)は、最後にコントラスト係数contrastを動的に調整し、以下の効果を得た.
フィルタ2:露出(白黒反転)
頂点シェーダはベースクラスGpuBaseFilterのままです.NO_FILTER_VERTEX_SHADER、1波のメタシェーダを分析して、露光の原理を発見するのは難しくありません:
実は反逆ですね.しかもダイナミック調整は不要、so easy(個_個)
前の効果図の意味:
フィルター3:モザイク
最后の1つも最も面白い1つのフィルターの効果で、各位の古い运転手は最も嫌いな1つかもしれません(斜め目笑.jpg)
内容が少し多いので、一緒に分析してみましょう.
分析が終わったら、効果図を見てみましょう.
プロジェクトのアドレス:https://github.com/MrZhaozhirong/NativeCppAppshaderセットはsrcmaincppgpufilterfilterに配置
前章では、nv 21ストリームをレンダリングするときにフィルタのシームレスな切り替えを行う方法について説明しました.この章の内容は前章に続き、コントラスト、露光、モザイクの3つのフィルタの特効を紹介し、フィルタ効果を動的に調整する方法について説明します.くだらないことは言わないで、show the code!
フィルター1:コントラスト
#include "GpuBaseFilter.hpp"
/**
* 。
* 0.0 4.0 , 1.0
*/
class GpuContrastFilter : public GpuBaseFilter {
public:
int getTypeId() { return FILTER_TYPE_CONTRAST; }
GpuContrastFilter()
{
CONTRAST_FRAGMENT_SHADER ="precision mediump float;
\
varying highp vec2 textureCoordinate;
\
uniform sampler2D SamplerRGB;
\
uniform sampler2D SamplerY;
\
uniform sampler2D SamplerU;
\
uniform sampler2D SamplerV;
\
uniform lowp float contrast;
\
mat3 colorConversionMatrix = mat3(
\
1.0, 1.0, 1.0,
\
0.0, -0.39465, 2.03211,
\
1.13983, -0.58060, 0.0);
\
vec3 yuv2rgb(vec2 pos)
\
{
\
vec3 yuv;
\
yuv.x = texture2D(SamplerY, pos).r;
\
yuv.y = texture2D(SamplerU, pos).r - 0.5;
\
yuv.z = texture2D(SamplerV, pos).r - 0.5;
\
return colorConversionMatrix * yuv;
\
}
\
void main()
\
{
\
vec4 textureColor = vec4(yuv2rgb(textureCoordinate), 1.0);
\
gl_FragColor = vec4((contrast*(textureColor.rgb - vec3(0.5)) + vec3(0.5)), textureColor.w);
\
}";
}
~GpuContrastFilter() {
if(!CONTRAST_FRAGMENT_SHADER.empty()) CONTRAST_FRAGMENT_SHADER.clear();
}
void init() {
GpuBaseFilter::init(NO_FILTER_VERTEX_SHADER.c_str(), CONTRAST_FRAGMENT_SHADER.c_str());
mContrastLocation = glGetUniformLocation(mGLProgId, "contrast");
mContrastValue = 1.0f;
}
void setAdjustEffect(float percent) {
mContrastValue = percent * 4.0f;
} // ( 0~4)
void onDraw(GLuint SamplerY_texId, GLuint SamplerU_texId, GLuint SamplerV_texId,
void* positionCords, void* textureCords)
{ // ...}
private:
std::string CONTRAST_FRAGMENT_SHADER;
GLint mContrastLocation;
float mContrastValue;
};
頂点シェーダはベースクラスGpuBaseFilterを使用します.NO_FILTER_VERTEX_SHADER、1波のメタシェーダを分析して、コントラストの原理を発見するのは難しくありません:
gl_FragColor = vec4((contrast*(textureColor.rgb - vec3(0.5)) + vec3(0.5)), textureColor.w);
textureColor.rgb−vec 3(0.5)は二分整列に用いられ、量子化と理解される.contrastはコントラスト因子である.コントラストを乗算して、異なる色の値のレベル範囲を拡大します.(経験範囲は0~4に抑える)
明らかにこのcontrastは動的に調整できるので、前章の内容の設計方法を思い出して、GpuFilterRenderでsetAdjustEffect(float percent)を追跡しても、renderOnDrawで呼び出されていることを発見するのは難しくありません.一部のコードは以下の通りです.
void GpuFilterRender::renderOnDraw(double elpasedInMilliSec)
{
//
mWindowSurface->makeCurrent();
yTextureId = updateTexture(dst_y, yTextureId, mFrameWidth, mFrameHeight);
uTextureId = updateTexture(dst_u, uTextureId, mFrameWidth/2, mFrameHeight/2);
vTextureId = updateTexture(dst_v, vTextureId, mFrameWidth/2, mFrameHeight/2);
// Filter
checkFilterChange();
if( mFilter!=NULL) {
mFilter->setAdjustEffect(mFilterEffectPercent);
mFilter->onDraw(yTextureId, uTextureId, vTextureId, positionCords, textureCords);
}
// ...
}
void GpuFilterRender::adjustFilterValue(int value, int max) {
mFilterEffectPercent = (float)value / (float)max;
//LOGD("GpuFilterRender adjust %f", mFilterEffectPercent);
}
///////////////gpu_filter_jni//////////////////////////////////
JNIEXPORT void JNICALL
Java_org_zzrblog_gpufilter_GpuFilterRender_adjustFilterValue(JNIEnv *env, jobject instance, jint value, jint max) {
if (render == NULL)
render = new GpuFilterRender();
render->adjustFilterValue(value, max);
}
トレースを続けると、ActivityによってSeekbarが呼び出され、CfeSchedulerが呼び出されることがわかります.adjustFilterValue(value,max)は、最後にコントラスト係数contrastを動的に調整し、以下の効果を得た.
フィルタ2:露出(白黒反転)
#include "GpuBaseFilter.hpp"
/**
* 。
*/
class GpuColorInvertFilter : public GpuBaseFilter {
public:
int getTypeId() { return FILTER_TYPE_COLOR_INVERT; }
GpuColorInvertFilter()
{
COLOR_INVERT_FRAGMENT_SHADER="precision mediump float;
\
varying highp vec2 textureCoordinate;
\
uniform sampler2D SamplerRGB;
\
uniform sampler2D SamplerY;
\
uniform sampler2D SamplerU;
\
uniform sampler2D SamplerV;
\
mat3 colorConversionMatrix = mat3(
\
1.0, 1.0, 1.0,
\
0.0, -0.39465, 2.03211,
\
1.13983, -0.58060, 0.0);
\
vec3 yuv2rgb(vec2 pos)
\
{
\
vec3 yuv;
\
yuv.x = texture2D(SamplerY, pos).r;
\
yuv.y = texture2D(SamplerU, pos).r - 0.5;
\
yuv.z = texture2D(SamplerV, pos).r - 0.5;
\
return colorConversionMatrix * yuv;
\
}
\
void main()
\
{
\
vec4 textureColor = vec4(yuv2rgb(textureCoordinate), 1.0);
\
gl_FragColor = vec4((1.0 - textureColor.rgb), textureColor.w);
\
}";
}
~GpuColorInvertFilter() {
if(!COLOR_INVERT_FRAGMENT_SHADER.empty()) COLOR_INVERT_FRAGMENT_SHADER.clear();
}
void init() {
GpuBaseFilter::init(NO_FILTER_VERTEX_SHADER.c_str(), COLOR_INVERT_FRAGMENT_SHADER.c_str());
}
private:
std::string COLOR_INVERT_FRAGMENT_SHADER;
};
頂点シェーダはベースクラスGpuBaseFilterのままです.NO_FILTER_VERTEX_SHADER、1波のメタシェーダを分析して、露光の原理を発見するのは難しくありません:
gl_FragColor = vec4((1.0 - textureColor.rgb), textureColor.w);
実は反逆ですね.しかもダイナミック調整は不要、so easy(個_個)
前の効果図の意味:
フィルター3:モザイク
最后の1つも最も面白い1つのフィルターの効果で、各位の古い运転手は最も嫌いな1つかもしれません(斜め目笑.jpg)
#include "GpuBaseFilter.hpp"
/**
* 。
*/
class GpuPixelationFilter : public GpuBaseFilter {
public:
int getTypeId() { return FILTER_TYPE_PIXELATION; }
GpuPixelationFilter()
{
PIXELATION_FRAGMENT_SHADER="precision highp float;
\
varying highp vec2 textureCoordinate;
\
uniform sampler2D SamplerRGB;
\
uniform sampler2D SamplerY;
\
uniform sampler2D SamplerU;
\
uniform sampler2D SamplerV;
\
mat3 colorConversionMatrix = mat3(
\
1.0, 1.0, 1.0,
\
0.0, -0.39465, 2.03211,
\
1.13983, -0.58060, 0.0);
\
uniform float imageWidthFactor;
\
uniform float imageHeightFactor;
\
uniform float pixel;
\
vec3 yuv2rgb(vec2 pos)
\
{
\
vec3 yuv;
\
yuv.x = texture2D(SamplerY, pos).r;
\
yuv.y = texture2D(SamplerU, pos).r-0.5;
\
yuv.z = texture2D(SamplerV, pos).r-0.5;
\
return colorConversionMatrix * yuv;
\
}
\
void main()
\
{
\
vec2 uv = textureCoordinate.xy;
\
float dx = pixel * imageWidthFactor;
\
float dy = pixel * imageHeightFactor;
\
vec2 coord = vec2(dx*floor(uv.x / dx), dy*floor(uv.y / dy));
\
gl_FragColor = vec4(yuv2rgb(coord), 1.0);
\
}";
}
~GpuPixelationFilter() {
if(!PIXELATION_FRAGMENT_SHADER.empty()) PIXELATION_FRAGMENT_SHADER.clear();
}
void init() {
GpuBaseFilter::init(NO_FILTER_VERTEX_SHADER.c_str(), PIXELATION_FRAGMENT_SHADER.c_str());
mPixelLocation = glGetUniformLocation(mGLProgId, "pixel");
mImageWidthFactorLocation = glGetUniformLocation(mGLProgId, "imageWidthFactor");
mImageHeightFactorLocation = glGetUniformLocation(mGLProgId, "imageHeightFactor");
mPixelValue = 1.0f;
}
void setAdjustEffect(float percent) {
if(percent==0.0f) percent=0.01f;
mPixelValue = percent * 100.0f;
}
void onOutputSizeChanged(int width, int height) {
GpuBaseFilter::onOutputSizeChanged(width, height);
glUniform1f(mImageWidthFactorLocation, 1.0f / width);
glUniform1f(mImageHeightFactorLocation, 1.0f / height);
}
// ...
void onDraw(GLuint SamplerY_texId, GLuint SamplerU_texId, GLuint SamplerV_texId,
void* positionCords, void* textureCords)
{
if (!mIsInitialized)
return;
glUseProgram(mGLProgId);
glUniform1f(mPixelLocation, mPixelValue);
glUniform1f(mImageWidthFactorLocation, 1.0f / mOutputWidth);
glUniform1f(mImageHeightFactorLocation, 1.0f / mOutputHeight);
// ,
}
};
内容が少し多いので、一緒に分析してみましょう.
uniform float imageWidthFactor; // , 1/10
uniform float imageHeightFactor;
uniform float pixel; //
void main()
{
vec2 uv = textureCoordinate.xy; //
float dx = pixel * imageWidthFactor; // ,
float dy = pixel * imageHeightFactor;
// floor(uv.x / dx)“ ”, , 720*1280,widthFacetor=72
// uv.x = 1,pixel = 1, 72*(floor(1/72)) = 0
// uv.x = 2,pixel = 1, 72*(floor(2/72)) = 0
// uv.x = 71,pixel = 1, 72*(floor(71/72)) = 0
// uv.x = 72,pixel = 1, 72*(floor(72/72)) = 72
// , , , 。
vec2 coord = vec2(dx*floor(uv.x / dx), dy*floor(uv.y / dy));
gl_FragColor = vec4(yuv2rgb(coord), 1.0);
}";
分析が終わったら、効果図を見てみましょう.
プロジェクトのアドレス:https://github.com/MrZhaozhirong/NativeCppAppshaderセットはsrcmaincppgpufilterfilterに配置