• Axiom3D:数据绑定基本流程


         在前面我们学习OpenGL时,不管绘制如球,立方体,平面,地面,动画模型中最常用的几个操作有创建缓冲区,写入缓冲区.在Axiom中,相关的操作被整合与组织到VertexData,IndexData中,所以在后面,我们会看到Axiom里元素如果要绘画在屏幕上的元素,几乎都会包含这二个类的实体.

         在看相关介绍前,我们先看下如下关系图:

       VertexData主要包含二个类的实体,一个是VertexDeclaration,另一个是VertexBufferBinding.

         VertexDeclaration是用来指定数据的组成结构,比如在前面我们使用OpenGL的混合顶点数组时,会用T2F_N3F_V3F指定对应数组每八个浮点数据一组,前二个指定纹理坐标,中间三个数据指定法线,最后三个数据指定顶点.VertexDeclaration类似这个T2F_N3F_V3F,他包含一系列VertexElement,每个VertexElement指定上面的T2F,N3F,V3F这种类型,请看下面一段代码:

     1 var decl = mesh.SharedVertexData.vertexDeclaration;
     2 var binding = mesh.SharedVertexData.vertexBufferBinding;
     3 
     4 var offset = 0;
     5 decl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.Position );
     6 offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
     7 decl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.Normal );
     8 offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
     9 decl.AddElement( 0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0 );
    10 offset += VertexElement.GetTypeSize( VertexElementType.Float2 );
    VertexElement
      在中间有AddElement就是增加一个VertexElement,其中Float3,Float2就是指如上的3F,2F.而Position,Normal,TexCoords分别对应上面的P,N,T.说到底,这个decl就是指定了如P3F_N3F_T2F这种结构.
      
      VertexBufferBinding主要成员包含一个Dictionary <short, HardwareVertexBuffer > Bindings的数据结构,其中HardwareVertexBuffer这个比较重要,可以看下一般如何创建HardwareVertexBuffer,如下:
     
     1 var vertices = new float[32]
     2                {
     3                    -100, -100, 0, // pos
     4                    0, 0, 1, // normal
     5                    0, 1, // texcoord
     6                    100, -100, 0, 0, 0, 1, 1, 1, 100, 100, 0, 0, 0, 1, 1, 0, -100, 100, 0, 0, 0, 1, 0, 0
     7                };
     8 var vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( decl, 4, BufferUsage.StaticWriteOnly );
     9 binding.SetBinding( 0, vbuf );
    10 vbuf.WriteData( 0, vbuf.Size, vertices, true );
    VertexBuffer

      看过OpenGL绑定过程的,一定看起来很熟悉是不是,实际差不多,在CreateVertexBuffer里,首先会在HardwareVertexBuffer结合decl与顶点个数4.这里为什么是4,其实大家可以算一下,decl里声明的是P3F_N3F_T2F,意思是每个顶点有八个数据来指明相关属性,而vertices的长度是32,就是指明这个数据只包含了4个顶点.然后我们可以计算我们需要申请的显存长度,sizeInBytes=4*8*sizeof(float)=128.然后如果我们使用OpenGL渲染,就会调用GLHardwareVertexBuffer,这个类的初始化里就使用了glGenBuffers.最后vbuf.WriteData操作就会调用glBufferData把相关数据写入到显存里.

         很明显,对比原来我们常用的OpenGL操作如下:

    1         this.vboID = glGenBuffers(1)
    2         glBindBuffer(GL_ARRAY_BUFFER,this.vboID)
    3         glBufferData (GL_ARRAY_BUFFER, len(vdata)*4, vdata, GL_STATIC_DRAW)
    4         this.eboID = glGenBuffers(1)
    5         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,this.eboID)
    6         glBufferData (GL_ELEMENT_ARRAY_BUFFER, len(vIndex)*4, vIndex,GL_STATIC_DRAW)
    glBindBuffer
      可以发现少了点什么,是的,我们只是写入了顶点数据,对应顶点索引没有,看看在Axiom里如何使用.
     1 var ibuf = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, 6, BufferUsage.StaticWriteOnly );
     2 
     3 var faces = new short[6]
     4             {
     5                 0, 1, 2, 0, 2, 3
     6             };
     7 sub.IndexData.indexBuffer = ibuf;
     8 sub.IndexData.indexCount = 6;
     9 sub.IndexData.indexStart = 0;
    10 ibuf.WriteData( 0, ibuf.Size, faces, true );
    IndexBuffer

      会发现不一样的是,顶点数据用的是HardwareVertexBuffer,而顶点索引用的HardwareIndexBuffer,基本用法一样,不同的调用的CreateIndexBuffer,结合前面与调试在相关位置,发现还是和前面一样,一样会调用glGenBuffers,glBindBuffer,glBufferData.不同前面是GL_ARRAY_BUFFER,这里是GL_ELEMENT_ARRAY_BUFFER.     

         我们知道,在底层不管是OpenGL或是D3D,他们都是C,C++及的语言,针对底层的指针操作,在C#中都由上面的BufferBase的派生类包装GCHandle提供相关的非托管内存访问托管对象的方法,能创建防GC回收托管对象.详细请看GCHandle 结构.在HardwareBuffer里的相关和内存,显存有关的操作全是用BufferBase来完成.具体请看Axiom3D:Buffer漫谈整个代码是创建一个四个点的面,分别创建顶点与顶点索引缓冲区,相对整个部分代码如下:

     1         /// <summary>
     2         /// Creates a plane as a submesh of the given mesh
     3         /// </summary>
     4         [OgreVersion( 1, 7, 2 )]
     5         private static void _createPlane( Mesh mesh )
     6         {
     7             var sub = mesh.CreateSubMesh();
     8             var vertices = new float[32]
     9                            {
    10                                -100, -100, 0, // pos
    11                                0, 0, 1, // normal
    12                                0, 1, // texcoord
    13                                100, -100, 0, 0, 0, 1, 1, 1, 100, 100, 0, 0, 0, 1, 1, 0, -100, 100, 0, 0, 0, 1, 0, 0
    14                            };
    15 
    16             mesh.SharedVertexData = new VertexData();
    17             mesh.SharedVertexData.vertexCount = 4;
    18             var decl = mesh.SharedVertexData.vertexDeclaration;
    19             var binding = mesh.SharedVertexData.vertexBufferBinding;
    20 
    21             var offset = 0;
    22             decl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.Position );
    23             offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
    24             decl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.Normal );
    25             offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
    26             decl.AddElement( 0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0 );
    27             offset += VertexElement.GetTypeSize( VertexElementType.Float2 );
    28 
    29             var vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( decl, 4, BufferUsage.StaticWriteOnly );
    30             binding.SetBinding( 0, vbuf );
    31 
    32             vbuf.WriteData( 0, vbuf.Size, vertices, true );
    33 
    34             sub.useSharedVertices = true;
    35             var ibuf = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, 6, BufferUsage.StaticWriteOnly );
    36 
    37             var faces = new short[6]
    38                         {
    39                             0, 1, 2, 0, 2, 3
    40                         };
    41             sub.IndexData.indexBuffer = ibuf;
    42             sub.IndexData.indexCount = 6;
    43             sub.IndexData.indexStart = 0;
    44             ibuf.WriteData( 0, ibuf.Size, faces, true );
    45 
    46             mesh.BoundingBox = new AxisAlignedBox( new Vector3( -100, -100, 0 ), new Vector3( 100, 100, 0 ) );
    47             mesh.BoundingSphereRadius = Utility.Sqrt( 100*100 + 100*100 );
    48         }
    createPlane
  • 相关阅读:
    在Windows环境下使用docker
    C# 8.0中的模式匹配
    C# 8.0的新的using语法——Using declarations
    任务调度框架FluentScheduler简介
    任务调度框架Hangfire 简介
    Linux下的sqlserver简单试用
    使用Puppeteer进行数据抓取(五)——快速调试
    使用ptrace向已运行进程中注入.so并执行相关函数(转)
    ARM汇编编程基础之一 —— 寄存器
    ARM 汇编与C调用的若干问题(一般函数调用情况)
  • 原文地址:https://www.cnblogs.com/zhouxin/p/3585325.html
Copyright © 2020-2023  润新知