OpenGLES使用(2)

學(xué)習(xí)并使用GLSL.分別實(shí)現(xiàn)置灰,翻轉(zhuǎn),正方形馬賽克,六邊形馬賽克,三角形馬賽克,以及縮放,靈魂出竅,抖動(dòng),閃白,毛刺.幻覺效果!

置灰效果

核心思路:在片元著色器中.將原圖中的所有顏色值與我們?cè)O(shè)定的灰色變換因子相乘獲取新的灰色顏色值

原圖.jpg
置灰效果.jpg

相關(guān)代碼如下:

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);

void main (void) {
    
    vec4 mask = texture2D(Texture, TextureCoordsVarying);
    //dot內(nèi)建函數(shù).將顏色值與變換因子相乘得到新的顏色值
    float luminance = dot(mask.rgb, W);
    gl_FragColor = vec4(vec3(luminance), 1.0);
}
顛倒濾鏡

核心思路:在片元著色器中.翻轉(zhuǎn)紋理坐標(biāo)y值.

顛倒圖.jpg

相關(guān)代碼如下:

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

void main (void) {
    
    vec4 color = texture2D(Texture, vec2(TextureCoordsVarying.x, 1.0-TextureCoordsVarying.y));
    gl_FragColor = color;
}
正方形馬賽克

核心思路:將整個(gè)紋理.分成多個(gè)小正方形.隨后將小正方形內(nèi)的所有紋理顏色值均取右上角的顏色值.

方便理解.jpg
正方形馬賽克.jpg

相關(guān)代碼如下:

precision highp float;
//紋理坐標(biāo)
uniform sampler2D Texture;
//紋理采樣器
varying vec2 TextureCoordsVarying;
//紋理圖片size
const vec2 TexSize = vec2(400.0, 400.0);
//馬賽克size
const vec2 MosaicSize = vec2(16.0, 16.0);

void main(){
//計(jì)算實(shí)際圖像位置
vec2 intXY = vec2(TextureCoordsVarying.x * TexSize.x, TextureCoordsVarying.y * TexSize.y);

//floor(x) 內(nèi)建函數(shù),返回小于/等于x最大的整數(shù),即向下取整
//floor(intXY.x/mosaicSize.x)*mosaicSize.x 計(jì)算出一個(gè)小馬賽克的坐標(biāo)
vec2 XYMosaic = vec2(floor(intXY.x/MosaicSize.x)*MosaicSize.x, floor(intXY.y/MosaicSize.y)*MosaicSize.y);

//換算回紋理坐標(biāo),此時(shí)的紋理坐標(biāo)是小馬賽克的部分的紋理坐標(biāo),即某一個(gè)色塊
vec2 UVMosaic = vec2(XYMosaic.x/TexSize.x, XYMosaic.y/TexSize.y);
//獲取到馬賽克后的紋理坐標(biāo)的顏色值
vec4 color = texture2D(Texture, UVMosaic);
//將馬賽克顏色值賦值給gl_FragColor
gl_FragColor = color;
}
六邊形馬賽克

核心思路:將整個(gè)紋理.分成多個(gè)正六邊形,根據(jù)行列的奇偶情況.可以對(duì)應(yīng)下圖中的兩種情況.即中心點(diǎn)為(0,0)(1,1),以及中心點(diǎn)為(0,1)(1,0),找到該規(guī)律以后將當(dāng)前紋理坐標(biāo)計(jì)算最近的中心點(diǎn).該中心點(diǎn)顏色值即為該紋理坐標(biāo)的顏色值.

方便理解.jpg
正六邊形.jpg

相關(guān)代碼如下:

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
//六邊形的邊長(zhǎng)
const float mosaicSize = 0.03;

void main(){

float length = mosaicSize;
//矩形的高的比例為√3,取值 √3/2 ,也可以直接取√3
float TR = 0.866025;
//矩形的長(zhǎng)的比例為3,取值 3/2 = 1.5,也可以直接取3
float TB = 1.5;

//取出紋理坐標(biāo)
float x = TextureCoordsVarying.x;
float y = TextureCoordsVarying.y;

//根據(jù)紋理坐標(biāo)計(jì)算出對(duì)應(yīng)的矩陣坐標(biāo) 
//即 矩陣坐標(biāo)wx = int(紋理坐標(biāo)x/ 矩陣長(zhǎng)),矩陣長(zhǎng) = TB*len
//即 矩陣坐標(biāo)wy = int(紋理坐標(biāo)y/ 矩陣寬),矩陣寬 = TR*len
int wx = int(x / TB / length);
int wy = int(y / TR / length);
vec2 v1, v2, vn;

//判斷wx是否為偶數(shù),等價(jià)于 wx % 2 == 0
if (wx/2 * 2 == wx) {
    if (wy/2 * 2 == wy) {//偶行偶列
        //(0,0),(1,1)
        v1 = vec2(length * TB * float(wx), length * TR * float(wy));
        v2 = vec2(length * TB * float(wx+1), length * TR * float(wy+1));
    }else{//偶行奇列
        //(0,1),(1,0)
        v1 = vec2(length * TB * float(wx), length * TR * float(wy+1));
        v2 = vec2(length * TB * float(wx+1), length * TR * float(wy));
    }
}else{
    if (wy/2 * 2 == wy) {//奇行偶列
        //(0,1),(1,0)
        v1 = vec2(length * TB * float(wx), length * TR * float(wy+1));
        v2 = vec2(length * TB * float(wx+1), length * TR * float(wy));
    }else{//奇行奇列
        //(0,0),(1,1)
        v1 = vec2(length * TB * float(wx), length * TR * float(wy));
        v2 = vec2(length * TB * float(wx+1), length * TR * float(wy+1));
    }
}
//利用距離公式,計(jì)算中心點(diǎn)與當(dāng)前像素點(diǎn)的距離
float s1 = sqrt(pow(v1.x-x, 2.0) + pow(v1.y-y, 2.0));
float s2 = sqrt(pow(v2.x-x, 2.0) + pow(v2.y-y, 2.0));

//選擇距離小的則為六邊形的中心點(diǎn),且獲取它的顏色
vn = (s1 < s2) ? v1 : v2;
//獲取六邊形中心點(diǎn)的顏色值
vec4 color = texture2D(Texture, vn);
gl_FragColor = color;
}
三邊形馬賽克

核心思路:前面準(zhǔn)備工作與六邊形馬賽克相似.需要將六邊形細(xì)分為6個(gè)三角形.如下圖.然后根據(jù)紋理坐標(biāo)找到所在三角形.并設(shè)定其紋理顏色為三角形的中心顏色

方便理解.jpg
三角形.jpg

相關(guān)代碼如下:

/...接上六邊形紋理相關(guān)代碼..../

vn = (s1 < s2) ? v1 : v2;
//獲取像素點(diǎn)與中心點(diǎn)的角度
float a = atan((x-vn.x)/(y-vn.y));

//判斷夾角,屬于哪個(gè)三角形,則獲取哪個(gè)三角形的中心點(diǎn)坐標(biāo)
vec2 area1 = vec2(vn.x, vn.y - mosaicSize * TR / 2.0);
vec2 area2 = vec2(vn.x + mosaicSize / 2.0, vn.y - mosaicSize * TR / 2.0);
vec2 area3 = vec2(vn.x + mosaicSize / 2.0, vn.y + mosaicSize * TR / 2.0);
vec2 area4 = vec2(vn.x, vn.y + mosaicSize * TR / 2.0);
vec2 area5 = vec2(vn.x - mosaicSize / 2.0, vn.y + mosaicSize * TR / 2.0);
vec2 area6 = vec2(vn.x - mosaicSize / 2.0, vn.y - mosaicSize * TR / 2.0);

if (a >= PI6 && a < PI6 * 3.0) {
    vn = area1;
}else if (a >= PI6 * 3.0 && a < PI6 * 5.0){
    vn = area2;
}else if ((a >= PI6 * 5.0 && a <= PI6 * 6.0) || (a < -PI6 * 5.0 && a > -PI6 * 6.0)){
    vn = area3;
}else if (a < -PI6 * 3.0 && a >= -PI6 * 5.0){
    vn = area4;
}else if (a <= -PI6 && a > -PI6 * 3.0){
    vn = area5;
}else if (a > -PI6 && a < PI6){
    vn = area6;
}
//獲取對(duì)應(yīng)三角形重心的顏色值
vec4 color = texture2D(Texture, vn);
// 將顏色值填充到片元著色器內(nèi)置變量gl_FragColor
gl_FragColor = color;
}
縮放效果

核心思路:在頂點(diǎn)著色器中.隨著時(shí)間的推移.讓頂點(diǎn)著色器的頂點(diǎn)呈現(xiàn)正弦振幅逐漸放大以及縮小.

方便理解.jpg
縮放.2021-02-24 17_23_39.gif

相關(guān)代碼如下:

attribute vec4 Position;
attribute vec2 TextureCoords;
varying vec2 TextureCoordsVarying;
//時(shí)間戳(隨著定時(shí)器的方法調(diào)用及時(shí)更新):從0開始一直遞增
uniform float Time;
const float PI = 3.1415926;

void main(){
//一次縮放效果的時(shí)長(zhǎng)
float duration = 0.6;
//最大縮放幅度
float maxAmplitude = 0.3;

//表示傳入的事件周期,即time的范圍被控制在0.0~0.6
//mod(a, b),求模運(yùn)算 等價(jià)于 a%b,GLSL中不支持%求模
float time = mod(Time,duration);

//amplitude表示振幅,引入PI的目的是為了使用sin函數(shù),將amplitude的范圍控制在1.0 ~ 1.3之間,并隨著時(shí)間變化
//這里可以不用取絕對(duì)值,因?yàn)榻嵌鹊姆秶恰?,π】,不會(huì)出現(xiàn)負(fù)數(shù)的情況
float amplitude = 1.0 + maxAmplitude * abs(sin(time * (PI / duration)));

//放大關(guān)鍵代碼:將頂點(diǎn)坐標(biāo)的x和y分別乘以一個(gè)放大系數(shù),即振幅,在紋理坐標(biāo)不變的情況下,就達(dá)到了拉伸的效果
//xy放大,zw保持不變
gl_Position = vec4(Position.x * amplitude, Position.y * amplitude, Position.zw);

//紋理坐標(biāo)傳遞給TextureCoordsVarying
TextureCoordsVarying = TextureCoords;
}
靈魂出竅

核心思路:在紋理上疊加一個(gè)放大的紋理.將兩個(gè)紋理的顏色混合實(shí)現(xiàn).并且放大的紋理層隨著時(shí)間的推移透明度逐步降低至0.以此反復(fù).


靈魂出竅.gif

相關(guān)代碼如下:

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
 //時(shí)間戳
uniform float Time;

void main (void) {
//一次靈魂出竅效果的時(shí)長(zhǎng)
float duration = 0.7;
//透明度上限值
float maxAlpha = 0.4;
//圖片放大的上限
float maxScale = 1.8;

//當(dāng)前進(jìn)度(時(shí)間戳與時(shí)長(zhǎng)使用mod取模),再除以時(shí)長(zhǎng) 得到【0, 1】,即百分比
float progress = mod(Time, duration) / duration; // 0~1
//當(dāng)前透明度 【0.4, 0】
float alpha = maxAlpha * (1.0 - progress);
//當(dāng)前縮放比例 【1.0, 1.8】
float scale = 1.0 + (maxScale - 1.0) * progress;

//獲取放大后的紋理坐標(biāo)
//將頂點(diǎn)坐標(biāo)對(duì)應(yīng)的紋理坐標(biāo)的x/y值到中心點(diǎn)的距離,縮小一定的比例,僅僅只是改變了紋理坐標(biāo),而保持頂點(diǎn)坐標(biāo)不變,從而達(dá)到拉伸效果.即中心點(diǎn)左邊的往左偏移.右邊的往右偏移
float weakX = 0.5 + (TextureCoordsVarying.x - 0.5) / scale;
float weakY = 0.5 + (TextureCoordsVarying.y - 0.5) / scale;
vec2 weakTextureCoords = vec2(weakX, weakY);

//獲取當(dāng)前像素點(diǎn)紋理坐標(biāo),放大后的紋理坐標(biāo)  
vec4 weakMask = texture2D(Texture, weakTextureCoords);

vec4 mask = texture2D(Texture, TextureCoordsVarying);
//2、顏色混合 內(nèi)建函數(shù)mix / 混合方程式
gl_FragColor = mask * (1.0 - alpha) + weakMask * alpha;
}
抖動(dòng)效果

核心思路:在紋理上疊加兩個(gè)放大的顏色偏移的紋理.將包含原始紋理在內(nèi)的顏色混合實(shí)現(xiàn).并且放大的紋理層隨著時(shí)間的推移.以此反復(fù).

抖動(dòng).gif

相關(guān)代碼如下:

void main(){
 //一次抖動(dòng)效果的時(shí)長(zhǎng)
float duration = 0.7;
//放大圖片的上限
float maxScale = 1.1;
//顏色偏移的步長(zhǎng)
float offset = 0.02;

//進(jìn)度 0 ~ 1
float progress = mod(Time, duration) / duration;
//顏色偏移值0 ~ 0.02
vec2 offsetCoords = vec2(offset, offset) * progress;
//縮放比例 1.0 ~ 1.1
float scale = 1.0 + (maxScale - 1.0) * progress;

//放大后的紋理坐標(biāo) 
//下面這種向量相加減的方式 等價(jià)于 靈魂出竅濾鏡中的單個(gè)計(jì)算x、y坐標(biāo)再組合的為紋理坐標(biāo)的方式
vec2 ScaleTextureCoords = vec2(0.5, 0.5) + (TextureCoordsVarying - vec2(0.5, 0.5)) / scale;

//獲取三組顏色:顏色偏移計(jì)算可以隨意,只要偏移量很小即可
//原始顏色 + offset
vec4 maskR = texture2D(Texture, ScaleTextureCoords + offsetCoords);
//原始顏色 - offset
vec4 maskB = texture2D(Texture, ScaleTextureCoords - offsetCoords);
//原始顏色
vec4 mask = texture2D(Texture, ScaleTextureCoords);

//從3組顏色中分別取出 紅色R,綠色G,藍(lán)色B,透明度A填充到內(nèi)置變量gl_FragColor內(nèi)
gl_FragColor = vec4(maskR.r, maskB.g, mask.b, mask.a);
}
閃白效果

核心思路:在原紋理上添加一個(gè)白色遮罩.且白色遮罩的透明度隨著時(shí)間的推移而變化.然后將白色遮罩與原紋理顏色混合

閃白.gif

相關(guān)代碼如下:

void main(){
//一次閃白的時(shí)長(zhǎng)
float duration = 0.6;
//將時(shí)間戳轉(zhuǎn)換到一個(gè)周期內(nèi),范圍是0 ~ 0.6
float time = mod(Time, duration);
//白色遮罩
vec4 whiteMask = vec4(1.0, 1.0, 1.0, 1.0);
// 振幅,范圍是0 ~ 1
//float amplitude = abs(sin(time * (PI / duration)));
float amplitude = sin(time * (PI / duration));

//獲取紋理坐標(biāo)對(duì)應(yīng)的紋素顏色值
vec4 mask = texture2D(Texture, TextureCoordsVarying);
//利用mix內(nèi)置函數(shù)進(jìn)行顏色混合,屬于線性混合
gl_FragColor = mix(mask, whiteMask, amplitude);
}
毛刺效果

核心思路:在原紋理中.當(dāng)像素點(diǎn)的偏移值小于一個(gè)設(shè)定值時(shí).才進(jìn)行偏移.否則乘以一個(gè)極小值.讓其還原.這樣隨著時(shí)間的推移.以此反復(fù).

毛刺.gif

相關(guān)代碼如下:

   //隨機(jī)數(shù)
    float rand(float n){
    //fract(x)返回x的小數(shù)部分
    //返回 sin(n) * 43758.5453123
    //sin(n) * 極大值,帶小數(shù)點(diǎn),想要隨機(jī)數(shù)算的比較低,乘的數(shù)就必須較大,噪聲隨機(jī)
    //如果想得到【0,1】范圍的小數(shù)值,可以將sin * 1
    //如果只保留小數(shù)部分,乘以一個(gè)極大值
    return fract(sin(n) * 43758.5453123);
    }

    void main(){
    //最大抖動(dòng)上限
    float maxJitter = 0.06;
    //一次毛刺效果的時(shí)長(zhǎng)
    float duration = 0.3;
    //紅色顏色偏移
    float colorROffset = 0.01;
    //綠色顏色偏移
    float colorBOffset = -0.025;
    
    //表示將傳入的事件轉(zhuǎn)換到一個(gè)周期內(nèi),范圍是 0 ~ 0.6,抖動(dòng)時(shí)長(zhǎng)變成0.6
    float time = mod(Time, duration * 2.0);
    //振幅,隨著時(shí)間變化,范圍是[0, 1]                                                                             
    float amplitude = max(sin(time * (PI / duration)), 0.0);
    
    //像素隨機(jī)偏移范圍 -1 ~ 1,* 2.0 - 1.0是為了得到【-1,1】范圍內(nèi)的隨機(jī)值
    float jitter = rand(TextureCoordsVarying.y) * 2.0 - 1.0;
    //判斷是否需要偏移,如果jitter范圍 < 最大范圍*振幅
    // abs(jitter) 范圍【0,1】
    // maxJitter * amplitude 范圍【0, 0.06】
    bool needOffset = abs(jitter) < maxJitter * amplitude;
    
    //獲取紋理x坐標(biāo),根據(jù)needOffset來計(jì)算它的x撕裂
    //needOffset = YES,則撕裂大
    //needOffset = NO,則撕裂小,需要降低撕裂 = *振幅*非常細(xì)微的數(shù)
    float textureX = TextureCoordsVarying.x + (needOffset ? jitter : (jitter * amplitude * 0.006));
    //獲取紋理撕裂后的x、y坐標(biāo)
    vec2 textureCoords = vec2(textureX, TextureCoordsVarying.y);
    
    //顏色偏移:獲取3組顏色
    //撕裂后的原圖顏色
    vec4 mask = texture2D(Texture, textureCoords);
    //根據(jù)撕裂計(jì)算后的紋理坐標(biāo),獲取紋素
    vec4 maskR = texture2D(Texture, textureCoords + vec2(colorROffset * amplitude, 0.0));
    //根據(jù)撕裂計(jì)算后的紋理坐標(biāo),獲取紋素
    vec4 maskB = texture2D(Texture, textureCoords + vec2(colorBOffset * amplitude, 0.0));
    
    //顏色主要撕裂,紅色和藍(lán)色部分,所以只調(diào)整紅色
    gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
    }
幻覺效果

核心思路:做殘影效果.并且將顏色做紅色偏移.隨著時(shí)間的遞進(jìn).做圓周運(yùn)動(dòng).也是多個(gè)紋理疊加產(chǎn)生效果

幻覺.gif

相關(guān)代碼如下:

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

const float PI = 3.1415926;
//一次幻覺效果的時(shí)長(zhǎng),即周期
const float duration = 2.0;

//這個(gè)函數(shù)可以計(jì)算出,在某個(gè)時(shí)刻圖片的具體位置,通過它可以每經(jīng)過一段時(shí)間,去生成一個(gè)新的mask
//轉(zhuǎn)圈產(chǎn)生幻影的單個(gè)像素點(diǎn)的顏色值
vec4 getMask(float time, vec2 textureCoords, float padding) {
   //圓心坐標(biāo)
    vec2 translation = vec2(sin(time * (PI * 2.0 / duration)),cos(time * (PI * 2.0 / duration)));
    
    //新的紋理坐標(biāo) = 原始紋理坐標(biāo) + 偏移量 * 圓周坐標(biāo)(新的圖層與圖層之間是有間距的,所以需要偏移)
    vec2 translationTextureCoords = textureCoords + padding * translation;
    
    //根據(jù)新的紋理坐標(biāo)獲取新圖層的紋素
    vec4 mask = texture2D(Texture, translationTextureCoords);
    
    return mask;
}

//這個(gè)函數(shù)可以計(jì)算出,某個(gè)時(shí)刻創(chuàng)建的層,在當(dāng)前時(shí)刻的透明度
//進(jìn)度:
float maskAlphaProgress(float currentTime, float hideTime, float startTime) {
//mod(時(shí)長(zhǎng)+持續(xù)時(shí)間 - 開始時(shí)間,時(shí)長(zhǎng))得到一個(gè)周期內(nèi)的time
    float time = mod(duration + currentTime - startTime, duration);
    //如果小于0.9,返回time,反之,返回0.9
    return min(time, hideTime);
}

void main(){
    //將傳入的時(shí)間戳轉(zhuǎn)換到一個(gè)周期內(nèi),time的范圍是【0,2】
    //獲得時(shí)間周期
    float time = mod(Time, duration);
    //放大后的倍數(shù)
    float scale = 1.2;
    //偏移量 = 0.083
    float padding = 0.5 * (1.0 - 1.0 / scale);
    //放大后的紋理坐標(biāo)
    vec2 textureCoords = vec2(0.5, 0.5) + (TextureCoordsVarying - vec2(0.5, 0.5)) / scale;
    
    //新建層的隱藏時(shí)間 即新建層什么時(shí)候隱藏 
    float hideTime = 0.9;
    //時(shí)間間隔:隔0.2s創(chuàng)建一個(gè)新層
    float timeGap = 0.2;
    
    //注意:只保留了紅色的透明的通道值,因?yàn)榛糜X效果殘留紅色
    //幻影殘留數(shù)據(jù)
    //max RGB alpha
    //新圖層的 R透明度
    float maxAlphaR = 0.5;
    //新圖層的 G透明度
    float maxAlphaG = 0.05;
    //新圖層的 B透明度
    float maxAlphaB = 0.05;
    
    //獲取新的圖層的坐標(biāo),需要傳入時(shí)間、紋理坐標(biāo)、偏移量
    vec4 mask = getMask(time, textureCoords, padding);
    //RGB :for循環(huán)中使用
    float alphaR = 1.0;
    float alphaG = 1.0;
    float alphaB = 1.0;
    
    //最終圖層顏色:初始化
    vec4 resultMask = vec4(0, 0, 0, 0);
    
    //循環(huán):每一層循環(huán)都會(huì)得到新的圖層的顏色,即幻影顏色
    //一次循環(huán)只是計(jì)算一個(gè)像素點(diǎn)的紋素,需要在真機(jī)運(yùn)行。模擬器會(huì)卡,主要是模擬器上是CPU模擬GPU的
    for (float f = 0.0; f < duration; f += timeGap) {
        float tmpTime = f;
        //獲取到【0,2】s內(nèi)所獲取的運(yùn)動(dòng)后的紋理坐標(biāo)
        //獲得幻影當(dāng)前時(shí)間的顏色值
        vec4 tmpMask = getMask(tmpTime, textureCoords, padding);
        
        //某個(gè)時(shí)刻創(chuàng)建的層,在當(dāng)前時(shí)刻的紅綠藍(lán)的透明度
        //臨時(shí)的透明度 = 根據(jù)時(shí)間推移RGB的透明度發(fā)生變化
        //獲得臨時(shí)的紅綠藍(lán)透明度
        float tmpAlphaR = maxAlphaR - maxAlphaR * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
        float tmpAlphaG = maxAlphaG - maxAlphaG * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
        float tmpAlphaB = maxAlphaB - maxAlphaB * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
        
        //累計(jì)每一層臨時(shí)RGB * RGB的臨時(shí)透明度
        //結(jié)果 += 臨時(shí)顏色 * 透明度,即剛產(chǎn)生的圖層的顏色
        resultMask += vec4(tmpMask.r * tmpAlphaR,tmpMask.g * tmpAlphaG,tmpMask.b * tmpAlphaB,1.0);
                           
        //透明度遞減
        alphaR -= tmpAlphaR;
        alphaG -= tmpAlphaG;
        alphaB -= tmpAlphaB;
    }
    
    //最終顏色 += 原始紋理的RGB * 透明度
    resultMask += vec4(mask.r * alphaR, mask.g * alphaG, mask.b * alphaB, 1.0);
    
    //將最終顏色填充到像素點(diǎn)里
    gl_FragColor = resultMask;
}

參考文獻(xiàn):OpenGL ES 案例13:動(dòng)效濾鏡(6種)
代碼地址:Demo

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容