本节我们来学习一下光照贴图的知识,还是在之前的基础上不断完善,效果越来越真实,本节实现的效果如下。
一共四个效果,上面两个是只有漫反射贴图的效果,下面两个是漫反射贴图和光照贴图一起的效果,左侧两个是加了光源随时间变化的影响。大部分的代码都和上一节相同,修改比较小,可以看到作者的思路就是把所有能完善的细节一步步的完善,这样就能得到更好的效果。
本节的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三个方法中计算物体最终的分量的结果也就很明确了。
对比一下本节最开始的效果,可以看到还是很真实的,加上镜面光照贴图之后,效果要更好,这就是细节的处理。
本节的内容到这里就结束了,下一节我们继续学习投光物的内容。