Android OpenGL ES 2.0 (三) 灯光per-vertex lighting

画完立方体后,在立方体旁边加了一个灯光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。

看下效果图:

Android OpenGL ES 2.0 (三) 灯光per-vertex lighting

Android OpenGL ES 2.0 (三) 灯光per-vertex lighting

你可能感兴趣的:(openGL ES)