OpenGL ES 之投影及各种变换及绘制方式

OpenGL ES 之投影及各种变换及绘制方式

两种投影方式

我们知道,在图元装配之后的光栅化阶段前,首先需要把虚拟3D世界的物体投影到二维平面上。OpenGL ES中常用的投影模式有两种,分别是正交投影与透视投影:

正交投影

OpenGL ES 2.0中,根据应用程序提供的投影矩阵,管线会确定一个可视空间区域,称之为视景体。视景体是由6个平面确定的,这6个平面分别为:上平面(up),下平面(down),做平面(left),右平面(right),远平面(far),近平面(near)。

场景中处于视景体内的物体会被投影到近平面上(视景体外的物体将被裁剪掉),然后再将近平面上投影出的内容映射到屏幕上的视口中。
对于正交投影而言,视景体及近平面的情况如图:

zhengjiao.png

我们可以看到,正交投影是平行投影的一种,其视景体是长方体,投影到近平面上的图形不会产生“近大远小”的效果。

我们可以这样来进行正交投影的设置:

Matrix.orthoM(
            mProjectMatirx, //投影矩阵
            0, //偏移量
            left,right,//near面的left,right
            bottom,top,//near面的bottom,top
            near,far//near面,far面与视点的距离
    );

透视投影

现实世界中,人眼观察物体时会有“近大远小”的效果,这种效果,是不能用正交投影来实现的,可以采用透视投影。透视投影的投影线是不平行的,他们相交于视点。

toushi.png

我们可以看到,透视投影的投影线互不平行,都相交于视点。因此同样尺寸大小的物体,近处的投影出来大,远处的投影出来小,从而产生了“近大远小”的效果。

我们可以这样来进行透视投影的设置:

Matrix.frustumM(
            mProjectMatirx, //投影矩阵
            0, //偏移量
            left,right,//near面的left,right
            bottom,top,//near面的bottom,top
            near,far//near面,far面与视点的距离
    );

有一张图,更能看清楚这两种投影的区别:

touying.png

各种变换

平移变换

将P点沿X,Y,Z轴平移mx,my,mz:

translate.png

其中我们把P矩阵前面的矩阵叫M矩阵

选择变换

OpenGL ES中,选择角度的正负可以用右手螺旋定制来确定:右手握住旋转轴,使大拇指指向旋转轴的正方向,4指环绕的方向即为旋转的正方向,也就是旋转角为正值

旋转的M矩阵为;

translate.png

上诉矩阵表示将指定的点P绕轴向量u选择Θ°,其中的ux,uy,uz表示u向量在x,y,z轴上的分量。

缩放变换
scale.png
变换的实质

变换实际上并不是直接针对物体进行的,而是针对坐标进行的。OpenGL ES中变换的实现机制可以理解为首先通过矩阵对坐标系进行变换,然后根据传入渲染管线的原始顶点坐标在最终变换结果坐标系中的位置来进行绘制。

绘制方式

  • GL_POINTS:点的唯一绘制方式,将其传入渲染管线的一系列顶点单独进行绘制

  • GL_LINES:将其传入渲染管线的一系列顶点按照顺序两两组织成线段进行绘制,若顶点个数为奇数,管线会自动忽略最后一个顶点


    lines.png
    • GL_LINE-STRIP:将其传入渲染管线的一系列顶点按照顺序依次组织成线段进行绘制。


      lineStrip.png
  • GL_LINE_LOOP;将其传入渲染管线的一系列顶点按照顺序依次组合成线段进行绘制,然后最后一个顶点与第一个顶点相连,形成线段环。


    lineLoop.png
  • GL_TRIANGLES;将其传入渲染管线的一系列顶点按照顺序每3个组成成一个三角形。


    triangle.png

-GL_TRIANGLE_STRIP;将其传入渲染管线的一系列顶点按照顺序依次组成成三角形进行绘制


triangleStrip.png
  • GL_TRIANGLE_FAN;将其传入渲染管线一系列顶点中的第一个顶点作为中心点,其他顶点作为边缘点绘制绘一系列组成扇形的相邻三角形


    triangleFan.png

顶点法

调用glDrawArrays方法,此方法是按照传入渲染管线顶点本身的顺序及选用的绘制方式将顶点组织成图元进行绘制,也称为顶点法。
之前试手项目中有用过,参考之前的文章

索引法

调用glDrawElements方法绘制时,不但要将顶点序列传进去,还需要将索引传入管线。

这次,我们画一个正方形;

先看效果:

square.jpg
public class Square {

private int mProgram;
private int maPositionHandle; //顶点位置的引用
private int maColorHandle; //顶点颜色属性引用

private String mVertexShader = "uniform mat4 uMVPMatrix;" +
        "attribute vec3 aPosition;" +
        "attribute vec4 aColor;" +
        "varying vec4 vColor;" +
        "void main(){" +
        "gl_Position =  vec4(aPosition,1);" + //根据总变换矩阵计算此次绘制此顶点的位置
        "vColor = aColor;" +
        "}";
private String mFragmentShader = "precision mediump float;" +
        "varying vec4 vColor;" +
        "void main(){" +
        "gl_FragColor = vColor;" +
        "}";

public static float[] mMMatrix = new float[16];//具体物体的3D变换矩阵

private FloatBuffer mVertexBuffer;//顶点坐标数据缓冲
private FloatBuffer mFragmentBuffer;//顶点着色数据缓冲

private ByteBuffer mIndexBuffer;//索引数据缓冲

private int mvCount = 0;//顶点数量
private int miCount = 0;//索引数

public  Square(){
    initVertex();
    initShader();
}

private void initVertex(){
    mvCount = 4;

    float[] vertexs = new float[]{
            0.5f,0.5f,0,
            0.5f,-0.5f,0,
            -0.5f,-0.5f,0,
            -0.5f,0.5f,0
    };

    ByteBuffer vbb = ByteBuffer.allocateDirect(vertexs.length*4);
    vbb.order(ByteOrder.nativeOrder());
    mVertexBuffer = vbb.asFloatBuffer();
    mVertexBuffer.put(vertexs);
    mVertexBuffer.position(0);

    float[] colors = new float[]{
            1,0,0,1,
            0,1,0,1,
            0,1,1,1,
            0,0,1,1
    };

    ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);
    cbb.order(ByteOrder.nativeOrder());
    mFragmentBuffer= cbb.asFloatBuffer();
    mFragmentBuffer.put(colors);
    mFragmentBuffer.position(0);

    miCount = 6;
    byte[] index = new byte[]{ //顶点索引
      0,1,2,0,2,3
    };

    mIndexBuffer = ByteBuffer.allocateDirect(index.length);
    mIndexBuffer.order(ByteOrder.nativeOrder());
    mIndexBuffer.put(index);
    mIndexBuffer.position(0);

}

private void initShader(){
    mProgram = shaderUtil.createProgram(mVertexShader,mFragmentShader);

    maPositionHandle = GLES30.glGetAttribLocation(mProgram,"aPosition");
    maColorHandle = GLES30.glGetAttribLocation(mProgram,"aColor");
}

public void drawSelf(){

    GLES30.glUseProgram(mProgram);

    //传入顶点位置数据
    GLES30.glVertexAttribPointer(maPositionHandle
            ,3,GLES30.GL_FLOAT,false,3*4,mVertexBuffer);
    
    //传入顶点颜色数据
    GLES30.glVertexAttribPointer(maColorHandle,
            4,GLES30.GL_FLOAT,false,4*4,mFragmentBuffer);
    GLES30.glEnableVertexAttribArray(maPositionHandle);//启用顶点位置数据
    GLES30.glEnableVertexAttribArray(maColorHandle);//启用顶点颜色数据
    GLES30.glDrawElements(GLES30.GL_TRIANGLES
            ,miCount,GLES30.GL_UNSIGNED_BYTE,mIndexBuffer);//开始绘制,传入索引
}
}

项目地址:https://github.com/vivianluomin/PracticeEveryDay/tree/master/LearnOpenGL

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,271评论 6 524
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,533评论 3 405
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,580评论 0 370
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,203评论 1 303
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,204评论 6 401
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,664评论 1 316
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,014评论 3 431
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,991评论 0 280
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,536评论 1 326
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,558评论 3 347
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,678评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,267评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,997评论 3 341
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,429评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,580评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,259评论 3 382
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,744评论 2 366

推荐阅读更多精彩内容