JayceLi  

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 at
103                 // the back. OpenGL has an optimization where all back-facing triangles are culled, since they
104                 // usually represent the backside of an object and aren't visible anyways.
105 
106                 // Front face
107                 -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 face
115                 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 face
123                 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 face
131                 -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 face
139                 -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 face
147                 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, A
156         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.0f
205         };
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) while
210         // 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 face
215                 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 face
223                 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 face
231                 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 face
239                 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 face
247                 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 face
255                 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.0f
261         };
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     @Override
288     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 testing
297         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 mapping
301         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 distance
309         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 and
320         // 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 texture
333         mTextureDataHandle = ToolsUtil.loadTexture(mActivityContext, R.drawable.aaa);
334     }
335 
336     @Override
337     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 same
343         // 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     @Override
356     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 texHeight
365         if((maxRenderbufferSize.get(0) <= texWidth) ||
366         (maxRenderbufferSize.get(0) <= texHeight))
367         {
368         // cannot use framebuffer objects as we need to create
369         // a depth buffer as a renderbuffer object
370         // return with appropriate error
371         }
372         // generate the framebuffer, renderbuffer, and texture object names
373         GLES20.glGenFramebuffers(1, framebuffer);
374         GLES20.glGenRenderbuffers(1, depthRenderbuffer);
375         GLES20.glGenTextures(1, texture);
376         // bind texture and load the texture mip-level 0
377         // texels are RGB565
378         // no texels need to be specified as we are going to draw into
379         // the texture
380         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 buffer
388         // width and height of renderbuffer = width and height of
389         // the texture
390         GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRenderbuffer.get(0));
391         GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16,
392         texWidth, texHeight);
393         // bind the framebuffer
394         GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, framebuffer.get(0));
395         // specify texture as color attachment
396         GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
397                 GLES20.GL_TEXTURE_2D, texture.get(0), 0);
398         // specify depth_renderbufer as depth attachment
399         GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT,
400                 GLES20.GL_RENDERBUFFER, depthRenderbuffer.get(0));
401         // check for framebuffer complete
402         int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
403         if(status == GLES20.GL_FRAMEBUFFER_COMPLETE)
404         {
405             // render to texture using FBO
406             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 framebuffer
438             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         // cleanup
473         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 information
484         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 information
491         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 information
497         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 matrix
504         // (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 matrix
511         // (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 attributes
105              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          try
151          {
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,每面都有一个旋转的立方体。

看看效果图吧:

 

 

posted on 2013-04-08 17:27  JayceLi  阅读(8640)  评论(1编辑  收藏  举报