Opengl ES系列学习--光照贴图

     本节我们来学习一下光照贴图的知识,还是在之前的基础上不断完善,效果越来越真实,本节实现的效果如下。

Opengl ES系列学习--光照贴图_第1张图片

     一共四个效果,上面两个是只有漫反射贴图的效果,下面两个是漫反射贴图和光照贴图一起的效果,左侧两个是加了光源随时间变化的影响。大部分的代码都和上一节相同,修改比较小,可以看到作者的思路就是把所有能完善的细节一步步的完善,这样就能得到更好的效果。

     本节的Render渲染类是GlLightMapRender,完整源码如下:

package com.opengl.learn.aric.lightmap;

import android.content.Context;
import android.opengl.GLES32;
import android.opengl.GLSurfaceView;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
import static android.opengl.GLES20.GL_DEPTH_BUFFER_BIT;
import static android.opengl.GLES20.GL_DEPTH_TEST;

public class GlLightMapRender implements GLSurfaceView.Renderer {
    private static final String TAG = GlLightMapRender.class.getSimpleName();
    private Context mContext;
    private int mWidth, mHeight;
    private LightMapCube mCube;
    private LightMapLight mLight;

    public GlLightMapRender(Context context) {
        mContext = context;
        mCube = new LightMapCube(mContext);
        mLight = new LightMapLight(mContext);
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        mCube.onSurfaceCreated();
        mLight.onSurfaceCreated();
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        mWidth = width;
        mHeight = height;
        mCube.onSurfaceChanged(gl, width, height);
        mLight.onSurfaceChanged(gl, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES32.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        GLES32.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        GLES32.glEnable(GL_DEPTH_TEST);

        for (int i = 0; i < 4; i++) {
            if (i == 0) {
                GLES32.glViewport(0, mHeight / 2, mWidth / 2, mHeight / 2);
            } else if (i == 1) {
                GLES32.glViewport(mWidth / 2, mHeight / 2, mWidth / 2, mHeight / 2);
            } else if (i == 2) {
                GLES32.glViewport(0, 0, mWidth / 2, mHeight / 2);
            } else if (i == 3) {
                GLES32.glViewport(mWidth / 2, 0, mWidth / 2, mHeight / 2);
            }

            mLight.onDrawFrame(i);
            mCube.onDrawFrame(i);
        }
    }
}

     调用glViewport变化视口四次,绘制出四个视图,这次因为我们把数据统一了,在Cube中使用到的光照的数据,也是直接调用光照的属性的,所以绘制顺序修改了一下,先调用mLight.onDrawFrame(i)绘制光源,然后再绘制立方体。

     光源LightMapLight类的完整源码如下:

package com.opengl.learn.aric.lightmap;

import android.content.Context;
import android.opengl.GLES32;
import android.opengl.Matrix;

import com.opengl.learn.OpenGLUtils;
import com.opengl.learn.R;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;

import static android.opengl.GLES20.GL_ARRAY_BUFFER;
import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_STATIC_DRAW;
import static android.opengl.GLES20.GL_TRIANGLES;
import static android.opengl.GLES20.glGenBuffers;
import static android.opengl.GLES20.glGetUniformLocation;

public class LightMapLight {
    private final float[] mVerticesData =
            {
                    // back face
                    0.5f, 0.5f, -0.5f,     // (5) Top-right far
                    0.5f, -0.5f, -0.5f,      // (7) Bottom-right far
                    -0.5f, -0.5f, -0.5f,     // (6) Bottom-left far
                    -0.5f, -0.5f, -0.5f,     // (6) Bottom-left far
                    -0.5f, 0.5f, -0.5f,     // (4) Top-left far
                    0.5f, 0.5f, -0.5f,     // (5) Top-right far

                    // front face
                    -0.5f, 0.5f, 0.5f,     // (0) Top-left near
                    -0.5f, -0.5f, 0.5f,     // (2) Bottom-left near
                    0.5f, -0.5f, 0.5f,     // (3) Bottom-right near
                    0.5f, -0.5f, 0.5f,     // (3) Bottom-right near
                    0.5f, 0.5f, 0.5f,     // (1) Top-right near
                    -0.5f, 0.5f, 0.5f,     // (0) Top-left near

                    // left face
                    -0.5f, 0.5f, -0.5f,     // (4) Top-left far
                    -0.5f, -0.5f, -0.5f,     // (6) Bottom-left far
                    -0.5f, -0.5f, 0.5f,     // (2) Bottom-left near
                    -0.5f, -0.5f, 0.5f,     // (2) Bottom-left near
                    -0.5f, 0.5f, 0.5f,     // (0) Top-left near
                    -0.5f, 0.5f, -0.5f,     // (4) Top-left far

                    // right face
                    0.5f, 0.5f, 0.5f,     // (1) Top-right near
                    0.5f, -0.5f, 0.5f,     // (3) Bottom-right near
                    0.5f, -0.5f, -0.5f,      // (7) Bottom-right far
                    0.5f, -0.5f, -0.5f,      // (7) Bottom-right far
                    0.5f, 0.5f, -0.5f,     // (5) Top-right far
                    0.5f, 0.5f, 0.5f,     // (1) Top-right near

                    // bottom face
                    -0.5f, -0.5f, 0.5f,     // (2) Bottom-left near
                    -0.5f, -0.5f, -0.5f,     // (6) Bottom-left far
                    0.5f, -0.5f, -0.5f,      // (7) Bottom-right far
                    0.5f, -0.5f, -0.5f,      // (7) Bottom-right far
                    0.5f, -0.5f, 0.5f,     // (3) Bottom-right near
                    -0.5f, -0.5f, 0.5f,     // (2) Bottom-left near

                    // top face
                    -0.5f, 0.5f, -0.5f,     // (4) Top-left far
                    -0.5f, 0.5f, 0.5f,     // (0) Top-left near
                    0.5f, 0.5f, 0.5f,     // (1) Top-right near
                    0.5f, 0.5f, 0.5f,     // (1) Top-right near
                    0.5f, 0.5f, -0.5f,     // (5) Top-right far
                    -0.5f, 0.5f, -0.5f,     // (4) Top-left far

            };

    public static float[] mLightColorsData = {1.0f, 1.0f, 1.0f};
    public static final float[] mLightPosData = {0f, 0f, 5.0f};

    private static final String TAG = LightMapLight.class.getSimpleName();
    private static final int BYTES_PER_FLOAT = 4;
    private static final int BYTES_PER_SHORT = 2;
    private static final int POSITION_COMPONENT_COUNT = 3;
    private static final int COLOR_COMPONENT_COUNT = 3;
    private static final int TEXTURE_COMPONENT_COUNT = 2;
    private static final int INDEX_COMPONENT_COUNT = 1;
    private static final int MATRIX_LENGHT = 16;
    private Context mContext;
    private int mLightProgram;
    private int uLightMatrixLocation, uLightColor;
    private FloatBuffer mVerticesBuffer;
    private FloatBuffer mColorsBuffer;
    private int mWidth, mHeight;
    private int mLightVAO, mLightVBO;
    private float[] uLightMatrix = new float[MATRIX_LENGHT];
    private float[] projectionMatrix = new float[MATRIX_LENGHT];
    private float[] modelMatrix = new float[MATRIX_LENGHT];
    private float[] viewMatrix = new float[MATRIX_LENGHT];
    private long startTime;

    public LightMapLight(Context context) {
        mContext = context;
        mVerticesBuffer = ByteBuffer.allocateDirect(mVerticesData.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();

        mVerticesBuffer.put(mVerticesData).position(0);
    }

    public void onSurfaceCreated() {
        mLightProgram = OpenGLUtils.loadProgram(mContext, R.raw.glmaterial_light_vertex, R.raw.glmaterial_light_fragment);
        uLightMatrixLocation = glGetUniformLocation(mLightProgram, "uMatrix");
        uLightColor = glGetUniformLocation(mLightProgram, "uLightColor");
        int[] array = new int[1];
        GLES32.glGenVertexArrays(1, array, 0);
        mLightVAO = array[0];
        array = new int[1];
        glGenBuffers(1, array, 0);
        mLightVBO = array[0];

        GLES32.glBindVertexArray(mLightVAO);

        mVerticesBuffer.position(0);
        GLES32.glBindBuffer(GL_ARRAY_BUFFER, mLightVBO);
        GLES32.glBufferData(GL_ARRAY_BUFFER, BYTES_PER_FLOAT * mVerticesData.length, mVerticesBuffer, GL_STATIC_DRAW);
        GLES32.glVertexAttribPointer(0, POSITION_COMPONENT_COUNT, GL_FLOAT, false, 0, 0);
        GLES32.glEnableVertexAttribArray(0);
    }

    public void onSurfaceChanged(GL10 gl, int width, int height) {
        mWidth = width;
        mHeight = height;
    }

    public void onDrawFrame(int index) {
        if (startTime == 0) {
            startTime = System.currentTimeMillis();
        }

        if (index % 2 == 0) {
            long now = System.currentTimeMillis();
            mLightColorsData[0] = (float) Math.sin((now - startTime) / 1000f * 2.0f);
            mLightColorsData[1] = (float) Math.sin((now - startTime) / 1000f * 0.7f);
            mLightColorsData[2] = (float) Math.sin((now - startTime) / 1000f * 1.3f);
        } else {
            mLightColorsData = new float[]{1.0f, 1.0f, 1.0f};
        }

        GLES32.glUseProgram(mLightProgram);
        GLES32.glEnableVertexAttribArray(0);
        GLES32.glBindVertexArray(mLightVAO);
        setLightMatrix();
        GLES32.glUniformMatrix4fv(uLightMatrixLocation, 1, false, uLightMatrix, 0);
        GLES32.glUniform3fv(uLightColor, 1, mLightColorsData, 0);
        GLES32.glDrawArrays(GL_TRIANGLES, 0, mVerticesData.length);
        GLES32.glBindVertexArray(0);
        GLES32.glDisableVertexAttribArray(3);
    }

    private void setLightMatrix() {
        Matrix.setIdentityM(modelMatrix, 0);
        Matrix.setIdentityM(viewMatrix, 0);

        float aspect = (float) mWidth / (float) mHeight;
        Matrix.perspectiveM(projectionMatrix, 0, 45f, aspect, 1.0f, 100f);
        Matrix.setLookAtM(viewMatrix, 0, 0f, 10f, 20f, 0f, 0f, 0f, 0f, 1f, 0f);
        Matrix.translateM(modelMatrix, 0, mLightPosData[0], mLightPosData[1], mLightPosData[2]);
        Matrix.scaleM(modelMatrix, 0, 0.5f, 0.5f, 0.5f);
        Matrix.rotateM(modelMatrix, 0, -60, 0f, 1f, 0f);

        Matrix.multiplyMM(uLightMatrix, 0, viewMatrix, 0, modelMatrix, 0);
        Matrix.multiplyMM(uLightMatrix, 0, projectionMatrix, 0, uLightMatrix, 0);
    }
}

     该类和Opengl ES系列学习--材质一节中的光照源码基本上完全相同,只是把mLightColorsData成员变量修改了一下,因为我们要在立方体中使用,所以正确的作法肯定是只在这里定义,在这里修改数据,不应该在其他地方也有定义,否则两个数据就可能出现不同,导致我们的效果达不到预期。这里也没有什么新的知识,全部都是之前用过的。

     立方体LightMapCube类的完整源码如下:

package com.opengl.learn.aric.lightmap;

import android.content.Context;
import android.opengl.GLES32;
import android.opengl.Matrix;
import android.util.Log;

import com.opengl.learn.OpenGLUtils;
import com.opengl.learn.R;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;

import static android.opengl.GLES20.GL_ARRAY_BUFFER;
import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_STATIC_DRAW;
import static android.opengl.GLES20.GL_TEXTURE0;
import static android.opengl.GLES20.GL_TEXTURE1;
import static android.opengl.GLES20.GL_TEXTURE_2D;
import static android.opengl.GLES20.GL_TRIANGLES;
import static android.opengl.GLES20.glGenBuffers;
import static android.opengl.GLES20.glGetUniformLocation;

public class LightMapCube {
    private final float[] mVerticesData =
            {
                    // back face
                    0.5f, 0.5f, -0.5f,     // (5) Top-right far
                    0.5f, -0.5f, -0.5f,      // (7) Bottom-right far
                    -0.5f, -0.5f, -0.5f,     // (6) Bottom-left far
                    -0.5f, -0.5f, -0.5f,     // (6) Bottom-left far
                    -0.5f, 0.5f, -0.5f,     // (4) Top-left far
                    0.5f, 0.5f, -0.5f,     // (5) Top-right far

                    // front face
                    -0.5f, 0.5f, 0.5f,     // (0) Top-left near
                    -0.5f, -0.5f, 0.5f,     // (2) Bottom-left near
                    0.5f, -0.5f, 0.5f,     // (3) Bottom-right near
                    0.5f, -0.5f, 0.5f,     // (3) Bottom-right near
                    0.5f, 0.5f, 0.5f,     // (1) Top-right near
                    -0.5f, 0.5f, 0.5f,     // (0) Top-left near

                    // left face
                    -0.5f, 0.5f, -0.5f,     // (4) Top-left far
                    -0.5f, -0.5f, -0.5f,     // (6) Bottom-left far
                    -0.5f, -0.5f, 0.5f,     // (2) Bottom-left near
                    -0.5f, -0.5f, 0.5f,     // (2) Bottom-left near
                    -0.5f, 0.5f, 0.5f,     // (0) Top-left near
                    -0.5f, 0.5f, -0.5f,     // (4) Top-left far

                    // right face
                    0.5f, 0.5f, 0.5f,     // (1) Top-right near
                    0.5f, -0.5f, 0.5f,     // (3) Bottom-right near
                    0.5f, -0.5f, -0.5f,      // (7) Bottom-right far
                    0.5f, -0.5f, -0.5f,      // (7) Bottom-right far
                    0.5f, 0.5f, -0.5f,     // (5) Top-right far
                    0.5f, 0.5f, 0.5f,     // (1) Top-right near

                    // bottom face
                    -0.5f, -0.5f, 0.5f,     // (2) Bottom-left near
                    -0.5f, -0.5f, -0.5f,     // (6) Bottom-left far
                    0.5f, -0.5f, -0.5f,      // (7) Bottom-right far
                    0.5f, -0.5f, -0.5f,      // (7) Bottom-right far
                    0.5f, -0.5f, 0.5f,     // (3) Bottom-right near
                    -0.5f, -0.5f, 0.5f,     // (2) Bottom-left near

                    // top face
                    -0.5f, 0.5f, -0.5f,     // (4) Top-left far
                    -0.5f, 0.5f, 0.5f,     // (0) Top-left near
                    0.5f, 0.5f, 0.5f,     // (1) Top-right near
                    0.5f, 0.5f, 0.5f,     // (1) Top-right near
                    0.5f, 0.5f, -0.5f,     // (5) Top-right far
                    -0.5f, 0.5f, -0.5f,     // (4) Top-left far

            };

    private final float[] mColorsData =
            {
                    1.0f, 0.0f, 0.0f,
                    0.0f, 1.0f, 0.0f,
                    0.0f, 0.0f, 1.0f,
                    1.0f, 1.0f, 0.0f,
            };

    private final float[] mTextureData =
            {
                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 0.0f,
                    0.0f, 0.0f,

                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 0.0f,
                    0.0f, 0.0f,

                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 0.0f,
                    0.0f, 0.0f,

                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 0.0f,
                    0.0f, 0.0f,

                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 0.0f,
                    0.0f, 0.0f,

                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 0.0f,
                    0.0f, 0.0f,
            };

    private final float[] mNormalData =
            {
                    0.0f, 0.0f, -1.0f,
                    0.0f, 0.0f, -1.0f,
                    0.0f, 0.0f, -1.0f,
                    0.0f, 0.0f, -1.0f,
                    0.0f, 0.0f, -1.0f,
                    0.0f, 0.0f, -1.0f,

                    0.0f, 0.0f, 1.0f,
                    0.0f, 0.0f, 1.0f,
                    0.0f, 0.0f, 1.0f,
                    0.0f, 0.0f, 1.0f,
                    0.0f, 0.0f, 1.0f,
                    0.0f, 0.0f, 1.0f,

                    -1.0f, 0.0f, 0.0f,
                    -1.0f, 0.0f, 0.0f,
                    -1.0f, 0.0f, 0.0f,
                    -1.0f, 0.0f, 0.0f,
                    -1.0f, 0.0f, 0.0f,
                    -1.0f, 0.0f, 0.0f,

                    1.0f, 0.0f, 0.0f,
                    1.0f, 0.0f, 0.0f,
                    1.0f, 0.0f, 0.0f,
                    1.0f, 0.0f, 0.0f,
                    1.0f, 0.0f, 0.0f,
                    1.0f, 0.0f, 0.0f,

                    0.0f, -1.0f, 0.0f,
                    0.0f, -1.0f, 0.0f,
                    0.0f, -1.0f, 0.0f,
                    0.0f, -1.0f, 0.0f,
                    0.0f, -1.0f, 0.0f,
                    0.0f, -1.0f, 0.0f,

                    0.0f, 1.0f, 0.0f,
                    0.0f, 1.0f, 0.0f,
                    0.0f, 1.0f, 0.0f,
                    0.0f, 1.0f, 0.0f,
                    0.0f, 1.0f, 0.0f,
                    0.0f, 1.0f, 0.0f,
            };

    private final float[] mEyePosData = {0f, 2f, 20f};
    private float[] mMateriallightColor = {1.0f, 1.0f, 1.0f};

    private static final String TAG = LightMapCube.class.getSimpleName();
    private static final int BYTES_PER_FLOAT = 4;
    private static final int BYTES_PER_SHORT = 2;
    private static final int POSITION_COMPONENT_COUNT = 3;
    private static final int COLOR_COMPONENT_COUNT = 3;
    private static final int TEXTURE_COMPONENT_COUNT = 2;
    private static final int INDEX_COMPONENT_COUNT = 1;
    private static final int NORMAL_COMPONENT_COUNT = 3;
    private static final int MATRIX_LENGHT = 16;
    private Context mContext;
    private int mProgramObject;
    private int containerTexture, borderTexture;
    private int uTextureFace;
    private int uModelMatrix, uViewMatrix, uProjectionMatrix, uLightColor, uLightPos, uViewPos, uIndex;
    private int materialDiffuse, materialvSpecular, materialsSpecular, materialShininess;
    private int lightAmbient, lightDiffuse, lightSpecular;
    private FloatBuffer mVerticesBuffer;
    private FloatBuffer mColorsBuffer;
    private FloatBuffer mTextureBuffer;
    private FloatBuffer mNormalBuffer;
    private ShortBuffer mIndicesBuffer;
    private int mWidth, mHeight;
    private int mVAO, mVBO, mCBO, mTBO, mNBO;
    private float[] modelMatrix = new float[MATRIX_LENGHT];
    private float[] viewMatrix = new float[MATRIX_LENGHT];
    private float[] projectionMatrix = new float[MATRIX_LENGHT];
    private float radius = 30f;
    private long startTime = 0;
    private float[][] directions = {
            {0f, 0.0f, -20f}, {2f, 0.0f, -20f}, {0f, 4.0f, -20f}, {0f, 4.2f, -20.5f}, {3.24f, -3.4f, -15.5f},
            {-3.1f, 2.0f, -7.5f}, {4.47f, -2.0f, -5.5f}, {-4.5f, 2.40f, -9.5f}, {5f, 0.2f, -20.5f}, {-5.43f, -2.3f, -8.5f},
    };

    public LightMapCube(Context context) {
        mContext = context;
        mVerticesBuffer = ByteBuffer.allocateDirect(mVerticesData.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();

        mVerticesBuffer.put(mVerticesData).position(0);

        mColorsBuffer = ByteBuffer.allocateDirect(mColorsData.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();
        mColorsBuffer.put(mColorsData).position(0);

        mTextureBuffer = ByteBuffer.allocateDirect(mTextureData.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();
        mTextureBuffer.put(mTextureData).position(0);

        mNormalBuffer = ByteBuffer.allocateDirect(mNormalData.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();
        mNormalBuffer.put(mNormalData).position(0);
    }

    public void onSurfaceCreated() {
        mProgramObject = OpenGLUtils.loadProgram(mContext, R.raw.gllightmap_cube_vertex, R.raw.gllightmap_cube_fragment);
        uTextureFace = glGetUniformLocation(mProgramObject, "uTextureFace");
        uModelMatrix = glGetUniformLocation(mProgramObject, "uModelMatrix");
        uViewMatrix = glGetUniformLocation(mProgramObject, "uViewMatrix");
        uProjectionMatrix = glGetUniformLocation(mProgramObject, "uProjectionMatrix");
        uLightColor = glGetUniformLocation(mProgramObject, "uLightColor");
        uLightPos = glGetUniformLocation(mProgramObject, "uLightPos");
        uViewPos = glGetUniformLocation(mProgramObject, "uViewPos");
        uIndex = glGetUniformLocation(mProgramObject, "uIndex");
        materialDiffuse = glGetUniformLocation(mProgramObject, "material.diffuse");
        materialvSpecular = glGetUniformLocation(mProgramObject, "material.vSpecular");
        materialsSpecular = glGetUniformLocation(mProgramObject, "material.sSpecular");
        materialShininess = glGetUniformLocation(mProgramObject, "material.shininess");
        lightAmbient = glGetUniformLocation(mProgramObject, "light.ambient");
        lightDiffuse = glGetUniformLocation(mProgramObject, "light.diffuse");
        lightSpecular = glGetUniformLocation(mProgramObject, "light.specular");
        int[] array = new int[1];
        GLES32.glGenVertexArrays(1, array, 0);
        mVAO = array[0];
        array = new int[4];
        glGenBuffers(4, array, 0);
        mVBO = array[0];
        mCBO = array[1];
        mTBO = array[2];
        mNBO = array[3];
        Log.e(TAG, "onSurfaceCreated, " + mProgramObject);
        containerTexture = OpenGLUtils.loadTexture(mContext, R.mipmap.lightmap_cube);
        borderTexture = OpenGLUtils.loadTexture(mContext, R.mipmap.lightmap_border);

        GLES32.glBindVertexArray(mVAO);

        mVerticesBuffer.position(0);
        GLES32.glBindBuffer(GL_ARRAY_BUFFER, mVBO);
        GLES32.glBufferData(GL_ARRAY_BUFFER, BYTES_PER_FLOAT * mVerticesData.length, mVerticesBuffer, GL_STATIC_DRAW);
        GLES32.glVertexAttribPointer(0, POSITION_COMPONENT_COUNT, GL_FLOAT, false, 0, 0);
        GLES32.glEnableVertexAttribArray(0);

        mTextureBuffer.position(0);
        GLES32.glBindBuffer(GL_ARRAY_BUFFER, mTBO);
        GLES32.glBufferData(GL_ARRAY_BUFFER, BYTES_PER_FLOAT * mTextureData.length, mTextureBuffer, GL_STATIC_DRAW);
        GLES32.glVertexAttribPointer(2, TEXTURE_COMPONENT_COUNT, GL_FLOAT, false, 0, 0);
        GLES32.glEnableVertexAttribArray(2);

        mNormalBuffer.position(0);
        GLES32.glBindBuffer(GL_ARRAY_BUFFER, mNBO);
        GLES32.glBufferData(GL_ARRAY_BUFFER, BYTES_PER_FLOAT * mNormalData.length, mNormalBuffer, GL_STATIC_DRAW);
        GLES32.glVertexAttribPointer(3, NORMAL_COMPONENT_COUNT, GL_FLOAT, false, 0, 0);
        GLES32.glEnableVertexAttribArray(3);
    }

    public void onSurfaceChanged(GL10 gl, int width, int height) {
        mWidth = width;
        mHeight = height;
    }

    public void onDrawFrame(int index) {
        if (startTime == 0) {
            startTime = System.currentTimeMillis();
        }

        GLES32.glUseProgram(mProgramObject);
        GLES32.glEnableVertexAttribArray(0);
        GLES32.glEnableVertexAttribArray(1);
        GLES32.glEnableVertexAttribArray(2);
        GLES32.glEnableVertexAttribArray(3);

        GLES32.glActiveTexture(GL_TEXTURE0);
        GLES32.glBindTexture(GL_TEXTURE_2D, containerTexture);
        GLES32.glUniform1i(materialDiffuse, 0);

        GLES32.glActiveTexture(GL_TEXTURE1);
        GLES32.glBindTexture(GL_TEXTURE_2D, borderTexture);
        GLES32.glUniform1i(materialsSpecular, 1);

        GLES32.glUniform3fv(uLightColor, 1, LightMapLight.mLightColorsData, 0);
        GLES32.glUniform3fv(uLightPos, 1, LightMapLight.mLightPosData, 0);
        GLES32.glUniform3fv(uViewPos, 1, mEyePosData, 0);

        GLES32.glUniform3f(materialDiffuse, 1.0f, 0.5f, 0.31f);
        GLES32.glUniform3f(materialvSpecular, 0.5f, 0.5f, 0.5f);
        GLES32.glUniform1f(materialShininess, 32.0f);

        mMateriallightColor = LightMapLight.mLightColorsData;

        GLES32.glUniform3f(lightAmbient, mMateriallightColor[0] * 0.2f, mMateriallightColor[1] * 0.2f, mMateriallightColor[2] * 0.2f);
        GLES32.glUniform3f(lightDiffuse, mMateriallightColor[0] * 0.5f, mMateriallightColor[1] * 0.5f, mMateriallightColor[2] * 0.5f);
        GLES32.glUniform3f(lightSpecular, 1.0f, 1.0f, 1.0f);

        GLES32.glBindVertexArray(mVAO);

        setCubeMatrix(0);
        GLES32.glUniformMatrix4fv(uModelMatrix, 1, false, modelMatrix, 0);
        GLES32.glUniformMatrix4fv(uViewMatrix, 1, false, viewMatrix, 0);
        GLES32.glUniformMatrix4fv(uProjectionMatrix, 1, false, projectionMatrix, 0);
        GLES32.glUniform1i(uIndex, index);
        GLES32.glDrawArrays(GL_TRIANGLES, 0, mVerticesData.length);

        GLES32.glBindVertexArray(0);
        GLES32.glDisableVertexAttribArray(0);
        GLES32.glDisableVertexAttribArray(1);
        GLES32.glDisableVertexAttribArray(2);
        GLES32.glDisableVertexAttribArray(3);
    }

    private void setCubeMatrix(int i) {
        Matrix.setIdentityM(modelMatrix, 0);
        Matrix.setIdentityM(viewMatrix, 0);
        Matrix.setIdentityM(projectionMatrix, 0);

        float aspect = (float) mWidth / (float) mHeight;
        Matrix.perspectiveM(projectionMatrix, 0, 45f, aspect, 1.0f, 100f);

        long now = System.currentTimeMillis();
        float camX = (float) (Math.sin((now - startTime) / 1000f) * radius);
        float camZ = (float) (Math.cos((now - startTime) / 1000f) * radius);
        Matrix.setLookAtM(viewMatrix, 0, mEyePosData[0], mEyePosData[1], mEyePosData[2], 0f, 0f, 0f, 0f, 1f, 0f);

        Matrix.translateM(modelMatrix, 0, directions[i][0], directions[i][1], directions[i][2]);
        Matrix.scaleM(modelMatrix, 0, 8f, 8f, 8f);
        Matrix.rotateM(modelMatrix, 0, -20, 0, 1f, 0);
    }
}

     也是和材质一节的大部分相同,差异的部分也全部是因为片段着色器的修改而适配的,我们来看一下片段着色器,源码如下:

#version 320 es
precision mediump float;

struct Material {
    sampler2D diffuse;
    sampler2D sSpecular;
    vec3 vSpecular;
    float shininess;
};

struct Light {
    vec3 position;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

vec4 objectColor;

out vec4 FragColor;
in vec3 outColor;
in vec2 outTexCoord;
in vec3 outNormal;
in vec3 outFragPos;

uniform vec3 uLightColor;
uniform vec3 uLightPos;
uniform vec3 uViewPos;
uniform int uIndex;
uniform Material material;
uniform Light light;

vec4 getAmbientFactor() {
    float ambientStrength = 0.2f;
    vec4 ambient = vec4(ambientStrength * texture(material.diffuse, outTexCoord).xyz * light.ambient, 1.0f);
    return ambient;
}

vec4 getDiffuseFactor() {
    vec3 normal = normalize(outNormal);
    vec3 lightDir = normalize(uLightPos - outFragPos);
    float diff = max(dot(normal, lightDir), 0.0);
    vec4 diffuse = vec4(diff * texture(material.diffuse, outTexCoord).xyz * light.diffuse, 1.0f);
    return diffuse;
}

vec4 getSpecularFactor() {
    vec3 viewDir = normalize(uViewPos - outFragPos);
    vec3 lightDir = normalize(uLightPos - outFragPos);
    vec3 reflectDir = reflect(-lightDir, outNormal);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0f), material.shininess);
    vec4 specular = vec4(1.0);

    if (uIndex < 2) {
        specular = vec4(spec * material.vSpecular * light.specular, 1.0f);
    } else {
        specular = vec4(spec * texture(material.sSpecular, outTexCoord).xyz * light.specular, 1.0f);
    }

    return specular;
}

void main() {
    vec4 ambient = getAmbientFactor();
    vec4 diffuse = getDiffuseFactor();
    vec4 specular = getSpecularFactor();

    FragColor = ambient + diffuse + specular;
}

     片段着色器的输出变量FragColor还是根据冯氏光照模型来实现的,把环境光照分量、漫反射分量、镜面反射分量加起来,就得到我们所能看到的颜色。和材质一节相比,就是把物体的材质换成了纹理:

struct Material {
    sampler2D diffuse;
    sampler2D sSpecular;
    vec3 vSpecular;
    float shininess;
};

     因为纹理能表现出来的细节更加真实,而不像颜色一样,一个物体的全部不可能都是一个颜色。getAmbientFactor、getDiffuseFactor、getSpecularFactor三个方法中计算物体最终的分量的结果也就很明确了。

     对比一下本节最开始的效果,可以看到还是很真实的,加上镜面光照贴图之后,效果要更好,这就是细节的处理。

     本节的内容到这里就结束了,下一节我们继续学习投光物的内容。

你可能感兴趣的:(Android源码解析,Opengl,ES,opengl,shader,java,android)