void DrawAttributeInfo(Scene scene)
        {
            // Separator.
            EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);

            EditorGUILayout.LabelField("Property Opinions", EditorStyles.boldLabel);
            EditorGUILayout.LabelField("Name: " + selectedAttribute.GetName());
            EditorGUILayout.LabelField("Type: " + selectedAttribute.GetTypeName().GetTfType().GetTypeName());
            EditorGUILayout.LabelField("IsArray: " + selectedAttribute.GetTypeName().IsArray());
            EditorGUILayout.LabelField("Composed Path: " + selectedAttribute.GetPath());
            EditorGUILayout.LabelField("Variability: " + selectedAttribute.GetVariability());
            EditorGUILayout.LabelField("Is Custom: " + selectedAttribute.IsCustom());
            double upper, lower, hasSamples;

            selectedAttribute.GetBracketingTimeSamples(scene.Time.GetValueOrDefault(), out lower, out upper,
                                                       out hasSamples);
            if (hasSamples > 0)
            {
                EditorGUILayout.LabelField("Braketing TimeSamples: [ " + lower + ", " + upper + " ]");
            }
            else
            {
                EditorGUILayout.LabelField("Braketing TimeSamples: [ ]");
            }

            EditorGUILayout.LabelField("TimeSamples: ");
            GUILayout.TextArea(string.Join(",",
                                           selectedAttribute.GetTimeSamples().Select(p => p.ToString()).ToArray()));

            // Spec are the low level API  in Sdf, the enable one to read and write a layer without
            // going through the composition graph. This is the fastest way to write USD data, but
            // also the most complicated.
            //
            // A property stack is an ordered list of all opinions about what this value should be.
            // The visualization below is a great debugging aid in production when something looks
            // wrong, but you have no idea why your value (opinion) isn't winning. It lets the user
            // understand how composition is working and shows them exactly what files are contributing
            // the final result.

            EditorGUILayout.LabelField("Authored Values: ");
            var specs = selectedAttribute.GetPropertyStack();

            if (specs.Count == 0)
            {
                EditorGUILayout.LabelField("[ Attribute has no authored opinions ]", EditorStyles.boldLabel);
            }

            foreach (var propSpec in specs)
            {
                EditorGUILayout.LabelField(propSpec.GetLayer().GetIdentifier());
            }

            // Separator.
            EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
        }
        /// <summary>
        /// Serializes the attribute value to USD-ASCII and writes it to Debug.Log.
        /// </summary>
        void DebugPrintAttr(Scene srcScene, UsdAttribute attr, UsdTimeCode time)
        {
            // Copy the desired attribute into a temp scene, with nothing other than this one attr.
            var tmpScene = Scene.Create();

            // Up-Axis is unrelated to the attribute, but it makes the generated USDA look more correct,
            // since it will include an up-axis.
            tmpScene.UpAxis = srcScene.UpAxis;

            // Define the owning prim for the attribute.
            var tmpPrim = tmpScene.Stage.DefinePrim(attr.GetPath().GetPrimPath(), attr.GetPrim().GetTypeName());

            // Define the attribute itself.
            var tmpAttr = tmpPrim.CreateAttribute(attr.GetName(), attr.GetTypeName());

            // Gather the default value and the value at the current time.
            var defaultVal = attr.Get(UsdTimeCode.Default());
            var valAtTime  = attr.Get(time);

            // Copy them to the new attribute.
            if (!defaultVal.IsEmpty())
            {
                tmpAttr.Set(defaultVal);
            }

            if (attr.ValueMightBeTimeVarying())
            {
                tmpAttr.Set(valAtTime, time);
            }

            // If this is an array, get the size.
            var arraySize = -1;

            if (valAtTime.IsArrayValued())
            {
                arraySize = (int)valAtTime.GetArraySize();
            }

            // Metadata cannot be time-varying.
            UsdMetadataValueMap metaData = attr.GetAllMetadata();

            foreach (var key in metaData.GetKeys())
            {
                tmpAttr.SetMetadata(key, metaData.GetValue(key));
            }

            // Export the single attribute to a string.
            var stringified = "";

            tmpScene.Stage.ExportToString(out stringified, addSourceFileComment: false);

            // Dispose the tmp scene.
            tmpScene.Close();
            tmpScene = null;

            // Print.
            if (arraySize > -1)
            {
                stringified = "Array Size: " + arraySize + "\n" + stringified;
            }

            Debug.Log("Path: <" + attr.GetPath().ToString() + ">\n" + stringified);
        }