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

 

posted @ 2014-03-06 21:00  天天不在  阅读(2234)  评论(11编辑  收藏  举报