`
chriszeng87
  • 浏览: 738490 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

OpenGL中的原语组装和光栅化

阅读更多

转自:http://blog.csdn.net/myarrow/article/details/7747733

 

一、什么是原语?

       原语就是可以用glDrawArrays和glDrawElements来进行画图的几何对象。原语由一系列顶点来描述,每个顶点包含位置、颜色、法线和纹理坐标。

       原语包括:点、线、三角行。

二、原语类型

1. 三角形原语类型

      1)GL_TRIANGLES:三角形顶点互不重用,如顶点{V0,V1,V2,V3,V4,V5},则描述了2个三角形,三角形顶点分别为:(V0,V1,V2)和(V3,V4,V5)。

      2)GL_TRIANGLE_STRIP:三角形顶点被重用,画一系列连接的三角形,三角形的最后2个顶点为下一个三角形的前面2个顶点。如顶点{V0,V1,V2,V3,V4},则描述了3个三角形,三角形顶点分别为:(V0,V1,V2),(V2,V1,V3)<注意此顺序,应该为逆时针方向> 和 (V2,V3,V4)。

      3)GL_TRIANGLE_FAN:三角形顶点被重用,画一系列连接的三角形,前面三角形的第1和3个顶点,为后面三角形的第1和2个顶点。如顶点{V0,V1,V2,V3,V4},则描述了3个三角形,三角形顶点分别为:(V0,V1,V2), (V0,V2,V3)和(V0,V3,V4)。

2. 线原语类型

      1)GL_LINES:线的顶点互不重用。如顶点{V0,V1,V2,V3,V4,V5},则描述了3条线,线顶点分别为:(V0,V1),(V2,V3)和 (V4,V5)。

      2)GL_LINE_STRIP:线的顶点被重用,前面线的最后一个顶点为下一条线的第一个顶点。如顶点{V0,V1,V2,V3},则描述了3条线,线顶点分别为:(V0,V1),(V1,V2)和 (V2,V3)。

      3)GL_LINE_LOOP:线的顶点被重用,与GL_LINE_STRIP类似,只是最后一条线的最后一个顶点与第一条线的第一个顶点相连。如顶点{V0,V1,V2,V3,V4},则描述了5条线,线顶点分别为:(V0,V1), (V1,V2), (V2,V3), (V3,V4)和 (V4,V0)。

      线的宽度可以通过函数“void glLineWidth(GLfloat width)”来设置。

3. 顶点原语

       GL_POINTS:对每个顶点进行画图。

       注:窗口坐标(0,0)位于窗口左下角。而点的坐标(0,0)位于窗口左上角。

       gl_PointSize是Vertex Shader中的一个内嵌变量,gl_PointCoord是Fragment Shader中的一个内嵌变量,其值取值范围为:[0.0,1.0],并且从左到右或从上到下地增加。

三、画图原语

       OpenGL ES 2.0有以下两个画图原语:

       1)glDrawArrays

       2)glDrawElements.

1. glDrawArrays

     void glDrawArrays(GLenum mode, GLint first, GLsizei count)
     • mode:指定要画的原语类型,有效值如下:
                GL_POINTS
                GL_LINES
                GL_LINE_STRIP
                GL_LINE_LOOP
                GL_TRIANGLES
                GL_TRIANGLE_STRIP
                GL_TRIANGLE_FAN

     • first:起始顶点在enabled vertex arrays中的索引

     • count:将被用于画图的顶点个数

     举例:glDrawArrays(GL_TRIANGLES, 0, 6)画了两个三角形,顶点的顶点数组索引分别为:(0, 1, 2)和(3, 4, 5)。

2. glDrawElements

    void glDrawElements(GLenum mode, GLsizei count,GLenum type, const GLvoid *indices)
    • mode:指定要画的原语类型,有效值如下:
                GL_POINTS
                GL_LINES
                GL_LINE_STRIP
                GL_LINE_LOOP
                GL_TRIANGLES
                GL_TRIANGLE_STRIP
                GL_TRIANGLE_FAN

    • count:指示在*indices中的顶点索引个数

       • type:指示在*indices中元素数据类型,有效值如下:

                GL_UNSIGNED_BYTE
                GL_UNSIGNED_SHORT
                GL_UNSIGNED_INT(可选,只有OES_element_index_uint扩展被实现时,才可使用)

     indices:存储顶点索引的数组或指针

3. glDrawArrays &glDrawElements各自用武之地

        如果Enbaled Vertex Array中的顶点不被多个原语所共享,则使用glDrawArrays较高效,因为省去了顶点索引数组;否则使用glDrawElements高效,因为同一个顶点在Enabled Vertex Array中只有一份数据,不存在多个数据copy,节省了内存空间。

        举例如下(画一个立方体):

1) 使用glDrawArrays的代码如下:

[cpp] view plaincopy
 
  1. #define VERTEX_POS_INDX 0  
  2. #define NUM_FACES 6  
  3. GLfloat vertices[] = { … }; // (x, y, z) per vertex  
  4. glEnableVertexAttribArray(VERTEX_POS_INDX);  
  5. glVertexAttribPointer(VERTEX_POS_INDX, 3, GL_FLOAT, GL_FALSE,0, vertices);  
  6. for (i=0; i<NUM_FACES; i++)  
  7. {  
  8.     glDrawArrays(GL_TRIANGLE_FAN, first, 4);  
  9.     first += 4;  
  10. }  
  11.   
  12. //or glDrawArrays(GL_TRIANGLES, 0, 36);  

注:总共8个顶点,却保存了24个顶点或36个顶点的数据。

2)使用glDrawElements的代码如下:

[cpp] view plaincopy
 
  1. #define VERTEX_POS_INDX 0  
  2. GLfloat vertices[] = { … };// (x, y, z) per vertex  
  3. GLubyte indices[36] = { 0, 1, 2, 0, 2, 3,  
  4.                         0, 3, 4, 0, 4, 5,  
  5.                         0, 5, 6, 0, 6, 1,  
  6.                         7, 6, 1, 7, 1, 2,  
  7.                         7, 4, 5, 7, 5, 6,  
  8.                         7, 2, 3, 7, 3, 4 };  
  9. glEnableVertexAttribArray(VERTEX_POS_INDX);  
  10. glVertexAttribPointer(VERTEX_POS_INDX, 3, GL_FLOAT, GL_FALSE,0, vertices);  
  11. glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(GLubyte),GL_UNSIGNED_BYTE, indices);  

4. 总结

       只要有顶点重用,使用glDrawElements 的性能比glDrawArrays要好,因为不仅CPU与GPU之间传递数据的内存带宽更小,且在GPU中占用的内存也更少。

四、原语组装(Primitive Assembly)

       OpenGL ES 2.0原语组装阶段如下图所示:

1. 坐标系统

2. 裁剪体(clip volume)

    裁剪体由近、远、左、右、上、下共6个裁剪面组成。如下图所示:

      在clipping阶段,每个原语都被裁剪体进行裁剪。并对每种原语执行如下操作来进行裁剪:

      1)Clipping triangles

            • 如果全部在裁剪体内,什么都不做

            • 如果全部不在裁剪体内,则丢弃

            • 如果部分在裁剪体内,则产生新的顶点并形成三角形FAN

      2)Clipping lines 

            • 如果全部在裁剪体内,什么都不做

            • 如果全部不在裁剪体内,则丢弃

            • 如果部分在裁剪体内,则产生新的顶点并形成新的LINE

      3)Clipping point sprites

            • 如果全部在裁剪体内,什么都不做

            • 如果全部不在裁剪体内,则丢弃

3. 透视除法(PerspectiveDivision 

        它的目标是把裁剪坐标变为归一化设备坐标,其取值范围为:[-1,1]。其实现方法为把坐标的每个分量除以Wc。裁剪坐标(Xc,Yc,Zc,Wc) 经过透视除法(Xc/Wc),(Yc/Wc),(Zc/Wc)则变成了归一化设备坐标(Xd,Yd,Zd)。

4. 视口变换(Viewport Transformation)

        它把归一化设备坐标(Xd,Yd,Zd)变换为窗口坐标或屏幕坐标(Xw,Yw,Zw)。

1)视口变换视口通过以下API设置:

        void glViewport(GLint x, GLint y, GLsizei w, GLsizei h)
        • x, y:指明视口左下角屏幕坐标(以像素为单位)

         w, h:指明视口的宽度和高度(以像素为单位)     

2)视口变换深度通过以下API设置:    

        void glDepthRange(GLclampf n, GLclampf f)
         n, f:指明要求的深度范围。默认值:n=0.0,f=1.0,值的范围为[0.0,1.0]。 
        

3)视口变换方法为:

      Ox = (x + w)/2,Oy = (y + h)/2,n 和 f 表示要求的深度范围。

  
五、光栅化(Rasterization)

        光栅化获取每个原语(如:点、线、三角形),然后为这个原语产生合适的Fragment。一个Fragment表示在屏幕空间中的一个像素位置(x,y),且fragment数据将被Fragment Shader处理以产生一个Fragment Color。

 六、选择(Culling)

        在三角形被光栅化之前,我需要确定哪些面对观察者,哪些面背对观察者。Culling操作丢弃哪些背对观察者的面,从而光栅化这些看不见的三角形,从而节约了GPU的时间,并提高了GPU的性能。相关函数如下:   

        1)void glFrontFace(GLenum dir)
        • dir:指示面对观察者的三角形的方向(GL_CW<顺时针>或GL_CCW<逆时针>),默认值为:GL_CCW。

                  CW: Clockwise,CCW:Counter-Clockwise

        2)void glCullFace(GLenum mode)

        • mode:指示三角形的哪个面被选择(GL_FRONT、GL_BACK、GL_FRONT_AND_BACK),默认值是GL_BACK。

 

        3)void glEnable(GLenum cap)
              void glDisable(GLenum cap)
        • cap:设置为GL_CULL_FACE,初始时,Culling被disabled掉了。

分享到:
评论

相关推荐

    OpenGL最好的入门和提高教材

    光栅化阶段包括消隐(确定哪些像素可见)和对像素进行颜色、深度和纹理的计算。这一阶段还可能包括反走样(antialiasing)和深度测试(depth testing)。 #### 二、OpenGL的操作种类: - **几何操作**:这些操作主要涉及...

    Xilinx原语的使用方法.pdf

    文档的清晰明了的讲解能够帮助设计师快速掌握不同原语的使用方法,以及如何在设计中正确地实例化和配置这些原语。 最后,文档中提到的Xilinx13.4是指Xilinx的某些设计工具版本,这可能是对Vivado或ISE设计套件的一...

    openGLES3.0Example_6_VertexBufferObjects.rar

    和光栅化。” 然而,如果我们不这样做会好得多 在每个绘制调用上复制顶点数据,但可以缓存 图形存储器中的数据。 这种方法可以显著地改进 同时也降低了内存带宽和渲染性能 功耗要求,这两者都是非常重要的 手持设备...

    xilinx fpga原语使用防范

    在 Verilog 中使用原语非常简单,将其作为模块名直接例化即可。 Xilinx 公司的原语按照功能分为 10 类,包括: 1. 计算组件:计算组件值得是 DSP48 核,也有人将其称为硬件乘法器,功能描述如表 3-6 所示。DSP48 ...

    xilinx V6 原语代码

    在实际应用中,设计者可以直接将这些原语代码复制到他们的工程文件中,然后通过综合工具(如Xilinx的ISE或Vivado)进行编译和实现,以生成适配V6 FPGA的配置文件。通过理解和利用这些原语,设计者能够实现高效的FPGA...

    Xilinx原语详解

    7. **实例化代码**:在实际设计中,使用HDL语言实例化这些原语,如`xilinxprimitive:BUFH`用于创建缓冲器,`xilinxprimitive:DPRAM`实例化分布式RAM,等等。理解原语的实例化语法是实现高效FPGA设计的关键。 8. **...

    Opengl建模技术在C#中的实现

    它由一系列渲染原语组成,包括点、线和多边形的绘制,以及复杂的特性如纹理映射、抗锯齿、阴影和光照效果,这些都使得OpenGL成为了游戏开发、虚拟现实、科学可视化和各种图形应用的首选工具。 C#作为Microsoft推出...

    计算机操作系统P(s)原语和V(s)原语实验

    总的来说,这个实验旨在让学生通过实践来掌握操作系统中的并发控制机制,特别是信号量机制的关键组件——P(s)和V(s)原语。这样的实践性学习有助于提升学生的理论与实践结合能力,为他们未来在操作系统设计与分析等...

    6用户定义的原语_verilog_原语_

    2. **实例化**:在设计中使用定义好的原语。如: ```verilog my_and u1 (a, b, c); ``` 这里`u1`是`my_and`原语的一个实例,将`a`和`b`作为输入,`c`作为输出。 3. **编译和综合**:编译Verilog代码时,编译器...

    xilinxFPGA资源调用原语

    在FPGA中,使用原语实现TDC可以提高系统的灵活性和定制性。TDC设计通常涉及触发器、计数器和比较器等原语的组合,以测量两个事件之间的时间差。 4. **原语的优势** - **效率**:原语直接映射到硬件,减少了逻辑...

    xilinx原语

    在VHDL或Verilog代码中,设计者可以直接调用Xilinx原语来创建特定的逻辑功能。例如,使用`XILINX_MUX`原语可以创建一个多路复用器,使用`XILINX_FF`原语可以创建一个触发器。通过这种方式,设计者可以精确控制硬件...

    7Series和ultrascale原语的详解文档.zip

    在数字集成电路设计中,原语(Primitives)是基本的逻辑构建块,它们构成了复杂的FPGA(现场可编程门阵列)和ASIC(应用特定集成电路)设计的基础。Xilinx是领先的FPGA供应商之一,提供了丰富的原语库供设计者使用。...

    操作系统习题及其解答,包括大量PV原语和死锁问题的题目及其解答

    在操作系统的学习过程中,PV原语和死锁问题是非常重要的知识点,本文将对这些知识点进行详细的解释和分析。 PV原语是指操作系统中用来实现进程同步和互斥的基本操作,包括P操作和V操作。P操作是指对信号量的减少...

    操作系统pv原语解释和例子

    ### 操作系统PV原语详解与实例解析 在操作系统领域,PV原语是实现进程间同步和互斥的重要工具,由荷兰计算机科学家Edsger Dijkstra于1965年提出。...在实际开发中,合理运用PV原语能够显著提高系统的稳定性和性能。

    opengl函数

    1. 初始化(Initialization):在OpenGL渲染管线中,初始化阶段通常包括设置渲染环境和参数,为后续的渲染步骤准备条件。 2. Mipmapping:Mipmapping是一种纹理过滤技术,用于优化纹理映射时的性能和视觉质量,它...

    Xilinx FPGA原语的使用方法pdf\Xilinx原语的使用方法2.pdf

    综上所述,Xilinx FPGA中的RAM/ROM组件,尤其是RAM16X1S和RAMB16,提供了丰富的功能和灵活性,是实现高效数据存储与处理的关键。理解并掌握这些组件的使用方法,对于FPGA设计者来说,是提高设计质量和性能的重要一步...

    FPGA全局时钟资源相关原语及使用

    这些原语通过硬件描述语言在FPGA设计中进行例化,以确保时钟信号的正确分布和缓冲。 IBUFG(输入缓冲全局)原语是与FPGA专用全局时钟输入管脚直接相连的全局缓冲器。所有从全局时钟管脚输入的信号都必须通过IBUFG...

    Xinlinx原语的用法1

    理解原语的结构和功能,以及如何在HDL代码中实例化和配置它们,将有助于实现高效、优化的FPGA设计方案。通过熟练运用原语,开发者可以充分利用FPGA的硬件资源,设计出满足特定需求的高性能数字系统。

Global site tag (gtag.js) - Google Analytics