opengl es3.0学习篇五:图元装配跟光栅化

opengl es学习篇五:图元装配跟光栅化

资料来源:

OpenGL ES3.0编程指南

https://www.khronos.org/opengl/wiki/Primitive

图元支持的几何类型

在opengl es中,图元可以用glDrawArrays()glDrawElements()glDrawRangeElements()等命令绘制几何图像。图元有一组表示顶点位置的顶点描述。

图元总共三部分:

  • 三角形
  • 直线
  • 点精灵
三角形

支持的三角形图元有GL_TRIANGLESGL_TRIANGLE_STRIPGL_TRIANGLE_FAN三种。现根据opengl官方的wiki整理如下:

  • GL_TRIANGLES: Vertices 0, 1, and 2 form a triangle. Vertices 3, 4, and 5 form a triangle. And so on.
  • GL_TRIANGLE_STRIP: Every group of 3 adjacent vertices forms a triangle. The face direction of the strip is determined by the winding of the first triangle. Each successive triangle will have its effective face order reversed, so the system compensates for that by testing it in the opposite way. A vertex stream of n length will generate n-2 triangles.
  • GL_TRIANGLE_FAN: The first vertex is always held fixed. From there on, every group of 2 adjacent vertices form a triangle with the first. So with a vertex stream, you get a list of triangles like so: (0, 1, 2) (0, 2, 3), (0, 3, 4), etc. A vertex stream of n length will generate n-2 triangles.
GL_TRIANGLES

GL_TRIANGLES而言,就是直接绘制一系列的单独的三角形,以如下图形举例,顶点V0,V1,V2组成一个三角形,顶点V3,V4,V5组成一个三角形。通过顶点数组可以组成三角形的数目为数组长度/3

GL_TRIANGLES

在Anroid中代码:

Demo地址https://github.com/JerryChan123/LearnOEL/tree/gl30 查看test for gl_triangle的提交

 static float triangleCoords[] = {   // in counterclockwise order:
            0.0f, 0.622008459f, 0.0f, // top
            -0.5f, 0f, 0.0f, // bottom left
            0.5f, 0f, 0.0f,  // bottom right
            0.5f, 0f, 0.0f,
            -0.5f, 0f, 0.0f,
            0.0f, -0.622008459f, 0.0f,
    };

    float color[] = {
            1.0f, 0.0f, 0.0f,1f,
            1.0f, 0.0f, 0.0f,1f,
            1.0f, 0.0f, 0.0f,1f,
            0f, 1.0f, 0.0f,1f,
            0f, 1.0f, 0.0f,1f,
            0f, 1.0f, 0.0f,1f};

 public void onDraw() {
        // Add program to OpenGL ES environment
        GLES30.glUseProgram(mProgram);

        // get handle to vertex shader's vPosition member
        mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");
//        createVertextBuffer(); //注意,这里注释掉了VBO,是因为打开后有Bug,具体是什么问题有待发现
        // Enable a handle to th、e triangle vertices
        GLES30.glEnableVertexAttribArray(mPositionHandle);
        // Prepare the triangle coordinate data
        GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                GLES30.GL_FLOAT, false,
                0, vertexBuffer);
        // get handle to fragment shader's vColor member
        mColorHandle = GLES30.glGetAttribLocation(mProgram, "aColor");
        // Set color for drawing the triangle
//        GLES30.glVertexAttrib4fv(mColorHandle,  color, 0);

        GLES30.glEnableVertexAttribArray(mColorHandle);
        GLES30.glVertexAttribPointer(mColorHandle, 4,
                GLES30.GL_FLOAT, false,
                0, colorBuffer);
        // Draw the triangle
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexCount);

        // Disable vertex array
        GLES30.glDisableVertexAttribArray(mPositionHandle);
    }

效果图如下:

test_for_gl_trian

GL_TRIANGLE_STRIP

GL_TRIANGLE_STRIP而言,英文翻译过来就是每个小组的三个临近的顶点组成一个三角形,一如下图形举例:

看见英文一大堆就晕了,其实简单的就是V0,V1,V2组成一个三角形,V1,V2,V3组成一个三角形,V2,V3,V4组成一个三角形,以此类推。通过顶点数组可以组成三角形的数目为数组长度-2

Android代码使用如下:


static float triangleCoords[] = {   // in counterclockwise order:
            0.0f, 0.622008459f, 0.0f, // top
            -0.5f, 0f, 0.0f, // bottom left
            0.5f, 0f, 0.0f,  // bottom right
            0.0f, -0.622008459f, 0.0f,
    };
    private final int mProgram;
    // Set color with red, green, blue and alpha (opacity) values
    float color[] = {
            1.0f, 0.0f, 0.0f,1f,
            0f, 1.0f, 0.0f,1f,
            0f, 0f, 1.0f,1f,
            0f, 0.0f, 0.0f,1f};
  public void onDraw() {
        ...
        GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, vertexCount);

        // Disable vertex array
        GLES30.glDisableVertexAttribArray(mPositionHandle);
    }

与上面代码的区别主要是在GL_TRIANGLE_STRIP参数的设置以及顶点数组数目的改变。实现效果如下所示:

GL_TRIANGLE_FAN

GL_TRIANGLE_FAN而言,表示一个扇形的三角形组成,看底下的图就能明白:

顶点V0为圆点,呈扇形画出,即V0,V1,V2一个三角形,V0,V2,V3一个三角形,以此类推。 Android代码示例:


static float triangleCoords[] = {   // in counterclockwise order:
            -0.5f, 0f, 0.0f, // bottom left
            0.0f, 0.622008459f, 0.0f, // top
            0.5f, 0f, 0.0f,  // bottom right
            0.0f, -0.622008459f, 0.0f,
    };
private final int mProgram;
    // Set color with red, green, blue and alpha (opacity) values
float color[] = {
            1.0f, 0.0f, 0.0f,1f,
            0f, 1.0f, 0.0f,1f,
            0f, 0f, 1.0f,1f,
            0f, 0.0f, 0.0f,1f};

public void onDraw() {
      ....
        GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, vertexCount);

        // Disable vertex array
        GLES30.glDisableVertexAttribArray(mPositionHandle);
    }

主要就是GL_TRIANGLE_FAN的设置以及数组位置的改变。实现效果与GL_TRIANGLE_STRIP相同。

直线

opengl es中支持的直线有GL_LINESGL_LINE_STRIPGL_LINE_LOOP三大类,三个变量的区别如下图所示:

gl_lines

n指的是直线顶点数组的长度

  • GL_LINES:绘制单独的线段,不相连接,总共绘制n/2条直线。
  • GL_LINE_STRIP:绘制一系列连接的线段,总共绘制n-1条。
  • GL_LINE_LOOP:会在最后一点连接起始点,总共绘制n条线段。

比较简单就不举例子了。

点精灵

点精灵是针对顶点进行绘制。点精灵通常将粒子效果作为点而非正方形绘制,从而实现高效渲染。点精灵是指定位置和半径的屏幕对齐的正方形,位置描述正方形的中心,半径用于计算点精灵的四个角坐标。

注意opengles窗口的坐标范围是:从左下角(原点)到右上角。

而点精灵的原点是在左上角 坐标值 从0-1.

gl_PointSize()是可用于在顶点着色器输出点半径的内建变量。与点图元相关的顶点着色器输出gl_PointSize很重要,否则,会被视为未定义,很可能会造成绘图错误。顶点着色器的输出gl_PointSize收到opengl es 3.0实现所支持的非平滑点尺寸范围的限制,可以用如下命令查询:

GLfloat pointSizeRange[2];
glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE,pointSizeRange);
//android中的表示
GLES30.glGetFloatv();

gl_PointCoord是只能在渲染图元为点精灵的时候用于片段着色器的内部建量。他用一个mediump精度限定符申明为一个vec2变量。gl_PointCoord属于区间[0,1],超出的则不显示。

图元的绘制

图元总共有五个绘制方法:

  • glDrawArrays
  • glDrawElements
  • glDrawRangeElements(不介绍)
  • glDrawArraysInstanced(不介绍)
  • glDrawElementsInstanced(不介绍)

在Android中只支持第一种跟第二种,Android native层有待考证支持的类型。

glDrawArrays用元素索引为first到first+count-1的元素指定的顶点绘制mode指定的图元。 查看上述使用GL_TRIANGLES写Demo的例子中的使用:

static float triangleCoords[] = {   // in counterclockwise order:
            0.0f, 0.622008459f, 0.0f, // top
            -0.5f, 0f, 0.0f, // bottom left
            0.5f, 0f, 0.0f,  // bottom right
            0.5f, 0f, 0.0f,
            -0.5f, 0f, 0.0f,
            0.0f, -0.622008459f, 0.0f,
    };
  GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexCount);//vertexCount=6

first等于0,first+count-1=5,所以取(0,1,2)和(3,4,5)作为两个三角形的顶点进行绘制。支持的model就是我们上面锁讲述的一系列几何类型。

如果是一系列顺序元素索引描述的图元,且几何图形顶点不共享,那么glDrawArrays是能支持的也很好用,但是游戏或者其他3D的应用程序的典型对象由多个三角形网格组成,其中元素不一定按照顺序,顶点通常在网格的三角形之间共享。使用glDrawElements可以比调用glDrawArrays更简单的将这些功能实现,而且内存消耗更小。

###图元装配

通过上述的glDraw*提供的顶点由顶点着色器执行,顶点着色器变换每个顶点的顶点位置。图元类型和顶点索引确定将被渲染的单独图元。对于每个单独图元与其对应的顶点,装配过程如上图所示。

下图中展示了通过顶点着色器和图元装配后的坐标系统:

顶点以物体或者本地坐标空间输入到opengl es中,在顶点着色器执行完后,顶点位置是被认为执行在裁剪空间之内的。顶点位置从本地坐标系统到裁剪坐标的变换通过加载执行对应矩阵来完成。

关于opengl es中的坐标系统需要单独写一篇文章。下面只是记录书中的内容

####裁剪 裁剪坐标的意义在于将判断顶点是否落在裁剪坐标空间内。裁剪坐标是由(x,y,z,w)指定的同类坐标,在裁剪空间(x,y,z,w)中定义的顶点坐标根据视景体(又称裁剪体)裁剪。 视景体由六个平面组成而成,这些平面被称作远,近,左,右,上,下裁剪平面,在裁剪坐标中,裁剪体如下:

  • -w<=x<=w
  • -w<=y<=w
  • -w<=z<=w

裁剪体如下所示:

####透视分割 透视分割取得裁剪坐标(x,y,z,w)指定的点,并将其投影到屏幕或者视口上。这个操作通过将(x,y,z)除以w进行,执行(x/w),(y/w),(z/w)操作之后,得到规范化的设备坐标(q,w,e),他们落在[-1.0,1.0]中,这些坐标会根据视口大小转换成真正的屏幕坐标。规范化的z坐标可以使用glDepthRangf()指定的near和far深度值转换成屏幕的z值,这些转换在视口变换时候进行。

####视口变换 视口是一个二维矩形窗口区域,是所有opengl es渲染最终显示的地方,可调用如下api进行设置:

	void glViewport(GLint x,GLint y,GLsizei w,Glsizei h)

从规范化坐标(x,w,z)到窗口坐标(q,w,e)的转换变化如下:

上述变化中Ox=x+w/2,Oy=y+h/2,n和f代表所需要的深度范围,可使用glDepthRangf()设置。

转载于:https://my.oschina.net/u/3863980/blog/1836202

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值