生活随笔
收集整理的這篇文章主要介紹了
NDK OpenGL ES 3.0 开发(十七):相机基础滤镜
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
該原創文章首發于微信公眾號:字節流動
相機基礎濾鏡
上文中我們通過 ImageReader 獲取到 Camera2 預覽的 YUV 數據,然后利用 OpenGLES 渲染實現相機預覽,這一節將利用 GLSL (OpenGL 著色器語言)基于不同的著色器實現多種基礎濾鏡。
GLSL 一些使用頻率比較高的內建函數
內建函數函數說明
| float distance (genType p0, genType p1) | 計算向量 p0 ,p1 之間的距離 |
| float length (genType x) | 返回向量 x 的長度 |
| genType floor (genType x) | 返回小于等于 x 的最大整數值 |
| genType ceil (genType x) | 返回大于等于 x 的最小整數值 |
| genType mod (genType x, float y) | 返回 x – y * floor (x / y) ,即求模計算 % |
| float dot (genType x, genType y) | 向量 x ,y 之間的點積 |
| vec3 cross (vec3 x, vec3 y) | 向量 x ,y 之間的叉積 |
| genType normalize (genType x) | 標準化向量,返回一個方向和 x 相同但長度為 1 的向量 |
動態網格
動態網格濾鏡主要是將紋理劃分為多個網格,然后根據一個偏移量動態改變網格線的寬度。mod 和 floor 為 GLSL 的內建函數,分別表示取模和取整。需要注意的是,計算之前需要將紋理坐標系轉換為圖片坐標系,保證網格沒有被拉伸。
#version 100
precision highp
float;
varying vec2 v_texcoord
;
uniform lowp sampler2D s_textureY
;
uniform lowp sampler2D s_textureU
;
uniform lowp sampler2D s_textureV
;
uniform
float u_offset
;
uniform vec2 texSize
;
vec4
YuvToRgb(vec2 uv
) {float y
, u
, v
, r
, g
, b
;y
= texture2D(s_textureY
, uv
).r
;u
= texture2D(s_textureU
, uv
).r
;v
= texture2D(s_textureV
, uv
).r
;u
= u
- 0.5;v
= v
- 0.5;r
= y
+ 1.403 * v
;g
= y
- 0.344 * u
- 0.714 * v
;b
= y
+ 1.770 * u
;return vec4(r
, g
, b
, 1.0);
}
void main()
{vec2 imgTexCoord
= v_texcoord
* texSize
;float sideLength
= texSize
.y
/ 6.0;float maxOffset
= 0.15 * sideLength
;float x
= mod(imgTexCoord
.x
, floor(sideLength
));float y
= mod(imgTexCoord
.y
, floor(sideLength
));float offset
= u_offset
* maxOffset
;if(offset
<= x
&& x
<= sideLength
- offset
&& offset
<= y
&& y
<= sideLength
- offset
){gl_FragColor
= YuvToRgb(v_texcoord
);}else{gl_FragColor
= vec4(1.0, 1.0, 1.0, 1.0);}
}
分屏
分屏濾鏡的原理是在多個指定區域內對整個紋理進行下采樣(縮小),從而實現整個圖像在多個區域內多次顯示。
#version 100
precision highp
float;
varying vec2 v_texcoord
;
uniform lowp sampler2D s_textureY
;
uniform lowp sampler2D s_textureU
;
uniform lowp sampler2D s_textureV
;
vec4
YuvToRgb(vec2 uv
) {float y
, u
, v
, r
, g
, b
;y
= texture2D(s_textureY
, uv
).r
;u
= texture2D(s_textureU
, uv
).r
;v
= texture2D(s_textureV
, uv
).r
;u
= u
- 0.5;v
= v
- 0.5;r
= y
+ 1.403 * v
;g
= y
- 0.344 * u
- 0.714 * v
;b
= y
+ 1.770 * u
;return vec4(r
, g
, b
, 1.0);
}
void main()
{vec2 newTexCoord
= v_texcoord
;if(newTexCoord
.x
< 0.5){newTexCoord
.x
= newTexCoord
.x
* 2.0;}else{newTexCoord
.x
= (newTexCoord
.x
- 0.5) * 2.0;}if(newTexCoord
.y
< 0.5){newTexCoord
.y
= newTexCoord
.y
* 2.0;}else{newTexCoord
.y
= (newTexCoord
.y
- 0.5) * 2.0;}gl_FragColor
= YuvToRgb(newTexCoord
);
}
縮放的圓
縮放的圓效果實現主要依賴偏移量來動態改變圓半徑的大小,在半徑區域內對紋理采樣顯示圖像,在半徑區域外返回一個固定顏色(如白色)。distance 也是 GLSL 的內建函數,用于計算兩點之間的距離。另外需要注意是,在計算之前首先要將紋理坐標系轉換為圖片坐標系,否則繪制的將會是一個橢圓形圖像(圖像寬高不同的情況下),想一想為什么會這樣?
#version 100
precision highp
float;
varying vec2 v_texcoord
;
uniform lowp sampler2D s_textureY
;
uniform lowp sampler2D s_textureU
;
uniform lowp sampler2D s_textureV
;
uniform
float u_offset
;
uniform vec2 texSize
;
vec4
YuvToRgb(vec2 uv
) {float y
, u
, v
, r
, g
, b
;y
= texture2D(s_textureY
, uv
).r
;u
= texture2D(s_textureU
, uv
).r
;v
= texture2D(s_textureV
, uv
).r
;u
= u
- 0.5;v
= v
- 0.5;r
= y
+ 1.403 * v
;g
= y
- 0.344 * u
- 0.714 * v
;b
= y
+ 1.770 * u
;return vec4(r
, g
, b
, 1.0);
}
void main()
{vec2 imgTex
= v_texcoord
* texSize
;float r
= (u_offset
+ 0.208 ) * texSize
.x
;if(distance(imgTex
, vec2(texSize
.x
/ 2.0, texSize
.y
/ 2.0)) < r
){gl_FragColor
= YuvToRgb(v_texcoord
);}else{gl_FragColor
= vec4(1.0, 1.0, 1.0, 1.0);}
}
在計算之前首先要將紋理坐標系轉換為圖片坐標系,其原因在于紋理縱橫坐標的取值范圍均為 [0, 1] ,從數值上看紋理的縱橫方向長度相同,但是在 OpenGL 采樣時,圖像的寬高比往往不是 1 ,這就導致了數值相同的縱橫坐標,對應不同的采樣權重,出現了預期繪制圓形而實際上卻繪制出橢圓的情況。
聯系與交流
技術交流/獲取源碼可以添加我的微信:Byte-Flow
總結
以上是生活随笔為你收集整理的NDK OpenGL ES 3.0 开发(十七):相机基础滤镜的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。