private static void ConvertVertexWeights(ContentProcessorContext context, string asset, BoneWeightCollection inputWeights, Dictionary <string, int> boneIndices, Byte4[] outputIndices, Vector4[] outputWeights, int vertexIndex, GeometryContent geometry, Dictionary <int, int> boneRemap) { inputWeights.NormalizeWeights(4); for (int i = 0; i < inputWeights.Count; i++) { BoneWeight weight = inputWeights[i]; if (!boneIndices.TryGetValue(weight.BoneName, out tempIndices[i])) { string boneName = weight.BoneName.Replace("__Skeleton", ""); if (!boneIndices.TryGetValue(boneName, out tempIndices[i])) { context.Logger.LogWarning(null, new ContentIdentity(asset), "Unknown bone name: " + weight.BoneName); //throw new InvalidContentException("Unknown bone name: " + weight.BoneName); continue; } } tempWeights[i] = weight.Weight; if (boneRemap != null) { tempIndices[i] = boneRemap[tempIndices[i]]; } } for (int j = inputWeights.Count; j < 4; j++) { tempIndices[j] = 0; tempWeights[j] = 0f; } outputIndices[vertexIndex] = new Byte4((float)tempIndices[0], (float)tempIndices[1], (float)tempIndices[2], (float)tempIndices[3]); outputWeights[vertexIndex] = new Vector4(tempWeights[0], tempWeights[1], tempWeights[2], tempWeights[3]); }
static void ConvertWeights(BoneWeightCollection inputWeights, Dictionary <string, int> boneIndices, Vector4[] outIndices, Vector4[] outWeights, int vertexIndex, GeometryContent geometry) { // we only handle 4 weights per bone const int maxWeights = 4; // create some temp arrays to hold our values int[] tempIndices = new int[maxWeights]; float[] tempWeights = new float[maxWeights]; // cull out any extra bones inputWeights.NormalizeWeights(maxWeights); // get our indices and weights for (int i = 0; i < inputWeights.Count; i++) { BoneWeight weight = inputWeights[i]; tempIndices[i] = boneIndices[weight.BoneName]; tempWeights[i] = weight.Weight; } // zero out any remaining spaces for (int i = inputWeights.Count; i < maxWeights; i++) { tempIndices[i] = 0; tempWeights[i] = 0; } // output the values outIndices[vertexIndex] = new Vector4(tempIndices[0], tempIndices[1], tempIndices[2], tempIndices[3]); outWeights[vertexIndex] = new Vector4(tempWeights[0], tempWeights[1], tempWeights[2], tempWeights[3]); }
// Convert BoneWeightCollection to Byte4 (bone indices) and Vector4 (bone weights). private void ConvertBoneWeights(BoneWeightCollection boneWeightCollection, Byte4[] boneIndices, Vector4[] boneWeights, int vertexIndex, GeometryContent geometry) { // Normalize weights. (Number of weights should be MaxBonesPerVertex. Sum should be 1.) boneWeightCollection.NormalizeWeights(MaxBonesPerVertex); // Convert BoneWeights object to bone indices and bone weights. for (int i = 0; i < boneWeightCollection.Count; i++) { BoneWeight boneWeight = boneWeightCollection[i]; int boneIndex = _skeleton.GetIndex(boneWeight.BoneName); if (boneIndex == -1) { string message = String.Format( CultureInfo.InvariantCulture, "Vertex references unknown bone name \"{0}\".", boneWeight.BoneName); throw new InvalidContentException(message, geometry.Parent.Identity); } _tempIndices[i] = boneIndex; _tempWeights[i] = boneWeight.Weight; } // Clear unused indices/weights. for (int i = boneWeightCollection.Count; i < MaxBonesPerVertex; i++) { _tempIndices[i] = 0; _tempWeights[i] = 0f; } boneIndices[vertexIndex] = new Byte4(_tempIndices[0], _tempIndices[1], _tempIndices[2], _tempIndices[3]); boneWeights[vertexIndex] = new Vector4(_tempWeights[0], _tempWeights[1], _tempWeights[2], _tempWeights[3]); }
// From the XNA CPU Skinning Sample under Ms-PL, (c) Microsoft Corporation private static void ConvertWeights( BoneWeightCollection weights, Dictionary <string, byte> boneIndices, Byte4[] outIndices, Vector4[] outWeights, int vertexIndex) { // we only handle 4 weights per bone const int maxWeights = 4; // create some tmp spans to hold our values Span <byte> tmpIndices = stackalloc byte[maxWeights]; Span <float> tmpWeights = stackalloc float[maxWeights]; // cull out any extra bones weights.NormalizeWeights(maxWeights); // get our indices and weights for (var i = 0; i < weights.Count; i++) { var weight = weights[i]; if (!boneIndices.ContainsKey(weight.BoneName)) { throw new Exception(string.Format( "Bone '{0}' was not found in the skeleton! Skeleton bones are: '{1}'.", weight.BoneName, string.Join("', '", boneIndices.Keys))); } tmpIndices[i] = boneIndices[weight.BoneName]; tmpWeights[i] = weight.Weight; } // zero out any remaining spaces for (int i = weights.Count; i < maxWeights; i++) { tmpIndices[i] = 0; tmpWeights[i] = 0; } // output the values outIndices[vertexIndex] = new Byte4(tmpIndices[0], tmpIndices[1], tmpIndices[2], tmpIndices[3]); outWeights[vertexIndex] = new Vector4(tmpWeights[0], tmpWeights[1], tmpWeights[2], tmpWeights[3]); }
/// <summary> /// Go through the vertex channels in the geometry and replace the /// BoneWeightCollection objects with weight and index channels. /// </summary> /// <param name="geometry">The geometry to process.</param> /// <param name="vertexChannelIndex">The index of the vertex channel to process.</param> /// <param name="context">The processor context.</param> protected override void ProcessVertexChannel(GeometryContent geometry, int vertexChannelIndex, ContentProcessorContext context) { bool boneCollectionsWithZeroWeights = false; if (geometry.Vertices.Channels[vertexChannelIndex].Name == VertexChannelNames.Weights()) { int meshIndex = (int)geometry.Parent.OpaqueData["MeshIndex"]; BoneIndexer indexer = indexers[meshIndex]; // Skin channels are passed in from importers as BoneWeightCollection objects VertexChannel <BoneWeightCollection> vc = (VertexChannel <BoneWeightCollection>) geometry.Vertices.Channels[vertexChannelIndex]; int maxBonesPerVertex = 0; for (int i = 0; i < vc.Count; i++) { int count = vc[i].Count; if (count > maxBonesPerVertex) { maxBonesPerVertex = count; } } // Add weights as colors (Converts well to 4 floats) // and indices as packed 4byte vectors. Color[] weightsToAdd = new Color[vc.Count]; Byte4[] indicesToAdd = new Byte4[vc.Count]; // Go through the BoneWeightCollections and create a new // weightsToAdd and indicesToAdd array for each BoneWeightCollection. for (int i = 0; i < vc.Count; i++) { BoneWeightCollection bwc = vc[i]; if (bwc.Count == 0) { boneCollectionsWithZeroWeights = true; continue; } bwc.NormalizeWeights(4); int count = bwc.Count; if (count > maxBonesPerVertex) { maxBonesPerVertex = count; } // Add the appropriate bone indices based on the bone names in the // BoneWeightCollection Vector4 bi = new Vector4(); bi.X = count > 0 ? indexer.GetBoneIndex(bwc[0].BoneName) : (byte)0; bi.Y = count > 1 ? indexer.GetBoneIndex(bwc[1].BoneName) : (byte)0; bi.Z = count > 2 ? indexer.GetBoneIndex(bwc[2].BoneName) : (byte)0; bi.W = count > 3 ? indexer.GetBoneIndex(bwc[3].BoneName) : (byte)0; indicesToAdd[i] = new Byte4(bi); Vector4 bw = new Vector4(); bw.X = count > 0 ? bwc[0].Weight : 0; bw.Y = count > 1 ? bwc[1].Weight : 0; bw.Z = count > 2 ? bwc[2].Weight : 0; bw.W = count > 3 ? bwc[3].Weight : 0; weightsToAdd[i] = new Color(bw); } // Remove the old BoneWeightCollection channel geometry.Vertices.Channels.Remove(vc); // Add the new channels geometry.Vertices.Channels.Add <Byte4>(VertexElementUsage.BlendIndices.ToString(), indicesToAdd); geometry.Vertices.Channels.Add <Color>(VertexElementUsage.BlendWeight.ToString(), weightsToAdd); } else { // No skinning info, so we let the base class process the channel base.ProcessVertexChannel(geometry, vertexChannelIndex, context); } if (boneCollectionsWithZeroWeights) { context.Logger.LogWarning("", geometry.Identity, "BonesWeightCollections with zero weights found in geometry."); } }
//-------------------------------------------------------------- //-------------------------------------------------------------- //-------------------------------------------------------------- //-------------------------------------------------------------- /* /// <summary> /// Gets or sets a value indicating whether alpha premultiply of vertex color is enabled. /// </summary> /// <value> /// <see langword="true"/> if alpha premultiply of vertex colors is enabled; otherwise, <see langword="false"/>. /// </value> [DefaultValue(true)] [DisplayName("Premultiply Vertex Colors")] [Description("If enabled, vertex color channels are converted to premultiplied alpha format.")] public virtual bool PremultiplyVertexColors { get { return _premultiplyVertexColors; } set { _premultiplyVertexColors = value; } } private bool _premultiplyVertexColors = true; */ //-------------------------------------------------------------- #endregion Other #if ANIMATION // Convert BoneWeightCollection to Byte4 (bone indices) and Vector4 (bone weights). private void ConvertBoneWeights(BoneWeightCollection boneWeightCollection, Byte4[] boneIndices, Vector4[] boneWeights, int vertexIndex, GeometryContent geometry) { // Normalize weights. (Number of weights should be MaxBonesPerVertex. Sum should be 1.) boneWeightCollection.NormalizeWeights(MaxBonesPerVertex); // Convert BoneWeights object to bone indices and bone weights. for (int i = 0; i < boneWeightCollection.Count; i++) { BoneWeight boneWeight = boneWeightCollection[i]; int boneIndex = _skeleton.GetIndex(boneWeight.BoneName); if (boneIndex == -1) { string message = String.Format( CultureInfo.InvariantCulture, "Vertex references unknown bone name \"{0}\".", boneWeight.BoneName); throw new InvalidContentException(message, geometry.Parent.Identity); } _tempIndices[i] = boneIndex; _tempWeights[i] = boneWeight.Weight; } // Clear unused indices/weights. for (int i = boneWeightCollection.Count; i < MaxBonesPerVertex; i++) { _tempIndices[i] = 0; _tempWeights[i] = 0f; } boneIndices[vertexIndex] = new Byte4(_tempIndices[0], _tempIndices[1], _tempIndices[2], _tempIndices[3]); boneWeights[vertexIndex] = new Vector4(_tempWeights[0], _tempWeights[1], _tempWeights[2], _tempWeights[3]); }