JayceLi  

画完立方体后,在立方体旁边加了一个灯光point light,也加上了旋转效果。

这里新加了normal data,用来作光计算的。

这里用的是per vertex lighting,所以光移动到立方体顶点位置的时候,可以看到,立方体平面的对边顶点沿线周围部分会特别亮。

对光的计算都在物体的vertex shader里。

Test3Renderer.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 android.opengl.GLES20;
 11 import android.opengl.Matrix;
 12 import android.opengl.GLSurfaceView;
 13 import android.os.SystemClock;
 14 import android.util.Log;
 15 
 16 public class Test3Renderer implements GLSurfaceView.Renderer
 17 {
 18     private static final String TAG = "Test3Renderer";
 19     private static final int BYTES_PER_FLOAT = 4;
 20     private final FloatBuffer mCubePositions;
 21     private final FloatBuffer mCubeColors;
 22     private final FloatBuffer mCubeNormals;
 23     
 24     private float[] mMVPMatrix = new float[16];
 25     private float[] mViewMatrix = new float[16];
 26     private float[] mModelMatrix = new float[16];
 27     private float[] mProjectionMatrix = new float[16];
 28     private float[] mLightModelMatrix = new float[16];
 29     
 30     private final float[] mLightPosInModelSpace = new float[] {0.0f, 0.0f, 0.0f, 1.0f};
 31     private final float[] mLightPosInWorldSpace = new float[4];
 32     private final float[] mLightPosInEyeSpace = new float[4];
 33     
 34     private int mMVPMatrixHandle;
 35     private int mMVMatrixHandle;
 36     private int mPositionHandle;
 37     private int mLightPosHandle;
 38     private int mColorHandle;
 39     private int mNormalHandle;
 40     private int mPerVertexProgramHandle;
 41     private int mPointProgramHandle;
 42     private final int POSITION_DATA_SIZE = 3;
 43     private final int COLOR_DATA_SIZE = 4;
 44     private final int NORMAL_DATA_SIZE = 3;
 45     
 46     public Test3Renderer()
 47     {
 48         final float cubePosition[] = 
 49         {
 50                 // Front face
 51                 -1.0f, 1.0f, 1.0f,                
 52                 -1.0f, -1.0f, 1.0f,
 53                 1.0f, 1.0f, 1.0f, 
 54                 -1.0f, -1.0f, 1.0f,                 
 55                 1.0f, -1.0f, 1.0f,
 56                 1.0f, 1.0f, 1.0f,
 57                 
 58                 // Right face
 59                 1.0f, 1.0f, 1.0f,                
 60                 1.0f, -1.0f, 1.0f,
 61                 1.0f, 1.0f, -1.0f,
 62                 1.0f, -1.0f, 1.0f,                
 63                 1.0f, -1.0f, -1.0f,
 64                 1.0f, 1.0f, -1.0f,
 65                 
 66                 // Back face
 67                 1.0f, 1.0f, -1.0f,                
 68                 1.0f, -1.0f, -1.0f,
 69                 -1.0f, 1.0f, -1.0f,
 70                 1.0f, -1.0f, -1.0f,                
 71                 -1.0f, -1.0f, -1.0f,
 72                 -1.0f, 1.0f, -1.0f,
 73                 
 74                 // Left face
 75                 -1.0f, 1.0f, -1.0f,                
 76                 -1.0f, -1.0f, -1.0f,
 77                 -1.0f, 1.0f, 1.0f, 
 78                 -1.0f, -1.0f, -1.0f,                
 79                 -1.0f, -1.0f, 1.0f, 
 80                 -1.0f, 1.0f, 1.0f, 
 81                 
 82                 // Top face
 83                 -1.0f, 1.0f, -1.0f,                
 84                 -1.0f, 1.0f, 1.0f, 
 85                 1.0f, 1.0f, -1.0f, 
 86                 -1.0f, 1.0f, 1.0f,                 
 87                 1.0f, 1.0f, 1.0f, 
 88                 1.0f, 1.0f, -1.0f,
 89                 
 90                 // Bottom face
 91                 1.0f, -1.0f, -1.0f,                
 92                 1.0f, -1.0f, 1.0f, 
 93                 -1.0f, -1.0f, -1.0f,
 94                 1.0f, -1.0f, 1.0f,                 
 95                 -1.0f, -1.0f, 1.0f,
 96                 -1.0f, -1.0f, -1.0f,    
 97         };
 98         
 99         final float[] cubeColor = 
100         {
101                 // Front face (red)
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                 1.0f, 0.0f, 0.0f, 1.0f,                
106                 1.0f, 0.0f, 0.0f, 1.0f,
107                 1.0f, 0.0f, 0.0f, 1.0f,
108                 
109                 // Right face (green)
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                 0.0f, 1.0f, 0.0f, 1.0f,                
114                 0.0f, 1.0f, 0.0f, 1.0f,
115                 0.0f, 1.0f, 0.0f, 1.0f,
116                 
117                 // Back face (blue)
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                 0.0f, 0.0f, 1.0f, 1.0f,                
122                 0.0f, 0.0f, 1.0f, 1.0f,
123                 0.0f, 0.0f, 1.0f, 1.0f,
124                 
125                 // Left face (yellow)
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                 1.0f, 1.0f, 0.0f, 1.0f,                
130                 1.0f, 1.0f, 0.0f, 1.0f,
131                 1.0f, 1.0f, 0.0f, 1.0f,
132                 
133                 // Top face (cyan)
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                 0.0f, 1.0f, 1.0f, 1.0f,                
138                 0.0f, 1.0f, 1.0f, 1.0f,
139                 0.0f, 1.0f, 1.0f, 1.0f,
140                 
141                 // Bottom face (magenta)
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                 1.0f, 0.0f, 1.0f, 1.0f,                
146                 1.0f, 0.0f, 1.0f, 1.0f,
147                 1.0f, 0.0f, 1.0f, 1.0f    
148         };
149         
150         final float[] cubeNormal =
151             {                                                
152                     // Front face
153                     0.0f, 0.0f, 1.0f,                
154                     0.0f, 0.0f, 1.0f,
155                     0.0f, 0.0f, 1.0f,
156                     0.0f, 0.0f, 1.0f,                
157                     0.0f, 0.0f, 1.0f,
158                     0.0f, 0.0f, 1.0f,
159                     
160                     // Right face 
161                     1.0f, 0.0f, 0.0f,                
162                     1.0f, 0.0f, 0.0f,
163                     1.0f, 0.0f, 0.0f,
164                     1.0f, 0.0f, 0.0f,                
165                     1.0f, 0.0f, 0.0f,
166                     1.0f, 0.0f, 0.0f,
167                     
168                     // Back face 
169                     0.0f, 0.0f, -1.0f,                
170                     0.0f, 0.0f, -1.0f,
171                     0.0f, 0.0f, -1.0f,
172                     0.0f, 0.0f, -1.0f,                
173                     0.0f, 0.0f, -1.0f,
174                     0.0f, 0.0f, -1.0f,
175                     
176                     // Left face 
177                     -1.0f, 0.0f, 0.0f,                
178                     -1.0f, 0.0f, 0.0f,
179                     -1.0f, 0.0f, 0.0f,
180                     -1.0f, 0.0f, 0.0f,                
181                     -1.0f, 0.0f, 0.0f,
182                     -1.0f, 0.0f, 0.0f,
183                     
184                     // Top face 
185                     0.0f, 1.0f, 0.0f,            
186                     0.0f, 1.0f, 0.0f,
187                     0.0f, 1.0f, 0.0f,
188                     0.0f, 1.0f, 0.0f,                
189                     0.0f, 1.0f, 0.0f,
190                     0.0f, 1.0f, 0.0f,
191                     
192                     // Bottom face 
193                     0.0f, -1.0f, 0.0f,            
194                     0.0f, -1.0f, 0.0f,
195                     0.0f, -1.0f, 0.0f,
196                     0.0f, -1.0f, 0.0f,                
197                     0.0f, -1.0f, 0.0f,
198                     0.0f, -1.0f, 0.0f
199             };
200         
201         mCubePositions = ByteBuffer.allocateDirect(cubePosition.length * BYTES_PER_FLOAT)
202                 .order(ByteOrder.nativeOrder()).asFloatBuffer();
203         mCubePositions.put(cubePosition).position(0);
204         mCubeColors = ByteBuffer.allocateDirect(cubeColor.length * BYTES_PER_FLOAT)
205                 .order(ByteOrder.nativeOrder()).asFloatBuffer();
206         mCubeColors.put(cubeColor).position(0);
207         mCubeNormals = ByteBuffer.allocateDirect(cubeNormal.length * BYTES_PER_FLOAT)
208                 .order(ByteOrder.nativeOrder()).asFloatBuffer();
209         mCubeNormals.put(cubeNormal).position(0);
210     }
211     
212     @Override
213     public void onDrawFrame(GL10 gl) {
214         // TODO Auto-generated method stub
215         GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
216         long time = SystemClock.uptimeMillis() % 10000L;        
217         float angleInDegrees = (360.0f / 10000.0f) * ((int) time);
218         
219         GLES20.glUseProgram(mPerVertexProgramHandle);
220         mMVPMatrixHandle = GLES20.glGetUniformLocation(mPerVertexProgramHandle, "u_MVPMatrix");
221         mPositionHandle = GLES20.glGetAttribLocation(mPerVertexProgramHandle, "a_Position");
222         mMVMatrixHandle = GLES20.glGetUniformLocation(mPerVertexProgramHandle, "u_MVMatrix"); 
223         mLightPosHandle = GLES20.glGetUniformLocation(mPerVertexProgramHandle, "u_LightPos");
224         mColorHandle = GLES20.glGetAttribLocation(mPerVertexProgramHandle, "a_Color");
225         mNormalHandle = GLES20.glGetAttribLocation(mPerVertexProgramHandle, "a_Normal"); 
226         
227         Matrix.setIdentityM(mLightModelMatrix, 0);
228         Matrix.translateM(mLightModelMatrix, 0, 0.0f, 0.0f, -5.0f);      
229         Matrix.rotateM(mLightModelMatrix, 0, angleInDegrees, 0.0f, 1.0f, 0.0f);
230         Matrix.translateM(mLightModelMatrix, 0, 0.0f, 0.0f, 2.0f);
231                
232         Matrix.multiplyMV(mLightPosInWorldSpace, 0, mLightModelMatrix, 0, mLightPosInModelSpace, 0);
233         Matrix.multiplyMV(mLightPosInEyeSpace, 0, mViewMatrix, 0, mLightPosInWorldSpace, 0); 
234         
235         Matrix.setIdentityM(mModelMatrix, 0);
236         Matrix.translateM(mModelMatrix, 0, 0.0f, 0.0f, -5.0f);
237         Matrix.rotateM(mModelMatrix, 0, angleInDegrees, 1.0f, 1.0f, 0.0f);   
238         drawCube(mCubePositions, mCubeColors, mCubeNormals);
239         
240         GLES20.glUseProgram(mPointProgramHandle);
241         drawLight();
242     }
243 
244     private void drawCube(final FloatBuffer cubePositionsBuffer, final FloatBuffer cubeColorsBuffer,final FloatBuffer cubeNormalsBuffer)
245     {
246         cubePositionsBuffer.position(0);
247         GLES20.glVertexAttribPointer(mPositionHandle, POSITION_DATA_SIZE, GLES20.GL_FLOAT, false, 0, cubePositionsBuffer);
248         GLES20.glEnableVertexAttribArray(mPositionHandle);
249         
250         cubeColorsBuffer.position(0);
251         GLES20.glVertexAttribPointer(mColorHandle, COLOR_DATA_SIZE, GLES20.GL_FLOAT, false, 0, cubeColorsBuffer);
252         GLES20.glEnableVertexAttribArray(mColorHandle);
253         
254         cubeNormalsBuffer.position(0);
255         GLES20.glVertexAttribPointer(mNormalHandle, NORMAL_DATA_SIZE, GLES20.GL_FLOAT, false, 0, cubeNormalsBuffer);
256         GLES20.glEnableVertexAttribArray(mNormalHandle);
257         
258         Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);   
259         GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0); 
260         
261         Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
262         GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
263         
264         GLES20.glUniform3f(mLightPosHandle, mLightPosInEyeSpace[0], mLightPosInEyeSpace[1], mLightPosInEyeSpace[2]);
265         
266         GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 36);
267     }
268     
269     private void drawLight()
270     {
271         final int pointMVPMatrixHandle = GLES20.glGetUniformLocation(mPointProgramHandle, "u_MVPMatrix");
272         final int pointPositionHandle = GLES20.glGetAttribLocation(mPointProgramHandle, "a_Position");
273         
274         GLES20.glVertexAttrib3f(pointPositionHandle, mLightPosInModelSpace[0], mLightPosInModelSpace[1], mLightPosInModelSpace[2]);
275         GLES20.glDisableVertexAttribArray(pointPositionHandle); 
276         
277         Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mLightModelMatrix, 0);
278         Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
279         GLES20.glUniformMatrix4fv(pointMVPMatrixHandle, 1, false, mMVPMatrix, 0);
280         
281         GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 1);
282     }
283     
284     @Override
285     public void onSurfaceChanged(GL10 gl, int width, int height) {
286         // TODO Auto-generated method stub
287         GLES20.glViewport(0, 0, width, height);
288         
289         final float ratio = (float) width / height;
290         final float left = -ratio;
291         final float right = ratio;
292         final float bottom = -1.0f;
293         final float top = 1.0f;
294         final float near = 1.0f;
295         final float far = 10.0f;
296         
297         Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
298     }
299 
300     @Override
301     public void onSurfaceCreated(GL10 gl, EGLConfig config) {
302         // TODO Auto-generated method stub
303         GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
304         GLES20.glEnable(GLES20.GL_CULL_FACE);
305         GLES20.glEnable(GLES20.GL_DEPTH_TEST);
306         // Position the eye behind the origin.
307         final float eyeX = 0.0f;
308         final float eyeY = 0.0f;
309         final float eyeZ = -0.5f;
310 
311         // We are looking toward the distance
312         final float lookX = 0.0f;
313         final float lookY = 0.0f;
314         final float lookZ = -5.0f;
315 
316         // Set our up vector. This is where our head would be pointing were we holding the camera.
317         final float upX = 0.0f;
318         final float upY = 1.0f;
319         final float upZ = 0.0f;
320 
321         // Set the view matrix. This matrix can be said to represent the camera position.
322         // NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination of a model and
323         // view matrix. In OpenGL 2, we can keep track of these matrices separately if we choose.
324         Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
325         
326         final String vertexShader = getVertexShader();
327         final String fragmentShader = getFragmentShader();
328         
329         final int vertexShaderHandle = compileShader(GLES20.GL_VERTEX_SHADER, vertexShader);
330         final int fragmentShaderHandle = compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);
331         mPerVertexProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, 
332                 new String[]{"a_Position", "a_Color", "a_Normal"});
333         
334         final String pointVertexShader =
335                 "uniform mat4 u_MVPMatrix;      \n"        
336               +    "attribute vec4 a_Position;     \n"        
337               + "void main()                    \n"
338               + "{                              \n"
339               + "   gl_Position = u_MVPMatrix   \n"
340               + "               * a_Position;   \n"
341               + "   gl_PointSize = 20.0;         \n"
342               + "}                              \n";
343             
344         final String pointFragmentShader = 
345                 "precision mediump float;       \n"                              
346               + "void main()                    \n"
347               + "{                              \n"
348               + "   gl_FragColor = vec4(1.0,    \n" 
349               + "   1.0, 1.0, 1.0);             \n"
350               + "}                              \n";
351         
352         final int pointVertexShaderHandle = compileShader(GLES20.GL_VERTEX_SHADER, pointVertexShader);
353         final int pointFragmentShaderHandle = compileShader(GLES20.GL_FRAGMENT_SHADER, pointFragmentShader);
354         mPointProgramHandle = createAndLinkProgram(pointVertexShaderHandle, pointFragmentShaderHandle,
355                 new String[]{"a_Position"});    
356         
357     }
358     
359     private String getVertexShader()
360     {
361         final String vertexShader =
362                 "uniform mat4 u_MVPMatrix;      \n"        // A constant representing the combined model/view/projection matrix.
363               + "uniform mat4 u_MVMatrix;       \n"        // A constant representing the combined model/view matrix.    
364               + "uniform vec3 u_LightPos;       \n"        // The position of the light in eye space.
365                 
366               + "attribute vec4 a_Position;     \n"        // Per-vertex position information we will pass in.
367               + "attribute vec4 a_Color;        \n"        // Per-vertex color information we will pass in.
368               + "attribute vec3 a_Normal;       \n"        // Per-vertex normal information we will pass in.
369               
370               + "varying vec4 v_Color;          \n"        // This will be passed into the fragment shader.
371               
372               + "void main()                    \n"     // The entry point for our vertex shader.
373               + "{                              \n"        
374             // Transform the vertex into eye space.
375               + "   vec3 modelViewVertex = vec3(u_MVMatrix * a_Position);              \n"
376             // Transform the normal's orientation into eye space.
377               + "   vec3 modelViewNormal = vec3(u_MVMatrix * vec4(a_Normal, 0.0));     \n"
378             // Will be used for attenuation.
379               + "   float distance = length(u_LightPos - modelViewVertex);             \n"
380             // Get a lighting direction vector from the light to the vertex.
381               + "   vec3 lightVector = normalize(u_LightPos - modelViewVertex);        \n"
382             // Calculate the dot product of the light vector and vertex normal. If the normal and light vector are
383             // pointing in the same direction then it will get max illumination.
384               + "   float diffuse = max(dot(modelViewNormal, lightVector), 0.1);       \n"                                                                       
385             // Attenuate the light based on distance.
386               + "   diffuse = diffuse * (1.0 / (1.0 + (0.25 * distance * distance)));  \n"
387             // Multiply the color by the illumination level. It will be interpolated across the triangle.
388               + "   v_Color = a_Color * diffuse;                                       \n"      
389             // gl_Position is a special variable used to store the final position.
390             // Multiply the vertex by the matrix to get the final point in normalized screen coordinates.        
391               + "   gl_Position = u_MVPMatrix * a_Position;                            \n"     
392               + "}                                                                     \n"; 
393             
394         return vertexShader;    
395     }
396     
397     private String getFragmentShader()
398     {
399         final String fragmentShader =
400                 "precision mediump float;       \n"        // Set the default precision to medium. We don't need as high of a 
401                                                         // precision in the fragment shader.                
402               + "varying vec4 v_Color;          \n"        // This is the color from the vertex shader interpolated across the 
403                                                           // triangle per fragment.              
404               + "void main()                    \n"        // The entry point for our fragment shader.
405               + "{                              \n"
406               + "   gl_FragColor = v_Color;     \n"        // Pass the color directly through the pipeline.          
407               + "}                              \n";
408             
409         return fragmentShader;        
410     }
411     
412     private int compileShader(final int shaderType, final String shaderSource)
413     {
414         int shaderHandle = GLES20.glCreateShader(shaderType);
415 
416         if (shaderHandle != 0) 
417         {
418             GLES20.glShaderSource(shaderHandle, shaderSource);
419             GLES20.glCompileShader(shaderHandle);
420 
421             final int[] compileStatus = new int[1];
422             GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
423 
424             if (compileStatus[0] == 0) 
425             {
426                 Log.e(TAG, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shaderHandle));
427                 GLES20.glDeleteShader(shaderHandle);
428                 shaderHandle = 0;
429             }
430         }
431 
432         if (shaderHandle == 0)
433         {            
434             throw new RuntimeException("Error creating shader.");
435         }
436         
437         return shaderHandle;
438     }
439     
440     private int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes) 
441     {
442         int programHandle = GLES20.glCreateProgram();
443         
444         if (programHandle != 0) 
445         {
446             GLES20.glAttachShader(programHandle, vertexShaderHandle);            
447             GLES20.glAttachShader(programHandle, fragmentShaderHandle);
448             
449             if (attributes != null)
450             {
451                 final int size = attributes.length;
452                 for (int i = 0; i < size; i++)
453                 {
454                     GLES20.glBindAttribLocation(programHandle, i, attributes[i]);
455                 }                        
456             }
457             
458             GLES20.glLinkProgram(programHandle);
459 
460             final int[] linkStatus = new int[1];
461             GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
462 
463             if (linkStatus[0] == 0) 
464             {                
465                 Log.e(TAG, "Error compiling program: " + GLES20.glGetProgramInfoLog(programHandle));
466                 GLES20.glDeleteProgram(programHandle);
467                 programHandle = 0;
468             }
469         }
470         
471         if (programHandle == 0)
472         {
473             throw new RuntimeException("Error creating program.");
474         }
475         
476         return programHandle;
477     }
478 }

这个程序里,把生成物体vertex shader 和 gragment shader的source string单独提取出了两个方法,便于使用。

分别是getVertexShader和getFragmentShader。

同样,把编译shader也提取成方法compileShader。

还有生成和连接program的方法createAndLinkProgram。

看下效果图:

posted on 2012-04-28 14:40  JayceLi  阅读(2291)  评论(3编辑  收藏  举报