但是当时只给三角形设置了一个统一的颜色,并没有给每个顶点设置颜色,下面我们给每个顶点设置一个颜色。
public class MainActivity extends AppCompatActivity {
MyOtherGLSurfaceView surfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
surfaceView = new MyOtherGLSurfaceView(this);
setContentView(surfaceView);
}
}
public class MyOtherGLSurfaceView extends GLSurfaceView{
public MyOtherGLSurfaceView(Context context) {
super(context);
//一定要有
setEGLContextClientVersion(2);
setRenderer(new Cube());
}
}
public class Cube implements GLSurfaceView.Renderer {
String vertexShaderCode = "attribute vec4 vPosition;\n" +
"uniform mat4 vMatrix;\n" +
"void main() {\n" +
" gl_Position = vMatrix*vPosition;\n" +
"}";
String fragmentShaderCode = "precision mediump float;\n" +
" uniform vec4 vColor;\n" +
" void main() {\n" +
" gl_FragColor = vColor;\n" +
" }";
int mProgram;
float triangleCoords[] = {
0.5f, 0.5f, 0.0f, // top
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f // bottom right
};
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; //顶点统一白色
FloatBuffer vertexBuffer;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//将背景设置为灰色
GLES20.glClearColor(0.5f,0.5f,0.5f,1.0f);
//申请底层空间
ByteBuffer bb = ByteBuffer.allocateDirect(
triangleCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
//将坐标数据转换为FloatBuffer,用以传入给OpenGL ES程序
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(triangleCoords);
vertexBuffer.position(0);
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
//创建一个空的OpenGLES程序
mProgram = GLES20.glCreateProgram();
//将顶点着色器加入到程序
GLES20.glAttachShader(mProgram, vertexShader);
//将片元着色器加入到程序中
GLES20.glAttachShader(mProgram, fragmentShader);
//连接到着色器程序
GLES20.glLinkProgram(mProgram);
}
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
//计算宽高比
float ratio=(float)width/height;
//设置透视投影
Matrix.frustumM(mProjectMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
//设置相机位置
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 7.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
//计算变换矩阵
Matrix.multiplyMM(mMVPMatrix,0,mProjectMatrix,0,mViewMatrix,0);
}
int mPositionHandle;
int COORDS_PER_VERTEX = 3;
int vertexStride = 12;
int mColorHandle;
int vertexCount = 3;
int mMatrixHandler;
@Override
public void onDrawFrame(GL10 gl) {
//将程序加入到OpenGLES2.0环境
GLES20.glUseProgram(mProgram);
//获取变换矩阵vMatrix成员句柄
mMatrixHandler= GLES20.glGetUniformLocation(mProgram,"vMatrix");
//指定vMatrix的值
GLES20.glUniformMatrix4fv(mMatrixHandler,1,false,mMVPMatrix,0);
//获取顶点着色器的vPosition成员句柄
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
//启用三角形顶点的句柄
GLES20.glEnableVertexAttribArray(mPositionHandle);
//准备三角形的坐标数据
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
//获取片元着色器的vColor成员的句柄
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
//设置绘制三角形的颜色
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
//绘制三角形
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
//禁止顶点数组的句柄
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
//编译着色器
public static int loadShader(int type, String shaderCode){
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
}
我们来分析代码中的重要内容,这样在绘制多彩三角形的时候就不会出现很多意想不到的问题。
先看其中的着色器部分:
String vertexShaderCode = "attribute vec4 vPosition;\n" +
"uniform mat4 vMatrix;\n" +
"void main() {\n" +
" gl_Position = vMatrix*vPosition;\n" +
"}";
String fragmentShaderCode = "precision mediump float;\n" +
" uniform vec4 vColor;\n" +
" void main() {\n" +
" gl_FragColor = vColor;\n" +
" }";
在顶点着色器部分我们设置了顶点句柄 vPosition 和矩阵句柄 vMatrix。
在片元着色器中我们设置了颜色句柄 vColor。
句柄的名字你可以随便起一个,只是我们后面操作对应的句柄的时候需要传入你自己定义的名字。如下:
//获取矩阵句柄,传入变换矩阵
mMatrixHandler= GLES20.glGetUniformLocation(mProgram,"vMatrix");
GLES20.glUniformMatrix4fv(mMatrixHandler,1,false,mMVPMatrix,0);
//获取顶点句柄,传入顶点坐标
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
//获取颜色句柄,传入顶点颜色
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
但是此时要记住片元着色器中的颜色句柄vColor是uniform 修饰的。常用修饰如下:
只改动了Render的代码
public class Cube implements GLSurfaceView.Renderer {
String vertexShaderCode = "attribute vec4 vPosition;\n" +
"uniform mat4 vMatrix;\n" +
"varying vec4 vColor;\n" +
"attribute vec4 aColoa;\n" +
"void main() {\n" +
" gl_Position = vMatrix*vPosition;\n" +
" vColor=aColoa;\n" +
"}" ;
String fragmentShaderCode = "precision mediump float;\n" +
" varying vec4 vColor;\n" +
" void main() {\n" +
" gl_FragColor = vColor;\n" +
" }";
int mProgram;
float triangleCoords[] = {
0.5f, 0.5f, 0.0f, // top
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f // bottom right
};
//三个顶点各自设置颜色
float colors[] = {
0.0f, 1.0f, 0.0f, 1.0f ,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
FloatBuffer vertexBuffer;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//将背景设置为灰色
GLES20.glClearColor(0.5f,0.5f,0.5f,1.0f);
//申请底层空间
ByteBuffer bb = ByteBuffer.allocateDirect(
triangleCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
//将坐标数据转换为FloatBuffer,用以传入给OpenGL ES程序
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(triangleCoords);
vertexBuffer.position(0);
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
//创建一个空的OpenGLES程序
mProgram = GLES20.glCreateProgram();
//将顶点着色器加入到程序
GLES20.glAttachShader(mProgram, vertexShader);
//将片元着色器加入到程序中
GLES20.glAttachShader(mProgram, fragmentShader);
//连接到着色器程序
GLES20.glLinkProgram(mProgram);
}
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
//计算宽高比
float ratio=(float)width/height;
//设置透视投影
Matrix.frustumM(mProjectMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
//设置相机位置
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 7.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
//计算变换矩阵
Matrix.multiplyMM(mMVPMatrix,0,mProjectMatrix,0,mViewMatrix,0);
}
int mPositionHandle;
int COORDS_PER_VERTEX = 3;
int vertexStride = 12;
int mColorHandle;
int vertexCount = 3;
int mMatrixHandler;
@Override
public void onDrawFrame(GL10 gl) {
//将程序加入到OpenGLES2.0环境
GLES20.glUseProgram(mProgram);
//获取变换矩阵vMatrix成员句柄
mMatrixHandler= GLES20.glGetUniformLocation(mProgram,"vMatrix");
//指定vMatrix的值
GLES20.glUniformMatrix4fv(mMatrixHandler,1,false,mMVPMatrix,0);
//获取顶点着色器的vPosition成员句柄
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
//启用三角形顶点的句柄
GLES20.glEnableVertexAttribArray(mPositionHandle);
//准备三角形的坐标数据
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
ByteBuffer dd = ByteBuffer.allocateDirect(
colors.length * 4);
dd.order(ByteOrder.nativeOrder());
FloatBuffer colorBuffer = dd.asFloatBuffer();
colorBuffer.put(colors);
colorBuffer.position(0);
//获取片元着色器的aColoa成员的句柄
mColorHandle = GLES20.glGetAttribLocation(mProgram, "aColoa");
//设置绘制三角形的颜色
GLES20.glEnableVertexAttribArray(mColorHandle);
GLES20.glVertexAttribPointer(mColorHandle,4,
GLES20.GL_FLOAT,false,
0,colorBuffer);
//绘制三角形
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
//禁止顶点数组的句柄
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
//编译着色器
public static int loadShader(int type, String shaderCode){
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
}
修改着色器,来看其中的着色器部分:
String vertexShaderCode = "attribute vec4 vPosition;\n" +
"uniform mat4 vMatrix;\n" +
"varying vec4 vColor;\n" +
"attribute vec4 aColoa;\n" +
"void main() {\n" +
" gl_Position = vMatrix*vPosition;\n" +
" vColor=aColoa;\n" +
"}" ;
String fragmentShaderCode = "precision mediump float;\n" +
" varying vec4 vColor;\n" +
" void main() {\n" +
" gl_FragColor = vColor;\n" +
" }";
我们看到其中的颜色变量 vColor是用 varying修饰的,表示这是从顶点着色器传到片元着色器的变量。
而在顶点着色器中 vColor 又是由 aColoa赋值的。
如果我们需要给每个顶点都传入颜色,就需要先获得aColoa句柄,然后对aColoa句柄传入顶点颜色数组。
在上面代码中有:
ByteBuffer dd = ByteBuffer.allocateDirect(
colors.length * 4);
dd.order(ByteOrder.nativeOrder());
FloatBuffer colorBuffer = dd.asFloatBuffer();
colorBuffer.put(colors);
colorBuffer.position(0);
//获取片元着色器的aColoa成员的句柄
mColorHandle = GLES20.glGetAttribLocation(mProgram, "aColoa");
//设置绘制三角形的颜色
GLES20.glEnableVertexAttribArray(mColorHandle);
GLES20.glVertexAttribPointer(mColorHandle,4,
GLES20.GL_FLOAT,false,
0,colorBuffer);
运行程序。