OpenGL ES (14): 重点-- 小总结 及--绘制多彩三角形

1.简述


  1. 之前我们绘制了三角形。 OpenGL ES (7): 绘制三角形
  2. 后来为了防止三角形不会变形,又使用了投影矩阵和相机视图变换矩阵。 OpenGL ES (8): 使用投影视图和相机视图
  3. 后来又加入旋转效果 。OpenGL ES (9): OpenGL ES 添加运动效果-旋转
  • 其中要注意的是你的 GLSurfaceView 必须设置 setEGLContextClientVersion(2);
  • 不然打开程序就是黑屏。

但是当时只给三角形设置了一个统一的颜色,并没有给每个顶点设置颜色,下面我们给每个顶点设置一个颜色。

2.先看之前的完整代码(省得倒回去查找)


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 修饰的。常用修饰如下:

  • attribute一般用于每个顶点都各不相同的量。如 vPosition
  • uniform一般用于对同一组顶点组成的3D物体中各个顶点都相同的量。如 vMatrix
  • varying一般用于从顶点着色器传入到片元着色器的量。接下来会讲到

3.绘制多彩三角形代码


只改动了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);

运行程序。

猜你喜欢

转载自blog.csdn.net/qq_38261174/article/details/83061945
今日推荐