真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

AndroidOpenGLES如何給相機添加濾鏡詳解

濾鏡介紹

創(chuàng)新互聯(lián)擁有10余年成都網(wǎng)站建設(shè)工作經(jīng)驗,為各大企業(yè)提供網(wǎng)站建設(shè)、網(wǎng)站設(shè)計服務(wù),對于網(wǎng)頁設(shè)計、PC網(wǎng)站建設(shè)(電腦版網(wǎng)站建設(shè))、app軟件定制開發(fā)、wap網(wǎng)站建設(shè)(手機版網(wǎng)站建設(shè))、程序開發(fā)、網(wǎng)站優(yōu)化(SEO優(yōu)化)、微網(wǎng)站、域名與空間等,憑借多年來在互聯(lián)網(wǎng)的打拼,我們在互聯(lián)網(wǎng)網(wǎng)站建設(shè)行業(yè)積累了很多網(wǎng)站制作、網(wǎng)站設(shè)計、網(wǎng)絡(luò)營銷經(jīng)驗,集策劃、開發(fā)、設(shè)計、營銷、管理等網(wǎng)站化運作于一體,具備承接各種規(guī)模類型的網(wǎng)站建設(shè)項目的能力。

目前市面上的濾鏡有很多,但整體歸類也就幾樣,都是在fragment shader中進行處理。目前濾鏡最常用的就是 lut濾鏡以及調(diào)整RGB曲線的濾鏡了。其他的類型變更大同小異。

動態(tài)濾鏡的構(gòu)建

為了實現(xiàn)動態(tài)下載的濾鏡,我們接下來實現(xiàn)一套濾鏡的json參數(shù),主要包括濾鏡類型、濾鏡名稱、vertex shader、fragment shader 文件、統(tǒng)一變量列表、與統(tǒng)一變量綁定的紋理圖片、默認濾鏡強度、是否帶紋理寬高偏移量、音樂路徑、音樂是否循環(huán)播放等參數(shù)。

json 以及各個字段的介紹如下:

{
 "filterList": [{
  "type": "filter", // 表明濾鏡類型,目前filter是只普通濾鏡,后續(xù)還會加入其它類型的濾鏡
  "name": "amaro", // 濾鏡名稱
  "vertexShader": "", // vertex shader 文件名
  "fragmentShader": "fragment.glsl", // fragment shader 文件名
  "uniformList":["blowoutTexture", "overlayTexture", "mapTexture"], // 統(tǒng)一變量
  "uniformData": { // 與統(tǒng)一變量綁定的紋理圖片
   "blowoutTexture": "blowout.png",
   "overlayTexture": "overlay.png",
   "mapTexture": "map.png"
  },
  "strength": 1.0,  // 默認濾鏡強度 0.0 ~ 1.0之間
  "texelOffset": 0,  // 是否需要支持寬高偏移值,即需要傳遞 1.0f/width, 1.0f/height到shader中
  "audioPath": "",  // 音樂路徑
  "audioLooping": 1  // 是否循環(huán)播放音樂
 }]
}

有了json 之后,我們需要解碼得到濾鏡參數(shù)對象,解碼如下:

/**
  * 解碼濾鏡數(shù)據(jù)
  * @param folderPath
  * @return
  */
 public static DynamicColor decodeFilterData(String folderPath)
   throws IOException, JSONException {

  File file = new File(folderPath, "json");
  String filterJson = FileUtils.convertToString(new FileInputStream(file));

  JSONObject jsonObject = new JSONObject(filterJson);
  DynamicColor dynamicColor = new DynamicColor();
  dynamicColor.unzipPath = folderPath;
  if (dynamicColor.filterList == null) {
   dynamicColor.filterList = new ArrayList<>();
  }

  JSONArray filterList = jsonObject.getJSONArray("filterList");
  for (int filterIndex = 0; filterIndex < filterList.length(); filterIndex++) {
   DynamicColorData filterData = new DynamicColorData();
   JSONObject jsonData = filterList.getJSONObject(filterIndex);
   String type = jsonData.getString("type");
   // TODO 目前濾鏡只做普通的filter,其他復(fù)雜的濾鏡類型后續(xù)在做處理
   if ("filter".equals(type)) {
    filterData.name = jsonData.getString("name");
    filterData.vertexShader = jsonData.getString("vertexShader");
    filterData.fragmentShader = jsonData.getString("fragmentShader");
    // 獲取統(tǒng)一變量字段
    JSONArray uniformList = jsonData.getJSONArray("uniformList");
    for (int uniformIndex = 0; uniformIndex < uniformList.length(); uniformIndex++) {
     String uniform = uniformList.getString(uniformIndex);
     filterData.uniformList.add(uniform);
    }

    // 獲取統(tǒng)一變量字段綁定的圖片資源
    JSONObject uniformData = jsonData.getJSONObject("uniformData");
    if (uniformData != null) {
     Iterator dataIterator = uniformData.keys();
     while (dataIterator.hasNext()) {
      String key = dataIterator.next();
      String value = uniformData.getString(key);
      filterData.uniformDataList.add(new DynamicColorData.UniformData(key, value));
     }
    }
    filterData.strength = (float) jsonData.getDouble("strength");
    filterData.texelOffset = (jsonData.getInt("texelOffset") == 1);
    filterData.audioPath = jsonData.getString("audioPath");
    filterData.audioLooping = (jsonData.getInt("audioLooping") == 1);
   }
   dynamicColor.filterList.add(filterData);
  }

  return dynamicColor;
 }

濾鏡的實現(xiàn)

在解碼得到濾鏡參數(shù)之后,我們接下來實現(xiàn)動態(tài)濾鏡渲染過程。為了方便構(gòu)建濾鏡,我們創(chuàng)建一個濾鏡資源加載器,代碼如下:

/**
 * 濾鏡資源加載器
 */
public class DynamicColorLoader {

 private static final String TAG = "DynamicColorLoader";

 // 濾鏡所在的文件夾
 private String mFolderPath;
 // 動態(tài)濾鏡數(shù)據(jù)
 private DynamicColorData mColorData;
 // 資源索引加載器
 private ResourceDataCodec mResourceCodec;
 // 動態(tài)濾鏡
 private final WeakReference mWeakFilter;
 // 統(tǒng)一變量列表
 private HashMap mUniformHandleList = new HashMap<>();
 // 紋理列表
 private int[] mTextureList;

 // 句柄
 private int mTexelWidthOffsetHandle = OpenGLUtils.GL_NOT_INIT;
 private int mTexelHeightOffsetHandle = OpenGLUtils.GL_NOT_INIT;
 private int mStrengthHandle = OpenGLUtils.GL_NOT_INIT;
 private float mStrength = 1.0f;
 private float mTexelWidthOffset = 1.0f;
 private float mTexelHeightOffset = 1.0f;

 public DynamicColorLoader(DynamicColorBaseFilter filter, DynamicColorData colorData, String folderPath) {
  mWeakFilter = new WeakReference<>(filter);
  mFolderPath = folderPath.startsWith("file://") ? folderPath.substring("file://".length()) : folderPath;
  mColorData = colorData;
  mStrength = (colorData == null) ? 1.0f : colorData.strength;
  Pair pair = ResourceCodec.getResourceFile(mFolderPath);
  if (pair != null) {
   mResourceCodec = new ResourceDataCodec(mFolderPath + "/" + (String) pair.first, mFolderPath + "/" + pair.second);
  }
  if (mResourceCodec != null) {
   try {
    mResourceCodec.init();
   } catch (IOException e) {
    Log.e(TAG, "DynamicColorLoader: ", e);
    mResourceCodec = null;
   }
  }
  if (!TextUtils.isEmpty(mColorData.audioPath)) {
   if (mWeakFilter.get() != null) {
    mWeakFilter.get().setAudioPath(Uri.parse(mFolderPath + "/" + mColorData.audioPath));
    mWeakFilter.get().setLooping(mColorData.audioLooping);
   }
  }
  loadColorTexture();
 }

 /**
  * 加載紋理
  */
 private void loadColorTexture() {
  if (mColorData.uniformDataList == null || mColorData.uniformDataList.size() <= 0) {
   return;
  }
  mTextureList = new int[mColorData.uniformDataList.size()];
  for (int dataIndex = 0; dataIndex < mColorData.uniformDataList.size(); dataIndex++) {
   Bitmap bitmap = null;
   if (mResourceCodec != null) {
    bitmap = mResourceCodec.loadBitmap(mColorData.uniformDataList.get(dataIndex).value);
   }
   if (bitmap == null) {
    bitmap = BitmapUtils.getBitmapFromFile(mFolderPath + "/" + String.format(mColorData.uniformDataList.get(dataIndex).value));
   }
   if (bitmap != null) {
    mTextureList[dataIndex] = OpenGLUtils.createTexture(bitmap);
    bitmap.recycle();
   } else {
    mTextureList[dataIndex] = OpenGLUtils.GL_NOT_TEXTURE;
   }
  }
 }


 /**
  * 綁定統(tǒng)一變量句柄
  * @param programHandle
  */
 public void onBindUniformHandle(int programHandle) {
  if (programHandle == OpenGLUtils.GL_NOT_INIT || mColorData == null) {
   return;
  }
  mStrengthHandle = GLES30.glGetUniformLocation(programHandle, "strength");
  if (mColorData.texelOffset) {
   mTexelWidthOffsetHandle = GLES30.glGetUniformLocation(programHandle, "texelWidthOffset");
   mTexelHeightOffsetHandle = GLES30.glGetUniformLocation(programHandle, "texelHeightOffset");
  } else {
   mTexelWidthOffsetHandle = OpenGLUtils.GL_NOT_INIT;
   mTexelHeightOffsetHandle = OpenGLUtils.GL_NOT_INIT;
  }
  for (int uniformIndex = 0; uniformIndex < mColorData.uniformList.size(); uniformIndex++) {
   String uniformString = mColorData.uniformList.get(uniformIndex);
   int handle = GLES30.glGetUniformLocation(programHandle, uniformString);
   mUniformHandleList.put(uniformString, handle);
  }
 }

 /**
  * 輸入紋理大小
  * @param width
  * @param height
  */
 public void onInputSizeChange(int width, int height) {
  mTexelWidthOffset = 1.0f / width;
  mTexelHeightOffset = 1.0f / height;
 }

 /**
  * 綁定濾鏡紋理,只需要綁定一次就行,不用重復(fù)綁定,減少開銷
  */
 public void onDrawFrameBegin() {
  if (mStrengthHandle != OpenGLUtils.GL_NOT_INIT) {
   GLES30.glUniform1f(mStrengthHandle, mStrength);
  }
  if (mTexelWidthOffsetHandle != OpenGLUtils.GL_NOT_INIT) {
   GLES30.glUniform1f(mTexelWidthOffsetHandle, mTexelWidthOffset);
  }
  if (mTexelHeightOffsetHandle != OpenGLUtils.GL_NOT_INIT) {
   GLES30.glUniform1f(mTexelHeightOffsetHandle, mTexelHeightOffset);
  }

  if (mTextureList == null || mColorData == null) {
   return;
  }
  // 逐個綁定紋理
  for (int dataIndex = 0; dataIndex < mColorData.uniformDataList.size(); dataIndex++) {
   for (int uniformIndex = 0; uniformIndex < mUniformHandleList.size(); uniformIndex++) {
    // 如果統(tǒng)一變量存在,則直接綁定紋理
    Integer handle = mUniformHandleList.get(mColorData.uniformDataList.get(dataIndex).uniform);
    if (handle != null && mTextureList[dataIndex] != OpenGLUtils.GL_NOT_TEXTURE) {
     OpenGLUtils.bindTexture(handle, mTextureList[dataIndex], dataIndex + 1);
    }
   }
  }
 }

 /**
  * 釋放資源
  */
 public void release() {
  if (mTextureList != null && mTextureList.length > 0) {
   GLES30.glDeleteTextures(mTextureList.length, mTextureList, 0);
   mTextureList = null;
  }
  if (mWeakFilter.get() != null) {
   mWeakFilter.clear();
  }
 }

 /**
  * 設(shè)置強度
  * @param strength
  */
 public void setStrength(float strength) {
  mStrength = strength;
 }
}

然后我們構(gòu)建一個DynamicColorFilter的基類,方便后續(xù)添加其他類型的濾鏡,代碼如下:

public class DynamicColorBaseFilter extends GLImageAudioFilter {

 // 顏色濾鏡參數(shù)
 protected DynamicColorData mDynamicColorData;
 protected DynamicColorLoader mDynamicColorLoader;

 public DynamicColorBaseFilter(Context context, DynamicColorData dynamicColorData, String unzipPath) {
  super(context, (dynamicColorData == null || TextUtils.isEmpty(dynamicColorData.vertexShader)) ? VERTEX_SHADER
      : getShaderString(context, unzipPath, dynamicColorData.vertexShader),
    (dynamicColorData == null || TextUtils.isEmpty(dynamicColorData.fragmentShader)) ? FRAGMENT_SHADER_2D
      : getShaderString(context, unzipPath, dynamicColorData.fragmentShader));
  mDynamicColorData = dynamicColorData;
  mDynamicColorLoader = new DynamicColorLoader(this, mDynamicColorData, unzipPath);
  mDynamicColorLoader.onBindUniformHandle(mProgramHandle);
 }

 @Override
 public void onInputSizeChanged(int width, int height) {
  super.onInputSizeChanged(width, height);
  if (mDynamicColorLoader != null) {
   mDynamicColorLoader.onInputSizeChange(width, height);
  }
 }

 @Override
 public void onDrawFrameBegin() {
  super.onDrawFrameBegin();
  if (mDynamicColorLoader != null) {
   mDynamicColorLoader.onDrawFrameBegin();
  }
 }

 @Override
 public void release() {
  super.release();
  if (mDynamicColorLoader != null) {
   mDynamicColorLoader.release();
  }
 }

 /**
  * 設(shè)置強度,調(diào)節(jié)濾鏡的輕重程度
  * @param strength
  */
 public void setStrength(float strength) {
  if (mDynamicColorLoader != null) {
   mDynamicColorLoader.setStrength(strength);
  }
 }

 /**
  * 根據(jù)解壓路徑和shader名稱讀取shader的字符串內(nèi)容
  * @param unzipPath
  * @param shaderName
  * @return
  */
 protected static String getShaderString(Context context, String unzipPath, String shaderName) {
  if (TextUtils.isEmpty(unzipPath) || TextUtils.isEmpty(shaderName)) {
   throw new IllegalArgumentException("shader is empty!");
  }
  String path = unzipPath + "/" + shaderName;
  if (path.startsWith("assets://")) {
   return OpenGLUtils.getShaderFromAssets(context, path.substring("assets://".length()));
  } else if (path.startsWith("file://")) {
   return OpenGLUtils.getShaderFromFile(path.substring("file://".length()));
  }
  return OpenGLUtils.getShaderFromFile(path);
 }

}

接下來我們構(gòu)建動態(tài)濾鏡組,因為動態(tài)濾鏡有可能有多個濾鏡組合而成。代碼如下:

public class GLImageDynamicColorFilter extends GLImageGroupFilter {

 public GLImageDynamicColorFilter(Context context, DynamicColor dynamicColor) {
  super(context);
  // 判斷數(shù)據(jù)是否存在
  if (dynamicColor == null || dynamicColor.filterList == null
    || TextUtils.isEmpty(dynamicColor.unzipPath)) {
   return;
  }
  // 添加濾鏡
  for (int i = 0; i < dynamicColor.filterList.size(); i++) {
   mFilters.add(new DynamicColorFilter(context, dynamicColor.filterList.get(i), dynamicColor.unzipPath));
  }
 }

 /**
  * 設(shè)置濾鏡強度
  * @param strength
  */
 public void setStrength(float strength) {
  for (int i = 0; i < mFilters.size(); i++) {
   if (mFilters.get(i) != null && mFilters.get(i) instanceof DynamicColorBaseFilter) {
    ((DynamicColorBaseFilter) mFilters.get(i)).setStrength(strength);
   }
  }
 }
}

總結(jié)

基本的動態(tài)濾鏡實現(xiàn)起來比較簡單,總的來說就是簡單的json參數(shù)、shader、統(tǒng)一變量和紋理綁定需要做成動態(tài)構(gòu)建的過程而已。

效果如下:

Android OpenGLES如何給相機添加濾鏡詳解
動態(tài)濾鏡效果

該效果是通過解壓asset目錄下的壓縮包資源來實現(xiàn)的。你只需要提供包含shader 、紋理資源、以及json的壓縮包即可更改濾鏡。

詳細實現(xiàn)過程,可參考本人的開源項目:
CainCamera

好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對創(chuàng)新互聯(lián)的支持。


分享名稱:AndroidOpenGLES如何給相機添加濾鏡詳解
網(wǎng)頁網(wǎng)址:http://weahome.cn/article/podieg.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部