編輯:關於Android編程
首先必須說,國內在OpenGL這方面特別是ndk上的分享太太太少
這中間遇到很多問題,而這些問題需要在書上,在網上,在各種資料上找,而且書上是java層調用,網上的缺少各種文件案例,只有在java層研究,在各種案例中找需要的知識點,遇到問題最終只有google搜外國網站才能解決。
接下來正文
——————————————————————————————
學習ndk應該都是從google配有的案例開始的吧:GL2JNIActivity
這個案例就是一個會變顏色的背景加一個綠色三角形
因為我開始學習紋理貼圖,所以打算將三角形換成貼圖
首先需要配置紋理
在GL2JNIView.java中修改Renderer類
private static class Renderer implements GLSurfaceView.Renderer { public void onDrawFrame(GL10 gl) { GL2JNILib.step(); } public void onSurfaceChanged(GL10 gl, int width, int height) { GL2JNILib.init(width, height); } private Context mContext; int textureId; private int[] TextureString = new int[1]; public void onSurfaceCreated(GL10 gl, EGLConfig config) { mContext = GL2JNIActivity.getContext(); //Bitmap bitmap = getBitmap(mContext,R.drawable.bac); Bitmap bitmap = getBitmap(mContext,R.drawable.wall); if(bitmap != null) { Log.e(step, bing the texture succeed!); gl.glEnable(GLES20.GL_TEXTURE_2D); gl.glGenTextures(1, TextureString,0); textureId= TextureString[0]; Log.e(textureId, String.valueOf(textureId)); gl.glBindTexture(GLES20.GL_TEXTURE_2D, textureId); gl.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); gl.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); gl.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); gl.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); GL2JNILib.setTextures(TextureString); // GL2JNILib.setTextures(textureId); bitmap.recycle(); } } private Bitmap getBitmap(Context context,int resId) { //getBitmap by decodeResources() // BitmapFactory.Options options = new BitmapFactory.Options(); // options.inScaled = false; // return BitmapFactory.decodeResource(context.getResources(), resId,options); //getBitmap by decodeStream() InputStream bitmapStream = null; bitmapStream = context.getResources().openRawResource(R.drawable.bac); return BitmapFactory.decodeStream(bitmapStream); //經驗證上面兩種方法都可以 } }因為這部分之前一直有問題,紋理試過一直閃爍,一直黑色,修改了很多地方,也不確定那些才是導致問題的根本原因,但是我盡可能貼出來,大家也多交流交流:
1.圖片格式要是2的倍數*2的倍數,而且有的說不超過1024有點不超過512,做測試還是用256*256的好了。
2.
gl.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);要在
gl.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); gl.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); gl.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); gl.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);之前
3.
gl.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);最後的參數要是
GLES20.GL_CLAMP_TO_EDGE
貌似跟mipmap有關
4.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
這個一定要放最後
5.
GL2JNILib.setTextures(TextureString);傳給C++層的參數一定要是int數組
接著是c++層的代碼
首先是腳本修改
static const char gVertexShader[] = attribute vec4 vPosition; attribute vec2 vTexCoords; varying vec2 colorVarying; void main() { gl_Position = vPosition; colorVarying = vTexCoords; } ; static const char gFragmentShader[] = precision mediump float; varying vec2 colorVarying; uniform sampler2D sampler; void main() { //gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); gl_FragColor = texture2D(sampler,colorVarying); } ;
添加了定點紋理坐標和傳遞給pixelShader變量
pixelShader添加了接收vertexShader傳過來的參數
bool setupGraphics(int w, int h)的修改
GLuint gProgram; GLuint gvPositionHandle; GLuint gvTexCoorHandle; bool setupGraphics(int w, int h) { printGLString(Version, GL_VERSION); printGLString(Vendor, GL_VENDOR); printGLString(Renderer, GL_RENDERER); printGLString(Extensions, GL_EXTENSIONS); LOGI(setupGraphics(%d, %d), w, h); gProgram = createProgram(gVertexShader, gFragmentShader); if (!gProgram) { LOGE(Could not create program.); return false; } gvPositionHandle = glGetAttribLocation(gProgram, vPosition); checkGlError(glGetAttribLocation); LOGI(glGetAttribLocation(Position) = %d , gvPositionHandle); gvTexCoorHandle = glGetAttribLocation(gProgram, vTexCoords); checkGlError(glGetAttribLocation); LOGI(glGetAttribLocation(TexCoords) = %d , gvTexCoorHandle); glViewport(0, 0, w, h); checkGlError(glViewport); return true; }添加了
gvTexCoorHandle = glGetAttribLocation(gProgram, vTexCoords);獲取紋理坐標屬性引用id
void renderFrame() 的修改
const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f }; const GLfloat gTexCoor[] = { 0.5f,0, 0,1, 1,1 }; void renderFrame() { static float grey; grey += 0.01f; if (grey > 1.0f) { grey = 0.0f; } glClearColor(grey, grey, grey, 1.0f); checkGlError(glClearColor); glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); //glClear( GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); checkGlError(glClear); glUseProgram(gProgram); checkGlError(glUseProgram); glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices); checkGlError(glVertexAttribPointer); glVertexAttribPointer(gvTexCoorHandle, 2, GL_FLOAT, GL_FALSE, 0, gTexCoor); checkGlError(glVertexAttribPointer); glEnableVertexAttribArray(gvPositionHandle); checkGlError(glEnableVertexAttribArray); glEnableVertexAttribArray(gvTexCoorHandle); checkGlError(glEnableVertexAttribArray); glActiveTexture(GL_TEXTURE0); checkGlError(glActiveTexture); glBindTexture(GL_TEXTURE_2D,mTexture[0]); checkGlError(glBindTexture); glDrawArrays(GL_TRIANGLES, 0, 3); checkGlError(glDrawArrays); }
添加接收Java層傳遞過來的紋理id
JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_setTextures(JNIEnv * env, jobject obj,jintArray texture) { mTexture = (GLuint *)env->GetIntArrayElements(texture,0); // m_texture = (unsigned int)env->GetIntArrayElements(texture,0);//it doesnt work!!!!what the fuck dont try this anymore!!! // const char *v = (const char *) m_texture; // LOGI(GL %s = %s , m_texture:, v); // v = (const char *) mTexture; // LOGI(GL %s = %s , mTexture:, v); }這裡有個問題就是導致後面黑色紋理的主要原因:
接收Java傳過來的id時要用GLuint*類型。這樣在上面
glBindTexture(GL_TEXTURE_2D,mTexture[0]);
傳進去才不會錯。
都怪我c++基礎不好...
最後希望大家能多點分享,像我這樣剛接觸OpenGL特別是在ndk上真的太少資料
項目下載鏈接:
http://download.csdn.net/detail/chrisfxs/7547637
工作中需要實現仿釘釘群頭像的一個功能,就是個人的頭像拼到一起顯示,看了一下市場上的APP好像微信的群聊頭像是組合的,QQ的頭像不是,別的好像也沒有了。給大家分享一下怎麼實
Android的消息處理有四個核心類:Handler、Looper、Message、MessageQueue,都在android.os包中。Android在UI線程和其他
實現的原理這裡說的不是熱修復怎麼實現修bug的原理,這裡說的是怎麼使用AndFix。如果你想了解更多的andFix實現原理,你可以參考下面的文章:https://gith
方法一:重寫TextView的onDraw方法,也挺直觀就是不太好控制顯示完圖片後再顯示字體所占空間的位置關系。一般如果字體是在圖片上重疊的推薦這樣寫。時間關系,這個不付