Android OpenGL ES 2.0 (五) 添加材质

还是一个旋转的立方体,现在给它加上材质。载入一个图片,立方体的每一面都贴上此图片。

现在相较第二篇画的立方体,又多了个参数材质。先看看载入图片的方法。

这是个辅助方法。单独写了个类。

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 
 9 public class ToolsUtil
10 {
11     public static int loadTexture(final Context context, final int resourceId)
12     {
13         final int[] textureHandle = new int[1];
14         GLES20.glGenTextures(1, textureHandle, 0);
15         
16         if(textureHandle[0] != 0)
17         {
18             final BitmapFactory.Options options = new BitmapFactory.Options();
19             options.inScaled = false;
20             
21             final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
22             GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
23             
24             GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
25             GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
26             
27             GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
28             bitmap.recycle();
29         }
30         
31         if(textureHandle[0] == 0)
32         {
33             throw new RuntimeException("failed to load texture");
34         }
35         
36         return textureHandle[0];
37     }
38 }

在Renderer里多了材质坐标,mCubeTextureCoordinates。

在fragmentShader里,颜色计算变成了gl_FragColor = v_Color * texture2D(u_Texture, v_TexCoordinate)。

看Renderer的实现:

Test5Renderer.java

  1 package com.android.jayce.test;
  2 
  3 import java.nio.ByteBuffer;
  4 import java.nio.ByteOrder;
  5 import java.nio.FloatBuffer;
  6 
  7 import javax.microedition.khronos.egl.EGLConfig;
  8 import javax.microedition.khronos.opengles.GL10;
  9 
 10 import com.learnopengles.android.R;
 11 
 12 import android.content.Context;
 13 import android.opengl.GLES20;
 14 import android.opengl.Matrix;
 15 import android.opengl.GLSurfaceView;
 16 import android.os.SystemClock;
 17 import android.util.Log;
 18 
 19 public class Test5Renderer implements GLSurfaceView.Renderer
 20 {
 21     private static final String TAG = "Test5Renderer";
 22     private Context mContext;
 23     private static final int BYTES_PER_FLOAT = 4;
 24     private final FloatBuffer mCubePositions;
 25     private final FloatBuffer mCubeColors;
 26     private final FloatBuffer mCubeTextureCoordinates;
 27     private float[] mMVPMatrix = new float[16];
 28     private float[] mViewMatrix = new float[16];
 29     private float[] mModelMatrix = new float[16];
 30     private float[] mProjectionMatrix = new float[16];
 31     private int mMVPMatrixHandle;
 32     private int mPositionHandle;
 33     private int mColorHandle;
 34     private int mTextureUniformHandle;
 35     private int mTextureCoordinateHandle;
 36     private int mTextureDataHandle;
 37     private int mProgramHandle;
 38     private final int POSITION_DATA_SIZE = 3;
 39     private final int COLOR_DATA_SIZE = 4;
 40     private final int TEXTURE_COORDINATE_DATA_SIZE = 2;
 41     
 42     public Test5Renderer(final Context context)
 43     {
 44         mContext = context;
 45         final float cubePosition[] = 
 46         {
 47                 // Front face
 48                 -1.0f, 1.0f, 1.0f,                
 49                 -1.0f, -1.0f, 1.0f,
 50                 1.0f, 1.0f, 1.0f, 
 51                 -1.0f, -1.0f, 1.0f,                 
 52                 1.0f, -1.0f, 1.0f,
 53                 1.0f, 1.0f, 1.0f,
 54                 
 55                 // Right face
 56                 1.0f, 1.0f, 1.0f,                
 57                 1.0f, -1.0f, 1.0f,
 58                 1.0f, 1.0f, -1.0f,
 59                 1.0f, -1.0f, 1.0f,                
 60                 1.0f, -1.0f, -1.0f,
 61                 1.0f, 1.0f, -1.0f,
 62                 
 63                 // Back face
 64                 1.0f, 1.0f, -1.0f,                
 65                 1.0f, -1.0f, -1.0f,
 66                 -1.0f, 1.0f, -1.0f,
 67                 1.0f, -1.0f, -1.0f,                
 68                 -1.0f, -1.0f, -1.0f,
 69                 -1.0f, 1.0f, -1.0f,
 70                 
 71                 // Left face
 72                 -1.0f, 1.0f, -1.0f,                
 73                 -1.0f, -1.0f, -1.0f,
 74                 -1.0f, 1.0f, 1.0f, 
 75                 -1.0f, -1.0f, -1.0f,                
 76                 -1.0f, -1.0f, 1.0f, 
 77                 -1.0f, 1.0f, 1.0f, 
 78                 
 79                 // Top face
 80                 -1.0f, 1.0f, -1.0f,                
 81                 -1.0f, 1.0f, 1.0f, 
 82                 1.0f, 1.0f, -1.0f, 
 83                 -1.0f, 1.0f, 1.0f,                 
 84                 1.0f, 1.0f, 1.0f, 
 85                 1.0f, 1.0f, -1.0f,
 86                 
 87                 // Bottom face
 88                 1.0f, -1.0f, -1.0f,                
 89                 1.0f, -1.0f, 1.0f, 
 90                 -1.0f, -1.0f, -1.0f,
 91                 1.0f, -1.0f, 1.0f,                 
 92                 -1.0f, -1.0f, 1.0f,
 93                 -1.0f, -1.0f, -1.0f,    
 94         };
 95         
 96         final float[] cubeColor = 
 97         {
 98                 // Front face (red)
 99                 1.0f, 0.0f, 0.0f, 1.0f,                
100                 1.0f, 0.0f, 0.0f, 1.0f,
101                 1.0f, 0.0f, 0.0f, 1.0f,
102                 1.0f, 0.0f, 0.0f, 1.0f,                
103                 1.0f, 0.0f, 0.0f, 1.0f,
104                 1.0f, 0.0f, 0.0f, 1.0f,
105                 
106                 // Right face (green)
107                 0.0f, 1.0f, 0.0f, 1.0f,                
108                 0.0f, 1.0f, 0.0f, 1.0f,
109                 0.0f, 1.0f, 0.0f, 1.0f,
110                 0.0f, 1.0f, 0.0f, 1.0f,                
111                 0.0f, 1.0f, 0.0f, 1.0f,
112                 0.0f, 1.0f, 0.0f, 1.0f,
113                 
114                 // Back face (blue)
115                 0.0f, 0.0f, 1.0f, 1.0f,                
116                 0.0f, 0.0f, 1.0f, 1.0f,
117                 0.0f, 0.0f, 1.0f, 1.0f,
118                 0.0f, 0.0f, 1.0f, 1.0f,                
119                 0.0f, 0.0f, 1.0f, 1.0f,
120                 0.0f, 0.0f, 1.0f, 1.0f,
121                 
122                 // Left face (yellow)
123                 1.0f, 1.0f, 0.0f, 1.0f,                
124                 1.0f, 1.0f, 0.0f, 1.0f,
125                 1.0f, 1.0f, 0.0f, 1.0f,
126                 1.0f, 1.0f, 0.0f, 1.0f,                
127                 1.0f, 1.0f, 0.0f, 1.0f,
128                 1.0f, 1.0f, 0.0f, 1.0f,
129                 
130                 // Top face (cyan)
131                 0.0f, 1.0f, 1.0f, 1.0f,                
132                 0.0f, 1.0f, 1.0f, 1.0f,
133                 0.0f, 1.0f, 1.0f, 1.0f,
134                 0.0f, 1.0f, 1.0f, 1.0f,                
135                 0.0f, 1.0f, 1.0f, 1.0f,
136                 0.0f, 1.0f, 1.0f, 1.0f,
137                 
138                 // Bottom face (magenta)
139                 1.0f, 0.0f, 1.0f, 1.0f,                
140                 1.0f, 0.0f, 1.0f, 1.0f,
141                 1.0f, 0.0f, 1.0f, 1.0f,
142                 1.0f, 0.0f, 1.0f, 1.0f,                
143                 1.0f, 0.0f, 1.0f, 1.0f,
144                 1.0f, 0.0f, 1.0f, 1.0f    
145         };
146         
147         final float[] cubeTextureCoordinate =
148             {                                                
149                     // Front face
150                     0.0f, 0.0f,                 
151                     0.0f, 1.0f,
152                     1.0f, 0.0f,
153                     0.0f, 1.0f,
154                     1.0f, 1.0f,
155                     1.0f, 0.0f,                
156                     
157                     // Right face 
158                     0.0f, 0.0f,                 
159                     0.0f, 1.0f,
160                     1.0f, 0.0f,
161                     0.0f, 1.0f,
162                     1.0f, 1.0f,
163                     1.0f, 0.0f,    
164                     
165                     // Back face 
166                     0.0f, 0.0f,                 
167                     0.0f, 1.0f,
168                     1.0f, 0.0f,
169                     0.0f, 1.0f,
170                     1.0f, 1.0f,
171                     1.0f, 0.0f,    
172                     
173                     // Left face 
174                     0.0f, 0.0f,                 
175                     0.0f, 1.0f,
176                     1.0f, 0.0f,
177                     0.0f, 1.0f,
178                     1.0f, 1.0f,
179                     1.0f, 0.0f,    
180                     
181                     // Top face 
182                     0.0f, 0.0f,                 
183                     0.0f, 1.0f,
184                     1.0f, 0.0f,
185                     0.0f, 1.0f,
186                     1.0f, 1.0f,
187                     1.0f, 0.0f,    
188                     
189                     // Bottom face 
190                     0.0f, 0.0f,                 
191                     0.0f, 1.0f,
192                     1.0f, 0.0f,
193                     0.0f, 1.0f,
194                     1.0f, 1.0f,
195                     1.0f, 0.0f
196             };
197         
198         mCubePositions = ByteBuffer.allocateDirect(cubePosition.length * BYTES_PER_FLOAT)
199                 .order(ByteOrder.nativeOrder()).asFloatBuffer();
200         mCubePositions.put(cubePosition).position(0);
201         mCubeColors = ByteBuffer.allocateDirect(cubeColor.length * BYTES_PER_FLOAT)
202                 .order(ByteOrder.nativeOrder()).asFloatBuffer();
203         mCubeColors.put(cubeColor).position(0);
204         mCubeTextureCoordinates = ByteBuffer.allocateDirect(cubeTextureCoordinate.length * BYTES_PER_FLOAT)
205                 .order(ByteOrder.nativeOrder()).asFloatBuffer();
206         mCubeTextureCoordinates.put(cubeTextureCoordinate).position(0);
207     }
208     
209     @Override
210     public void onDrawFrame(GL10 gl) {
211         // TODO Auto-generated method stub
212         GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
213         long time = SystemClock.uptimeMillis() % 10000L;        
214         float angleInDegrees = (360.0f / 10000.0f) * ((int) time);
215         GLES20.glUseProgram(mProgramHandle);
216         mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
217         mTextureUniformHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_Texture");
218         mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");
219         mColorHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Color");
220         mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate");
221         
222         GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
223         GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
224         GLES20.glUniform1i(mTextureUniformHandle, 0);
225         
226         Matrix.setIdentityM(mModelMatrix, 0);
227         Matrix.translateM(mModelMatrix, 0, 0.0f, 0.0f, -5.0f);
228         Matrix.rotateM(mModelMatrix, 0, angleInDegrees, 1.0f, 1.0f, 0.0f);   
229         drawCube(mCubePositions, mCubeColors, mCubeTextureCoordinates);
230     }
231 
232     private void drawCube(final FloatBuffer cubePositionsBuffer, final FloatBuffer cubeColorsBuffer, final FloatBuffer cubeTextureCoordinatesBuffer)
233     {
234         cubePositionsBuffer.position(0);
235         GLES20.glVertexAttribPointer(mPositionHandle, POSITION_DATA_SIZE, GLES20.GL_FLOAT, false, 0, cubePositionsBuffer);
236         GLES20.glEnableVertexAttribArray(mPositionHandle);
237         
238         cubeColorsBuffer.position(0);
239         GLES20.glVertexAttribPointer(mColorHandle, COLOR_DATA_SIZE, GLES20.GL_FLOAT, false, 0, cubeColorsBuffer);
240         GLES20.glEnableVertexAttribArray(mColorHandle);
241         
242         cubeTextureCoordinatesBuffer.position(0);
243         GLES20.glVertexAttribPointer(mTextureCoordinateHandle, TEXTURE_COORDINATE_DATA_SIZE, 
244                 GLES20.GL_FLOAT, false, 0, cubeTextureCoordinatesBuffer);
245         GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
246         
247         Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);   
248         Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
249         GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
250         GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 36);
251     }
252     
253     @Override
254     public void onSurfaceChanged(GL10 gl, int width, int height) {
255         // TODO Auto-generated method stub
256         GLES20.glViewport(0, 0, width, height);
257         
258         final float ratio = (float) width / height;
259         final float left = -ratio;
260         final float right = ratio;
261         final float bottom = -1.0f;
262         final float top = 1.0f;
263         final float near = 1.0f;
264         final float far = 10.0f;
265         
266         Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
267     }
268 
269     @Override
270     public void onSurfaceCreated(GL10 gl, EGLConfig config) {
271         // TODO Auto-generated method stub
272         GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
273         GLES20.glEnable(GLES20.GL_CULL_FACE);
274         GLES20.glEnable(GLES20.GL_DEPTH_TEST);
275         // Position the eye behind the origin.
276         final float eyeX = 0.0f;
277         final float eyeY = 0.0f;
278         final float eyeZ = -0.5f;
279 
280         // We are looking toward the distance
281         final float lookX = 0.0f;
282         final float lookY = 0.0f;
283         final float lookZ = -5.0f;
284 
285         // Set our up vector. This is where our head would be pointing were we holding the camera.
286         final float upX = 0.0f;
287         final float upY = 1.0f;
288         final float upZ = 0.0f;
289 
290         // Set the view matrix. This matrix can be said to represent the camera position.
291         // NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination of a model and
292         // view matrix. In OpenGL 2, we can keep track of these matrices separately if we choose.
293         Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
294         
295         final String vertexShader = getVertexShader();
296         final String fragmentShader = getFragmentShader();
297         
298         final int vertexShaderHandle = compileShader(GLES20.GL_VERTEX_SHADER, vertexShader);
299         final int fragmentShaderHandle = compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);
300         
301         mProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, 
302                 new String[]{"a_Position", "a_Color", "a_TexCoordinate"});
303         
304         mTextureDataHandle = ToolsUtil.loadTexture(mContext, R.drawable.bumpy_bricks_public_domain);
305         
306     }
307     
308     private String getVertexShader()
309     {
310         final String vertexShader =
311                 "uniform mat4 u_MVPMatrix;      \n"        // A constant representing the combined model/view/projection matrix.
312                 
313               + "attribute vec4 a_Position;     \n"        // Per-vertex position information we will pass in.
314               + "attribute vec4 a_Color;        \n"        // Per-vertex color information we will pass in.    
315               + "attribute vec2 a_TexCoordinate;\n"    // Per-vertex texture coordinate information we will pass in. 
316               
317               + "varying vec4 v_Color;          \n"        // This will be passed into the fragment shader.
318               + "varying vec2 v_TexCoordinate;  \n"     // This will be passed into the fragment shader.  
319               
320               + "void main()                    \n"        // The entry point for our vertex shader.
321               + "{                              \n"
322               + "   v_Color = a_Color;          \n"        // Pass the color through to the fragment shader. 
323                                                           // It will be interpolated across the triangle.
324               + "   v_TexCoordinate = a_TexCoordinate;\n"// Pass through the texture coordinate.
325               + "   gl_Position = u_MVPMatrix   \n"     // gl_Position is a special variable used to store the final position.
326               + "               * a_Position;   \n"     // Multiply the vertex by the matrix to get the final point in                                                                      
327               + "}                              \n";    // normalized screen coordinates.                                                               \n"; 
328             
329         return vertexShader;    
330     }
331     
332     private String getFragmentShader()
333     {
334         final String fragmentShader =
335                 "precision mediump float;       \n"        // Set the default precision to medium. We don't need as high of a 
336                                                         // precision in the fragment shader.
337               + "uniform sampler2D u_Texture;   \n"     // The input texture.
338               + "varying vec4 v_Color;          \n"        // This is the color from the vertex shader interpolated across the 
339                                                           // triangle per fragment.    
340               + "varying vec2 v_TexCoordinate;  \n"     // Interpolated texture coordinate per fragment.
341               
342               + "void main()                    \n"        // The entry point for our fragment shader.
343               + "{                              \n"
344               + "   gl_FragColor = v_Color * texture2D(u_Texture, v_TexCoordinate);     \n"        // Pass the color directly through the pipeline.          
345               + "}                              \n";
346             
347         return fragmentShader;        
348     }
349     
350     private int compileShader(final int shaderType, final String shaderSource)
351     {
352         int shaderHandle = GLES20.glCreateShader(shaderType);
353 
354         if (shaderHandle != 0) 
355         {
356             GLES20.glShaderSource(shaderHandle, shaderSource);
357             GLES20.glCompileShader(shaderHandle);
358 
359             final int[] compileStatus = new int[1];
360             GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
361 
362             if (compileStatus[0] == 0) 
363             {
364                 Log.e(TAG, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shaderHandle));
365                 GLES20.glDeleteShader(shaderHandle);
366                 shaderHandle = 0;
367             }
368         }
369 
370         if (shaderHandle == 0)
371         {            
372             throw new RuntimeException("Error creating shader.");
373         }
374         
375         return shaderHandle;
376     }
377     
378     private int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes) 
379     {
380         int programHandle = GLES20.glCreateProgram();
381         
382         if (programHandle != 0) 
383         {
384             GLES20.glAttachShader(programHandle, vertexShaderHandle);            
385             GLES20.glAttachShader(programHandle, fragmentShaderHandle);
386             
387             if (attributes != null)
388             {
389                 final int size = attributes.length;
390                 for (int i = 0; i < size; i++)
391                 {
392                     GLES20.glBindAttribLocation(programHandle, i, attributes[i]);
393                 }                        
394             }
395             
396             GLES20.glLinkProgram(programHandle);
397 
398             final int[] linkStatus = new int[1];
399             GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
400 
401             if (linkStatus[0] == 0) 
402             {                
403                 Log.e(TAG, "Error compiling program: " + GLES20.glGetProgramInfoLog(programHandle));
404                 GLES20.glDeleteProgram(programHandle);
405                 programHandle = 0;
406             }
407         }
408         
409         if (programHandle == 0)
410         {
411             throw new RuntimeException("Error creating program.");
412         }
413         
414         return programHandle;
415     }
416     
417 }

在Activity里初始化Renderer时要加参数context.

看效果图:

原文地址:https://www.cnblogs.com/jayceli/p/2475559.html