Skip to main content
MOGRE GeneratingAMesh        

If you look at the original code snippet for generating a Mesh, you will see that some pointers arithmetic is needed. That could be fine with C++, but by default C# does not support pointer arithmetic. However, by using the unsafe keyword, it is possible to define an unsafe context in which pointers can be used. In order to hide the complexity of unsafe code we use the following class:

Copy to clipboard
using System; using Mogre; namespace Mogre.Helpers { /// <summary> /// A helper class for manual mesh // This class hide unsafe code /// This code is based on MeshBuilderHelper.h /// originally developed by rastaman 11/16/2005 /// </summary> public class MeshBuilderHelper { public MeshBuilderHelper(String name, String resourcegroup, bool usesharedvertices, uint vertexstart, uint vertexcount) { mName = name; mResourceGroup = resourcegroup; mVertextStart = vertexstart; mVertexCount = vertexcount; // Return now if already exists if (MeshManager.Singleton.ResourceExists(name)) return; mMeshPtr = MeshManager.Singleton.CreateManual(mName, mResourceGroup); mSubMesh = mMeshPtr.CreateSubMesh(); mSubMesh.useSharedVertices = usesharedvertices; mSubMesh.vertexData = new VertexData(); mSubMesh.vertexData.vertexStart = mVertextStart; mSubMesh.vertexData.vertexCount = mVertexCount; offset = 0; mIndexType = HardwareIndexBuffer.IndexType.IT_16BIT; } public virtual VertexElement AddElement(VertexElementType theType, VertexElementSemantic semantic) { VertexElement ve = mSubMesh.vertexData.vertexDeclaration.AddElement(0, offset, theType, semantic); offset += VertexElement.GetTypeSize(theType); return ve; } public virtual void CreateVertexBuffer(uint numVerts, HardwareBuffer.Usage usage) { CreateVertexBuffer(numVerts, usage, false); } public virtual void CreateVertexBuffer(uint numVerts, HardwareBuffer.Usage usage, bool useShadowBuffer) { mVertexSize = offset; mNumVerts = numVerts; mvbuf = HardwareBufferManager.Singleton.CreateVertexBuffer( mVertexSize, mNumVerts, usage, useShadowBuffer); unsafe { pVBuffStart = mvbuf.Lock(HardwareBuffer.LockOptions.HBL_DISCARD); } } public virtual void SetVertFloat(uint vertexindex, uint byteoffset, float val1) { if (vertexindex >= mNumVerts) throw new IndexOutOfRangeException( "'vertexIndex' cannot be greater than the number of vertices."); unsafe { byte* pp = (byte*)pVBuffStart; pp += (mVertexSize * vertexindex) + byteoffset; float* p = (float*)pp; *p = val1; } } public virtual void SetVertFloat(uint vertexindex, uint byteoffset, float val1, float val2) { if (vertexindex >= mNumVerts) throw new IndexOutOfRangeException( "'vertexIndex' cannot be greater than the number of vertices."); unsafe { byte* pp = (byte*)pVBuffStart; pp += (mVertexSize * vertexindex) + byteoffset; float* p = (float*)pp; *p++ = val1; *p = val2; } } public virtual void SetVertFloat(uint vertexindex, uint byteoffset, float val1, float val2, float val3) { if (vertexindex >= mNumVerts) throw new IndexOutOfRangeException( "'vertexIndex' cannot be greater than the number of vertices."); unsafe { byte* pp = (byte*)pVBuffStart; pp += (mVertexSize * vertexindex) + byteoffset; float* p = (float*)pp; *p++ = val1; *p++ = val2; *p = val3; } } public virtual void SetVertFloat(uint vertexindex, uint byteoffset, float val1, float val2, float val3, float val4) { if (vertexindex >= mNumVerts) throw new IndexOutOfRangeException( "'vertexIndex' cannot be greater than the number of vertices."); unsafe { byte* pp = (byte*)pVBuffStart; pp += (mVertexSize * vertexindex) + byteoffset; float* p = (float*)pp; *p++ = val1; *p++ = val2; *p++ = val3; *p = val4; } } public virtual void CreateIndexBuffer(uint triaglecount, HardwareIndexBuffer.IndexType itype, HardwareBuffer.Usage usage) { CreateIndexBuffer(triaglecount, itype, usage, false); } public virtual void CreateIndexBuffer(uint triaglecount, HardwareIndexBuffer.IndexType itype, HardwareBuffer.Usage usage, bool useShadowBuffer) { mvbuf.Unlock(); mTriagleCount = triaglecount; mIndexType = itype; mSubMesh.vertexData.vertexBufferBinding.SetBinding(0, mvbuf); mSubMesh.indexData.indexCount = mTriagleCount * 3; HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager.Singleton .CreateIndexBuffer(mIndexType, mTriagleCount * 3, usage, useShadowBuffer); mSubMesh.indexData.indexBuffer = ibuf; unsafe { pIBuffStart = ibuf.Lock(HardwareBuffer.LockOptions.HBL_DISCARD); } } public virtual void SetIndex16bit(uint triagleIdx, ushort vidx1, ushort vidx2, ushort vidx3) { if (triagleIdx >= mTriagleCount) throw new IndexOutOfRangeException( "'triagleIdx' cannot be greater than the number of triangles."); if (mIndexType != HardwareIndexBuffer.IndexType.IT_16BIT) throw new NotSupportedException( "HardwareIndexBuffer.IndexType other than 'IT_16BIT' is not supported."); unsafe { ushort* p = (ushort*)pIBuffStart; p += (triagleIdx * 3); *p++ = vidx1; *p++ = vidx2; *p = vidx3; } } public virtual void SetIndex32bit(uint triagleIdx, uint vidx1, uint vidx2, uint vidx3) { if (triagleIdx >= mTriagleCount) throw new IndexOutOfRangeException( "'triagleIdx' cannot be greater than the number of triangles."); if (mIndexType != HardwareIndexBuffer.IndexType.IT_16BIT) throw new NotSupportedException( "HardwareIndexBuffer.IndexType other than 'IT_16BIT' is not supported."); unsafe { uint* p = (uint*)pIBuffStart; p += (triagleIdx * 3); *p++ = vidx1; *p++ = vidx2; *p = vidx3; } } public virtual MeshPtr Load(String materialname) { mSubMesh.indexData.indexBuffer.Unlock(); mSubMesh.MaterialName = materialname; mMeshPtr.Load(); return mMeshPtr; } #region Protected and Private fields protected MeshPtr mMeshPtr; protected SubMesh mSubMesh; protected String mName, mResourceGroup; protected uint mVertextStart, mVertexCount; protected HardwareVertexBufferSharedPtr mvbuf; protected uint offset; protected uint mVertexSize; protected uint mNumVerts; protected unsafe void* pVBuffStart = (void*)0; protected uint mTriagleCount; protected HardwareIndexBuffer.IndexType mIndexType; protected unsafe void* pIBuffStart = (void*)0; #endregion } }

Remember that you must compile your MeshBuilderHelper class with the unsafe option. Now, you can create your own mesh. In our example, we create a classical triangle with the following code.

Copy to clipboard
void CreateTriangle(string name) { MeshBuilderHelper mbh = new MeshBuilderHelper(name, "General", false, 0, 3); UInt32 offPos = mbh.AddElement(VertexElementType.VET_FLOAT3, VertexElementSemantic.VES_POSITION).Offset; UInt32 offDiff = mbh.AddElement(VertexElementType.VET_FLOAT3, VertexElementSemantic.VES_DIFFUSE).Offset; mbh.CreateVertexBuffer(3, HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY); mbh.SetVertFloat(0, offPos, 0, 0, 0); //position mbh.SetVertFloat(0, offDiff, 1, 0, 0); //color mbh.SetVertFloat(1, offPos, 0, 10, 0); //position mbh.SetVertFloat(1, offDiff, 0, 0, 1); //color mbh.SetVertFloat(2, offPos, 10, 0, 0); //position mbh.SetVertFloat(2, offDiff, 0, 1, 0); //color mbh.CreateIndexBuffer(1, HardwareIndexBuffer.IndexType.IT_16BIT, HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY); mbh.SetIndex16bit(0, (UInt16)0, (UInt16)2, (UInt16)1); // we create a material for our triangle. This could/must be defined outside MaterialPtr material = MaterialManager.Singleton.Create("Test/ColourTest", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME); material.GetTechnique(0).GetPass(0).VertexColourTracking = (int)TrackVertexColourEnum.TVC_AMBIENT; MeshPtr m = mbh.Load("Test/ColourTest"); m._setBounds(new AxisAlignedBox(0.0f, 0.0f, 0.0f, 10.0f, 10.0f, 10.0f), false); m._setBoundingSphereRadius((float)System.Math.Sqrt(10.0f * 10.0f + 10.0f * 10.0f)); }


To display this triangle within your Mogre application, you'll need to set up a material definition that looks like:

Copy to clipboard
material Test/ColourTest { technique { pass { ambient vertexcolour } } }


Alternatively, the material can be created directly in C#:

Copy to clipboard
MaterialPtr material = MaterialManager.Singleton.Create("Test/ColourTest", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME); material.GetTechnique(0).GetPass(0).VertexColourTracking = (int)TrackVertexColourEnum.TVC_AMBIENT;

In our example we have defined the material inside our CreateTriangle function, but you are free to define it before calling CreateTriangle.

Now, if I want to insert the mesh into a scene:

Copy to clipboard
public override void CreateScene() { CreateTriangle("myTriangle"); Entity ent1 = base.sceneMgr.CreateEntity("Triangle1", "myTriangle"); SceneNode node1 = base.sceneMgr.RootSceneNode.CreateChildSceneNode("TriangleNode"); node1.AttachObject(ent1); }


A final note. If you are using the sample Application, our camera is too far from our triangle. I recomend to use this code in your main program:

Copy to clipboard
public override void CreateCamera() { // Create the camera camera = sceneMgr.CreateCamera("PlayerCam"); // Position it at 30 in Z direction camera.Position = new Vector3(0, 0, 30); // Look at our triangle camera.LookAt(new Vector3(5, 5, 5)); camera.NearClipDistance = 1; }


Finally, if everything is OK, you will see:
TriangleScreenshotWithMogre.jpg