本节我们来学习一下颜色的知识,在看完原作者讲解的颜色的知识的基础上,只要我们理解了,应该就能提取出重点,其实本节的重点就是下面这一句话。

所以我们要作的就是计算出物体颜色和光源颜色,然后把它们两个相乘,得到的就是目标颜色了。只有清晰的明确了目标,知道我们要干什么,这样效率才能更高,不至于被方向搞乱。本节我们实现的效果如下:

我们是仿照作者的实现,加了一个橙色的光源,而且在上一节的基础上,继续使用所有的纹理,作者是先去掉,后面的章节又加上的,我们索性就直接使用了。可以看到黑夜中,一个橙色的光源发出的光照射着这十个立方体,立方体本身都被照成了橙色。

本节因为要画立方体和光源,两个属性不同,所以我们就把它们的着色器全部独立分开了;针对功能实现的不同,我们也把立方体抽取为ColorCube类,把光源抽取为ColorLight类,各自处理各自的逻辑,互不影响,这样即使出问题,也更容易查找分析。

因为我们把功能抽取出来之后,Render渲染类倒时简单了多很,GlColorRender类非常简单,完整源码如下:

package com.opengl.learn.aric.color;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 GlColorRender implements GLSurfaceView.Renderer {private static final String TAG = GlColorRender.class.getSimpleName();private Context mContext;private int mWidth, mHeight;private ColorCube mCube;private ColorLight mLight;public GlColorRender(Context context) {mContext = context;mCube = new ColorCube(mContext);mLight = new ColorLight(mContext);}@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {mCube.onSurfaceCreated();mLight.onSurfaceCreated();}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {mWidth = width;mHeight = height;mCube.onSurfaceChanged(gl, width, height);mLight.onSurfaceChanged(gl, width, height);}@Overridepublic void onDrawFrame(GL10 gl) {GLES32.glViewport(0, 0, mWidth, mHeight);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);mCube.onDrawFrame();mLight.onDrawFrame();}
}

对象封装后,Render类的功能就非常清晰了,它只提供绘制的流程,具体的绘制功能由每个封装类自己实现,它当中也没有什么特殊的逻辑,我们就不再说明了。

接下来我们看一下ColorLight,完整源码如下:

package com.opengl.learn.aric.color;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 ColorLight {private final float[] mVerticesData ={// back face0.5f, 0.5f, -0.5f,     // (5) Top-right far0.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 far0.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 near0.5f, -0.5f, 0.5f,     // (3) Bottom-right near0.5f, -0.5f, 0.5f,     // (3) Bottom-right near0.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 face0.5f, 0.5f, 0.5f,     // (1) Top-right near0.5f, -0.5f, 0.5f,     // (3) Bottom-right near0.5f, -0.5f, -0.5f,      // (7) Bottom-right far0.5f, -0.5f, -0.5f,      // (7) Bottom-right far0.5f, 0.5f, -0.5f,     // (5) Top-right far0.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 far0.5f, -0.5f, -0.5f,      // (7) Bottom-right far0.5f, -0.5f, -0.5f,      // (7) Bottom-right far0.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 near0.5f, 0.5f, 0.5f,     // (1) Top-right near0.5f, 0.5f, 0.5f,     // (1) Top-right near0.5f, 0.5f, -0.5f,     // (5) Top-right far-0.5f, 0.5f, -0.5f,     // (4) Top-left far};private final float[] mLightColorsData = {1.0f, 0.5f, 0.31f};private static final String TAG = ColorLight.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];public ColorLight(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.glcolor_light_vertex, R.raw.glcolor_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(3, POSITION_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() {GLES32.glUseProgram(mLightProgram);GLES32.glEnableVertexAttribArray(3);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.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);}
}

我们还是把光源定义为一个立方体,所以它还是继续沿用我们绘制立方体时的顶点坐标数据,正交投影矩阵Matrix.perspectiveM(projectionMatrix, 0, 45f, aspect, 1.0f, 100f)和上一节绘制立方体时一模一样,都使用相同的矩阵;摄像机的视图矩阵也和绘制立方体时一样,Matrix.setLookAtM(viewMatrix, 0, 0f, 10f, 20f, 0f, 0f, 0f, 0f, 1f, 0f),我们还是把摄像机放在Y轴10个单位,Z轴20个单位的地方去查看场景中心,相当于俯视;然后我们把光源沿X、Y、Z三个方向都缩小0.5倍,再把它沿Y轴旋转-60度,也就是朝左向旋转,光源就摆放好了。

这里需要说明一下,我们在本节开始时说到,物体颜色乘以光源颜色得到最终的效果,这是指针对物体的,光源是不需要作这样的计算的,这个大家要考虑清楚。光源的顶点着色器源码如下:

#version 320 es
layout(location = 3) in vec3 aPosition;
uniform mat4 uMatrix;void main()
{gl_Position = uMatrix * vec4(aPosition, 1.0);
}

很简单,变换矩阵的结果乘以顶点坐标就可以了,记往变换矩阵在左,顶点坐标在右,千万不能搞错!!片段着色器源码如下:

#version 320 es
precision mediump float;
uniform vec3 uLightColor;
out vec4 FragColor;void main()
{FragColor = vec4(uLightColor, 1f);
}

定义光源的颜色为uLightColor,我们使用uniform类型的变量直接赋值,也就不用在经过顶点着色的中转了。

再来看一下ColorCube,该类的完整源码如下:

package com.opengl.learn.aric.color;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 ColorCube {private final float[] mVerticesData ={// back face0.5f, 0.5f, -0.5f,     // (5) Top-right far0.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 far0.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 near0.5f, -0.5f, 0.5f,     // (3) Bottom-right near0.5f, -0.5f, 0.5f,     // (3) Bottom-right near0.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 face0.5f, 0.5f, 0.5f,     // (1) Top-right near0.5f, -0.5f, 0.5f,     // (3) Bottom-right near0.5f, -0.5f, -0.5f,      // (7) Bottom-right far0.5f, -0.5f, -0.5f,      // (7) Bottom-right far0.5f, 0.5f, -0.5f,     // (5) Top-right far0.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 far0.5f, -0.5f, -0.5f,      // (7) Bottom-right far0.5f, -0.5f, -0.5f,      // (7) Bottom-right far0.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 near0.5f, 0.5f, 0.5f,     // (1) Top-right near0.5f, 0.5f, 0.5f,     // (1) Top-right near0.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[] mLightColorsData = {1.0f, 0.5f, 0.31f};private static final String TAG = ColorCube.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 mProgramObject;private int uTextureContainer, containerTexture;private int uTextureFace, faceTexture;private int uMatrixLocation, uLightColor;private FloatBuffer mVerticesBuffer;private FloatBuffer mColorsBuffer;private FloatBuffer mTextureBuffer;private ShortBuffer mIndicesBuffer;private int mWidth, mHeight;private int mVAO, mVBO, mCBO, mTBO;private float[] uMatrix = 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 float radius = 30f;private long startTime = 0;private float[][] directions = {{0f, 0.0f, -10f}, {2.3f, 1.7f, -15.0f}, {-2.5f, -0.2f, -20.5f}, {-0.8f, -1.65f, -12.3f}, {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 ColorCube(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);}public void onSurfaceCreated() {mProgramObject = OpenGLUtils.loadProgram(mContext, R.raw.glcolor_cube_vertex, R.raw.glcolor_cube_fragment);uTextureContainer = glGetUniformLocation(mProgramObject, "uTextureContainer");uTextureFace = glGetUniformLocation(mProgramObject, "uTextureFace");uMatrixLocation = glGetUniformLocation(mProgramObject, "uMatrix");uLightColor = glGetUniformLocation(mProgramObject, "uLightColor");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];Log.e(TAG, "onSurfaceCreated, " + mProgramObject + ", uTexture: " + uTextureContainer + ", uTextureFace: " + uTextureFace);containerTexture = OpenGLUtils.loadTexture(mContext, R.mipmap.container);faceTexture = OpenGLUtils.loadTexture(mContext, R.mipmap.awesomeface);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);}public void onSurfaceChanged(GL10 gl, int width, int height) {mWidth = width;mHeight = height;}public void onDrawFrame() {if (startTime == 0) {startTime = System.currentTimeMillis();}GLES32.glUseProgram(mProgramObject);GLES32.glEnableVertexAttribArray(0);GLES32.glEnableVertexAttribArray(1);GLES32.glEnableVertexAttribArray(2);GLES32.glActiveTexture(GL_TEXTURE0);GLES32.glBindTexture(GL_TEXTURE_2D, containerTexture);GLES32.glUniform1i(uTextureContainer, 0);GLES32.glActiveTexture(GL_TEXTURE1);GLES32.glBindTexture(GL_TEXTURE_2D, faceTexture);GLES32.glUniform1i(uTextureFace, 1);GLES32.glUniform3fv(uLightColor, 1, mLightColorsData, 0);GLES32.glBindVertexArray(mVAO);for (int i = 0; i < directions.length; i++) {setCubeMatrix(i);GLES32.glUniformMatrix4fv(uMatrixLocation, 1, false, uMatrix, 0);GLES32.glDrawArrays(GL_TRIANGLES, 0, mVerticesData.length);}GLES32.glBindVertexArray(0);GLES32.glDisableVertexAttribArray(0);GLES32.glDisableVertexAttribArray(1);GLES32.glDisableVertexAttribArray(2);}private void setCubeMatrix(int i) {Matrix.setIdentityM(uMatrix, 0);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, 0f, 10f, 20f, 0f, 0f, 0f, 0f, 1f, 0f);Matrix.translateM(modelMatrix, 0, directions[i][0], directions[i][1], directions[i][2]);int[] rotate = {0, 0, 0};int remaind = i % 3;rotate[remaind] = 1;long degree = (now - startTime) / 100 * 5 * i;Matrix.rotateM(modelMatrix, 0, degree, rotate[0], rotate[1], rotate[2]);Matrix.multiplyMM(uMatrix, 0, viewMatrix, 0, modelMatrix, 0);Matrix.multiplyMM(uMatrix, 0, projectionMatrix, 0, uMatrix, 0);}
}

和上一节中绘制的立方体差别也比较小,因为十个立方体的位置排布的太紧,所以我调整了下directions向量中的值,让它们分散一些。因为最终的效果颜色是物体颜色乘以光源颜色,所以我们这里也要把光源颜色传递到着色器中,和绘制光源时一样,我们还是使用uniform变量直接定义它,其他的绘制的逻辑和上一节基本完全相同。

立方体的顶点着色器的完整源码如下:

#version 320 es
layout(location = 0) in vec3 aPosition;
layout(location = 1) in vec3 aColor;
layout(location = 2) in vec2 aTexCoord;
uniform mat4 uMatrix;out vec3 outColor;
out vec2 outTexCoord;void main()
{outColor = aColor;outTexCoord = aTexCoord;gl_Position = uMatrix * vec4(aPosition, 1.0);
}

这里的outColor、aColor这两个变量其实已经没用了,可以直接删除掉;outTexCoord还是中转纹理坐标到片段着色器中,没什么好说的。

最后来看一下立方体的片段着色器,源码如下:

#version 320 es
precision mediump float;
out vec4 FragColor;
in vec3 outColor;
in vec2 outTexCoord;
uniform sampler2D uTextureContainer;
uniform sampler2D uTextureFace;
uniform vec3 uLightColor;void main()
{vec4 color = mix(texture(uTextureContainer, outTexCoord), texture(uTextureFace, outTexCoord), 0.2);FragColor = color * vec4(uLightColor, 1.0);
}

color变量还是两个纹理进行插值混合的结果,也就相当于物体本身的颜色;uLightColor就是光源颜色了,按照最开始的原理,将它们两个相乘就得到物体显示的最终效果了,简单吧。

好了,本节的内容就这么多了,越往后看,大家会越发现,到后边的那些非常炫的效果,都是基于一些物理定理或者前人总结的原理上实现出来的,相当于我们就是把定理或者原理中的变量一个个计算出来,然后按照定理计算一下,就可以得到最终的效果了,必须要有这样的认识,我们才能有提纲挈领的认识和掌握。

下一节我们继续学习基础光照的知识。

Opengl ES系列学习--颜色相关推荐

  1. Opengl ES系列学习--顶点属性、顶点数组和缓冲区对象

    本节我们继续来看一下<OPENGL ES 3.0编程指南 原书第2版(中文版)>书中第6章的内容,PDF下载地址:OPENGL ES 3.0编程指南 原书第2版(中文版),代码下载地址:O ...

  2. Opengl ES系列学习--顶点着色器

    本节我们继续来看一下<OPENGL ES 3.0编程指南 原书第2版(中文版)>书中第8章的内容,PDF下载地址:OPENGL ES 3.0编程指南 原书第2版(中文版),代码下载地址:O ...

  3. Opengl ES系列学习--glViewport API使用

    去年有分析了一些Opengl ES的实例,但是后面在实际的工作中,发现根基不牢,工作中使用的一些复杂场景还是理解的不够透彻,所以回过心来,必须把基础把扎实.从这节开始,我们后面对一些非常基础普通的Op ...

  4. Opengl ES系列学习--莫比乌斯带

    一个莫比乌斯带的shader,效果如下: Java类为GlMobiusRender,完整源码如下: package com.opengl.learn.aric;import android.conte ...

  5. Opengl ES系列学习--太阳

    继续积累Shadertoy,大家也可去Shader女神的CSDN逛逛:Shader女神.使用别人写好的shader实现的一个太阳的效果,太漂亮了!!! 该效果实现是GlSunRender类,完整源码如 ...

  6. OpenGl文章 Android OpenGL ES 简明开发教程

    Android OpenGL ES 简明开发教程 分类:android学习笔记2011-12-14 15:04375人阅读评论(0)收藏举报 ApiDemos 的Graphics示例中含有OpenGL ...

  7. IOS OpenGL ES GPUImage 滤色混合 GPUImageScreenBlendFilter

    目录 一.简介 二.效果演示 三.源码下载 四.猜你喜欢 零基础 OpenGL (ES) 学习路线推荐 : OpenGL (ES) 学习目录 >> OpenGL ES 基础 零基础 Ope ...

  8. IOS – OpenGL ES 图像柏林噪点/花边噪点 GPUImagePerlinNoiseFilter

    目录 一.简介 二.效果演示 三.源码下载 四.猜你喜欢 零基础 OpenGL (ES) 学习路线推荐 : OpenGL (ES) 学习目录 >> OpenGL ES 基础 零基础 Ope ...

  9. IOS – OpenGL ES 图像鱼眼扩散效果 GPUImageBulgeDistortionFilter

    目录 一.简介 二.效果演示 三.源码下载 四.猜你喜欢 零基础 OpenGL (ES) 学习路线推荐 : OpenGL (ES) 学习目录  >> OpenGL ES 基础 零基础 Op ...

最新文章

  1. 前端入门(雨滴特效,css)
  2. 【NetApp】7mode options选项解释
  3. 为什么不应该重写service方法?
  4. 如何监听WebView完成加载URL?
  5. 桁架机器人运动视频_桁架机器人的直线定位单元
  6. 怎么进入python官网-Python的安装及简单的使用
  7. c面试题总结(含答案)
  8. mapreduce与spark的区别--内容详细
  9. Firebird数据库的Select语句
  10. html th width无效 解决方法
  11. 2022最新第四方聚合支付系统源码+详细搭建教程
  12. python requests 最新抓取百度翻译内容,js逆向,亲测有效
  13. 【Oracle】并行等待之PX Deq Credit: send blkd
  14. 垃圾收集器面试总结(一)
  15. MaterialSkin与系统Panel容器结合使用,实现自适应舒适布局
  16. spring组合注解
  17. linux mint19 无线网卡wifi速度慢解决办法
  18. CMOS和CCD相机对比
  19. RN TSX基于react-native-vector-icons和iconfont.cn 的生成自定义Icon组件的工具
  20. 英语语法汇总(7.介词)

热门文章

  1. 如何运用DDD(一):值对象
  2. iPhone手机装机必备的5个APP,每个都让你欲罢不能,瞬间逼格满满!
  3. 就当花儿没开过,就当我没来过
  4. CnOpenData数据产品入驻福建大数据交易所!
  5. netapp管理地址_NetApp ONTAP Simulator部署指南(1)
  6. 搜狐这个Firefox合法吗?
  7. 用友添加nc显示服务器不可用,NC启动服务的时候出现这个问题,急求解决
  8. 多元宇宙量子计算机进展,斯蒂芬霍金的最后一篇论文提出了无限的多元宇宙理论...
  9. Win11遇到问题需要重启怎么办?
  10. proe指定服务器安装,ucs-c系列服务器安装配置-v1