OpenGLES2.0笔记

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值