OpenGLES2.0笔记

来源:互联网 发布:php软件开发工具 编辑:程序博客网 时间:2024/05/21 06:16

capacity:容量
allocate:分配
Coord:坐标
vertex:顶点
Square:平面
Program:程序
Compile:编译
font:字体
pname:工程名称
Validate:验证
Uniform:均匀

ByteBuffer和FloatBuffer是java.nio包下的类
ByteBuffer bb=ByteBuffer.allocate(capacity);//参数是一个容量
ByteBuffer bb2=ByteBuffer.allocateDirect(capacity);//这个方法在参与I/O操作性能会更好

called unimplemented OpenGL ES API 报错。。

坐标系:安卓中的坐标系在横屏的时候会变形,变粗,所以在横屏的时候需要处理摄像机。
屏幕的左上角是(-1.0,1.0)横向向右为X轴正向,纵向向下为Y轴负向,其范围都是从 -1到 +1。

我们在该类中定义的float类型的数据并不能直接被opengl使用,float[]是属于虚拟机环境的,而Opengl作为本地系统库
直接运行在硬件上,所以我们需要将float[] 转化为FloatBuffer以使数据可以被opengl使用
//如下浮点数组代表的是一个三角形的顶点坐标
float[] vertex={0.1f,0.1f,
0.1f,0.1f,
0.1f,0.1f};
//浮点缓冲
FloatBuffer fb=FloatBuffer.allocate(int capacity);
//把顶点坐标添加到FloatBuffer中,并把位置0作为开始位置。
fb.put(vertex);
fb.position(0);

着色器语言(shading language),由C/C++编写
如下是顶点shader
attribute vec4 a_Position;
void main()
{
gl_Position = a_Position;
}

gl_Position即opengl定义的顶点的坐标,我们目的就是通过这个来告诉opengl我们的顶点数据。
vec4是着色器语言中的向量类型的一种,包含了四个浮点数的向量

如下是面shader
precision mediump float;
uniform vec4 u_Color;
void main()
{
gl_FragColor = u_Color;
}

传入一个颜色信息。这里注意一下 上面顶点着色器的 限定符 attribute 和 uniform 。attribute 一般用于每个顶点
各不相同的量,如顶点位置等,后者一般用于同一组顶点组成的相同的量,如光源位置,一组颜色等。

编写shader的帮助类ShaderHelper和TextResourceReader,可以直接使用。
在使用的时候通过TextResourceReader的readTextFileFromResource(Context context,int resourceId)方法返回shader字符串,然后再用ShaderHelper的buildProgram(String vertexShaderSource,String fragmentShaderSource)返回的内容直接使用。
ShaderHelper主要功能是
1,读取shader文本内容
2,编译shader
3,将顶点shader和面shader链接成program
4,验证program
TextResourceReader主要功能是
1,把shader源代码通过流的转换返回我们需要的shader字符串。

public class ShaderHelper {    private static final String TAG = "ShaderHelper";    /**     * 加载并编译顶点shader,返回得到的opengl id     * @param shaderCode     * @return     */    public static int compileVertexShader(String shaderCode) {        return compileShader(GL_VERTEX_SHADER, shaderCode);    }    /**     * 加载并编译片段shader,返回opengl id     * @param shaderCode     * @return     */    public static int compileFragmentShader(String shaderCode) {        return compileShader(GL_FRAGMENT_SHADER, shaderCode);    }    /**     * 加载并编译着色器,返回opengl id     * @param type     * @param shaderCode     * @return     */    private static int compileShader(int type, String shaderCode) {        // 建立新的着色器对象        final int shaderObjectId = glCreateShader(type);        if (shaderObjectId == 0) {            if (LoggerConfig.ON) {                Log.w(TAG, "不能创建新的着色器.");            }            return 0;        }        // 传递着色器资源代码.        glShaderSource(shaderObjectId, shaderCode);        //编译着色器        glCompileShader(shaderObjectId);        // 获取编译的状态        final int[] compileStatus = new int[1];        glGetShaderiv(shaderObjectId, GL_COMPILE_STATUS,            compileStatus, 0);        if (LoggerConfig.ON) {            //打印log            Log.v(TAG, "代码编译结果:" + "\n" + shaderCode                + "\n:" + glGetShaderInfoLog(shaderObjectId));        }        // 确认编译的状态        if (compileStatus[0] == 0) {            // 如果编译失败,则删除该对象            glDeleteShader(shaderObjectId);            if (LoggerConfig.ON) {                Log.w(TAG, "编译失败!.");            }            return 0;        }        // 返回着色器的opengl id        return shaderObjectId;    }    /**     * 链接顶点着色器和片段着色器成一个program     * 并返回这个pragram的opengl id     * @param vertexShaderId     * @param fragmentShaderId     * @return     */    public static int linkProgram(int vertexShaderId, int fragmentShaderId) {        // 新建一个program对象        final int programObjectId = glCreateProgram();        if (programObjectId == 0) {            if (LoggerConfig.ON) {                Log.w(TAG, "不能新建一个 program");            }            return 0;        }        //把点shader添加到program中        glAttachShader(programObjectId, vertexShaderId);        //把shader添加到program中        glAttachShader(programObjectId, fragmentShaderId);        //将两个着色器连接成一个program        glLinkProgram(programObjectId);        // 获取连接状态        final int[] linkStatus = new int[1];        glGetProgramiv(programObjectId, GL_LINK_STATUS,linkStatus, 0);        if (LoggerConfig.ON) {            // Print the program info log to the Android log output.            Log.v(                TAG,                "Results of linking program:\n"                    + glGetProgramInfoLog(programObjectId));        }        // 验证连接状态        if (linkStatus[0] == 0) {            // 如果失败就删除            glDeleteProgram(programObjectId);            if (LoggerConfig.ON) {                Log.w(TAG, "连接 program 失败!.");            }            return 0;        }        // Return the program object ID.        return programObjectId;    }    /**     * Validates an OpenGL program. Should only be called when developing the     * application.     */    public static boolean validateProgram(int programObjectId) {        glValidateProgram(programObjectId);        final int[] validateStatus = new int[1];        glGetProgramiv(programObjectId, GL_VALIDATE_STATUS,            validateStatus, 0);        Log.v(TAG, "Results of validating program: " + validateStatus[0]            + "\nLog:" + glGetProgramInfoLog(programObjectId));        return validateStatus[0] != 0;    }    /**     * /**     * 编译,连接 ,返回 program 的 ID     * @param vertexShaderSource     * @param fragmentShaderSource     * @return     */    public static int buildProgram(String vertexShaderSource,        String fragmentShaderSource) {        int program;        // Compile the shaders.        int vertexShader = compileVertexShader(vertexShaderSource);        int fragmentShader = compileFragmentShader(fragmentShaderSource);        // Link them into a shader program.        program = linkProgram(vertexShader, fragmentShader);        if (LoggerConfig.ON) {            validateProgram(program);        }        return program;    }}

如下工具类TextResourceReader是把shader源代码通过流的转换返回我们需要的shader字符串。

public class TextResourceReader {    public static String readTextFileFromResource(Context context,        int resourceId) {        StringBuilder body = new StringBuilder();        try {            InputStream inputStream =                 context.getResources().openRawResource(resourceId);            InputStreamReader inputStreamReader =                 new InputStreamReader(inputStream);            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);            String nextLine;            while ((nextLine = bufferedReader.readLine()) != null) {                body.append(nextLine);                body.append('\n');            }        } catch (IOException e) {            throw new RuntimeException(                "Could not open resource: " + resourceId, e);        } catch (Resources.NotFoundException nfe) {            throw new RuntimeException("Resource not found: " + resourceId, nfe);        }        return body.toString();    }}

方便打印的工具类

public class LoggerConfig {    public static final boolean ON = true;}

图形类

public class Square2 {      private Context context;      /*------------------第一步: 修改顶点数据-------------------------*/      //矩形(其实是菱形)顶点坐标 ,按逆时针    static float squareCoords[] = { -0.25f,  0.5f , // top left          0.75f,  0.5f  ,   // top right         -0.75f, -0.5f  ,   // bottom left          0.25f, -0.5f  };  // bottom right      //float类型的字节数,用于给FloatBuffer指定容量时使用    private static final int BYTES_PER_FLOAT = 4;      // 数组中每个顶点的坐标数      static final int COORDS_PER_VERTEX = 2;      /*------------------第二步: 修改顶点个数-------------------------*/      private static final int POSITION_COMPONENT_COUNT = 4;      //要把定义的float坐标数组转化成FloatBuffer类型,因为它是直接运行在硬件上的,不是java虚拟机。    private FloatBuffer vertexBuffer;    //A_POSITION是顶点shader的变量名,U_COLOR是片段shader的变量名 ,它们用于匹配shader文件中的变量。    private static final String A_POSITION = "a_Position";    private static final String U_COLOR = "u_Color";    //------------获得program的ID的含义类似的      private int uColorLocation;      private int aPositionLocation;      private int program;//保存program的id      //矩形的构造方法    public Square2(Context context) {          this.context = context;          vertexBuffer = ByteBuffer                  .allocateDirect(squareCoords.length * BYTES_PER_FLOAT)                  .order(ByteOrder.nativeOrder())                  .asFloatBuffer();          // 把坐标数组加入FloatBuffer中,并且从0下标开始读取         vertexBuffer.put(squareCoords);          vertexBuffer.position(0);          getProgram();          //----------第三步: 获取这两个ID ,通过匹配shader文件中的变量来获取        uColorLocation = GLES20.glGetUniformLocation(program, U_COLOR);          aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);          //---------第四步: 传入数据          //GLES20.glVertexAttribPointer(int indx, int size, int type, boolean normalized, int stride, Buffer ptr)        //int index:???        //int size:每个顶点的坐标数        //int type:类型,用GLES20.GL_FLOAT        //boolean normalized:???是否统一化        //int stride:???跨度           //Buffer ptr:承载坐标数组转换成的FloatBuffer。        GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,                  GLES20.GL_FLOAT, false, 0, vertexBuffer);          //使面变成顶点数组???        GLES20.glEnableVertexAttribArray(aPositionLocation);      }      //获取program,    private void getProgram(){          //获取顶点shader文本          String vertexShaderSource = TextResourceReader                  .readTextFileFromResource(context, R.raw.simple_vertex_shader);          //获取片段shader文本          String fragmentShaderSource = TextResourceReader                  .readTextFileFromResource(context, R.raw.simple_fragment_shader);          //获取program的id          program = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);          //使用该program        GLES20.glUseProgram(program);      }      public void draw(){          GLES20.glUniform4f(uColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);               //绘制模式        //GLES20.glDrawArrays(int mode, int first, int count)        //int mode:绘制模式, GLES20.GL_TRIANGLE_STRIP:将传入的顶点按照顺序依次连接进行绘制        //int first:从数组的哪个位置开始        //int count:绘制的个数        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, POSITION_COMPONENT_COUNT);      }}

Render类

public class MyRender implements Renderer {      private Context context;      public MyRender(Context context){          this.context = context;      }      //定义三角形对象      Triangle triangle;      Square2 square;      public void onSurfaceCreated(GL10 gl, EGLConfig config) {          Log.w("MyRender","onSurfaceCreated");          // TODO Auto-generated method stub          //First:设置清空屏幕用的颜色,前三个参数对应红绿蓝,最后一个对应alpha          glClearColor(1.0f, 1.0f, 1.0f, 0.0f);//      triangle = new Triangle(context);          square = new Square2(context);      }      public void onSurfaceChanged(GL10 gl, int width, int height) {          Log.w("MyRender","onSurfaceChanged");          // TODO Auto-generated method stub          //Second:设置视口尺寸,即告诉opengl可以用来渲染的surface大小          glViewport(0,0,width,height);      }      public void onDrawFrame(GL10 gl) {          Log.w("MyRender","onDrawFrame");          // TODO Auto-generated method stub          //Third:清空屏幕,擦除屏幕上所有的颜色,并用之前glClearColor定义的颜色填充整个屏幕          glClear(GL_COLOR_BUFFER_BIT);          square.draw();      }  }

Activity

public class MainActivity extends Activity {    private GLSurfaceView glSurfaceView;      @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          glSurfaceView = new GLSurfaceView(this);          glSurfaceView.setEGLContextClientVersion(2); // Pick an OpenGL ES 2.0 context.          glSurfaceView.setRenderer(new MyRender(this));          setContentView(glSurfaceView);      }  }

手机的屏幕和普通的OpenGL的坐标系不一样,因为手机横竖屏转换的时候会拉伸,
它的坐标系是Y轴向上为正,向下为负,X轴向右为正,X轴向左为负。
坐标范围是
左上角(-1.0,1.0);
右上角(1.0,1.0);
左下角(-1.0,-1.0);
右下角(1.0,-1.0);
一个正方形按照Z字形画出两个三角形,重合的点可以复用前提是在draw的时候使用GLES20.GL_TRIANGLE_STRIP模式,在画图之前需要指定顶点数量,每个顶点所占有的坐标数(坐标是从数组中依次获取,必须把float数组转换成FloatBuffer类型,OpenGL是直接在硬件中进行的,不是虚拟机)。如果使用的是不复用的模式,那么一个矩形需要指定6对坐标,也就是画出两个三角形。

画圆

0 0
原创粉丝点击