Android(安卓)OpenGL ES 2.0 (七) FramebufferObject(FBO)
16lz
2021-01-26
Android平台上简单的FramebufferObject示例。
FramebufferObject的概念就不说了,参考OpenGL ES 2.0 Programming Guide的第10章。
下面是render framebuffer到texture的例子。
代码的主要流程是:
创建framebuffer,绑定framebuffer,render framebuffer到texture,切换回system提供的framebuffer,利用之前产生的texture.
方便起见,两个render流程用的同样的shader.
下面是renderer的代码,Test7Renderer.java
1 package com.android.jayce.test; 2 3 import java.nio.ByteBuffer; 4 import java.nio.ByteOrder; 5 import java.nio.FloatBuffer; 6 import java.nio.IntBuffer; 7 8 import javax.microedition.khronos.egl.EGLConfig; 9 import javax.microedition.khronos.opengles.GL10; 10 11 import android.content.Context; 12 import android.opengl.GLES20; 13 import android.opengl.GLSurfaceView; 14 import android.opengl.Matrix; 15 import android.os.SystemClock; 16 17 import com.android.jayce.test.R; 18 19 /** 20 * This class implements our custom renderer. Note that the GL10 parameter passed in is unused for OpenGL ES 2.0 21 * renderers -- the static class GLES20 is used instead. 22 */ 23 public class Test7Renderer implements GLSurfaceView.Renderer 24 { 25 /** Used for debug logs. */ 26 private static final String TAG = "Test7Renderer"; 27 28 private final Context mActivityContext; 29 30 /** 31 * Store the model matrix. This matrix is used to move models from object space (where each model can be thought 32 * of being located at the center of the universe) to world space. 33 */ 34 private float[] mModelMatrix = new float[16]; 35 36 /** 37 * Store the view matrix. This can be thought of as our camera. This matrix transforms world space to eye space; 38 * it positions things relative to our eye. 39 */ 40 private float[] mViewMatrix = new float[16]; 41 42 /** Store the projection matrix. This is used to project the scene onto a 2D viewport. */ 43 private float[] mProjectionMatrix = new float[16]; 44 45 /** Allocate storage for the final combined matrix. This will be passed into the shader program. */ 46 private float[] mMVPMatrix = new float[16]; 47 48 /** Store our model data in a float buffer. */ 49 private final FloatBuffer mCubePositions; 50 private final FloatBuffer mCubeColors; 51 private final FloatBuffer mCubeTextureCoordinates; 52 53 /** This will be used to pass in the transformation matrix. */ 54 private int mMVPMatrixHandle; 55 56 /** This will be used to pass in the modelview matrix. */ 57 private int mMVMatrixHandle; 58 59 /** This will be used to pass in the texture. */ 60 private int mTextureUniformHandle; 61 62 /** This will be used to pass in model position information. */ 63 private int mPositionHandle; 64 65 /** This will be used to pass in model color information. */ 66 private int mColorHandle; 67 68 /** This will be used to pass in model texture coordinate information. */ 69 private int mTextureCoordinateHandle; 70 71 /** How many bytes per float. */ 72 private final int mBytesPerFloat = 4; 73 74 /** Size of the position data in elements. */ 75 private final int mPositionDataSize = 3; 76 77 /** Size of the color data in elements. */ 78 private final int mColorDataSize = 4; 79 80 /** Size of the texture coordinate data in elements. */ 81 private final int mTextureCoordinateDataSize = 2; 82 83 /** This is a handle to our cube shading program. */ 84 private int mProgramHandle; 85 86 /** This is a handle to our texture data. */ 87 private int mTextureDataHandle; 88 89 /** 90 * Initialize the model data. 91 */ 92 public Test7Renderer(final Context activityContext) 93 { 94 mActivityContext = activityContext; 95 96 // Define points for a cube. 97 98 // X, Y, Z 99 final float[] cubePositionData =100 {101 // In OpenGL counter-clockwise winding is default. This means that when we look at a triangle,102 // if the points are counter-clockwise we are looking at the "front". If not we are looking at103 // the back. OpenGL has an optimization where all back-facing triangles are culled, since they104 // usually represent the backside of an object and aren't visible anyways.105 106 // Front face107 -1.0f, 1.0f, 1.0f,108 -1.0f, -1.0f, 1.0f,109 1.0f, 1.0f, 1.0f,110 -1.0f, -1.0f, 1.0f,111 1.0f, -1.0f, 1.0f,112 1.0f, 1.0f, 1.0f,113 114 // Right face115 1.0f, 1.0f, 1.0f,116 1.0f, -1.0f, 1.0f,117 1.0f, 1.0f, -1.0f,118 1.0f, -1.0f, 1.0f,119 1.0f, -1.0f, -1.0f,120 1.0f, 1.0f, -1.0f,121 122 // Back face123 1.0f, 1.0f, -1.0f,124 1.0f, -1.0f, -1.0f,125 -1.0f, 1.0f, -1.0f,126 1.0f, -1.0f, -1.0f,127 -1.0f, -1.0f, -1.0f,128 -1.0f, 1.0f, -1.0f,129 130 // Left face131 -1.0f, 1.0f, -1.0f,132 -1.0f, -1.0f, -1.0f,133 -1.0f, 1.0f, 1.0f,134 -1.0f, -1.0f, -1.0f,135 -1.0f, -1.0f, 1.0f,136 -1.0f, 1.0f, 1.0f,137 138 // Top face139 -1.0f, 1.0f, -1.0f,140 -1.0f, 1.0f, 1.0f,141 1.0f, 1.0f, -1.0f,142 -1.0f, 1.0f, 1.0f,143 1.0f, 1.0f, 1.0f,144 1.0f, 1.0f, -1.0f,145 146 // Bottom face147 1.0f, -1.0f, -1.0f,148 1.0f, -1.0f, 1.0f,149 -1.0f, -1.0f, -1.0f,150 1.0f, -1.0f, 1.0f,151 -1.0f, -1.0f, 1.0f,152 -1.0f, -1.0f, -1.0f,153 };154 155 // R, G, B, A156 final float[] cubeColorData =157 {158 // Front face (red)159 1.0f, 0.0f, 0.0f, 1.0f,160 1.0f, 0.0f, 0.0f, 1.0f,161 1.0f, 0.0f, 0.0f, 1.0f,162 1.0f, 0.0f, 0.0f, 1.0f,163 1.0f, 0.0f, 0.0f, 1.0f,164 1.0f, 0.0f, 0.0f, 1.0f,165 166 // Right face (green)167 0.0f, 1.0f, 0.0f, 1.0f,168 0.0f, 1.0f, 0.0f, 1.0f,169 0.0f, 1.0f, 0.0f, 1.0f,170 0.0f, 1.0f, 0.0f, 1.0f,171 0.0f, 1.0f, 0.0f, 1.0f,172 0.0f, 1.0f, 0.0f, 1.0f,173 174 // Back face (blue)175 0.0f, 0.0f, 1.0f, 1.0f,176 0.0f, 0.0f, 1.0f, 1.0f,177 0.0f, 0.0f, 1.0f, 1.0f,178 0.0f, 0.0f, 1.0f, 1.0f,179 0.0f, 0.0f, 1.0f, 1.0f,180 0.0f, 0.0f, 1.0f, 1.0f,181 182 // Left face (yellow)183 1.0f, 1.0f, 0.0f, 1.0f,184 1.0f, 1.0f, 0.0f, 1.0f,185 1.0f, 1.0f, 0.0f, 1.0f,186 1.0f, 1.0f, 0.0f, 1.0f,187 1.0f, 1.0f, 0.0f, 1.0f,188 1.0f, 1.0f, 0.0f, 1.0f,189 190 // Top face (cyan)191 0.0f, 1.0f, 1.0f, 1.0f,192 0.0f, 1.0f, 1.0f, 1.0f,193 0.0f, 1.0f, 1.0f, 1.0f,194 0.0f, 1.0f, 1.0f, 1.0f,195 0.0f, 1.0f, 1.0f, 1.0f,196 0.0f, 1.0f, 1.0f, 1.0f,197 198 // Bottom face (magenta)199 1.0f, 0.0f, 1.0f, 1.0f,200 1.0f, 0.0f, 1.0f, 1.0f,201 1.0f, 0.0f, 1.0f, 1.0f,202 1.0f, 0.0f, 1.0f, 1.0f,203 1.0f, 0.0f, 1.0f, 1.0f,204 1.0f, 0.0f, 1.0f, 1.0f205 };206 207 // S, T (or X, Y)208 // Texture coordinate data.209 // Because images have a Y axis pointing downward (values increase as you move down the image) while210 // OpenGL has a Y axis pointing upward, we adjust for that here by flipping the Y axis.211 // What's more is that the texture coordinates are the same for every face.212 final float[] cubeTextureCoordinateData =213 {214 // Front face215 0.0f, 0.0f,216 0.0f, 1.0f,217 1.0f, 0.0f,218 0.0f, 1.0f,219 1.0f, 1.0f,220 1.0f, 0.0f,221 222 // Right face223 0.0f, 0.0f,224 0.0f, 1.0f,225 1.0f, 0.0f,226 0.0f, 1.0f,227 1.0f, 1.0f,228 1.0f, 0.0f,229 230 // Back face231 0.0f, 0.0f,232 0.0f, 1.0f,233 1.0f, 0.0f,234 0.0f, 1.0f,235 1.0f, 1.0f,236 1.0f, 0.0f,237 238 // Left face239 0.0f, 0.0f,240 0.0f, 1.0f,241 1.0f, 0.0f,242 0.0f, 1.0f,243 1.0f, 1.0f,244 1.0f, 0.0f,245 246 // Top face247 0.0f, 0.0f,248 0.0f, 1.0f,249 1.0f, 0.0f,250 0.0f, 1.0f,251 1.0f, 1.0f,252 1.0f, 0.0f,253 254 // Bottom face255 0.0f, 0.0f,256 0.0f, 1.0f,257 1.0f, 0.0f,258 0.0f, 1.0f,259 1.0f, 1.0f,260 1.0f, 0.0f261 };262 263 // Initialize the buffers.264 mCubePositions = ByteBuffer.allocateDirect(cubePositionData.length * mBytesPerFloat)265 .order(ByteOrder.nativeOrder()).asFloatBuffer();266 mCubePositions.put(cubePositionData).position(0);267 268 mCubeColors = ByteBuffer.allocateDirect(cubeColorData.length * mBytesPerFloat)269 .order(ByteOrder.nativeOrder()).asFloatBuffer();270 mCubeColors.put(cubeColorData).position(0);271 272 mCubeTextureCoordinates = ByteBuffer.allocateDirect(cubeTextureCoordinateData.length * mBytesPerFloat)273 .order(ByteOrder.nativeOrder()).asFloatBuffer();274 mCubeTextureCoordinates.put(cubeTextureCoordinateData).position(0);275 }276 277 protected String getVertexShader(int shader)278 {279 return ToolsUtil.readTextFileFromRawResource(mActivityContext, shader);280 }281 282 protected String getFragmentShader(int shader)283 {284 return ToolsUtil.readTextFileFromRawResource(mActivityContext, shader);285 }286 287 @Override288 public void onSurfaceCreated(GL10 glUnused, EGLConfig config)289 {290 // Set the background clear color to black.291 GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);292 293 // Use culling to remove back faces.294 GLES20.glEnable(GLES20.GL_CULL_FACE);295 296 // Enable depth testing297 GLES20.glEnable(GLES20.GL_DEPTH_TEST);298 299 // The below glEnable() call is a holdover from OpenGL ES 1, and is not needed in OpenGL ES 2.300 // Enable texture mapping301 GLES20.glEnable(GLES20.GL_TEXTURE_2D);302 303 // Position the eye in front of the origin.304 final float eyeX = 0.0f;305 final float eyeY = 0.0f;306 final float eyeZ = -0.5f;307 308 // We are looking toward the distance309 final float lookX = 0.0f;310 final float lookY = 0.0f;311 final float lookZ = -5.0f;312 313 // Set our up vector. This is where our head would be pointing were we holding the camera.314 final float upX = 0.0f;315 final float upY = 1.0f;316 final float upZ = 0.0f;317 318 // Set the view matrix. This matrix can be said to represent the camera position.319 // NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination of a model and320 // view matrix. In OpenGL 2, we can keep track of these matrices separately if we choose.321 Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);322 323 final String vertexShader = getVertexShader(R.raw.per_pixel_vertex_shader);324 final String fragmentShader = getFragmentShader(R.raw.per_pixel_fragment_shader);325 326 final int vertexShaderHandle = ToolsUtil.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader);327 final int fragmentShaderHandle = ToolsUtil.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);328 329 mProgramHandle = ToolsUtil.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle,330 new String[] {"a_Position", "a_Color", "a_TexCoordinate"});331 332 // Load the texture333 mTextureDataHandle = ToolsUtil.loadTexture(mActivityContext, R.drawable.aaa);334 }335 336 @Override337 public void onSurfaceChanged(GL10 glUnused, int width, int height)338 {339 // Set the OpenGL viewport to the same size as the surface.340 GLES20.glViewport(0, 0, width, height);341 342 // Create a new perspective projection matrix. The height will stay the same343 // while the width will vary as per aspect ratio.344 final float ratio = (float) width / height;345 final float left = -ratio;346 final float right = ratio;347 final float bottom = -1.0f;348 final float top = 1.0f;349 final float near = 1.0f;350 final float far = 10.0f;351 352 Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);353 }354 355 @Override356 public void onDrawFrame(GL10 glUnused)357 {358 IntBuffer framebuffer = IntBuffer.allocate(1);359 IntBuffer depthRenderbuffer = IntBuffer.allocate(1);360 IntBuffer texture = IntBuffer.allocate(1);361 int texWidth = 480, texHeight = 480;362 IntBuffer maxRenderbufferSize = IntBuffer.allocate(1);363 GLES20.glGetIntegerv(GLES20.GL_MAX_RENDERBUFFER_SIZE, maxRenderbufferSize);364 // check if GL_MAX_RENDERBUFFER_SIZE is >= texWidth and texHeight365 if((maxRenderbufferSize.get(0) <= texWidth) ||366 (maxRenderbufferSize.get(0) <= texHeight))367 {368 // cannot use framebuffer objects as we need to create369 // a depth buffer as a renderbuffer object370 // return with appropriate error371 }372 // generate the framebuffer, renderbuffer, and texture object names373 GLES20.glGenFramebuffers(1, framebuffer);374 GLES20.glGenRenderbuffers(1, depthRenderbuffer);375 GLES20.glGenTextures(1, texture);376 // bind texture and load the texture mip-level 0377 // texels are RGB565378 // no texels need to be specified as we are going to draw into379 // the texture380 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture.get(0));381 GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, texWidth, texHeight,382 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_SHORT_5_6_5, null);383 GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);384 GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);385 GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);386 GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);387 // bind renderbuffer and create a 16-bit depth buffer388 // width and height of renderbuffer = width and height of389 // the texture390 GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRenderbuffer.get(0));391 GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16,392 texWidth, texHeight);393 // bind the framebuffer394 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, framebuffer.get(0));395 // specify texture as color attachment396 GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,397 GLES20.GL_TEXTURE_2D, texture.get(0), 0);398 // specify depth_renderbufer as depth attachment399 GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT,400 GLES20.GL_RENDERBUFFER, depthRenderbuffer.get(0));401 // check for framebuffer complete402 int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);403 if(status == GLES20.GL_FRAMEBUFFER_COMPLETE)404 {405 // render to texture using FBO406 GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);407 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);408 409 // Do a complete rotation every 10 seconds.410 long time = SystemClock.uptimeMillis() % 10000L;411 float angleInDegrees = (360.0f / 10000.0f) * (2 * (int) time);412 413 GLES20.glUseProgram(mProgramHandle);414 415 // Set program handles for cube drawing.416 mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");417 mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVMatrix");418 mTextureUniformHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_Texture");419 mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");420 mColorHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Color");421 mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate");422 423 // Set the active texture unit to texture unit 0.424 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);425 426 // Bind the texture to this unit.427 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);428 429 // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.430 GLES20.glUniform1i(mTextureUniformHandle, 0);431 432 Matrix.setIdentityM(mModelMatrix, 0);433 Matrix.translateM(mModelMatrix, 0, 0.0f, -1.0f, -5.0f);434 Matrix.rotateM(mModelMatrix, 0, angleInDegrees, 1.0f, 1.0f, 0.0f);435 drawCube();436 437 // render to window system provided framebuffer438 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);439 GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);440 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);441 442 // Do a complete rotation every 10 seconds.443 time = SystemClock.uptimeMillis() % 10000L;444 angleInDegrees = (360.0f / 10000.0f) * ((int) time);445 446 GLES20.glUseProgram(mProgramHandle);447 448 // Set program handles for cube drawing.449 mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");450 mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVMatrix");451 mTextureUniformHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_Texture");452 mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");453 mColorHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Color");454 mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate");455 456 // Set the active texture unit to texture unit 0.457 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);458 459 // Bind the texture to this unit.460 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture.get(0)/*mTextureDataHandle*/);461 462 // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.463 GLES20.glUniform1i(mTextureUniformHandle, 0);464 465 Matrix.setIdentityM(mModelMatrix, 0);466 Matrix.translateM(mModelMatrix, 0, 0.0f, 0.0f, -5.0f);467 Matrix.rotateM(mModelMatrix, 0, angleInDegrees, 1.0f, 1.0f, 0.0f);468 drawCube();469 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);470 }471 472 // cleanup473 GLES20.glDeleteRenderbuffers(1, depthRenderbuffer);474 GLES20.glDeleteFramebuffers(1, framebuffer);475 GLES20.glDeleteTextures(1, texture);476 }477 478 /**479 * Draws a cube.480 */481 private void drawCube()482 {483 // Pass in the position information484 mCubePositions.position(0);485 GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false,486 0, mCubePositions);487 488 GLES20.glEnableVertexAttribArray(mPositionHandle);489 490 // Pass in the color information491 mCubeColors.position(0);492 GLES20.glVertexAttribPointer(mColorHandle, mColorDataSize, GLES20.GL_FLOAT, false,493 0, mCubeColors);494 GLES20.glEnableVertexAttribArray(mColorHandle);495 496 // Pass in the texture coordinate information497 mCubeTextureCoordinates.position(0);498 GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false,499 0, mCubeTextureCoordinates);500 501 GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);502 503 // This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix504 // (which currently contains model * view).505 Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);506 507 // Pass in the modelview matrix.508 GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0);509 510 // This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix511 // (which now contains model * view * projection).512 Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);513 514 // Pass in the combined matrix.515 GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);516 517 // Draw the cube.518 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 36);519 }520 }
还有一个辅助类,ToolsUtil.java:
1 package com.android.jayce.test; 2 3 import android.content.Context; 4 import android.graphics.Bitmap; 5 import android.graphics.BitmapFactory; 6 import android.opengl.GLES20; 7 import android.opengl.GLUtils; 8 import android.util.Log; 9 10 import java.io.BufferedReader; 11 import java.io.IOException; 12 import java.io.InputStream; 13 import java.io.InputStreamReader; 14 15 public class ToolsUtil 16 { 17 public static int loadTexture(final Context context, final int resourceId) 18 { 19 final int[] textureHandle = new int[1]; 20 GLES20.glGenTextures(1, textureHandle, 0); 21 22 if(textureHandle[0] != 0) 23 { 24 final BitmapFactory.Options options = new BitmapFactory.Options(); 25 options.inScaled = false; 26 27 final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options); 28 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]); 29 30 GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 31 GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); 32 33 GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 34 bitmap.recycle(); 35 } 36 37 if(textureHandle[0] == 0) 38 { 39 throw new RuntimeException("failed to load texture"); 40 } 41 42 return textureHandle[0]; 43 } 44 45 /** 46 * Helper function to compile a shader. 47 * 48 * @param shaderType The shader type. 49 * @param shaderSource The shader source code. 50 * @return An OpenGL handle to the shader. 51 */ 52 public static int compileShader(final int shaderType, final String shaderSource) 53 { 54 int shaderHandle = GLES20.glCreateShader(shaderType); 55 56 if (shaderHandle != 0) 57 { 58 // Pass in the shader source. 59 GLES20.glShaderSource(shaderHandle, shaderSource); 60 61 // Compile the shader. 62 GLES20.glCompileShader(shaderHandle); 63 64 // Get the compilation status. 65 final int[] compileStatus = new int[1]; 66 GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 67 68 // If the compilation failed, delete the shader. 69 if (compileStatus[0] == 0) 70 { 71 GLES20.glDeleteShader(shaderHandle); 72 shaderHandle = 0; 73 } 74 } 75 76 if (shaderHandle == 0) 77 { 78 throw new RuntimeException("Error creating shader."); 79 } 80 81 return shaderHandle; 82 } 83 84 /** 85 * Helper function to compile and link a program. 86 * 87 * @param vertexShaderHandle An OpenGL handle to an already-compiled vertex shader. 88 * @param fragmentShaderHandle An OpenGL handle to an already-compiled fragment shader. 89 * @param attributes Attributes that need to be bound to the program. 90 * @return An OpenGL handle to the program. 91 */ 92 public static int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes) 93 { 94 int programHandle = GLES20.glCreateProgram(); 95 96 if (programHandle != 0) 97 { 98 // Bind the vertex shader to the program. 99 GLES20.glAttachShader(programHandle, vertexShaderHandle);100 101 // Bind the fragment shader to the program.102 GLES20.glAttachShader(programHandle, fragmentShaderHandle);103 104 // Bind attributes105 if (attributes != null)106 {107 final int size = attributes.length;108 for (int i = 0; i < size; i++)109 {110 GLES20.glBindAttribLocation(programHandle, i, attributes[i]);111 }112 }113 114 // Link the two shaders together into a program.115 GLES20.glLinkProgram(programHandle);116 117 // Get the link status.118 final int[] linkStatus = new int[1];119 GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);120 121 // If the link failed, delete the program.122 if (linkStatus[0] == 0)123 {124 GLES20.glDeleteProgram(programHandle);125 programHandle = 0;126 }127 }128 129 if (programHandle == 0)130 {131 throw new RuntimeException("Error creating program.");132 }133 134 return programHandle;135 }136 137 public static String readTextFileFromRawResource(final Context context,138 final int resourceId)139 {140 final InputStream inputStream = context.getResources().openRawResource(141 resourceId);142 final InputStreamReader inputStreamReader = new InputStreamReader(143 inputStream);144 final BufferedReader bufferedReader = new BufferedReader(145 inputStreamReader);146 147 String nextLine;148 final StringBuilder body = new StringBuilder();149 150 try151 {152 while ((nextLine = bufferedReader.readLine()) != null)153 {154 body.append(nextLine);155 body.append('\n');156 }157 }158 catch (IOException e)159 {160 return null;161 }162 163 return body.toString();164 }165 166 }
使用的shader, per_pixel_vertex_shader.glsl:
1 uniform mat4 u_MVPMatrix; // A constant representing the combined model/view/projection matrix. 2 uniform mat4 u_MVMatrix; // A constant representing the combined model/view matrix. 3 4 attribute vec4 a_Position; // Per-vertex position information we will pass in. 5 attribute vec4 a_Color; // Per-vertex color information we will pass in. 6 attribute vec2 a_TexCoordinate; // Per-vertex texture coordinate information we will pass in. 7 8 varying vec3 v_Position; // This will be passed into the fragment shader. 9 varying vec4 v_Color; // This will be passed into the fragment shader. 10 varying vec2 v_TexCoordinate; // This will be passed into the fragment shader. 11 12 // The entry point for our vertex shader. 13 void main() 14 { 15 // Transform the vertex into eye space. 16 v_Position = vec3(u_MVMatrix * a_Position); 17 18 // Pass through the color.19 v_Color = a_Color;20 21 // Pass through the texture coordinate.22 v_TexCoordinate = a_TexCoordinate; 23 24 // gl_Position is a special variable used to store the final position.25 // Multiply the vertex by the matrix to get the final point in normalized screen coordinates.26 gl_Position = u_MVPMatrix * a_Position; 27 }
使用的shader, per_pixel_fragment_shader.glsl:
1 precision mediump float; // Set the default precision to medium. We don't need as high of a 2 // precision in the fragment shader. 3 uniform sampler2D u_Texture; // The input texture. 4 5 varying vec3 v_Position; // Interpolated position for this fragment. 6 varying vec4 v_Color; // This is the color from the vertex shader interpolated across the 7 varying vec2 v_TexCoordinate; // Interpolated texture coordinate per fragment. 8 9 // The entry point for our fragment shader.10 void main() 11 { 12 // Multiply the color by the diffuse illumination level and texture value to get final output color.13 gl_FragColor = (v_Color * texture2D(u_Texture, v_TexCoordinate)); 14 }
好了,就这么多了,可以看到旋转立方体每一面的texture都是用的自己创建的framebuffer render的texture,每面都有一个旋转的立方体。
看看效果图吧:
更多相关文章
- Android(安卓)通知流程
- Android(安卓)Camera 二 JNI JAVA和C/CPP图像数据传输流程分析
- Android中 一些维持状态的经验
- Android(安卓)UI绘制流程之测量篇
- Android系统启动流程 -3
- Android(安卓)系统启动流程总结
- Android(安卓)Zxing 扫描条码实现竖屏模式(portrait mode) 摄像
- Android可平移缩放旋转的ImageView的实现
- android jni开发流程