Android-openGL ES绘制点.线段.三角形

openGL ES绘制的基本流程

1.创建一个类,继承自GLSurfaceView
2.创建渲染器Render,实现三个方法
3.创建绘制对象,初始化顶点数据
4.开始绘制

准备工作

首先创建一个类,继承自GLSurfaceView,重写两个参数构造方法.跟自定义View一样,一个参数构造是为在代码中new的形式创建对象,两个参数构造是为在XML中创建对象.
在构造方法中建立init方法,准备初始化工作.

  1. 创建view对象
public class EGLView extends GLSurfaceView {

    public EGLView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        EGLRenderer renderer = new EGLRenderer();//创建渲染器
        setRenderer(renderer);//设置渲染器
        setRenderMode(RENDERMODE_CONTINUOUSLY);//设置渲染模式为主动渲染
    }

    //创建渲染器Rander对象
    private class EGLRenderer implements Renderer {
       private SanJiaoXing sanJiaoXing;
       @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            gl.glClearColor(0, 1, 1, 1);//设置背景色
            //也在这里对绘制对象进行初始化
            //此处以三角形为例,绘制其他,替换掉即可
            sanJiaoXing = new SanJiaoXing();
        }

        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            gl.glViewport(0, 0, width, height);//设置视口为整个屏幕,前两参数是屏幕原点,后两个参数为屏幕宽高
            gl.glMatrixMode(GL10.GL_PROJECTION);//设置投影矩阵
            gl.glLoadIdentity();//使矩阵生效
            float r = (float) width / height;//获得宽高比
            gl.glFrustumf(-r, r, -1, 1, 1, 20);//设置视角大小
        }

        @Override
        public void onDrawFrame(GL10 gl) {

            gl.glClear(GL10.GL_DEPTH_BUFFER_BIT | GL10.GL_COLOR_BUFFER_BIT);//清理深度缓存和颜色缓存
            gl.glMatrixMode(GL10.GL_MODELVIEW);//设置模型矩阵
            gl.glLoadIdentity();//使矩阵生效
            //为防止渲染图像渲染在近平面之前,我们对图像进行Z轴平移
            gl.glTranslatef(0, 0, -1.5f);//z轴平移1.5

            //在这里进行绘制
            //此处以三角形为例,绘制其他,替换掉即可
            sanJiaoXing.drawSelf(gl);
        }
  }
}

Android-openGL ES绘制点.线段.三角形_第1张图片
宽高比.png

视口大小中,我们获得的宽高比:

为了计算方便,我们将高度H设置为单位长度1,则宽度应为r = W/H.
设中心点为0,那么,左右上下分别为-r,r,1,-1.

投影分类:正交投影/透视投影

正交投影:没有近大远小效果


Android-openGL ES绘制点.线段.三角形_第2张图片
正交投影.png

透视投影:有近大远小效果,视野更宽广


Android-openGL ES绘制点.线段.三角形_第3张图片
透视投影.png
Render类

我们继承Render,实现了三个方法,分别为

onSurfaceCreated
onSurfaceChanged
onDrawFrame

onSurfaceCreated只在第一次初始化的时候调用,初始化结束后会调用onSurfaceChanged.每次渲染时会调用onDrawFrame.

渲染分为主动渲染(RENDERMODE_CONTINOUSLY)和等待渲染(RENDERMODE_WHEN_DIRTY).
主动渲染就是一直不停的在渲染,会持续调用onDrawFrame进行绘制.
等待渲染只有在调用requestRender()方法时才会唤醒onDrawFrame进行绘制.

我们在init()方法中对Render进行初始化.

  1. 在Activity的xml里引用刚才建立的view





  1. 准备的工具类(青坏坏版),将数组放入缓冲区
public abstract class OpenGLUtils {

    public FloatBuffer getFloatbuffer(float[] ver) {
        ByteBuffer vbb = ByteBuffer.allocateDirect(ver.length * 4);
        vbb.order(ByteOrder.nativeOrder());
        FloatBuffer buffer = vbb.asFloatBuffer();
        buffer.put(ver);
        buffer.position(0);
        return buffer;
    }

    public ByteBuffer getByteBuffer(byte[] indices) {
        //创建三角形构造索引数据缓冲
        ByteBuffer indexBuffer = ByteBuffer.allocateDirect(indices.length);
        indexBuffer.put(indices);
        indexBuffer.position(0);
        return indexBuffer;
    }

    public IntBuffer getIntBuffer(int[] ver) {
        //创建顶点坐标数据缓存,由于不同平台字节顺序不同,数据单元不是字节的
        // 一定要经过ByteBuffer转换,关键是通过ByteOrder设置nativeOrder()
        //一个整数四个字节,根据最新分配的内存块来创建一个有向的字节缓冲
        ByteBuffer vbb = ByteBuffer.allocateDirect(ver.length * 4);
        vbb.order(ByteOrder.nativeOrder());//设置这个字节缓冲的字节顺序为本地平台的字节顺序
        IntBuffer intBuffer = vbb.asIntBuffer();//转换为int型缓冲
        intBuffer.put(ver);//向缓冲区中放入顶点坐标数据
        intBuffer.position(0);//设置缓冲区的起始位置
        return intBuffer;
    }
}
  1. 创建绘制对象
public class SanJiaoXing extends OpenGLUtils {

  public SanJiaoXing() {
        init();
    }

  private void init() {

  }

  public void drawSelf(GL10 gl) {
  }

}

开始绘制

绘制点

import com.otitan.opengltest.utils.OpenGLUtils;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import javax.microedition.khronos.opengles.GL10;

public class Points extends OpenGLUtils {

    private IntBuffer verBuffer;
    private IntBuffer colorBuffer;
    private ByteBuffer indexBuffer;

    public Points () {
        init();
    }

    private void init() {
        //顶点数据

        int UNIT_SIZE = 10000;//比例
        int var[] = new int[]{//初始化6个点,每三个一组(x,y,z坐标)
                -3 * UNIT_SIZE, -2 * UNIT_SIZE, 0,
                0, -2 * UNIT_SIZE, 0,
                -1 * UNIT_SIZE, 1 * UNIT_SIZE, 0,
                2 * UNIT_SIZE, -3 * UNIT_SIZE, 0,
                1 * UNIT_SIZE, 2 * UNIT_SIZE, 0,

                2 * UNIT_SIZE, 1 * UNIT_SIZE, 0
        };

        verBuffer = getIntBuffer(var);//创建数据缓冲

        //颜色数据
        int one = 65536;//支持65536色彩通道
        //顶点个数=颜色个数
        //颜色数据(RGB A)
        int color[] = new int[]{
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0
        };
        colorBuffer = getIntBuffer(color);

        //创建索引数组
        byte index[] = new byte[]{
                0, 1, 2, 3, 4, 5
        };

        indexBuffer = getByteBuffer(index);//注意此处为byte类型
    }

    //绘制自身
    public void drawSelf(GL10 gl) {
        //启用顶点数组坐标
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        //启用顶点颜色数组
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

        //设置画笔,给画笔设置顶点数据
        gl.glVertexPointer(3,//verBuffer中多少个数据是一个顶点
          GL10.GL_FIXED,//数据类型-这个代表整形
          0,//顶点间隔,默认0
          verBuffer );//顶点数据

        //给画笔指定顶点颜色数据
        gl.glColorPointer(4,GL10.GL_FIXED,0,colorBuffer);//同顶点数据

        gl.glPointSize(20);//设置点大小,太小的话看不见
        gl.glDrawElements(GL10.GL_POINTS,//绘制类型
               6, //绘制顶点个数,即索引数组中点个数,可小于数组长度
               GL10.GL_UNSIGNED_BYTE, indexBuffer);
    }
}

点绘制效果如下:


Android-openGL ES绘制点.线段.三角形_第4张图片
点.jpg

绘制线段

import com.otitan.opengltest.utils.OpenGLUtils;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import javax.microedition.khronos.opengles.GL10;

public class Line extends OpenGLUtils {

    private IntBuffer verBuffer;
    private IntBuffer colorBuffer;
    private ByteBuffer indexBuffer;

    public Line() {
        init();
    }

    private void init() {
        //顶点数据

        int UNIT_SIZE = 10000;
        int var[] = new int[]{
                -3 * UNIT_SIZE, -2 * UNIT_SIZE, 0,
                0, -2 * UNIT_SIZE, 0,
                -1 * UNIT_SIZE, 1 * UNIT_SIZE, 0,
                2 * UNIT_SIZE, -3 * UNIT_SIZE, 0,
                1 * UNIT_SIZE, 2 * UNIT_SIZE, 0,

                2 * UNIT_SIZE, 1 * UNIT_SIZE, 0
        };

        verBuffer = getIntBuffer(var);

        //颜色数据
        int one = 65536;
        int color[] = new int[]{
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0
        };
        colorBuffer = getIntBuffer(color);

        //创建索引数组
        byte index[] = new byte[]{
                0, 1, 2, 3, 4, 5
        };

        indexBuffer = getByteBuffer(index);
    }

    public void drawSelf(GL10 gl) {
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

        gl.glVertexPointer(3, GL10.GL_FIXED, 0, verBuffer);

        gl.glColorPointer(4, GL10.GL_FIXED, 0, colorBuffer);

        gl.glLineWidth(30);//设置线宽,线太窄时看不见
        gl.glDrawElements(GL10.GL_LINES, 6, GL10.GL_UNSIGNED_BYTE, indexBuffer);
    }
}

正常绘制:两个点一组进行点的绘制,如果只有一个点就会舍弃这个点

正常绘制效果如下:
gl.glDrawElements(GL10.GL_LINES, 6, GL10.GL_UNSIGNED_BYTE, indexBuffer);

Android-openGL ES绘制点.线段.三角形_第5张图片
正常绘制.png

条带线:按照顶点顺序连接顶点

gl.glDrawElements(GL10.GL_LINE_STRIP, 6, GL10.GL_UNSIGNED_BYTE, indexBuffer);
条带线绘制效果如下:

Android-openGL ES绘制点.线段.三角形_第6张图片
line_strip.jpg

循环线:按照顶点顺序连接顶点,最后一个点连接第一点
gl.glDrawElements(GL10.GL_LINE_LOOP, 6, GL10.GL_UNSIGNED_BYTE, indexBuffer);
循环线效果如下:

Android-openGL ES绘制点.线段.三角形_第7张图片
循环线.jpg

绘制三角形

import com.otitan.opengltest.utils.OpenGLUtils;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import javax.microedition.khronos.opengles.GL10;


public class SanJiaoXing extends OpenGLUtils {

    private IntBuffer verBuffer;
    private IntBuffer colorBuffer;
    private ByteBuffer indexBuffer;

    public SanJiaoXing() {
        init();
    }

    private void init() {
        //顶点数据

        int UNIT_SIZE = 10000;
        int var[] = new int[]{
                -3 * UNIT_SIZE, -2 * UNIT_SIZE, 0,
                0, -2 * UNIT_SIZE, 0,
                -1 * UNIT_SIZE, 1 * UNIT_SIZE, 0,
                2 * UNIT_SIZE, -3 * UNIT_SIZE, 0,
                1 * UNIT_SIZE, 2 * UNIT_SIZE, 0,
                2 * UNIT_SIZE, 1 * UNIT_SIZE, 0
        };

        verBuffer = getIntBuffer(var);

        //颜色数据
        int one = 65536;
        int color[] = new int[]{
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0
        };
        colorBuffer = getIntBuffer(color);

        //创建索引数组,即绘制点位的顺序,此处为顺序绘制,亦可乱序绘制
        //如1,0,3,2,5,4
        //顺序不同,绘制效果亦不同
        byte index[] = new byte[]{
                0, 1, 2, 3, 4, 5
        };

        indexBuffer = getByteBuffer(index);
    }

    public void drawSelf(GL10 gl) {
        //启用顶点数组坐标
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        //启用顶点颜色数组
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

        //设置画笔,给画笔设置顶点数据
        gl.glVertexPointer(3,//verBuffer中多少个数据是一个顶点
          GL10.GL_FIXED,//数据类型-这个代表整形
          0,//顶点间隔,默认0
          verBuffer );//顶点数据

        //给画笔指定顶点颜色数据
        gl.glColorPointer(4,GL10.GL_FIXED,0,colorBuffer);//同顶点数据

        //索引法绘制 
        gl.glDrawElements(GL10.GL_TRIANGLES,//绘制模型(点1,线段3,三角形3)
          6,//绘制顶点个数,即索引数组中点个数,可小于数组长度
          GL10.GL_UNSIGNED_BYTE,indexBuffer);
    }
}

三角形绘制效果:

正常效果,三个点一组,如果不够三个点就会舍弃多余的点.
如下面两图,上面是当绘制5个点时的效果,下面为绘制6个点时效果.

gl.glDrawElements(GL10.GL_TRIANGLES, 5, GL10.GL_UNSIGNED_BYTE, indexBuffer);
5个点效果如下:

Android-openGL ES绘制点.线段.三角形_第8张图片
GL_TRIANGLES.png

gl.glDrawElements(GL10.GL_TRIANGLES, 6, GL10.GL_UNSIGNED_BYTE, indexBuffer);
6个点效果如下:
Android-openGL ES绘制点.线段.三角形_第9张图片
GL_TRIANGLES 2.png

三角形带:顶点按照顺序依次 组成三角形绘制,最后实际形成的是一个三角型带!

gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 6, GL10.GL_UNSIGNED_BYTE, indexBuffer);
三角形带效果如下:

Android-openGL ES绘制点.线段.三角形_第10张图片
_STRIP.png

三角形扇面:将第一个点作为中心点,其他点作为边缘点,绘制一系列的组成扇形的三角形

gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 6, GL10.GL_UNSIGNED_BYTE, indexBuffer);
三角形扇面效果如下:

Android-openGL ES绘制点.线段.三角形_第11张图片
_FAN.png

以上均为索引法绘制,下面展示下数组法绘制:

package com.otitan.opengltest.draw;

import com.otitan.opengltest.utils.OpenGLUtils;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import javax.microedition.khronos.opengles.GL10;

public class SanJiaoXing extends OpenGLUtils {

    private IntBuffer verBuffer;
    private IntBuffer colorBuffer;
    //private ByteBuffer indexBuffer;

    public SanJiaoXing() {
        init();
    }

    private void init() {
        //顶点数据

        int UNIT_SIZE = 10000;
        int var[] = new int[]{
                -3 * UNIT_SIZE, -2 * UNIT_SIZE, 0,
                0, -2 * UNIT_SIZE, 0,
                -1 * UNIT_SIZE, 1 * UNIT_SIZE, 0,
                2 * UNIT_SIZE, -3 * UNIT_SIZE, 0,
                1 * UNIT_SIZE, 2 * UNIT_SIZE, 0,

                2 * UNIT_SIZE, 1 * UNIT_SIZE, 0
        };

        verBuffer = getIntBuffer(var);

        //颜色数据
        int one = 65536;
        int color[] = new int[]{
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0,
                one, 0, 0, 0
        };
        colorBuffer = getIntBuffer(color);

        //使用数组法,索引值就不需要了
        //创建索引数组
        //byte index[] = new byte[]{
        //       0, 1, 2, 3, 4, 5
        //};

        //indexBuffer = getByteBuffer(index);
    }

    public void drawSelf(GL10 gl) {
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

        gl.glVertexPointer(3, GL10.GL_FIXED, 0, verBuffer);

        gl.glColorPointer(4, GL10.GL_FIXED, 0, colorBuffer);

        //此为索引法绘制
        //gl.glDrawElements(GL10.GL_TRIANGLE_FAN, 6, GL10.GL_UNSIGNED_BYTE, indexBuffer);


        //数组法绘制
        gl.glDrawArrays(
             GL10.GL_TRIANGLE_FAN,//绘制类型
             0, //起始值,即顶点数据三个数据为一组,从哪个组开始绘制
             6);//绘制个数
    }
}

效果和之前的扇面三角形是一样的,不再重复展示.上面7种绘制,均可使用数组法.有兴趣可自己尝试.

你可能感兴趣的:(Android-openGL ES绘制点.线段.三角形)