前言
隨著通信技術的快速發展,以及視頻業務的激烈擴張,作為研發人員,對音視頻這塊的知識還是需要知道一些的,渲染作為其中的一個重要組成部分,本系列就用通俗易懂的語言,來介紹opengl,
OpenGL 是啥?
opengl 全名是open graphics library , 用于渲染2d,3d影像的跨平臺,跨語言的應用程式編程介面,
OpenGL 能做什么?
opengl能做的事情有很多,比如可以對影像進行各種美顏,濾鏡,裁剪,貼紙等處理,源影像資料可以是來自相機,檔案,圖片等,像業內有名的GPUImage就是用opengl來做的,可以體驗一下,
小試牛刀
廢話少說,干就完事了,在實際專案體驗中來加深對opengl的理解吧,
我們用android開發環境來體驗opengl的渲染能力,本次的需求是使用opengl的能力在手機螢屏上畫一個三角形,
想想之前如果有這樣的需求,android開發應該怎么做呢? 應該是要問設計要一張三角形的圖片資源,然后直接放imageview上面展示出來,或者就自定義一個view,然后自己draw出來吧,無論怎么做,布局檔案上都需要放一個view控制元件,
那么這次我們也放一個控制元件把,不過放的不是普通的view,而是GLSurfaceview,還記得原來作業那會,雖然知道有GLSurfaceview這個東西,但是從來沒用過,也不知道能干啥,現在才知道,它是專門給opengl配合用的,
- 布局檔案添加,GLSurfaceview,
- 自定義Render,
- GLSurfaceview設定Render,
自定義render繼承自 GLSurfaceview內的IRender介面,IRender介面有三個回呼方法,這個三個回呼方法比較重要一點的是,這三個回呼方法都屬于GL執行緒,這是關鍵,
public class MyRender implements GLSurfaceView.Renderer {
private static final String TAG = "MyRender";
private final Context context;
private Triangle triangle;
public MyRender(Context context) {
this.context = context;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Log.d(TAG, "onSurfaceCreated: ");
String vertexSource = FileUtils.readTextFromRawResource(context, "base_vertex.glsl");
String fragmentSource = FileUtils.readTextFromRawResource(context, "base_fragment.glsl");
int vertexShaderId = GlUtils.createAndCompileVertexShader(vertexSource);
int fragmentShaderId = GlUtils.createAndCompileFragmentShader(fragmentSource);
Log.d(TAG, "onSurfaceCreated: vertexShaderId = "+vertexShaderId+"--fragmentShaderId = "+fragmentShaderId);
int program = GlUtils.createProgram(vertexShaderId, fragmentShaderId);
triangle = new Triangle(program);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
Log.d(TAG, "onSurfaceChanged: width = "+width+"--height = "+height);
GLES20.glClearColor(1f, 0f, 0f, 1f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
triangle.draw();
}
}
根據上面的自定義的render,分析一波,在onSurfaceCreate回呼中,
- 先是拿到了頂點著色器和片元著色器的內容GLSL(Open GL Shader Language),(PS: 相關名詞不懂沒關系,后面系列的文章會介紹,這里現有概念即可)
- 然后根據他兩的內容,分別創建了對應的著色器id,這里可以理解為著色器的參考,我們就可以通過id開訪問對應的著色器,
- 然后跟據頂點著色器和片元著色器創建了一個program(程式),通過program id來訪問,
onSurfaceChanged回呼中,拿到了view 的寬和高的資訊,通過這個資訊,主要呼叫了glviewport 函式來設定視口的大小,這里可以把視口理解為繪制區域,0,0 代表區域左上角的位置,width,height就是區域的寬高, 至于那兩個clear函式,就理解清理顏色快取的操作吧,
onDrawFrame 顧名思義就是畫內容咯,這里我們就打算把畫三角形的操作放這里,
在上面我們看到Triangle, 本著面向物件的思想,Triangle里面必然都是三角形相關的資訊了,
public class Triangle {
private static final String VERTEX_COOR_LABEL = "vCoordinate";
private static final String COLOR_LABEL = "aColor";
private final int program;
private static final float[] sVertex = {
0f, 0.5f,
-0.5f, 0f,
0.5f, 0f
};
private static final float[] sColor = {
1.0f, 0f, 0f,
0f, 1.0f, 0f,
0f, 0f, 1.0f
};
private final int vertexCoorHandle;
private final int aColorHandle;
private final FloatBuffer vertexCoorBuffer;
private final FloatBuffer colorBuffer;
public Triangle(int program) {
this.program = program;
vertexCoorHandle = GLES20.glGetAttribLocation(program, VERTEX_COOR_LABEL);
aColorHandle = GLES20.glGetAttribLocation(program, COLOR_LABEL);
vertexCoorBuffer = ByteBuffer.allocateDirect(2 * 3 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
vertexCoorBuffer.clear();
vertexCoorBuffer.put(sVertex);
colorBuffer = ByteBuffer.allocateDirect(3 * 3 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
colorBuffer.clear();
colorBuffer.put(sColor);
}
public void draw() {
GLES20.glUseProgram(program);
vertexCoorBuffer.position(0);
GLES20.glEnableVertexAttribArray(vertexCoorHandle);
GLES20.glVertexAttribPointer(vertexCoorHandle, 2, GLES20.GL_FLOAT, false, 0, vertexCoorBuffer);
colorBuffer.position(0);
GLES20.glEnableVertexAttribArray(aColorHandle);
GLES20.glVertexAttribPointer(aColorHandle, 3, GLES20.GL_FLOAT, false, 0, colorBuffer);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
GLES20.glDisableVertexAttribArray(vertexCoorHandle);
GLES20.glDisableVertexAttribArray(aColorHandle);
}
}
臥槽這一堆,gles開空的函式呼叫好多啊,完全不能理解具體用法啊?
看到這,不要慌,后面的會慢慢介紹的,哪能一下子啥都知道啊?(ps:我一下也說不明白,,,,)
總的來說,這個類就是,對三角形的描述,比如:sVertex float陣列來描述三角形的三個頂點的位置,此時聰明的你會想到,sVertex這個陣列有6個元素,三角形3個頂點的話,那就是每個頂點2個元素,正好是x,y; 平面直角坐標系的點的坐標值,但是這個數值怎么這么小呢,才0,0.5f, 可取的范圍是多少呢?
答案是:頂點可取的范圍是-1,1; 同時這里的坐標系是opengl坐標系,具體介紹,看后續,本文不解釋,
sColor 陣列描述每個頂點的顏色,rgb表示,所以這里是三個元素對應一個頂點,
在建構式里,雖然不知道函式具體作用,但是可以根據名稱猜出來它的功能(ps: 所以寫程式的程序還是要做好命名作業,好的命名讓別人看的舒服啊)
建構式里通過GLES20.glGetAttribLocation 函式,拿到索引,然后把頂點位置,顏色資訊,塞進去,
把資訊塞進去的代碼如下:
`
vertexCoorBuffer.position(0);
GLES20.glEnableVertexAttribArray(vertexCoorHandle);
GLES20.glVertexAttribPointer(vertexCoorHandle, 2, GLES20.GL_FLOAT, false, 0, vertexCoorBuffer);
colorBuffer.position(0);
GLES20.glEnableVertexAttribArray(aColorHandle);
GLES20.glVertexAttribPointer(aColorHandle, 3, GLES20.GL_FLOAT, false, 0, colorBuffer);
`
然后再呼叫 GLES20.glDrawArrays 來畫影像,
最后看下入口的代碼:
public class MainActivity extends AppCompatActivity {
private GLSurfaceView glSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
glSurfaceView = findViewById(R.id.content_view);
glSurfaceView.setEGLContextClientVersion(2);
glSurfaceView.setRenderer(new MyRender(this));
glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
}
然后我們看下運行效果:

總結
回顧下做了什么吧,
- 利用GLSL語法,創建了頂點著色器和片元著色器,(這都說的啥?)
- 利用這兩個著色器創建了program程式,(program??)
- 通過program訪問到了三角形屬性的句柄,因而我們可以把我們定義的屬性值賦值進去,(勉強聽懂)
- 使用glviewport 指定渲染的區域,因為GLSurfaceview設定的是全屏,所以指定渲染區域也是全屏,(背景顏色為啥是紅色?)
- draw時候,把顏色位置屬性設定進去,呼叫了glDrawArrays, 把三角形畫了出來,(假裝聽懂,,)
嗯,經過復盤回顧,對細節處可能不清除,但是大致的流程應該是知道了,后面的文章,會再逐個介紹不懂的地方,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/237675.html
標籤:其他
上一篇:抖音一鍵取消點贊實體原始碼
