public HeightMapInfoContent(ModelContent model, MeshContent terrainMesh, float terrainScale, int terrainWidth, int terrainLength) { Model = model; if (terrainMesh == null) { throw new ArgumentNullException("terrainMesh"); } if (terrainWidth <= 0) { throw new ArgumentOutOfRangeException("terrainWidth"); } if (terrainLength <= 0) { throw new ArgumentOutOfRangeException("terrainLength"); } TerrainScale = terrainScale; Height = new float[terrainWidth, terrainLength]; Normals = new Vector3[terrainWidth, terrainLength]; GeometryContent item = terrainMesh.Geometry[0]; for (int i = 0; i < item.Vertices.VertexCount; i++) { Vector3 vector3 = item.Vertices.Positions[i]; Vector3 item1 = (Vector3)item.Vertices.Channels[VertexChannelNames.Normal()][i]; int x = (int)(vector3.X / terrainScale + (terrainWidth - 1) / 2f); int z = (int)(vector3.Z / terrainScale + (terrainLength - 1) / 2f); Height[x, z] = vector3.Y; Normals[x, z] = item1; } }
public static bool NeedsSplitting(MeshContent mesh, int maxBones) { SortedDictionary <string, object> skinnedBones = new SortedDictionary <string, object>(); foreach (GeometryContent geom in mesh.Geometry) { VertexChannel <BoneWeightCollection> weightChannel = null; foreach (VertexChannel channel in geom.Vertices.Channels) { if (channel.Name == VertexChannelNames.Weights()) { weightChannel = (VertexChannel <BoneWeightCollection>)channel; break; } } if (weightChannel != null) { foreach (BoneWeightCollection weights in weightChannel) { foreach (BoneWeight weight in weights) { if (!skinnedBones.ContainsKey(weight.BoneName)) { skinnedBones.Add(weight.BoneName, null); } } } } } return(skinnedBones.Keys.Count > maxBones); }
/// <summary> /// Make sure all of the geometry contains a vertex color channel. /// </summary> /// <param name="mesh"></param> private static void EnsureVertexColors(MeshContent mesh) { foreach (GeometryContent meshPart in mesh.Geometry) { //if ((meshPart.Name != null) && !meshPart.Name.StartsWith("SCP_")) { bool foundColor = false; foreach (VertexChannel channel in meshPart.Vertices.Channels) { if (channel.Name == VertexChannelNames.Color(0)) { foundColor = true; break; } } if (!foundColor) { int cnt = meshPart.Vertices.VertexCount; Vector4[] colors = new Vector4[cnt]; for (int i = 0; i < cnt; ++i) { colors[i] = Vector4.One; } meshPart.Vertices.Channels.Add <Vector4>( VertexChannelNames.Color(0).ToString(), colors); } } } }
private static void ColorMaterials(MeshContent mesh) { foreach (GeometryContent meshPart in mesh.Geometry) { Vector4 constColor = MatColor(meshPart); bool foundColor = false; foreach (VertexChannel channel in meshPart.Vertices.Channels) { if (channel.Name == VertexChannelNames.Color(0)) { foundColor = true; VertexChannel <Vector4> colorChannel = (VertexChannel <Vector4>)channel; for (int i = 0; i < colorChannel.Count; ++i) { colorChannel[i] = constColor; } } } if (!foundColor) { int cnt = meshPart.Vertices.VertexCount; Vector4[] colors = new Vector4[cnt]; for (int i = 0; i < cnt; ++i) { colors[i] = constColor; } meshPart.Vertices.Channels.Add <Vector4>( VertexChannelNames.Color(0).ToString(), colors); } } }
private static bool MeshHasSkinning(MeshContent mesh) { bool flag; bool flag1; IEnumerator <GeometryContent> enumerator = mesh.Geometry.GetEnumerator(); try { do { flag1 = enumerator.MoveNext(); if (flag1) { GeometryContent current = enumerator.Current; flag1 = current.Vertices.Channels.Contains(VertexChannelNames.Weights()); } else { flag = true; return(flag); } }while (flag1); flag = false; return(flag); } finally { flag1 = enumerator == null; if (!flag1) { enumerator.Dispose(); } } flag = true; return(flag); }
static void ProcessWeightsChannel(GeometryContent geometry, int vertexChannelIndex, SerializableSkeleton skeleton) { Dictionary <string, int> boneIndices = skeleton.boneIndexByName; // convert all of our bone weights into the correct indices and weight values VertexChannel <BoneWeightCollection> inputWeights = geometry.Vertices.Channels[vertexChannelIndex] as VertexChannel <BoneWeightCollection>; Vector4[] outputIndices = new Vector4[inputWeights.Count]; Vector4[] outputWeights = new Vector4[inputWeights.Count]; for (int i = 0; i < inputWeights.Count; i++) { ConvertWeights(inputWeights[i], boneIndices, outputIndices, outputWeights, i, geometry); } // create our new channel names int usageIndex = VertexChannelNames.DecodeUsageIndex(inputWeights.Name); string indicesName = VertexChannelNames.EncodeName(Microsoft.Xna.Framework.Graphics.VertexElementUsage.BlendIndices, usageIndex); string weightsName = VertexChannelNames.EncodeName(Microsoft.Xna.Framework.Graphics.VertexElementUsage.BlendWeight, usageIndex); // add in the index and weight channels geometry.Vertices.Channels.Insert(vertexChannelIndex + 1, indicesName, outputIndices); geometry.Vertices.Channels.Insert(vertexChannelIndex + 2, weightsName, outputWeights); // remove the original weights channel geometry.Vertices.Channels.RemoveAt(vertexChannelIndex); }
public void BasicMeshBuilderTest() { var output = CreateBasicMesh(material1); Assert.NotNull(output); Assert.NotNull(output.Geometry); Assert.NotNull(output.Positions); Assert.AreEqual(new Vector3(0, 0, 0), output.Positions[0]); Assert.AreEqual(new Vector3(1, 0, 0), output.Positions[1]); Assert.AreEqual(new Vector3(1, 1, 1), output.Positions[2]); Assert.AreEqual(1, output.Geometry.Count); Assert.AreEqual(0, output.Geometry[0].Indices[0]); Assert.AreEqual(1, output.Geometry[0].Indices[1]); Assert.AreEqual(2, output.Geometry[0].Indices[2]); Assert.AreEqual(0, output.Geometry[0].Vertices.PositionIndices[0]); Assert.AreEqual(1, output.Geometry[0].Vertices.PositionIndices[1]); Assert.AreEqual(2, output.Geometry[0].Vertices.PositionIndices[2]); Assert.AreEqual(new Vector3(0, 0, 0), output.Geometry[0].Vertices.Positions[0]); Assert.AreEqual(new Vector3(1, 0, 0), output.Geometry[0].Vertices.Positions[1]); Assert.AreEqual(new Vector3(1, 1, 1), output.Geometry[0].Vertices.Positions[2]); //Check if normals are generated Assert.NotNull(output.Geometry[0].Vertices.Channels[VertexChannelNames.Normal(0)]); Assert.AreEqual(material1, output.Geometry[0].Material); Assert.AreEqual(Matrix.Identity, output.Transform); Assert.AreEqual(3, output.Positions.Count); Assert.AreEqual("Mesh1", output.Name); }
private int[] ComputeBoneSet(GeometryContent geometry, ContentProcessorContext context, string asset, Dictionary <string, int> boneIndices) { SortedDictionary <int, bool> indicesInUse = new SortedDictionary <int, bool>(); foreach (VertexChannel vc in geometry.Vertices.Channels) { string str = VertexChannelNames.DecodeBaseName(vc.Name); if (str == "Weights") { VertexChannel <BoneWeightCollection> channel = vc as VertexChannel <BoneWeightCollection>; if (vc == null) { continue; } for (int n = 0; n < channel.Count; n++) { VertexWeightsInUse(context, asset, channel[n], boneIndices, indicesInUse); } } } int[] values = new int[indicesInUse.Count]; int i = 0; foreach (int index in indicesInUse.Keys) { values[i++] = index; } return(values); }
/// <summary> /// Creates the vertex channel using the MeshBuilder (no data is added yet). /// </summary> protected virtual void Create() { var usage = _colladaVertexChannel.Description.VertexElementUsage; int usageIndex = _colladaVertexChannel.Description.UsageIndex; // Construct correct usage string String usageString = VertexChannelNames.EncodeName(usage, usageIndex); // Generic standard channel (TexCoord, Normal, Binormal, etc.) switch (_colladaVertexChannel.Description.VertexElementFormat) { case VertexElementFormat.Vector4: _channelIndex = _meshBuilder.CreateVertexChannel <Vector4>(usageString); break; case VertexElementFormat.Vector3: _channelIndex = _meshBuilder.CreateVertexChannel <Vector3>(usageString); break; case VertexElementFormat.Vector2: _channelIndex = _meshBuilder.CreateVertexChannel <Vector2>(usageString); break; case VertexElementFormat.Single: _channelIndex = _meshBuilder.CreateVertexChannel <Single>(usageString); break; default: throw new Exception("Unexpected vertex element format"); } }
static void ProcessWeightsChannel(GeometryContent geometry, int vertexChannelIndex) { // create a map of Name->Index of the bones BoneContent skeleton = MeshHelper.FindSkeleton(geometry.Parent); Dictionary <string, int> boneIndices = new Dictionary <string, int>(); IList <BoneContent> flattenedBones = MeshHelper.FlattenSkeleton(skeleton); for (int i = 0; i < flattenedBones.Count; i++) { boneIndices.Add(flattenedBones[i].Name, i); } // convert all of our bone weights into the correct indices and weight values VertexChannel <BoneWeightCollection> inputWeights = geometry.Vertices.Channels[vertexChannelIndex] as VertexChannel <BoneWeightCollection>; Vector4[] outputIndices = new Vector4[inputWeights.Count]; Vector4[] outputWeights = new Vector4[inputWeights.Count]; for (int i = 0; i < inputWeights.Count; i++) { ConvertWeights(inputWeights[i], boneIndices, outputIndices, outputWeights, i, geometry); } // create our new channel names int usageIndex = VertexChannelNames.DecodeUsageIndex(inputWeights.Name); string indicesName = VertexChannelNames.EncodeName(VertexElementUsage.BlendIndices, usageIndex); string weightsName = VertexChannelNames.EncodeName(VertexElementUsage.BlendWeight, usageIndex); // add in the index and weight channels geometry.Vertices.Channels.Insert(vertexChannelIndex + 1, indicesName, outputIndices); geometry.Vertices.Channels.Insert(vertexChannelIndex + 2, weightsName, outputWeights); // remove the original weights channel geometry.Vertices.Channels.RemoveAt(vertexChannelIndex); }
/// <summary> /// As an optimization, ProcessVertexChannel is overriden to remove data which /// is not used by the vertex shader. /// </summary> /// <param name="geometry">the geometry object which contains the /// vertex channel</param> /// <param name="vertexChannelIndex">the index of the vertex channel /// to operate on</param> /// <param name="context">the context that the processor is operating /// under. in most cases, this parameter isn't necessary; but could /// be used to log a warning that a channel had been removed.</param> protected override void ProcessVertexChannel(GeometryContent geometry, int vertexChannelIndex, ContentProcessorContext context) { String vertexChannelName = geometry.Vertices.Channels[vertexChannelIndex].Name; // if this vertex channel has an acceptable names, process it as normal. if (acceptableVertexChannelNames.Contains(vertexChannelName)) { base.ProcessVertexChannel(geometry, vertexChannelIndex, context); } // otherwise, remove it from the vertex channels; it's just extra data // we don't need. else { geometry.Vertices.Channels.Remove(vertexChannelName); } // Remove texture channel for untextured meshes if (!geometry.Vertices.Channels.Contains(VertexChannelNames.TextureCoordinate(0))) { geometry.Vertices.Channels.Remove(VertexChannelNames.TextureCoordinate(0)); } // Remove vertex weights for unskinned meshes if (!geometry.Vertices.Channels.Contains(VertexChannelNames.Weights())) { geometry.Vertices.Channels.Remove(VertexChannelNames.Weights()); } }
private static void ProcessWeightsChannel( GeometryContent geometry, int vertexChannelIndex, ContentIdentity identity) { // NOTE: Portions of this code is from the XNA CPU Skinning // sample under Ms-PL, (c) Microsoft Corporation. // create a map of Name->Index of the bones var skeleton = MeshHelper.FindSkeleton(geometry.Parent); if (skeleton == null) { throw new InvalidContentException( "Skeleton not found. Meshes that contain a Weights vertex channel cannot " + "be processed without access to the skeleton data.", identity); } var boneIndices = new Dictionary <string, byte>(); var flattenedBones = MeshHelper.FlattenSkeleton(skeleton); if (flattenedBones.Count > byte.MaxValue) { throw new NotSupportedException("The flattened skeleton contains more than 255 bones."); } for (int i = 0; i < flattenedBones.Count; i++) { boneIndices.Add(flattenedBones[i].Name, (byte)i); } var vertexChannel = geometry.Vertices.Channels[vertexChannelIndex]; if (!(vertexChannel is VertexChannel <BoneWeightCollection> inputWeights)) { throw new InvalidContentException( string.Format( "Vertex channel \"{0}\" is the wrong type. It has element type {1}. Type {2} is expected.", vertexChannel.Name, vertexChannel.ElementType.FullName, typeof(BoneWeightCollection).FullName), identity); } var outputIndices = new Byte4[inputWeights.Count]; var outputWeights = new Vector4[inputWeights.Count]; for (var i = 0; i < inputWeights.Count; i++) { ConvertWeights(inputWeights[i], boneIndices, outputIndices, outputWeights, i); } // create our new channel names var usageIndex = VertexChannelNames.DecodeUsageIndex(inputWeights.Name); var indicesName = VertexChannelNames.EncodeName(VertexElementUsage.BlendIndices, usageIndex); var weightsName = VertexChannelNames.EncodeName(VertexElementUsage.BlendWeight, usageIndex); // add in the index and weight channels geometry.Vertices.Channels.Insert(vertexChannelIndex + 1, indicesName, outputIndices); geometry.Vertices.Channels.Insert(vertexChannelIndex + 2, weightsName, outputWeights); // remove the original weights channel geometry.Vertices.Channels.RemoveAt(vertexChannelIndex); }
public void SetChannelData() { var mb = MeshBuilder.StartMesh("Test"); mb.SetMaterial(material1); var channelIndex = mb.CreateVertexChannel <Vector2>(VertexChannelNames.TextureCoordinate(0)); var p1 = mb.CreatePosition(0f, 0f, 0f); var p2 = mb.CreatePosition(1f, 0f, 0f); var p3 = mb.CreatePosition(0f, 1f, 0f); var t1 = Vector2.Zero; var t2 = Vector2.UnitX; var t3 = Vector2.UnitY; // this should be overwritten by the next call mb.SetVertexChannelData(channelIndex, t3); mb.SetVertexChannelData(channelIndex, t1); // setting the material here should not reset the channel data mb.SetMaterial(material2); mb.AddTriangleVertex(p1); mb.SetVertexChannelData(channelIndex, t2); mb.AddTriangleVertex(p2); mb.SetVertexChannelData(channelIndex, t3); mb.AddTriangleVertex(p3); var mesh = mb.FinishMesh(); var geom = mesh.Geometry[0]; var texChannel = geom.Vertices.Channels[channelIndex]; Assert.AreEqual(t1, texChannel[0]); Assert.AreEqual(t2, texChannel[1]); Assert.AreEqual(t3, texChannel[2]); }
public static string GetXNAName(VertexAttribute attr) { switch (attr.usage) { case COLOR: return(VertexChannelNames.Color(0)); case NORMAL: return(VertexChannelNames.Normal()); case TEX_COORD: return(VertexChannelNames.TextureCoordinate(attr.attrIndex)); case BONE_WEIGHT: return(VertexChannelNames.Weights(attr.attrIndex)); case TANGENT: return(VertexChannelNames.Tangent(0)); case BINORMAL: return(VertexChannelNames.Binormal(0)); } return(null); }
private bool ValidateGeometry(GeometryContent geometry, ContentProcessorContext context) { // Check if the geometry has material if (geometry.Material == null) { throw new InvalidContentException(string.Format( "Mesh {0} has a geometry that does not have a material.", geometry.Parent.Name)); } // Check if the geometry has skinning information if (!geometry.Vertices.Channels.Contains(VertexChannelNames.Weights())) { /* * context.Logger.LogWarning(null, geometry.Parent.Identity, * string.Format("Mesh {0} has a geometry that does not have a skinning " + * "blend weights channel and will be skipped.", geometry.Parent.Name)); * * geometry.Parent.Geometry.Remove(geometry); */ throw new InvalidContentException(string.Format("Mesh {0} has a geometry " + "that does not have a skinning blend weights channel.", geometry.Parent.Name)); } return(true); }
private static void ProcessWeightsChannel(ContentProcessorContext context, string asset, GeometryContent geometry, int vertexChannelIndex, Dictionary <string, int> boneIndices, Dictionary <int, int> boneRemap) { if (boneIndices == null) { throw new InvalidContentException("Mesh has bone weights with no skeleton"); } VertexChannelCollection channels = geometry.Vertices.Channels; VertexChannel channel2 = channels[vertexChannelIndex]; VertexChannel <BoneWeightCollection> channel = channel2 as VertexChannel <BoneWeightCollection>; Byte4[] outputIndices = new Byte4[channel.Count]; Vector4[] outputWeights = new Vector4[channel.Count]; for (int i = 0; i < channel.Count; i++) { BoneWeightCollection inputWeights = channel[i]; ConvertVertexWeights(context, asset, inputWeights, boneIndices, outputIndices, outputWeights, i, geometry, boneRemap); } int usageIndex = VertexChannelNames.DecodeUsageIndex(channel.Name); string name = VertexChannelNames.EncodeName(VertexElementUsage.BlendIndices, usageIndex); string str = VertexChannelNames.EncodeName(VertexElementUsage.BlendWeight, usageIndex); channels.Insert <Byte4>(vertexChannelIndex + 1, name, outputIndices); channels.Insert <Vector4>(vertexChannelIndex + 2, str, outputWeights); channels.RemoveAt(vertexChannelIndex); }
/// <summary> /// This function removes geometry that contains no bone weights, because the ModelProcessor /// will throw an exception if we give it geometry content like that. /// </summary> /// <param name="node"></param> /// <param name="context"></param> static void RemoveInvalidGeometry(NodeContent node, ContentProcessorContext context) { MeshContent meshContent = node as MeshContent; if (meshContent != null) { // Maintain a list of all the geometry that was invalid that we will be removing List <GeometryContent> removeGeometry = new List <GeometryContent>(); foreach (GeometryContent geometry in meshContent.Geometry) { VertexChannelCollection channels = geometry.Vertices.Channels; // Does this geometry contain bone weight information? if (geometry.Vertices.Channels.Contains(VertexChannelNames.Weights(0))) { bool removed = false; VertexChannel <BoneWeightCollection> weights = geometry.Vertices.Channels.Get <BoneWeightCollection>(VertexChannelNames.Weights(0)); foreach (BoneWeightCollection collection in weights) { // If we don't have any weights, then this isn't going to be good. The geometry has no bone weights, // so lets just remove it. if (collection.Count <= 0) { removeGeometry.Add(geometry); removed = true; break; } else { // Otherwise, normalize the weights. This call is probably unnecessary. collection.NormalizeWeights(4); } } //If we removed something from this geometry, just remove the whole geometry - there's no point in going farther if (removed) { break; } } } // Remove all the invalid geometry we found, and log a warning. foreach (GeometryContent geometry in removeGeometry) { meshContent.Geometry.Remove(geometry); context.Logger.LogWarning(null, null, "Mesh part {0} has been removed because it has no bone weights associated with it.", geometry.Name); } } // Recursively call this function for each child foreach (NodeContent child in node.Children) { RemoveInvalidGeometry(child, context); } }
/// <summary> /// Converts a single piece of input geometry into our instanced format. /// </summary> void ProcessGeometry(GeometryContent geometry) { int indexCount = geometry.Indices.Count; int vertexCount = geometry.Vertices.VertexCount; // Validate that the number of vertices is suitable for instancing. if (vertexCount > ushort.MaxValue) { throw new InvalidContentException( string.Format("Geometry contains {0} vertices: " + "this is too many to be instanced.", vertexCount)); } if (vertexCount > ushort.MaxValue / 8) { context.Logger.LogWarning(null, rootNode.Identity, "Geometry contains {0} vertices: " + "this will only allow it to be instanced " + "{1} times per batch. A model with fewer " + "vertices would be more efficient.", vertexCount, ushort.MaxValue / vertexCount); } // Validate that the vertex channels we are going to use to pass // through our instancing data aren't already in use. VertexChannelCollection vertexChannels = geometry.Vertices.Channels; for (int i = 1; i <= 4; i++) { if (vertexChannels.Contains(VertexChannelNames.TextureCoordinate(i))) { throw new InvalidContentException( string.Format("Model already contains data for texture " + "coordinate channel {0}, but instancing " + "requires this channel for its own use.", i)); } } // Flatten the flexible input vertex channel data into // a simple GPU style vertex buffer byte array. VertexBufferContent vertexBufferContent; VertexElement[] vertexElements; geometry.Vertices.CreateVertexBuffer(out vertexBufferContent, out vertexElements, context.TargetPlatform); int vertexStride = VertexDeclaration.GetVertexStrideSize(vertexElements, 0); // Convert the input material. MaterialContent material = ProcessMaterial(geometry.Material); // Add the new piece of geometry to our output model. outputModel.AddModelPart(indexCount, vertexCount, vertexStride, vertexElements, vertexBufferContent, geometry.Indices, material); }
public void SetMaterialDoesNotClearChannels() { var mb = MeshBuilder.StartMesh("Test"); var mat = new BasicMaterialContent(); mb.CreateVertexChannel <Vector2>(VertexChannelNames.TextureCoordinate(0)); mb.SetMaterial(mat); Assert.DoesNotThrow(() => mb.SetVertexChannelData(0, Vector2.Zero)); }
private void ProcessGeometry(GeometryContent xnaGeometry) { // find and process the geometry's bone weights for (int i = 0; i < xnaGeometry.Vertices.Channels.Count; i++) { string channelName = xnaGeometry.Vertices.Channels[i].Name; string baseName = VertexChannelNames.DecodeBaseName(channelName); if (baseName == "Weights") { ProcessWeightsChannel(xnaGeometry, i, outputModel.skeleton); } } // retrieve the four vertex channels we require for CPU skinning. we ignore any // other channels the model might have. string normalName = VertexChannelNames.EncodeName(Microsoft.Xna.Framework.Graphics.VertexElementUsage.Normal, 0); string texCoordName = VertexChannelNames.EncodeName(Microsoft.Xna.Framework.Graphics.VertexElementUsage.TextureCoordinate, 0); string blendWeightName = VertexChannelNames.EncodeName(Microsoft.Xna.Framework.Graphics.VertexElementUsage.BlendWeight, 0); string blendIndexName = VertexChannelNames.EncodeName(Microsoft.Xna.Framework.Graphics.VertexElementUsage.BlendIndices, 0); VertexChannel <Vector3> normals = xnaGeometry.Vertices.Channels[normalName] as VertexChannel <Vector3>; VertexChannel <Vector2> texCoords = xnaGeometry.Vertices.Channels[texCoordName] as VertexChannel <Vector2>; VertexChannel <Vector4> blendWeights = xnaGeometry.Vertices.Channels[blendWeightName] as VertexChannel <Vector4>; VertexChannel <Vector4> blendIndices = xnaGeometry.Vertices.Channels[blendIndexName] as VertexChannel <Vector4>; // create our array of vertices int triangleCount = xnaGeometry.Indices.Count / 3; SerializableVertex[] vertices = new SerializableVertex[xnaGeometry.Vertices.VertexCount]; for (int i = 0; i < vertices.Length; i++) { vertices[i] = new SerializableVertex { position = xnaGeometry.Vertices.Positions[i], normal = normals[i], texture = texCoords[i], blendweights = blendWeights[i], blendindices = blendIndices[i] }; } int[] indices = new int[xnaGeometry.Indices.Count]; for (int i = 0; i < xnaGeometry.Indices.Count; i++) { indices[i] = xnaGeometry.Indices[i]; } SerializableMesh mesh = new SerializableMesh(); mesh.name = string.Format("mesh_{0}_{1}", outputModel.meshList.Count, xnaGeometry.Name); mesh.textureName = GetTextureName(xnaGeometry); mesh.vertices = vertices; mesh.indices = indices; outputModel.meshList.Add(mesh); }
private DRModelNodeContent CreateModel(Texture2DContent input, ContentProcessorContext context, HeightField heightField) { // We use the XNA MeshBuilder to create the model. MeshBuilder meshBuilder = MeshBuilder.StartMesh(input.Name); int numberOfSamplesX = heightField.NumberOfSamplesX; int numberOfSamplesZ = heightField.NumberOfSamplesZ; int numberOfCellsInX = numberOfSamplesX - 1; int numberOfCellsInZ = numberOfSamplesZ - 1; // Add vertex positions. for (int z = 0; z < numberOfSamplesZ; z++) { for (int x = 0; x < numberOfSamplesX; x++) { meshBuilder.CreatePosition((float)x / numberOfCellsInX * heightField.WidthX, heightField.Samples[z * numberOfSamplesX + x], (float)z / numberOfCellsInZ * heightField.WidthZ); } } // Set a BasicMaterial for the model. var material = new BasicMaterialContent { SpecularColor = Vector3.Zero, Texture = new ExternalReference <TextureContent>(TextureFilename, input.Identity) }; meshBuilder.SetMaterial(material); // Add texture coordinates. Each height field cell consists of two triangles. int textureChannelId = meshBuilder.CreateVertexChannel <Vector2>(VertexChannelNames.TextureCoordinate(0)); for (int x = 0; x < numberOfCellsInX; x++) { for (int z = 0; z < numberOfCellsInZ; z++) { // First triangle. AddVertex(meshBuilder, textureChannelId, x, z, numberOfSamplesX, numberOfSamplesZ); AddVertex(meshBuilder, textureChannelId, x + 1, z, numberOfSamplesX, numberOfSamplesZ); AddVertex(meshBuilder, textureChannelId, x, z + 1, numberOfSamplesX, numberOfSamplesZ); // Second triangle. AddVertex(meshBuilder, textureChannelId, x, z + 1, numberOfSamplesX, numberOfSamplesZ); AddVertex(meshBuilder, textureChannelId, x + 1, z, numberOfSamplesX, numberOfSamplesZ); AddVertex(meshBuilder, textureChannelId, x + 1, z + 1, numberOfSamplesX, numberOfSamplesZ); } } // Create MeshContent. FinishMesh() automatically computes normal vectors. MeshContent meshContent = meshBuilder.FinishMesh(); // Call the DRModelProcessor to convert the MeshContent to DRModelNodeContent. DRModelNodeContent model = context.Convert <MeshContent, DRModelNodeContent>(meshContent, "DRModelProcessor"); return(model); }
public void CannotCallCreateMethodsAfterAddingVertex() { var builder = MeshBuilder.StartMesh("Mesh1"); builder.CreatePosition(new Vector3(0, 0, 0)); builder.AddTriangleVertex(0); Assert.Throws <InvalidOperationException>( () => builder.CreatePosition(new Vector3(1, 2, 3))); Assert.Throws <InvalidOperationException>( () => builder.CreateVertexChannel <Vector2>(VertexChannelNames.TextureCoordinate(0))); }
// Generates the tangent frames for all meshes. Note: for the normal generation, the // texture channel is needed. Unfortunatly the arena model doesn't seem to be consistent // in the used texture channels. We therefore have to find the correct channel by analysing // all the used channel indices for all geometry batches in each mesh. private void GenerateTangents(NodeContent input, ContentProcessorContext context) { MeshContent mesh = input as MeshContent; int channel = -1; // find the index of the texture channel (sometimes 0, sometimes 1) if (mesh != null) { // loop through all geometry batches foreach (GeometryContent geometryBatch in mesh.Geometry) { // check the index of the texture channel foreach (VertexChannel vertexChannel in geometryBatch.Vertices.Channels) { // is this a texture channel if (vertexChannel.Name.Contains("Texture")) { // extract index (last letter, convert it to int) char c = vertexChannel.Name[vertexChannel.Name.Length - 1]; int curChannel = (int)(c - '0'); if (channel == -1) { // first time we see a texture channel for this mesh: store index channel = curChannel; } else if (channel != curChannel) { // we have already seen a texture channel for this mesh, but with a // different index => signal error channel = -2; } } } } // have we found a valid texture channel? if (channel >= 0) { // compute tangent frames MeshHelper.CalculateTangentFrames(mesh, VertexChannelNames.TextureCoordinate(channel), VertexChannelNames.Tangent(0), VertexChannelNames.Binormal(0)); } } // recurse to all children foreach (NodeContent child in input.Children) { GenerateTangents(child, context); } }
private VertexChannel <BoneWeightCollection> GetWeightChannel(GeometryContent geom) { foreach (VertexChannel channel in geom.Vertices.Channels) { if (channel.Name == VertexChannelNames.Weights()) { return((VertexChannel <BoneWeightCollection>)channel); } } return(null); }
private void GetWeightChannel() { foreach (VertexChannel channel in geom.Vertices.Channels) { if (channel.Name == VertexChannelNames.Weights()) { weightChannel = (VertexChannel <BoneWeightCollection>)channel; break; } } }
/// <summary> /// Checks whether mesh contains skinning information. /// </summary> /// <param name="mesh"></param> /// <returns></returns> static bool MeshHasSkinning(MeshContent mesh) { foreach (GeometryContent geometry in mesh.Geometry) { if (!geometry.Vertices.Channels.Contains(VertexChannelNames.Weights())) { return(false); } } return(true); }
private void AddVertexColorChannel(VertexContent content) { if (content.Channels.Contains(VertexChannelNames.Color(0)) == false) { List <Microsoft.Xna.Framework.Color> VertexColors = new List <Microsoft.Xna.Framework.Color>(); for (int i = 0; i < content.VertexCount; i++) { VertexColors.Add(Color.Purple); } content.Channels.Add(VertexChannelNames.Color(0), VertexColors); } }
/// <summary> /// Adds all the buffered channels to the mesh and merges duplicate positions/verts /// </summary> private void AddAllChannels() { bool recalcNormal = false; if (model.AnimationOptions.Contains("RecalcNormals") || (normals == null && !hasNormals)) { recalcNormal = true; } else { AddChannel <Vector3>(VertexElementUsage.Normal.ToString() + "0", normals); } if (texCoords != null) { AddChannel <Vector2>("TextureCoordinate0", texCoords); } //for (int i = 0; i < weightIndices.Count; i++) //{ // AddChannel<Byte4>(VertexElementUsage.BlendIndices.ToString() + i.ToString(), // weightIndices[i]); //} //for (int i = 0; i < weights.Count; i++) //{ // AddChannel<Vector4>(VertexElementUsage.BlendWeight.ToString() + i.ToString(), // weights[i]); //} bool isSkinned = false; foreach (BoneWeightCollection bwc in skinInfo) { if (bwc.Count > 0) { isSkinned = true; break; } } if (isSkinned) { AddChannel <BoneWeightCollection>(VertexChannelNames.Weights(), skinInfo.ToArray()); } MeshHelper.MergeDuplicatePositions(mesh, 0); MeshHelper.MergeDuplicateVertices(mesh); if (recalcNormal) { MeshHelper.CalculateNormals(mesh, true); } MeshHelper.OptimizeForCache(mesh); }
protected virtual void ProcessVertexChannel( GeometryContent geometry, int vertexChannelIndex, ContentProcessorContext context) { var channel = geometry.Vertices.Channels[vertexChannelIndex]; // TODO: According to docs, channels with VertexElementUsage.Color -> Color // Channels[VertexChannelNames.Weights] -> { Byte4 boneIndices, Color boneWeights } if (channel.Name.StartsWith(VertexChannelNames.Weights(), StringComparison.Ordinal)) { ProcessWeightsChannel(geometry, vertexChannelIndex, _identity); } }
public override ModelContent Process(Texture2DContent input, ContentProcessorContext context) { var builder = MeshBuilder.StartMesh("terrain"); input.ConvertBitmapType(typeof(PixelBitmapContent <float>)); var heightField = (PixelBitmapContent <float>)input.Mipmaps[0]; for (var y = 0; y < heightField.Height; y++) { for (var x = 0; x < heightField.Width; x++) { Vector3 position; position.X = TerrainScale * (x - (heightField.Width - 1) / 2.0f); position.Z = TerrainScale * (y - (heightField.Height - 1) / 2.0f); position.Y = (heightField.GetPixel(x, y) - 1) * TerrainBumpiness; builder.CreatePosition(position); } } var material = new BasicMaterialContent { SpecularColor = new Vector3(.4f, .4f, .4f) }; var directory = Path.GetDirectoryName(input.Identity.SourceFilename); var texture = Path.Combine(directory, TerrainTexture); material.Texture = new ExternalReference <TextureContent>(texture); builder.SetMaterial(material); var texCoordId = builder.CreateVertexChannel <Vector2>(VertexChannelNames.TextureCoordinate(0)); for (var y = 0; y < heightField.Height - 1; y++) { for (var x = 0; x < heightField.Width - 1; x++) { AddVertex(builder, texCoordId, heightField.Width, x, y); AddVertex(builder, texCoordId, heightField.Width, x + 1, y); AddVertex(builder, texCoordId, heightField.Width, x + 1, y + 1); AddVertex(builder, texCoordId, heightField.Width, x, y); AddVertex(builder, texCoordId, heightField.Width, x + 1, y + 1); AddVertex(builder, texCoordId, heightField.Width, x, y + 1); } } var terrainMesh = builder.FinishMesh(); var model = context.Convert <MeshContent, ModelContent>(terrainMesh, "ModelProcessor"); model.Tag = new HeightMapInfoContent(heightField, TerrainScale, TerrainBumpiness); return(model); }