Axiom3D:数据绑定基本流程

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

     在看相关介绍前,我们先看下如下关系图:
Axiom3D:数据绑定基本流程

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

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

 var decl = mesh.SharedVertexData.vertexDeclaration;
var binding = mesh.SharedVertexData.vertexBufferBinding; var offset = ;
decl.AddElement( , offset, VertexElementType.Float3, VertexElementSemantic.Position );
offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
decl.AddElement( , offset, VertexElementType.Float3, VertexElementSemantic.Normal );
offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
decl.AddElement( , offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, );
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,如下:
 
 var vertices = new float[]
{
-, -, , // pos
, , , // normal
, , // texcoord
, -, , , , , , , , , , , , , , , -, , , , , , ,
};
var vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( decl, , BufferUsage.StaticWriteOnly );
binding.SetBinding( , vbuf );
vbuf.WriteData( , 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操作如下:

         this.vboID = glGenBuffers()
glBindBuffer(GL_ARRAY_BUFFER,this.vboID)
glBufferData (GL_ARRAY_BUFFER, len(vdata)*, vdata, GL_STATIC_DRAW)
this.eboID = glGenBuffers()
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,this.eboID)
glBufferData (GL_ELEMENT_ARRAY_BUFFER, len(vIndex)*, vIndex,GL_STATIC_DRAW)

glBindBuffer

  可以发现少了点什么,是的,我们只是写入了顶点数据,对应顶点索引没有,看看在Axiom里如何使用.

 var ibuf = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, , BufferUsage.StaticWriteOnly );

 var faces = new short[]
{
, , , , ,
};
sub.IndexData.indexBuffer = ibuf;
sub.IndexData.indexCount = ;
sub.IndexData.indexStart = ;
ibuf.WriteData( , 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漫谈整个代码是创建一个四个点的面,分别创建顶点与顶点索引缓冲区,相对整个部分代码如下:

         /// <summary>
/// Creates a plane as a submesh of the given mesh
/// </summary>
[OgreVersion( , , )]
private static void _createPlane( Mesh mesh )
{
var sub = mesh.CreateSubMesh();
var vertices = new float[]
{
-, -, , // pos
, , , // normal
, , // texcoord
, -, , , , , , , , , , , , , , , -, , , , , , ,
}; mesh.SharedVertexData = new VertexData();
mesh.SharedVertexData.vertexCount = ;
var decl = mesh.SharedVertexData.vertexDeclaration;
var binding = mesh.SharedVertexData.vertexBufferBinding; var offset = ;
decl.AddElement( , offset, VertexElementType.Float3, VertexElementSemantic.Position );
offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
decl.AddElement( , offset, VertexElementType.Float3, VertexElementSemantic.Normal );
offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
decl.AddElement( , offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, );
offset += VertexElement.GetTypeSize( VertexElementType.Float2 ); var vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( decl, , BufferUsage.StaticWriteOnly );
binding.SetBinding( , vbuf ); vbuf.WriteData( , vbuf.Size, vertices, true ); sub.useSharedVertices = true;
var ibuf = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, , BufferUsage.StaticWriteOnly ); var faces = new short[]
{
, , , , ,
};
sub.IndexData.indexBuffer = ibuf;
sub.IndexData.indexCount = ;
sub.IndexData.indexStart = ;
ibuf.WriteData( , ibuf.Size, faces, true ); mesh.BoundingBox = new AxisAlignedBox( new Vector3( -, -, ), new Vector3( , , ) );
mesh.BoundingSphereRadius = Utility.Sqrt( * + * );
}

createPlane

上一篇:转: requestAnimationFrame,Web中写动画的另一种选择


下一篇:java switch 优化