Defines a part of a complete 3D mesh.
Models which make up the definition of a discrete 3D object are made up of potentially multiple parts. This is because different parts of the mesh may use different materials or use different vertex formats, such that a rendering state change is required between them.

Like the Mesh class, instatiations of 3D objects in the scene share the SubMesh instances, and have the option of overriding their material differences on a per-object basis if required. See the SubEntity class for more information.

 public static void CopyBoneAssignments(SubMesh dst, SubMesh src, Dictionary<uint, uint> vertexIdMap)
 {
     foreach (KeyValuePair<uint, uint> vertexMapping in vertexIdMap) {
         if (!src.BoneAssignmentList.ContainsKey((int)vertexMapping.Key))
             continue;
         List<VertexBoneAssignment> srcVbaList = src.BoneAssignmentList[(int)vertexMapping.Key];
         foreach (VertexBoneAssignment srcVba in srcVbaList) {
             Debug.Assert(srcVba.vertexIndex == (int)vertexMapping.Key);
             VertexBoneAssignment dstVba = new VertexBoneAssignment();
             dstVba.boneIndex = srcVba.boneIndex;
             dstVba.vertexIndex = (int)vertexMapping.Value;
             dstVba.weight = srcVba.weight;
             dst.AddBoneAssignment(dstVba);
         }
     }
 }
예제 #2
0
		private void _generateCurvedPlaneVertexData( HardwareVertexBuffer vbuf, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 transform, bool firstTime, bool normals, Matrix4 rotation, float curvature, int numTexCoordSets, float xTexCoord, float yTexCoord, SubMesh subMesh, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength )
		{
			Vector3 vec;
			unsafe
			{
				// lock the vertex buffer
				IntPtr data = vbuf.Lock( BufferLocking.Discard );

				float* pData = (float*)data.ToPointer();

				for ( int y = 0; y <= ySegments; y++ )
				{
					for ( int x = 0; x <= xSegments; x++ )
					{
						// centered on origin
						vec.x = ( x * xSpace ) - halfWidth;
						vec.y = ( y * ySpace ) - halfHeight;

						// Here's where curved plane is different from standard plane.  Amazing, I know.
						Real diff_x = ( x - ( (Real)xSegments / 2 ) ) / (Real)xSegments;
						Real diff_y = ( y - ( (Real)ySegments / 2 ) ) / (Real)ySegments;
						Real dist = Utility.Sqrt( diff_x * diff_x + diff_y * diff_y );
						vec.z = ( -Utility.Sin( ( 1 - dist ) * ( Utility.PI / 2 ) ) * curvature ) + curvature;

						// Transform by orientation and distance
						Vector3 pos = transform.TransformAffine( vec );

						*pData++ = pos.x;
						*pData++ = pos.y;
						*pData++ = pos.z;

						// Build bounds as we go
						if ( firstTime )
						{
							min = vec;
							max = vec;
							maxSquaredLength = vec.LengthSquared;
							firstTime = false;
						}
						else
						{
							min.Floor( vec );
							max.Ceil( vec );
							maxSquaredLength = Utility.Max( maxSquaredLength, vec.LengthSquared );
						}

						if ( normals )
						{
							// This part is kinda 'wrong' for curved planes... but curved planes are
							//   very valuable outside sky planes, which don't typically need normals
							//   so I'm not going to mess with it for now.

							// Default normal is along unit Z
							//vec = Vector3::UNIT_Z;
							// Rotate
							vec = rotation.TransformAffine( vec );

							*pData++ = vec.x;
							*pData++ = vec.y;
							*pData++ = vec.z;
						}

						for ( int i = 0; i < numTexCoordSets; i++ )
						{
							*pData++ = x * xTexCoord;
							*pData++ = 1 - ( y * yTexCoord );
						} // for texCoords
					} // for x
				} // for y

				// unlock the buffer
				vbuf.Unlock();

				subMesh.useSharedVertices = true;

			} // unsafe
		}
예제 #3
0
		/// <summary>
		///		Used to generate a face list based on vertices.
		/// </summary>
		private void _tesselate2DMesh( SubMesh subMesh, int width, int height, bool doubleSided, BufferUsage indexBufferUsage, bool indexShadowBuffer )
		{
			int vInc, uInc, v, u, iterations;
			int vCount, uCount;

			vInc = 1;
			v = 0;

			iterations = doubleSided ? 2 : 1;

			// setup index count
			subMesh.indexData.indexCount = ( width - 1 ) * ( height - 1 ) * 2 * iterations * 3;

			// create the index buffer using the current API
			subMesh.indexData.indexBuffer =
				HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, subMesh.indexData.indexCount, indexBufferUsage, indexShadowBuffer );

			short v1, v2, v3;

			// grab a reference for easy access
			HardwareIndexBuffer idxBuffer = subMesh.indexData.indexBuffer;

			// lock the whole index buffer
			IntPtr data = idxBuffer.Lock( BufferLocking.Discard );

			unsafe
			{
				short* pIndex = (short*)data.ToPointer();

				while ( 0 < iterations-- )
				{
					// make tris in a zigzag pattern (strip compatible)
					u = 0;
					uInc = 1;

					vCount = height - 1;

					while ( 0 < vCount-- )
					{
						uCount = width - 1;

						while ( 0 < uCount-- )
						{
							// First Tri in cell
							// -----------------
							v1 = (short)( ( ( v + vInc ) * width ) + u );
							v2 = (short)( ( v * width ) + u );
							v3 = (short)( ( ( v + vInc ) * width ) + ( u + uInc ) );
							// Output indexes
							*pIndex++ = v1;
							*pIndex++ = v2;
							*pIndex++ = v3;
							// Second Tri in cell
							// ------------------
							v1 = (short)( ( ( v + vInc ) * width ) + ( u + uInc ) );
							v2 = (short)( ( v * width ) + u );
							v3 = (short)( ( v * width ) + ( u + uInc ) );
							// Output indexes
							*pIndex++ = v1;
							*pIndex++ = v2;
							*pIndex++ = v3;

							// Next column
							u += uInc;

						} // while uCount

						v += vInc;
						u = 0;

					} // while vCount

					v = height - 1;
					vInc = -vInc;
				} // while iterations
			}// unsafe

			// unlock the buffer
			idxBuffer.Unlock();
		}
 public void AddSubmesh(SubMesh subMesh)
 {
     subMeshes.Add(subMesh);
     AddSubmeshIndexData(subMesh.IndexData);
     foreach (IndexData indexData in subMesh.LodFaceList)
         AddSubmeshIndexData(indexData);
 }
 public static void CopySubMesh(SubMesh dstSubMesh, SubMesh srcSubMesh, SubMeshData subMeshData)
 {
     dstSubMesh.OperationType = srcSubMesh.OperationType;
     dstSubMesh.useSharedVertices = srcSubMesh.useSharedVertices;
     dstSubMesh.MaterialName = srcSubMesh.MaterialName;
     CopyIndexData(dstSubMesh.IndexData, srcSubMesh.IndexData, subMeshData.VertexIdMap);
     if (!srcSubMesh.useSharedVertices) {
         dstSubMesh.useSharedVertices = false;
         dstSubMesh.vertexData = new VertexData();
         CopyVertexData(dstSubMesh.VertexData, srcSubMesh.VertexData, subMeshData.VertexIdMap);
         CopyBoneAssignments(dstSubMesh, srcSubMesh, subMeshData.VertexIdMap);
     }
     Debug.Assert(srcSubMesh.VertexAnimationType == VertexAnimationType.None);
 }
예제 #6
0
		/// <summary>
		///   Look up or calculate the geometry data to use for this SubMesh
		/// </summary>
		/// <param name="sm"> </param>
		/// <returns> </returns>
		public List<SubMeshLodGeometryLink> DetermineGeometry( SubMesh sm )
		{
			// First, determine if we've already seen this submesh before
			if ( mSubMeshGeometryLookup.ContainsKey( sm ) )
			{
				return mSubMeshGeometryLookup[ sm ];
			}

			// Otherwise, we have to create a new one
			var lodList = new List<SubMeshLodGeometryLink>();
			mSubMeshGeometryLookup[ sm ] = lodList;

			int numLods = sm.Parent.IsLodManual ? 1 : sm.Parent.LodLevelCount;
			lodList.Capacity = numLods;

			for ( int lod = 0; lod < numLods; ++lod )
			{
				SubMeshLodGeometryLink geomLink = lodList[ lod ];
				IndexData lodIndexData;
				if ( lod == 0 )
				{
					lodIndexData = sm.IndexData;
				}
				else
				{
					lodIndexData = sm.LodFaceList[ lod - 1 ];
				}
				// Can use the original mesh geometry?
				if ( sm.useSharedVertices )
				{
					if ( sm.Parent.SubMeshCount == 1 )
					{
						// Ok, this is actually our own anyway
						geomLink.vertexData = sm.Parent.SharedVertexData;
						geomLink.indexData = lodIndexData;
					}
					else
					{
						// We have to split it
						SplitGeometry( sm.Parent.SharedVertexData,
						               lodIndexData, ref geomLink );
					}
				}
				else
				{
					if ( lod == 0 )
					{
						// Ok, we can use the existing geometry; should be in full
						// use by just this SubMesh
						geomLink.vertexData = sm.vertexData;
						geomLink.indexData = sm.indexData;
					}
					else
					{
						// We have to split it
						SplitGeometry( sm.vertexData,
						               lodIndexData, ref geomLink );
					}
				}

				Debug.Assert( geomLink.vertexData.vertexStart == 0,
				              "Cannot use vertexStart > 0 on indexed geometry due to rendersystem incompatibilities - see the docs!" );
			}

			return lodList;
		}
 protected void WriteSubMeshTextureAliases(BinaryWriter writer, SubMesh subMesh)
 {
     LogManager.Instance.Write("Exporting submesh texture aliases...");
     foreach (KeyValuePair<string, string> pair in subMesh.TextureAliases) {
         long start_offset = writer.Seek(0, SeekOrigin.Current);
         WriteChunk(writer, MeshChunkID.SubMeshTextureAlias, 0);
         WriteString(writer, pair.Key);
         WriteString(writer, pair.Value);
         long end_offset = writer.Seek(0, SeekOrigin.Current);
         writer.Seek((int)start_offset, SeekOrigin.Begin);
         WriteChunk(writer, MeshChunkID.SubMeshTextureAlias, (int)(end_offset - start_offset));
         writer.Seek((int)end_offset, SeekOrigin.Begin);
     }
 }
예제 #8
0
 /// <summary>
 ///		This is only used if the SceneManager chooses to render the node. This option can be set
 ///		for SceneNodes at SceneManager.DisplaySceneNodes, and for entities based on skeletal 
 ///		models using Entity.DisplaySkeleton = true.
 ///	 </summary>
 public void GetRenderOperation(RenderOperation op)
 {
     if(nodeSubMesh == null) {
         Mesh nodeMesh = MeshManager.Instance.Load("axes.mesh");
         nodeSubMesh = nodeMesh.GetSubMesh(0);
     }
     // return the render operation of the submesh itself
     nodeSubMesh.GetRenderOperation(op);
 }
 protected void ReadBoneAssignments(XmlNode node, SubMesh subMesh)
 {
     foreach (XmlNode childNode in node.ChildNodes) {
         switch (childNode.Name) {
             case "vertexboneassignment":
                 ReadVertexBoneAssigment(childNode, subMesh);
                 break;
             default:
                 DebugMessage(childNode);
                 break;
         }
     }
 }
예제 #10
0
        /// <summary>
        ///   Look up or calculate the geometry data to use for this SubMesh
        /// </summary>
        /// <param name="sm"> </param>
        /// <returns> </returns>
        public List <SubMeshLodGeometryLink> DetermineGeometry(SubMesh sm)
        {
            // First, determine if we've already seen this submesh before
            if (mSubMeshGeometryLookup.ContainsKey(sm))
            {
                return(mSubMeshGeometryLookup[sm]);
            }

            // Otherwise, we have to create a new one
            var lodList = new List <SubMeshLodGeometryLink>();

            mSubMeshGeometryLookup[sm] = lodList;

            int numLods = sm.Parent.IsLodManual ? 1 : sm.Parent.LodLevelCount;

            lodList.Capacity = numLods;

            for (int lod = 0; lod < numLods; ++lod)
            {
                SubMeshLodGeometryLink geomLink = lodList[lod];
                IndexData lodIndexData;
                if (lod == 0)
                {
                    lodIndexData = sm.IndexData;
                }
                else
                {
                    lodIndexData = sm.LodFaceList[lod - 1];
                }
                // Can use the original mesh geometry?
                if (sm.useSharedVertices)
                {
                    if (sm.Parent.SubMeshCount == 1)
                    {
                        // Ok, this is actually our own anyway
                        geomLink.vertexData = sm.Parent.SharedVertexData;
                        geomLink.indexData  = lodIndexData;
                    }
                    else
                    {
                        // We have to split it
                        SplitGeometry(sm.Parent.SharedVertexData,
                                      lodIndexData, ref geomLink);
                    }
                }
                else
                {
                    if (lod == 0)
                    {
                        // Ok, we can use the existing geometry; should be in full
                        // use by just this SubMesh
                        geomLink.vertexData = sm.vertexData;
                        geomLink.indexData  = sm.indexData;
                    }
                    else
                    {
                        // We have to split it
                        SplitGeometry(sm.vertexData,
                                      lodIndexData, ref geomLink);
                    }
                }

                Debug.Assert(geomLink.vertexData.vertexStart == 0,
                             "Cannot use vertexStart > 0 on indexed geometry due to rendersystem incompatibilities - see the docs!");
            }

            return(lodList);
        }
        /// <summary>
        ///		Used to generate a face list based on vertices.
        /// </summary>
        /// <param name="subMesh"></param>
        /// <param name="xSegments"></param>
        /// <param name="ySegments"></param>
        /// <param name="doubleSided"></param>
        private void Tesselate2DMesh(SubMesh subMesh, int width, int height, bool doubleSided, BufferUsage indexBufferUsage, bool indexShadowBuffer)
        {
            int vInc, uInc, v, u, iterations;
            int vCount, uCount;

            vInc = 1;
            v    = 0;

            iterations = doubleSided ? 2 : 1;

            // setup index count
            subMesh.indexData.indexCount = (width - 1) * (height - 1) * 2 * iterations * 3;

            // create the index buffer using the current API
            subMesh.indexData.indexBuffer =
                HardwareBufferManager.Instance.CreateIndexBuffer(IndexType.Size16, subMesh.indexData.indexCount, indexBufferUsage, indexShadowBuffer);

            short v1, v2, v3;

            // grab a reference for easy access
            HardwareIndexBuffer idxBuffer = subMesh.indexData.indexBuffer;

            // lock the whole index buffer
            IntPtr data = idxBuffer.Lock(BufferLocking.Discard);

            unsafe {
                short *pIndex = (short *)data.ToPointer();

                while (0 < iterations--)
                {
                    // make tris in a zigzag pattern (strip compatible)
                    u    = 0;
                    uInc = 1;

                    vCount = height - 1;

                    while (0 < vCount--)
                    {
                        uCount = width - 1;

                        while (0 < uCount--)
                        {
                            // First Tri in cell
                            // -----------------
                            v1 = (short)(((v + vInc) * width) + u);
                            v2 = (short)((v * width) + u);
                            v3 = (short)(((v + vInc) * width) + (u + uInc));
                            // Output indexes
                            *pIndex++ = v1;
                            *pIndex++ = v2;
                            *pIndex++ = v3;
                            // Second Tri in cell
                            // ------------------
                            v1 = (short)(((v + vInc) * width) + (u + uInc));
                            v2 = (short)((v * width) + u);
                            v3 = (short)((v * width) + (u + uInc));
                            // Output indexes
                            *pIndex++ = v1;
                            *pIndex++ = v2;
                            *pIndex++ = v3;

                            // Next column
                            u += uInc;
                        } // while uCount

                        v += vInc;
                        u  = 0;
                    } // while vCount

                    v    = height - 1;
                    vInc = -vInc;
                } // while iterations
            }     // unsafe

            // unlock the buffer
            idxBuffer.Unlock();
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="name"></param>
        /// <param name="plane"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="curvature"></param>
        /// <param name="xSegments"></param>
        /// <param name="ySegments"></param>
        /// <param name="normals"></param>
        /// <param name="numberOfTexCoordSets"></param>
        /// <param name="uTiles"></param>
        /// <param name="vTiles"></param>
        /// <param name="upVector"></param>
        /// <param name="orientation"></param>
        /// <param name="vertexBufferUsage"></param>
        /// <param name="indexBufferUsage"></param>
        /// <param name="vertexShadowBuffer"></param>
        /// <param name="indexShadowBuffer"></param>
        /// <returns></returns>
        public Mesh CreateCurvedIllusionPlane(string name, Plane plane, float width, float height, float curvature, int xSegments, int ySegments, bool normals, int numberOfTexCoordSets, float uTiles, float vTiles, Vector3 upVector, Quaternion orientation, BufferUsage vertexBufferUsage, BufferUsage indexBufferUsage, bool vertexShadowBuffer, bool indexShadowBuffer)
        {
            Mesh    mesh    = CreateManual(name);
            SubMesh subMesh = mesh.CreateSubMesh(name + "SubMesh");

            // set up vertex data, use a single shared buffer
            mesh.SharedVertexData = new VertexData();
            VertexData vertexData = mesh.SharedVertexData;

            // set up vertex declaration
            VertexDeclaration vertexDeclaration = vertexData.vertexDeclaration;
            int currentOffset = 0;

            // always need positions
            vertexDeclaration.AddElement(0, currentOffset, VertexElementType.Float3, VertexElementSemantic.Position);
            currentOffset += VertexElement.GetTypeSize(VertexElementType.Float3);

            // optional normals
            if (normals)
            {
                vertexDeclaration.AddElement(0, currentOffset, VertexElementType.Float3, VertexElementSemantic.Normal);
                currentOffset += VertexElement.GetTypeSize(VertexElementType.Float3);
            }

            for (ushort i = 0; i < numberOfTexCoordSets; i++)
            {
                // assumes 2d texture coordinates
                vertexDeclaration.AddElement(0, currentOffset, VertexElementType.Float2, VertexElementSemantic.TexCoords, i);
                currentOffset += VertexElement.GetTypeSize(VertexElementType.Float2);
            }

            vertexData.vertexCount = (xSegments + 1) * (ySegments + 1);

            // allocate vertex buffer
            HardwareVertexBuffer vertexBuffer = HardwareBufferManager.Instance.CreateVertexBuffer(vertexDeclaration.GetVertexSize(0), vertexData.vertexCount, vertexBufferUsage, vertexShadowBuffer);

            // set up the binding, one source only
            VertexBufferBinding binding = vertexData.vertexBufferBinding;

            binding.SetBinding(0, vertexBuffer);

            // work out the transform required, default orientation of plane is normal along +z, distance 0
            Matrix4 xlate, xform, rot;
            Matrix3 rot3 = Matrix3.Identity;

            xlate = rot = Matrix4.Identity;

            // determine axes
            Vector3 zAxis, yAxis, xAxis;

            zAxis = plane.Normal;
            zAxis.Normalize();
            yAxis = upVector;
            yAxis.Normalize();
            xAxis = yAxis.Cross(zAxis);
            if (xAxis.Length == 0)
            {
                throw new AxiomException("The up vector for a plane cannot be parallel to the planes normal.");
            }

            rot3.FromAxes(xAxis, yAxis, zAxis);
            rot = rot3;

            // set up standard xform from origin
            xlate.Translation = plane.Normal * -plane.D;

            // concatenate
            xform = xlate * rot;

            // generate vertex data, imagine a large sphere with the camera located near the top,
            // the lower the curvature, the larger the sphere.  use the angle from the viewer to the
            // points on the plane
            float cameraPosition;      // camera position relative to the sphere center

            // derive sphere radius (unused)
            //float sphereDistance;      // distance from the camera to the sphere along box vertex vector
            float sphereRadius;

            // actual values irrelevant, it's the relation between the sphere's radius and the camera's position which is important
            float SPHERE_RADIUS   = 100;
            float CAMERA_DISTANCE = 5;

            sphereRadius   = SPHERE_RADIUS - curvature;
            cameraPosition = sphereRadius - CAMERA_DISTANCE;

            // lock the whole buffer
            float   xSpace           = width / xSegments;
            float   ySpace           = height / ySegments;
            float   halfWidth        = width / 2;
            float   halfHeight       = height / 2;
            Vector3 vec              = Vector3.Zero;
            Vector3 norm             = Vector3.Zero;
            Vector3 min              = Vector3.Zero;
            Vector3 max              = Vector3.Zero;
            float   maxSquaredLength = 0;
            bool    firstTime        = true;

            // generate vertex data
            GenerateCurvedIllusionPlaneVertexData(vertexBuffer, ySegments, xSegments, xSpace, halfWidth, ySpace, halfHeight, xform, firstTime, normals, orientation, cameraPosition, sphereRadius, uTiles, vTiles, numberOfTexCoordSets, ref min, ref max, ref maxSquaredLength);

            // generate face list
            subMesh.useSharedVertices = true;
            Tesselate2DMesh(subMesh, xSegments + 1, ySegments + 1, false, indexBufferUsage, indexShadowBuffer);

            // generate bounds for the mesh
            mesh.BoundingBox          = new AxisAlignedBox(min, max);
            mesh.BoundingSphereRadius = MathUtil.Sqrt(maxSquaredLength);

            mesh.Load();
            mesh.Touch();

            return(mesh);
        }
        public Mesh CreateBoneMesh(string name)
        {
            Mesh mesh = CreateManual(name);

            mesh.SkeletonName = name + ".skeleton";
            SubMesh subMesh = mesh.CreateSubMesh("BoneSubMesh");

            subMesh.useSharedVertices = true;
            subMesh.MaterialName      = "BaseWhite";

            // short[] faces = { 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 2, 1, 2, 5, 1, 5, 4, 1, 4, 3, 1, 3, 2 };
            // short[] faces = { 0, 3, 2, 0, 4, 3, 0, 5, 4, 0, 2, 5, 1, 5, 2, 1, 4, 5, 1, 3, 4, 1, 2, 3 };
            short[] faces = { 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 2, 1, 2, 5, 1, 5, 4, 1, 4, 3, 1, 3, 2,
                              0, 3, 2, 0, 4, 3, 0, 5, 4, 0, 2, 5, 1, 5, 2, 1, 4, 5, 1, 3, 4, 1, 2, 3 };
            int     faceCount   = faces.Length / 3; // faces per bone
            int     vertexCount = 6;                // vertices per bone

            // set up vertex data, use a single shared buffer
            mesh.SharedVertexData = new VertexData();
            VertexData vertexData = mesh.SharedVertexData;

            // set up vertex declaration
            VertexDeclaration vertexDeclaration = vertexData.vertexDeclaration;
            int currentOffset = 0;

            // always need positions
            vertexDeclaration.AddElement(0, currentOffset, VertexElementType.Float3, VertexElementSemantic.Position);
            currentOffset += VertexElement.GetTypeSize(VertexElementType.Float3);
            vertexDeclaration.AddElement(0, currentOffset, VertexElementType.Float3, VertexElementSemantic.Normal);
            currentOffset += VertexElement.GetTypeSize(VertexElementType.Float3);

            int boneCount = mesh.Skeleton.BoneCount;

            // I want 6 vertices per bone - exclude the root bone
            vertexData.vertexCount = boneCount * vertexCount;

            // allocate vertex buffer
            HardwareVertexBuffer vertexBuffer = HardwareBufferManager.Instance.CreateVertexBuffer(vertexDeclaration.GetVertexSize(0), vertexData.vertexCount, BufferUsage.StaticWriteOnly);

            // set up the binding, one source only
            VertexBufferBinding binding = vertexData.vertexBufferBinding;

            binding.SetBinding(0, vertexBuffer);

            Vector3[] vertices = new Vector3[vertexData.vertexCount];
            GetVertices(ref vertices, mesh.Skeleton.RootBone);

            // Generate vertex data
            unsafe {
                // lock the vertex buffer
                IntPtr data = vertexBuffer.Lock(BufferLocking.Discard);

                float *pData = (float *)data.ToPointer();

                foreach (Vector3 vec in vertices)
                {
                    // assign to geometry
                    *pData++ = vec.x;
                    *pData++ = vec.y;
                    *pData++ = vec.z;
                    // fake normals
                    *pData++ = 0;
                    *pData++ = 1;
                    *pData++ = 0;
                }

                // unlock the buffer
                vertexBuffer.Unlock();
            } // unsafe


            // Generate index data
            HardwareIndexBuffer indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer(IndexType.Size16, faces.Length * boneCount, BufferUsage.StaticWriteOnly);

            subMesh.indexData.indexBuffer = indexBuffer;
            subMesh.indexData.indexCount  = faces.Length * boneCount;
            subMesh.indexData.indexStart  = 0;
            for (ushort boneIndex = 0; boneIndex < mesh.Skeleton.BoneCount; ++boneIndex)
            {
                Axiom.Animating.Bone bone = mesh.Skeleton.GetBone(boneIndex);
                short[] tmpFaces          = new short[faces.Length];
                for (int tmp = 0; tmp < faces.Length; ++tmp)
                {
                    tmpFaces[tmp] = (short)(faces[tmp] + vertexCount * bone.Handle);
                }
                indexBuffer.WriteData(faces.Length * bone.Handle * sizeof(short), tmpFaces.Length * sizeof(short), tmpFaces, true);
            }

            for (ushort boneIndex = 0; boneIndex < mesh.Skeleton.BoneCount; ++boneIndex)
            {
                Axiom.Animating.Bone bone       = mesh.Skeleton.GetBone(boneIndex);
                Axiom.Animating.Bone parentBone = bone;
                if (bone.Parent != null)
                {
                    parentBone = (Axiom.Animating.Bone)bone.Parent;
                }
                for (int vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex)
                {
                    Axiom.Animating.VertexBoneAssignment vba = new Axiom.Animating.VertexBoneAssignment();
                    // associate the base of the joint display with the bone's parent,
                    // and the rest of the points with the bone.
                    vba.boneIndex   = parentBone.Handle;
                    vba.weight      = 1.0f;
                    vba.vertexIndex = vertexCount * bone.Handle + vertexIndex;
                    mesh.AddBoneAssignment(vba);
                }
            }

            mesh.Load();
            mesh.Touch();

            return(mesh);
        }
        private static void GeneratePlaneVertexData(HardwareVertexBuffer vbuf, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 transform, bool firstTime, bool normals, Matrix4 rotation, int numTexCoordSets, float xTexCoord, float yTexCoord, SubMesh subMesh, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength)
        {
            Vector3 vec;

            unsafe {
                // lock the vertex buffer
                IntPtr data = vbuf.Lock(BufferLocking.Discard);

                float *pData = (float *)data.ToPointer();

                for (int y = 0; y <= ySegments; y++)
                {
                    for (int x = 0; x <= xSegments; x++)
                    {
                        // centered on origin
                        vec.x = (x * xSpace) - halfWidth;
                        vec.y = (y * ySpace) - halfHeight;
                        vec.z = 0.0f;

                        vec = transform * vec;

                        *pData++ = vec.x;
                        *pData++ = vec.y;
                        *pData++ = vec.z;

                        // Build bounds as we go
                        if (firstTime)
                        {
                            min = vec;
                            max = vec;
                            maxSquaredLength = vec.LengthSquared;
                            firstTime        = false;
                        }
                        else
                        {
                            min.Floor(vec);
                            max.Ceil(vec);
                            maxSquaredLength = MathUtil.Max(maxSquaredLength, vec.LengthSquared);
                        }

                        if (normals)
                        {
                            vec = Vector3.UnitZ;
                            vec = rotation * vec;

                            *pData++ = vec.x;
                            *pData++ = vec.y;
                            *pData++ = vec.z;
                        }

                        for (int i = 0; i < numTexCoordSets; i++)
                        {
                            *pData++ = x * xTexCoord;
                            *pData++ = 1 - (y * yTexCoord);
                        } // for texCoords
                    }     // for x
                }         // for y

                // unlock the buffer
                vbuf.Unlock();

                subMesh.useSharedVertices = true;
            } // unsafe
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="name">Name of the plane mesh.</param>
        /// <param name="plane">Plane to use for distance and orientation of the mesh.</param>
        /// <param name="width">Width in world coordinates.</param>
        /// <param name="height">Height in world coordinates.</param>
        /// <param name="xSegments">Number of x segments for tesselation.</param>
        /// <param name="ySegments">Number of y segments for tesselation.</param>
        /// <param name="normals">If true, plane normals are created.</param>
        /// <param name="numTexCoordSets">Number of 2d texture coord sets to use.</param>
        /// <param name="uTile">Number of times the texture should be repeated in the u direction.</param>
        /// <param name="vTile">Number of times the texture should be repeated in the v direction.</param>
        /// <param name="upVec">The up direction of the plane.</param>
        /// <returns></returns>
        public Mesh CreatePlane(string name, Plane plane, float width, float height, int xSegments, int ySegments, bool normals, int numTexCoordSets, float uTile, float vTile, Vector3 upVec,
                                BufferUsage vertexBufferUsage, BufferUsage indexBufferUsage, bool vertexShadowBuffer, bool indexShadowBuffer)
        {
            Mesh    mesh    = CreateManual(name);
            SubMesh subMesh = mesh.CreateSubMesh(name + "SubMesh");

            mesh.SharedVertexData = new VertexData();
            VertexData vertexData = mesh.SharedVertexData;

            VertexDeclaration decl = vertexData.vertexDeclaration;
            int currOffset         = 0;

            // add position data
            decl.AddElement(0, currOffset, VertexElementType.Float3, VertexElementSemantic.Position);
            currOffset += VertexElement.GetTypeSize(VertexElementType.Float3);

            // normals are optional
            if (normals)
            {
                decl.AddElement(0, currOffset, VertexElementType.Float3, VertexElementSemantic.Normal);
                currOffset += VertexElement.GetTypeSize(VertexElementType.Float3);
            }

            // add texture coords
            for (ushort i = 0; i < numTexCoordSets; i++)
            {
                decl.AddElement(0, currOffset, VertexElementType.Float2, VertexElementSemantic.TexCoords, i);
                currOffset += VertexElement.GetTypeSize(VertexElementType.Float2);
            }

            vertexData.vertexCount = (xSegments + 1) * (ySegments + 1);

            // create a new vertex buffer (based on current API)
            HardwareVertexBuffer vbuf =
                HardwareBufferManager.Instance.CreateVertexBuffer(decl.GetVertexSize(0), vertexData.vertexCount, vertexBufferUsage, vertexShadowBuffer);

            // get a reference to the vertex buffer binding
            VertexBufferBinding binding = vertexData.vertexBufferBinding;

            // bind the first vertex buffer
            binding.SetBinding(0, vbuf);

            // transform the plane based on its plane def
            Matrix4 translate = Matrix4.Identity;
            Matrix4 transform = Matrix4.Zero;
            Matrix4 rotation  = Matrix4.Identity;
            Matrix3 rot3x3    = Matrix3.Zero;

            Vector3 xAxis, yAxis, zAxis;

            zAxis = plane.Normal;
            zAxis.Normalize();
            yAxis = upVec;
            yAxis.Normalize();
            xAxis = yAxis.Cross(zAxis);

            if (xAxis.Length == 0)
            {
                throw new AxiomException("The up vector for a plane cannot be parallel to the planes normal.");
            }

            rot3x3.FromAxes(xAxis, yAxis, zAxis);
            rotation = rot3x3;

            // set up transform from origin
            translate.Translation = plane.Normal * -plane.D;

            transform = translate * rotation;

            float   xSpace           = width / xSegments;
            float   ySpace           = height / ySegments;
            float   halfWidth        = width / 2;
            float   halfHeight       = height / 2;
            float   xTexCoord        = (1.0f * uTile) / xSegments;
            float   yTexCoord        = (1.0f * vTile) / ySegments;
            Vector3 vec              = Vector3.Zero;
            Vector3 min              = Vector3.Zero;
            Vector3 max              = Vector3.Zero;
            float   maxSquaredLength = 0;
            bool    firstTime        = true;

            // generate vertex data
            GeneratePlaneVertexData(vbuf, ySegments, xSegments, xSpace, halfWidth, ySpace, halfHeight, transform, firstTime, normals, rotation, numTexCoordSets, xTexCoord, yTexCoord, subMesh, ref min, ref max, ref maxSquaredLength);

            // generate face list
            Tesselate2DMesh(subMesh, xSegments + 1, ySegments + 1, false, indexBufferUsage, indexShadowBuffer);

            // generate bounds for the mesh
            mesh.BoundingBox          = new AxisAlignedBox(min, max);
            mesh.BoundingSphereRadius = MathUtil.Sqrt(maxSquaredLength);

            mesh.Load();
            mesh.Touch();

            return(mesh);
        }
예제 #16
0
		protected virtual void ReadSubMeshBoneAssignment( BinaryReader reader, SubMesh sub )
		{
			var assignment = new VertexBoneAssignment();

			// read the data from the file
			assignment.vertexIndex = ReadInt( reader );
			assignment.boneIndex = ReadUShort( reader );
			assignment.weight = ReadFloat( reader );

			// add the assignment to the mesh
			sub.AddBoneAssignment( assignment );
		}
예제 #17
0
		protected void WriteSubMeshOperation( BinaryWriter writer, SubMesh subMesh )
		{
			var start_offset = writer.Seek( 0, SeekOrigin.Current );
			WriteChunk( writer, MeshChunkID.SubMeshOperation, 0 );

			WriteUShort( writer, (ushort)subMesh.operationType );

			var end_offset = writer.Seek( 0, SeekOrigin.Current );
			writer.Seek( (int)start_offset, SeekOrigin.Begin );
			WriteChunk( writer, MeshChunkID.SubMeshOperation, (int)( end_offset - start_offset ) );
			writer.Seek( (int)end_offset, SeekOrigin.Begin );
		}
        protected void ReadFaces(XmlNode node, SubMesh subMesh, IndexType indexType)
        {
            uint faceCount = uint.Parse(node.Attributes["count"].Value);

            int faceIndex = 0;
            int[,] data = new int[faceCount, 3];
            foreach (XmlNode childNode in node.ChildNodes) {
                switch (childNode.Name) {
                    case "face":
                        ReadFace(childNode, data, faceIndex++);
                        break;
                    default:
                        DebugMessage(childNode);
                        break;
                }
            }

            int count = data.GetLength(1);
            subMesh.indexData.indexStart = 0;
            subMesh.indexData.indexCount = data.GetLength(0) * data.GetLength(1);

            HardwareIndexBuffer idxBuffer = null;

            // create the index buffer
            idxBuffer =
                HardwareBufferManager.Instance.
                CreateIndexBuffer(
                indexType,
                subMesh.indexData.indexCount,
                mesh.IndexBufferUsage,
                mesh.UseIndexShadowBuffer);

            IntPtr indices = idxBuffer.Lock(BufferLocking.Discard);

            if (indexType == IndexType.Size32) {
                // read the ints into the buffer data
                unsafe {
                    int* pInts = (int*)indices.ToPointer();
                    for (int i = 0; i < faceCount; ++i)
                        for (int j = 0; j < count; ++j) {
                            Debug.Assert(i * count + j < subMesh.indexData.indexCount, "Wrote off end of index buffer");
                            pInts[i * count + j] = data[i, j];
                        }
                }
            } else {
                // read the shorts into the buffer data
                unsafe {
                    short* pShorts = (short*)indices.ToPointer();
                    for (int i = 0; i < faceCount; ++i)
                        for (int j = 0; j < count; ++j) {
                            Debug.Assert(i * count + j < subMesh.indexData.indexCount, "Wrote off end of index buffer");
                            pShorts[i * count + j] = (short)data[i, j];
                        }
                }
            }
            // unlock the buffer to commit
            idxBuffer.Unlock();

            // save the index buffer
            subMesh.indexData.indexBuffer = idxBuffer;
        }
        protected void WriteSubMesh(BinaryWriter writer, SubMesh subMesh)
        {
            long start_offset = writer.Seek(0, SeekOrigin.Current);
            WriteChunk(writer, MeshChunkID.SubMesh, 0);

            WriteString(writer, subMesh.MaterialName);
            WriteBool(writer, subMesh.useSharedVertices);
            WriteUInt(writer, (uint)subMesh.indexData.indexCount);
            bool indexes32bit = (subMesh.indexData.indexBuffer.Type == IndexType.Size32);
            WriteBool(writer, indexes32bit);
            IntPtr buf = subMesh.indexData.indexBuffer.Lock(BufferLocking.Discard);
            try {
                if (indexes32bit)
                    WriteInts(writer, subMesh.indexData.indexCount, buf);
                else
                    WriteShorts(writer, subMesh.indexData.indexCount, buf);
            } finally {
                subMesh.indexData.indexBuffer.Unlock();
            }
            if (!subMesh.useSharedVertices)
                WriteGeometry(writer, subMesh.vertexData);

            WriteSubMeshTextureAliases(writer, subMesh);

            WriteSubMeshOperation(writer, subMesh);

            Dictionary<int, List<VertexBoneAssignment>> weights = subMesh.BoneAssignmentList;
            foreach (int v in weights.Keys) {
                List<VertexBoneAssignment> vbaList = weights[v];
                foreach (VertexBoneAssignment vba in vbaList)
                    WriteSubMeshBoneAssignment(writer, vba);
            }

            // Write the texture alias (not currently supported)

            long end_offset = writer.Seek(0, SeekOrigin.Current);
            writer.Seek((int)start_offset, SeekOrigin.Begin);
            WriteChunk(writer, MeshChunkID.SubMesh, (int)(end_offset - start_offset));
            writer.Seek((int)end_offset, SeekOrigin.Begin);
        }
        protected void ReadGeometry(XmlNode node, SubMesh subMesh)
        {
            if (subMesh.useSharedVertices)
                throw new Exception("I don't support shared vertices");

            VertexData vertexData = new VertexData();
            subMesh.vertexData = vertexData;

            vertexData.vertexStart = 0;
            vertexData.vertexCount = int.Parse(node.Attributes["vertexcount"].Value);

            XmlVertexData xmlVertexData = new XmlVertexData(vertexData.vertexCount);

            // Read in the various vertex buffers for this geometry, and
            // consolidate them into one vertex buffer.
            foreach (XmlNode childNode in node.ChildNodes) {
                switch (childNode.Name) {
                    case "vertexbuffer":
                        ReadVertexBuffer(childNode, subMesh.vertexData, xmlVertexData);
                        break;
                    default:
                        DebugMessage(childNode);
                        break;
                }
            }

            xmlVertexDataDict[subMesh] = xmlVertexData;
        }
예제 #21
0
파일: Water.cs 프로젝트: WolfgangSt/axiom
		public WaterMesh( String meshName, float planeSize, int cmplx )
		{ // najak R-F
			// Assign Fields to the Initializer values
			this.meshName = meshName;
			this.size = planeSize;
			this.cmplx = cmplx;  // Number of Rows/Columns in the Water Grid representation
			cmplxAdj = (float)System.Math.Pow( ( cmplx / 64f ), 1.4f ) * 2;
			numFaces = 2 * (int)System.Math.Pow( cmplx, 2 );  // Each square is split into 2 triangles.
			numVertices = (int)System.Math.Pow( ( cmplx + 1 ), 2 ); // Vertex grid is (Complexity+1) squared

			// Allocate and initialize space for calculated Normals
			vNorms = new Vector3[ cmplx + 1, cmplx + 1 ]; // vertex Normals for each grid point
			fNorms = new Vector3[ cmplx, cmplx, 2 ]; // face Normals for each triangle

			// Create mesh and submesh to represent the Water
			mesh = (Mesh)MeshManager.Instance.CreateManual( meshName, ResourceGroupManager.DefaultResourceGroupName, null );
			subMesh = mesh.CreateSubMesh();
			subMesh.useSharedVertices = false;

			// Construct metadata to describe the buffers associated with the water submesh
			subMesh.vertexData = new VertexData();
			subMesh.vertexData.vertexStart = 0;
			subMesh.vertexData.vertexCount = numVertices;

			// Define local variables to point to the VertexData Properties
			VertexDeclaration vdecl = subMesh.vertexData.vertexDeclaration;  // najak: seems like metadata
			VertexBufferBinding vbind = subMesh.vertexData.vertexBufferBinding; // najak: pointer to actual buffer

			//najak: Set metadata to describe the three vertex buffers that will be accessed.
			vdecl.AddElement( 0, 0, VertexElementType.Float3, VertexElementSemantic.Position );
			vdecl.AddElement( 1, 0, VertexElementType.Float3, VertexElementSemantic.Normal );
			vdecl.AddElement( 2, 0, VertexElementType.Float2, VertexElementSemantic.TexCoords );

			// Prepare buffer for positions - todo: first attempt, slow
			// Create the Position Vertex Buffer and Bind it index 0 - Write Only
			posVBuf = HwBufMgr.CreateVertexBuffer( vdecl.Clone(0), numVertices, BufferUsage.DynamicWriteOnly );
			vbind.SetBinding( 0, posVBuf );

			// Prepare buffer for normals - write only
			// Create the Normals Buffer and Bind it to index 1 - Write only
			normVBuf = HwBufMgr.CreateVertexBuffer( vdecl.Clone(1), numVertices, BufferUsage.DynamicWriteOnly );
			vbind.SetBinding( 1, normVBuf );

			// Prepare Texture Coordinates buffer (static, written only once)
			// Creates a 2D buffer of 2D coordinates: (Complexity X Complexity), pairs.
			//    Each pair indicates the normalized coordinates of the texture to map to.
			//    (0,1.00), (0.02, 1.00), (0.04, 1.00), ... (1.00,1.00)
			//    (0,0.98), (0.02, 0.98), (0.04, 1.00), ... (1.00,0.98)
			//    ...
			//    (0,0.00), (0.02, 0.00), (0.04, 0.00), ... (1.00,0.00)
			// This construct is simple and is used to calculate the Texture map.
			// Todo: Write directly to the buffer, when Axiom supports this in safe manner
			float[ , , ] tcBufDat = new float[ cmplx + 1, cmplx + 1, 2 ];
			for ( int i = 0; i <= cmplx; i++ )
			{
				// 2D column iterator for texture map
				for ( int j = 0; j <= cmplx; j++ )
				{
					// 2D row iterator for texture map
					// Define the normalized(0..1) X/Y-coordinates for this element of the 2D grid
					tcBufDat[ i, j, 0 ] = (float)i / cmplx;
					tcBufDat[ i, j, 1 ] = 1.0f - ( (float)j / ( cmplx ) );
				}
			}

			// Now Create the actual hardware buffer to contain the Texture Coordinate 2d map.
			//   and Bind it to buffer index 2
			tcVBuf = HwBufMgr.CreateVertexBuffer( vdecl.Clone(2), numVertices, BufferUsage.StaticWriteOnly );
			tcVBuf.WriteData( 0, tcVBuf.Size, tcBufDat, true );
			vbind.SetBinding( 2, tcVBuf );

			// Create a Graphics Buffer on non-shared vertex indices (3 points for each triangle).
			//  Since the water grid consist of [Complexity x Complexity] squares, each square is
			//  split into 2 right triangles 45-90-45.  That is how the water mesh is constructed.
			//  Therefore the number of faces = 2 * Complexity * Complexity
			ushort[ , , ] idxBuf = new ushort[ cmplx, cmplx, 6 ];
			for ( int i = 0; i < cmplx; i++ )
			{ // iterate the rows
				for ( int j = 0; j < cmplx; j++ )
				{ // iterate the columns
					// Define 4 corners of each grid
					ushort p0 = (ushort)( i * ( cmplx + 1 ) + j ); // top left point on square
					ushort p1 = (ushort)( i * ( cmplx + 1 ) + j + 1 ); // top right
					ushort p2 = (ushort)( ( i + 1 ) * ( cmplx + 1 ) + j ); // bottom left
					ushort p3 = (ushort)( ( i + 1 ) * ( cmplx + 1 ) + j + 1 ); // bottom right

					// Split Square Grid element into 2 adjacent triangles.
					idxBuf[ i, j, 0 ] = p2;
					idxBuf[ i, j, 1 ] = p1;
					idxBuf[ i, j, 2 ] = p0; // top-left triangle
					idxBuf[ i, j, 3 ] = p2;
					idxBuf[ i, j, 4 ] = p3;
					idxBuf[ i, j, 5 ] = p1; // bottom-right triangle
				}
			}
			// Copy Index Buffer to the Hardware Index Buffer
			HardwareIndexBuffer hdwrIdxBuf = HwBufMgr.CreateIndexBuffer( IndexType.Size16, 3 * numFaces, BufferUsage.StaticWriteOnly, true );
			hdwrIdxBuf.WriteData( 0, numFaces * 3 * 2, idxBuf, true );

			// Set index buffer for this submesh
			subMesh.indexData.indexBuffer = hdwrIdxBuf;
			subMesh.indexData.indexStart = 0;
			subMesh.indexData.indexCount = 3 * numFaces;

			//Prepare Vertex Position Buffers (Note: make 3, since each frame is function of previous two)
			vBufs = new Vector3[ 3 ][ , ];
			for ( int b = 0; b < 3; b++ )
			{
				vBufs[ b ] = new Vector3[ cmplx + 1, cmplx + 1 ];
				for ( int y = 0; y <= cmplx; y++ )
				{
					for ( int x = 0; x <= cmplx; x++ )
					{
						vBufs[ b ][ y, x ].x = (float)( x ) / (float)( cmplx ) * (float)size;
						vBufs[ b ][ y, x ].y = 0;
						vBufs[ b ][ y, x ].z = (float)( y ) / (float)( cmplx ) * (float)size;
					}
				}
			}

			curBufNum = 0;
			vBuf = vBufs[ curBufNum ];
			posVBuf.WriteData( 0, posVBuf.Size, vBufs[ 0 ], true );

			AxisAlignedBox meshBounds = new AxisAlignedBox( new Vector3( 0, 0, 0 ), new Vector3( size, 0, size ) );
			mesh.BoundingBox = meshBounds;  //	mesh->_setBounds(meshBounds); // najak: can't find _setBounds()

			mesh.Load();
			mesh.Touch();

		} // end WaterMesh Constructor
        protected void ReadVertexBoneAssigment(XmlNode node, SubMesh subMesh)
        {
            VertexBoneAssignment assignment = new VertexBoneAssignment();

            // read the data from the file
            assignment.vertexIndex = int.Parse(node.Attributes["vertexindex"].Value);
            assignment.boneIndex = ushort.Parse(node.Attributes["boneindex"].Value); ;
            assignment.weight = float.Parse(node.Attributes["weight"].Value); ;

            // add the assignment to the mesh
            subMesh.AddBoneAssignment(assignment);
        }
예제 #23
0
파일: Mesh.cs 프로젝트: ryan-bunker/axiom3d
		/// <summary>
		///		Creates a new <see cref="SubMesh"/> and gives it a name.
		/// </summary>
		/// <param name="name">Name of the new <see cref="SubMesh"/>.</param>
		/// <returns>A new <see cref="SubMesh"/> with this Mesh as its parent.</returns>
		public SubMesh CreateSubMesh( string name )
		{
			var subMesh = new SubMesh();
			subMesh.Name = name;

			// set the parent of the subMesh to us
			subMesh.Parent = this;

			// add to the list of child meshes
			this._subMeshList.Add( subMesh );

			return subMesh;
		}
 protected XmlElement WriteBoneAssignments(SubMesh subMesh)
 {
     return WriteBoneAssignments(subMesh.BoneAssignmentList);
 }
 public void AddSubmeshData(SubMesh subMesh)
 {
     SubMeshData smd = null;
     if (!subMesh.useSharedVertices)
         smd = new SubMeshData(subMesh.VertexData);
     else {
         if (sharedSubMeshData == null)
             sharedSubMeshData = new SubMeshData(subMesh.VertexData);
         smd = sharedSubMeshData;
     }
     smd.AddSubmesh(subMesh);
     subMeshDataMap[subMesh.Name] = smd;
 }
        protected XmlElement WriteFaces(SubMesh subMesh, IndexType indexType, bool isTriList)
        {
            XmlElement node = document.CreateElement("faces");

            // Extract the hardware vertex buffer data into this array
            int[,] data = new int[subMesh.NumFaces, 3];

            HardwareIndexBuffer idxBuffer = subMesh.indexData.indexBuffer;
            IntPtr indices = idxBuffer.Lock(BufferLocking.ReadOnly);

            if (isTriList)
                GetTriangleListIndices(ref data, indices, indexType, subMesh.indexData.indexCount);
            else
                GetTriangleStripOrFanIndices(ref data, indices, indexType, subMesh.indexData.indexCount);

            // unlock the buffer
            idxBuffer.Unlock();

            int faceCount = data.GetLength(0);

            XmlAttribute attr;
            attr = document.CreateAttribute("count");
            attr.Value = faceCount.ToString();
            node.Attributes.Append(attr);

            if (isTriList) {
                for (int i = 0; i < faceCount; ++i) {
                    XmlElement childNode = WriteFace(ref data, i);
                    node.AppendChild(childNode);
                }
            } else {
                // triangle strip or fan
                if (faceCount != 0) {
                    XmlElement childNode = WriteFace(ref data, 0);
                    node.AppendChild(childNode);
                }
                for (int i = 1; i < faceCount; ++i) {
                    XmlElement childNode = WriteNextFace(ref data, i);
                    node.AppendChild(childNode);
                }
            }

            return node;
        }
        protected XmlElement WriteGeometry(SubMesh subMesh)
        {
            XmlElement node = document.CreateElement("geometry");
            XmlAttribute attr;

            attr = document.CreateAttribute("vertexcount");
            attr.Value = subMesh.vertexData.vertexCount.ToString();
            node.Attributes.Append(attr);
            return WriteGeometry(xmlVertexDataDict[subMesh], node);
        }
        protected XmlElement WriteSubmesh(SubMesh subMesh)
        {
            XmlElement node = document.CreateElement("submesh");
            XmlAttribute attr;

            attr = document.CreateAttribute("material");
            attr.Value = subMesh.MaterialName;
            node.Attributes.Append(attr);

            attr = document.CreateAttribute("usesharedvertices");
            attr.Value = (subMesh.useSharedVertices) ? "true" : "false";
            node.Attributes.Append(attr);

            VertexData vertexData =
                (subMesh.useSharedVertices) ? mesh.SharedVertexData : subMesh.vertexData;
            IndexType indexType = IndexType.Size16;
            if (vertexData.vertexCount > short.MaxValue)
                indexType = IndexType.Size32;

            attr = document.CreateAttribute("use32bitindexes");
            attr.Value = (indexType == IndexType.Size32) ? "true" : "false";
            node.Attributes.Append(attr);

            bool isTriList = true;

            // TODO: Support things other than triangle lists
            attr = document.CreateAttribute("operationtype");
            RenderOperation op = new RenderOperation();
            subMesh.GetRenderOperation(op);
            switch (op.operationType) {
                case OperationType.TriangleList:
                    attr.Value = "triangle_list";
                    break;
                case OperationType.TriangleStrip:
                    attr.Value = "triangle_strip";
                    isTriList = false;
                    break;
                case OperationType.TriangleFan:
                    attr.Value = "triangle_fan";
                    isTriList = false;
                    break;
                default:
                    throw new AxiomException("Export of non triangle lists is not supported");
            }
            node.Attributes.Append(attr);

            XmlElement childNode;

            childNode = WriteFaces(subMesh, indexType, isTriList);
            node.AppendChild(childNode);

            if (!subMesh.useSharedVertices) {
                childNode = WriteGeometry(subMesh);
                node.AppendChild(childNode);
            }

            if (subMesh.BoneAssignmentList.Count > 0) {
                childNode = WriteBoneAssignments(subMesh);
                node.AppendChild(childNode);
            }

            return node;
        }
예제 #29
0
		private void _generatePlaneVertexData( HardwareVertexBuffer vbuf, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 transform, bool firstTime, bool normals, Matrix4 rotation, int numTexCoordSets, float xTexCoord, float yTexCoord, SubMesh subMesh, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength )
		{
			Vector3 vec;
			unsafe
			{
				// lock the vertex buffer
				IntPtr data = vbuf.Lock( BufferLocking.Discard );

				float* pData = (float*)data.ToPointer();

				for ( int y = 0; y <= ySegments; y++ )
				{
					for ( int x = 0; x <= xSegments; x++ )
					{
						// centered on origin
						vec.x = ( x * xSpace ) - halfWidth;
						vec.y = ( y * ySpace ) - halfHeight;
						vec.z = 0.0f;

						vec = transform.TransformAffine( vec );

						*pData++ = vec.x;
						*pData++ = vec.y;
						*pData++ = vec.z;

						// Build bounds as we go
						if ( firstTime )
						{
							min = vec;
							max = vec;
							maxSquaredLength = vec.LengthSquared;
							firstTime = false;
						}
						else
						{
							min.Floor( vec );
							max.Ceil( vec );
							maxSquaredLength = Utility.Max( maxSquaredLength, vec.LengthSquared );
						}

						if ( normals )
						{
							vec = Vector3.UnitZ;
							vec = rotation.TransformAffine( vec );

							*pData++ = vec.x;
							*pData++ = vec.y;
							*pData++ = vec.z;
						}

						for ( int i = 0; i < numTexCoordSets; i++ )
						{
							*pData++ = x * xTexCoord;
							*pData++ = 1 - ( y * yTexCoord );
						} // for texCoords
					} // for x
				} // for y

				// unlock the buffer
				vbuf.Unlock();

				subMesh.useSharedVertices = true;

			} // unsafe
		}
        protected XmlElement WriteSubmeshName(SubMesh subMesh, int index)
        {
            XmlElement node = document.CreateElement("submeshname");
            XmlAttribute attr;

            attr = document.CreateAttribute("index");
            attr.Value = index.ToString();
            node.Attributes.Append(attr);

            attr = document.CreateAttribute("name");
            attr.Value = subMesh.Name;
            node.Attributes.Append(attr);

            return node;
        }
예제 #31
0
		protected virtual void ReadSubMeshOperation( BinaryReader reader, SubMesh sub )
		{
			sub.operationType = (OperationType)ReadShort( reader );
		}
예제 #32
0
		protected List<SubMeshLodGeometryLink> DetermineGeometry( SubMesh sm )
		{
			// First, determine if we've already seen this submesh before
			List<SubMeshLodGeometryLink> lodList;
			if ( this.subMeshGeometryLookup.TryGetValue( sm, out lodList ) )
			{
				return lodList;
			}
			// Otherwise, we have to create a new one
			lodList = new List<SubMeshLodGeometryLink>();
			this.subMeshGeometryLookup[ sm ] = lodList;
			var numLods = sm.Parent.IsLodManual ? 1 : sm.Parent.LodLevelCount;
			for ( var lod = 0; lod < numLods; ++lod )
			{
				var geomLink = new SubMeshLodGeometryLink();
				lodList.Add( geomLink );
				var lodIndexData = lod == 0 ? sm.indexData : sm.LodFaceList[ lod - 1 ];
				// Can use the original mesh geometry?
				if ( sm.useSharedVertices )
				{
					if ( sm.Parent.SubMeshCount == 1 )
					{
						// Ok, this is actually our own anyway
						geomLink.vertexData = sm.Parent.SharedVertexData;
						geomLink.indexData = lodIndexData;
					}
					else
					{
						// We have to split it
						SplitGeometry( sm.Parent.SharedVertexData, lodIndexData, geomLink );
					}
				}
				else
				{
					if ( lod == 0 )
					{
						// Ok, we can use the existing geometry; should be in full
						// use by just this SubMesh
						geomLink.vertexData = sm.VertexData;
						geomLink.indexData = sm.IndexData;
					}
					else
					{
						// We have to split it
						SplitGeometry( sm.VertexData, lodIndexData, geomLink );
					}
				}
				Debug.Assert( geomLink.vertexData.vertexStart == 0,
				              "Cannot use vertexStart > 0 on indexed geometry due to " +
				              "rendersystem incompatibilities - see the docs!" );
			}
			return lodList;
		}
예제 #33
0
		protected void WriteSubMesh( BinaryWriter writer, SubMesh subMesh )
		{
			// cache header location
			var start_offset = writer.Seek( 0, SeekOrigin.Current );

			// Header 
			WriteChunk( writer, MeshChunkID.SubMesh, 0 );

			// Name
			WriteString( writer, subMesh.MaterialName );

			// useSharedVertices
			WriteBool( writer, subMesh.useSharedVertices );

			// indexCount
			WriteUInt( writer, (uint)subMesh.indexData.indexCount );

			// indexes32bit
			var indexes32bit = ( subMesh.indexData.indexBuffer.Type == IndexType.Size32 );
			WriteBool( writer, indexes32bit );

			var buf = subMesh.indexData.indexBuffer.Lock( BufferLocking.Discard );
			try
			{
				if ( indexes32bit )
				{
					WriteInts( writer, subMesh.indexData.indexCount, buf );
				}
				else
				{
					WriteShorts( writer, subMesh.indexData.indexCount, buf );
				}
			}
			finally
			{
				subMesh.indexData.indexBuffer.Unlock();
			}
			if ( !subMesh.useSharedVertices )
			{
				WriteGeometry( writer, subMesh.vertexData );
			}
			WriteSubMeshOperation( writer, subMesh );

			var weights = subMesh.BoneAssignmentList;
			foreach ( var v in weights.Keys )
			{
				var vbaList = weights[ v ];
				foreach ( var vba in vbaList )
				{
					WriteSubMeshBoneAssignment( writer, vba );
				}
			}

			// Write the texture alias (not currently supported)

			var end_offset = writer.Seek( 0, SeekOrigin.Current );
			writer.Seek( (int)start_offset, SeekOrigin.Begin );
			WriteChunk( writer, MeshChunkID.SubMesh, (int)( end_offset - start_offset ) );
			writer.Seek( (int)end_offset, SeekOrigin.Begin );
		}
        /// <summary>
        ///    Iterate over the the vertices, building up a bounding
        ///    box for the submesh.
        /// </summary>
        protected void CreateSubMeshBoundingBox(SubMesh subMesh)
        {
            AxisAlignedBox box = new AxisAlignedBox();
            IndexData indexData = subMesh.indexData;
            int count = indexData.indexCount;
            IndexType type = indexData.indexBuffer.Type;
            VertexData vertexData = null;
            if (mesh.SharedVertexData != null)
                vertexData = mesh.SharedVertexData;
            else
                vertexData = subMesh.vertexData;
            VertexElement posElem = vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position);
            int offset = posElem.Offset;
            Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
            Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
            HardwareVertexBuffer posBuffer = vertexData.vertexBufferBinding.GetBuffer(posElem.Source);
            int vertexSize = posBuffer.VertexSize;
            try {
                IntPtr indexPtr = indexData.indexBuffer.Lock(BufferLocking.ReadOnly);
                try {
                    IntPtr posPtr = posBuffer.Lock(BufferLocking.ReadOnly);
                    unsafe {
                        byte* pBaseVertex = (byte*)posPtr.ToPointer();
                        short* p16Idx = null;
                        int* p32Idx = null;
                        if (type == IndexType.Size16)
                            p16Idx = (short*)indexPtr.ToPointer();
                        else
                            p32Idx = (int*)indexPtr.ToPointer();
                        for (int i=0; i<count; i++) {
                            int index = (type == IndexType.Size16 ? p16Idx[i] : p32Idx[i]);
                            byte* pVertex = pBaseVertex + (index * vertexSize);
                            float* pReal = (float*)(pVertex + offset);
                            float x = *pReal++;
                            if (x < min.x)
                                min.x = x;
                            if (x > max.x)
                                max.x = x;

                            float y = *pReal++;
                            if (y < min.y)
                                min.y = y;
                            if (y > max.y)
                                max.y = y;

                            float z = *pReal++;
                            if (z < min.z)
                                min.z = z;
                            if (z > max.z)
                                max.z = z;
                        }
                    }
                } finally {
                    posBuffer.Unlock();
                }
            } finally {
                indexData.indexBuffer.Unlock();
            }
            subMesh.BoundingBox = new AxisAlignedBox(min, max);
        }
예제 #35
0
		protected void WriteMeshLodGenerated( BinaryWriter writer, SubMesh subMesh, int usageIndex )
		{
			var start_offset = writer.Seek( 0, SeekOrigin.Current );
			WriteChunk( writer, MeshChunkID.MeshLODGenerated, 0 );

			var indexData = subMesh.lodFaceList[ usageIndex - 1 ];
			var indexes32bit = ( indexData.indexBuffer.Type == IndexType.Size32 );

			WriteInt( writer, indexData.indexCount );
			WriteBool( writer, indexes32bit );

			// lock the buffer
			var data = indexData.indexBuffer.Lock( BufferLocking.ReadOnly );

			if ( indexes32bit )
			{
				WriteInts( writer, indexData.indexCount, data );
			}
			else
			{
				WriteShorts( writer, indexData.indexCount, data );
			}

			indexData.indexBuffer.Unlock();

			var end_offset = writer.Seek( 0, SeekOrigin.Current );
			writer.Seek( (int)start_offset, SeekOrigin.Begin );
			WriteChunk( writer, MeshChunkID.MeshLODGenerated, (int)( end_offset - start_offset ) );
			writer.Seek( (int)end_offset, SeekOrigin.Begin );
		}
        private static MeshTriangle[] ExtractSubmeshTriangles( SubMesh subMesh )
        {
            int[] vertIdx = new int[ 3 ];
            Vector3[] vertPos = new Vector3[ 3 ];
            VertexElement posElem = subMesh.vertexData.vertexDeclaration.FindElementBySemantic( VertexElementSemantic.Position );
            HardwareVertexBuffer posBuffer = posBuffer = subMesh.vertexData.vertexBufferBinding.GetBuffer( posElem.Source );
            IntPtr indexPtr = subMesh.indexData.indexBuffer.Lock( BufferLocking.ReadOnly );
            IntPtr posPtr = posBuffer.Lock( BufferLocking.ReadOnly );
            int posOffset = posElem.Offset / sizeof( float );
            int posStride = posBuffer.VertexSize / sizeof( float );
            int numFaces = subMesh.indexData.indexCount / 3;
            MeshTriangle[] triangles = new MeshTriangle[ numFaces ];
            unsafe
            {
                int* pIdxInt32 = null;
                short* pIdxShort = null;
                float* pVPos = (float*) posPtr.ToPointer();
                if( subMesh.indexData.indexBuffer.Type == IndexType.Size32 )
                    pIdxInt32 = (int*) indexPtr.ToPointer();
                else
                    pIdxShort = (short*) indexPtr.ToPointer();

                // loop through all faces to calculate the tangents
                for( int n = 0; n < numFaces; n++ )
                {
                    for( int i = 0; i < 3; i++ )
                    {
                        // get indices of vertices that form a polygon in the position buffer
                        if( subMesh.indexData.indexBuffer.Type == IndexType.Size32 )
                            vertIdx[ i ] = pIdxInt32[ 3 * n + i ];
                        else
                            vertIdx[ i ] = pIdxShort[ 3 * n + i ];
                        vertPos[ i ].x = pVPos[ vertIdx[ i ] * posStride + posOffset ];
                        vertPos[ i ].y = pVPos[ vertIdx[ i ] * posStride + posOffset + 1 ];
                        vertPos[ i ].z = pVPos[ vertIdx[ i ] * posStride + posOffset + 2 ];
                    }
                    triangles[ n ] = new MeshTriangle( vertPos[ 0 ], vertPos[ 1 ], vertPos[ 2 ] );
                }
            }
            posBuffer.Unlock();
            subMesh.indexData.indexBuffer.Unlock();
            if( DoLog )
            {
                int count = triangles.Length;
                Log( string.Format( " extracted {0} triangles", count ) );
                for( int i = 0; i < count; i++ )
                    Log( string.Format( "  {0}", triangles[ i ].ToString() ) );
            }
            return triangles;
        }