OpenGL ES for Android(简单光照)

939 阅读2分钟

简介

从这篇开始学习光照相关的知识,可以先阅读文档learnopengl-cn.github.io/02%20Lighti…,了解光照的相关概念。

相关案例

光照至少需要一个光源和一个物体才能显示出的效果,那么我们就需要定义光源和物体的顶点位置和颜色,参考我们实现立方体的文章添加立方体并设置颜色,设置光源的颜色是白色,设置物体本来的颜色是橘色,那么光源照射之后的颜色就是两种颜色的叠加,我们直接设置颜色,物体着色器的代码如下:

      vertexShaderCode =
              "uniform mat4 uMVPMatrix;" +
                      "attribute vec4 aPosition;" +
                      "varying vec3 lColor;" +
                      "varying vec3 oColor;" +
                      "void main() {" +
                      "  gl_Position = uMVPMatrix * aPosition;" +
                      "  lColor = vec3(1.0, 1.0, 1.0);" +
                      "  oColor = vec3(1.0, 0.5, 0.31);" +
                      "}";
      fragmentShaderCode =
              "precision mediump float;" +
                    "varying vec3 lColor;" +
                      "varying vec3 oColor;" +
                      "void main() {" +
                      "  gl_FragColor = vec4(lColor * oColor, 1.0);" +
                      "}";


使用光照颜色(lColor)和物体颜色(oColor)叠加相乘后生成物体的颜色。

这次我们设置观察点在右上方,可以看到立方体的右上角

Matrix.setLookAtM(viewMatrix, 0, 0.8f, 0.8f, 4f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

因为这次要绘制物体和光源两个立方体,所以还有设置光源着色器代码,因为是个纯白色的比较简单,这里不再赘述,最后附上代码:

  @Override
      public void onDrawFrame(GL10 gl) {
          super.onDrawFrame(gl);
          // ---------- 绘制物品 ---------------
          int shaderProgram = OpenGLUtil.createProgram(vertexShaderCode, fragmentShaderCode);
          GLES20.glUseProgram(shaderProgram);
          // 传入顶点坐标
          int positionHandle = GLES20.glGetAttribLocation(shaderProgram, "aPosition");
          GLES20.glEnableVertexAttribArray(positionHandle);
          GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT,
                  false, 3 * 4, OpenGLUtil.createFloatBuffer(CubeCoords));
 
          int mMVPMatrixHandle = GLES20.glGetUniformLocation(shaderProgram, "uMVPMatrix");
          GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, vPMatrix, 0);
 
          // 绘制顶点
          GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, indices.length,
                  GLES20.GL_UNSIGNED_SHORT, OpenGLUtil.createShortBuffer(indices));
 
          // ---------- 绘制光源 ---------------
          int lightProgram = OpenGLUtil.createProgram(vertexLightShaderCode, fragmentLightShaderCode);
          GLES20.glUseProgram(lightProgram);
          // 传入顶点坐标
          int lightPositionHandle = GLES20.glGetAttribLocation(lightProgram, "aPosition");
          GLES20.glEnableVertexAttribArray(lightPositionHandle);
          GLES20.glVertexAttribPointer(lightPositionHandle, 3, GLES20.GL_FLOAT,
                  false, 3 * 4,  OpenGLUtil.createFloatBuffer(CubeCoords));
 
          int mMVPMatrixHandle1 = GLES20.glGetUniformLocation(lightProgram, "uMVPMatrix");
          // 移动光源的位置
          Matrix.translateM(vPMatrix2, 0, 0.7f, 0.8f, 0f);
          // 缩放光源
          Matrix.scaleM(vPMatrix2, 0, 0.1f, 0.1f, 0.1f);
         // 计算
          //Matrix.multiplyMM(vPMatrix, 0, tempMatrix, 0, translateMatrix, 0);
          GLES20.glUniformMatrix4fv(mMVPMatrixHandle1, 1, false, vPMatrix2, 0);
 
          // 绘制顶点
          GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, indices.length,
                  GLES20.GL_UNSIGNED_SHORT, OpenGLUtil.createShortBuffer(indices));
 
          GLES20.glDisableVertexAttribArray(positionHandle);
          GLES20.glDisableVertexAttribArray(lightPositionHandle);
      }


效果图如下:



我们看到物体整体颜色一样,和现实世界的光照效果还是有差异的。现实世界的效果应该是背面比较比较暗的,还有光线的强弱,光源的颜色等等,这些都是以后学习的内容。