Ejemplo n.º 1
0
    public HoudiniGeoAttribute createAttribute(HoudiniGeoAttribute.Preset preset)
    {
        HoudiniGeoAttribute new_attribute = ScriptableObject.CreateInstance <HoudiniGeoAttribute>();

        new_attribute.init(myMesh, preset);
        new_attribute.prName = getUniqueAttributeName(new_attribute.prName);
        addAttribute(new_attribute);
        return(new_attribute);
    }
    public HoudiniGeoAttribute createAttribute(string suggested_name)
    {
        string temp_name = getUniqueAttributeName(suggested_name);
        HoudiniGeoAttribute new_attribute = ScriptableObject.CreateInstance <HoudiniGeoAttribute>();

        new_attribute.init(myMesh, temp_name, HoudiniGeoAttribute.Type.FLOAT, 3);
        addAttribute(new_attribute);
        return(new_attribute);
    }
    private void addAttribute(HoudiniGeoAttribute new_attribute)
    {
        myAttributes.Add(new_attribute);

        if (myActiveAttribute == null)
        {
            myActiveAttribute = new_attribute;
        }

        refreshMesh();
    }
    public HoudiniGeoAttribute copy()
    {
        HoudiniGeoAttribute new_attribute =
            ScriptableObject.CreateInstance <HoudiniGeoAttribute>();

        new_attribute.reset();

        new_attribute.myName = myName;

        new_attribute.myType = myType;
        new_attribute.myOriginalAttributeOwner = myOriginalAttributeOwner;
        new_attribute.myTupleSize              = myTupleSize;
        new_attribute.myVertexCount            = myVertexCount;
        new_attribute.myInitializedVertexCount = myInitializedVertexCount;

        new_attribute.myPaintMode = myPaintMode;

        if (myType == Type.INT || myType == Type.BOOL)
        {
            new_attribute.myIntPaintValue = new int[myIntPaintValue.Length];
            myIntPaintValue.CopyTo(new_attribute.myIntPaintValue, 0);

            new_attribute.myIntMin = myIntMin;
            new_attribute.myIntMax = myIntMax;

            new_attribute.myIntData = new int[myIntData.Length];
            myIntData.CopyTo(new_attribute.myIntData, 0);
        }
        else if (myType == Type.FLOAT)
        {
            new_attribute.myFloatPaintValue = new float[myFloatPaintValue.Length];
            myFloatPaintValue.CopyTo(new_attribute.myFloatPaintValue, 0);

            new_attribute.myFloatMin = myFloatMin;
            new_attribute.myFloatMax = myFloatMax;

            new_attribute.myFloatData = new float[myFloatData.Length];
            myFloatData.CopyTo(new_attribute.myFloatData, 0);
        }
        else if (myType == Type.STRING)
        {
            new_attribute.myStringPaintValue = new string[myStringPaintValue.Length];
            myStringPaintValue.CopyTo(new_attribute.myStringPaintValue, 0);

            new_attribute.myStringData = new string[myStringData.Length];
            myStringData.CopyTo(new_attribute.myStringData, 0);
        }

        return(new_attribute);
    }
Ejemplo n.º 5
0
    public HoudiniGeoAttributeManager copy()
    {
        HoudiniGeoAttributeManager new_manager =
            ScriptableObject.CreateInstance <HoudiniGeoAttributeManager>();

        // It's ok to init the new manager with the mesh, mesh renderer, and mesh
        // collider of the old manager because these things will be overwritten
        // on next cook. I think.
        new_manager.init(myMesh, myMeshRenderer, myMeshCollider, myTransform);

        for (int i = 0; i < myAttributes.Count; ++i)
        {
            HoudiniGeoAttribute new_attribute = myAttributes[i].copy();
            new_manager.addAttribute(new_attribute);
        }

        return(new_manager);
    }
    public override void OnInspectorGUI()
    {
        if (myGeoAttributeManager == null)
        {
            return;
        }

        bool is_editable = true;

        // We can only build or do anything if we can link to our libraries.
#if !(UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || (UNITY_METRO && UNITY_EDITOR))
        is_editable = false;
        HoudiniGUI.help(HoudiniConstants.HAPI_UNSUPPORTED_PLATFORM_MSG, MessageType.Info);
#else
        if (!is_editable)
        {
            HoudiniGUI.help("This mesh is not editable.", MessageType.Info);
        }
#endif // !( UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || ( UNITY_METRO && UNITY_EDITOR ) )

        bool gui_enable = GUI.enabled;
        GUI.enabled = is_editable;

        myAssetInput.prShowHoudiniControls
            = HoudiniGUI.foldout("Houdini Controls", myAssetInput.prShowHoudiniControls, true);
        if (myAssetInput.prShowHoudiniControls)
        {
            if (!myAssetInput.isPrefab())
            {
                if (GUILayout.Button("Rebuild"))
                {
                    myAssetInput.buildAll();
                }

                if (GUILayout.Button("Recook"))
                {
                    myAssetInput.buildClientSide();
                }
            }
        }

        // Draw Help Pane
        myAssetInput.prShowHelp = HoudiniGUI.foldout("Asset Help", myAssetInput.prShowHelp, true);
        if (myAssetInput.prShowHelp)
        {
            drawHelpBox(myHelpText);
        }

        ///////////////////////////////////////////////////////////////////////
        // Draw Asset Settings
        // These don't affect the asset directly so they don't trigger rebuilds.

        myAssetInput.prShowAssetSettings = HoudiniGUI.foldout("Asset Settings", myAssetInput.prShowAssetSettings, true);
        if (myAssetInput.prShowAssetSettings)
        {
            // Enable Cooking Toggle
            createToggleForProperty(
                "enable_cooking", "Enable Cooking", "prEnableCooking",
                ref myUndoInfo.enableCooking, null, !HoudiniHost.isEnableCookingDefault());

            HoudiniGUI.separator();

            // Cooking Triggers Downstream Cooks Toggle
            createToggleForProperty(
                "cooking_triggers_downstream_cooks", "Cooking Triggers Downstream Cooks",
                "prCookingTriggersDownCooks", ref myUndoInfo.cookingTriggersDownCooks,
                null, !HoudiniHost.isCookingTriggersDownCooksDefault(),
                !myAssetInput.prEnableCooking, " (all cooking is disabled)");

            HoudiniGUI.separator();

            // Push Unity Transform To Houdini Engine Toggle
            createToggleForProperty(
                "push_unity_transform_to_houdini_engine", "Push Unity Transform To Houdini Engine",
                "prPushUnityTransformToHoudini", ref myUndoInfo.pushUnityTransformToHoudini,
                null, !HoudiniHost.isPushUnityTransformToHoudiniDefault());

            // Transform Change Triggers Cooks Toggle
            createToggleForProperty(
                "transform_change_triggers_cooks", "Transform Change Triggers Cooks",
                "prTransformChangeTriggersCooks", ref myUndoInfo.transformChangeTriggersCooks,
                null, !HoudiniHost.isTransformChangeTriggersCooksDefault(),
                !myAssetInput.prEnableCooking, " (all cooking is disabled)");
        }

        ///////////////////////////////////////////////////////////////////////
        // Draw Point Attributes

        myAssetInput.prShowAttributesTable = HoudiniGUI.foldout("Point Attributes", myAssetInput.prShowAttributesTable, true);
        if (myAssetInput.prShowAttributesTable)
        {
            // Draw Create Point Attributes Action Bar
            {
                string[] preset_labels = new string[] {
                    "Create Point Attribute:", "Custom", "Color", "UV", "Normal", "Bool", "Int", "Float", "String"
                };
                int[] preset_values = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 };

                GUIStyle style = new GUIStyle(EditorStyles.popup);
                style.fixedHeight   = 18;
                style.margin.bottom = 6;
                int preset_selected = EditorGUILayout.IntPopup(
                    0, preset_labels, preset_values, style);

                if (preset_selected == 1)
                {
                    myGeoAttributeManager.createAttribute();
                    myAssetInput.prHasAttributeChanges = true;
                }
                else if (preset_selected > 1)
                {
                    HoudiniGeoAttribute.Preset preset = (HoudiniGeoAttribute.Preset)(preset_selected - 2);
                    myGeoAttributeManager.createAttribute(preset);
                    myAssetInput.prHasAttributeChanges = true;
                }
            }

            // Draw recook notice.
            string help_msg = "There are uncommitted attribute changes. Press 'Recook' when ready.";
            if (myAssetInput.prHasError)
            {
                help_msg += "\nError: " + myAssetInput.prErrorMsg;
            }
            if (myAssetInput.prHasAttributeChanges)
            {
                HoudiniGUI.help(help_msg, MessageType.Info);
            }
            else
            {
                HoudiniGUI.help("Ready", MessageType.Info);
            }

            HoudiniGUI.separator();

            string[] type_labels = new string[] { "bool", "int", "float", "string" };
            int[]    type_values = new int[] { 0, 1, 2, 3 };

            string[] tuple_labels = new string[] { "1", "2", "3", "4", "5" };
            int[]    tuple_values = new int[] { 1, 2, 3, 4, 5 };

            // Draw table header.
            {
                EditorGUILayout.BeginHorizontal();

                GUIStyle label_style = new GUIStyle(EditorStyles.label);
                label_style.padding.right = -5;
                label_style.margin.left   = -5;
                label_style.border.right  = -10;

                EditorGUILayout.LabelField("Name", GUILayout.MinWidth(100));
                EditorGUILayout.LabelField("Type", GUILayout.Width(50));
                EditorGUILayout.LabelField("Tuple", GUILayout.Width(50));
                EditorGUILayout.LabelField("|", GUILayout.Width(8));
                EditorGUILayout.LabelField("Min", GUILayout.Width(50));
                EditorGUILayout.LabelField("Max", GUILayout.Width(50));
                EditorGUILayout.LabelField("", GUILayout.Width(27));

                EditorGUILayout.EndHorizontal();
            }

            for (int i = 0; i < myGeoAttributeManager.prAttributes.Count; ++i)
            {
                HoudiniGeoAttribute attrib = myGeoAttributeManager.prAttributes[i];

                EditorGUILayout.BeginHorizontal();

                // Attribute Name
                string new_name = EditorGUILayout.TextField(attrib.prName, GUILayout.MinWidth(100));
                if (new_name != attrib.prName)
                {
                    attrib.prName = new_name;
                    myAssetInput.prHasAttributeChanges = true;
                }

                // Attribute Type
                HoudiniGeoAttribute.Type new_attrib_type = (HoudiniGeoAttribute.Type)EditorGUILayout.IntPopup(
                    (int)attrib.prType, type_labels, type_values, GUILayout.Width(50));
                if (new_attrib_type != attrib.prType)
                {
                    attrib.prType = new_attrib_type;
                    myAssetInput.prHasAttributeChanges = true;
                }

                // Attribute Tuple Size
                int new_tuple_size = EditorGUILayout.IntPopup(
                    attrib.prTupleSize, tuple_labels, tuple_values, GUILayout.Width(50));
                if (new_tuple_size != attrib.prTupleSize)
                {
                    attrib.prTupleSize = new_tuple_size;
                    myAssetInput.prHasAttributeChanges = true;
                }

                EditorGUILayout.LabelField("|", GUILayout.Width(8));

                // Range
                if (attrib.prType == HoudiniGeoAttribute.Type.STRING)
                {
                    EditorGUILayout.LabelField("N/A", GUILayout.MinWidth(20));
                }
                else
                {
                    if (attrib.prType == HoudiniGeoAttribute.Type.BOOL || attrib.prType == HoudiniGeoAttribute.Type.INT)
                    {
                        attrib.prIntMin =
                            EditorGUILayout.IntField("", attrib.prIntMin, GUILayout.Width(50));
                    }
                    else if (attrib.prType == HoudiniGeoAttribute.Type.FLOAT)
                    {
                        attrib.prFloatMin =
                            EditorGUILayout.FloatField("", attrib.prFloatMin, GUILayout.Width(50));
                    }

                    if (attrib.prType == HoudiniGeoAttribute.Type.BOOL || attrib.prType == HoudiniGeoAttribute.Type.INT)
                    {
                        attrib.prIntMax =
                            EditorGUILayout.IntField("", attrib.prIntMax, GUILayout.Width(50));
                    }
                    else if (attrib.prType == HoudiniGeoAttribute.Type.FLOAT)
                    {
                        attrib.prFloatMax =
                            EditorGUILayout.FloatField("", attrib.prFloatMax, GUILayout.Width(50));
                    }
                }

                EditorGUILayout.LabelField("|", GUILayout.Width(8));

                GUIStyle label_style = new GUIStyle(EditorStyles.label);
                label_style.fontStyle = FontStyle.Bold;
                if (GUILayout.Button("X", label_style, GUILayout.Width(15), GUILayout.Height(15)))
                {
                    myGeoAttributeManager.deleteAttribute(attrib.prName);
                    myAssetInput.prHasAttributeChanges = true;
                }

                EditorGUILayout.EndHorizontal();
            }

            {
                EditorGUILayout.BeginHorizontal();
                GUIStyle label_style = new GUIStyle(EditorStyles.label);
                label_style.fontStyle     = FontStyle.Normal;
                label_style.alignment     = TextAnchor.MiddleRight;
                label_style.padding.left  = 0;
                label_style.margin.left   = 0;
                label_style.padding.right = 0;
                label_style.margin.right  = 0;
                EditorGUILayout.LabelField("Delete Attribute", label_style, GUILayout.MinWidth(40));

                label_style.fontStyle     = FontStyle.Bold;
                label_style.padding.left  = 0;
                label_style.margin.left   = 6;
                label_style.padding.right = 5;
                label_style.margin.right  = 5;
                EditorGUILayout.LabelField("↲", label_style, GUILayout.Width(10));

                EditorGUILayout.EndHorizontal();
            }
        }         // Show Attributes Table

        GUI.enabled = gui_enable;
    }
Ejemplo n.º 7
0
    public void refresh(bool reload_asset)
    {
        if (prObjectControl == null)
        {
            Debug.LogError("Why is my object control null on a refresh?");
            return;
        }

        GameObject geo_node = gameObject;

        // Get Geo info.
        HAPI_GeoInfo geo_info = new HAPI_GeoInfo();

        HoudiniHost.getGeoInfo(prAssetId, prObjectId, prGeoId, out geo_info);

        if (geo_info.type == HAPI_GeoType.HAPI_GEOTYPE_INPUT)
        {
            return;
        }

        if (!reload_asset && !geo_info.hasGeoChanged && !geo_info.hasMaterialChanged)
        {
            return;
        }

        if (reload_asset || geo_info.type == HAPI_GeoType.HAPI_GEOTYPE_CURVE)
        {
            for (int i = 0; i < myParts.Count; ++i)
            {
                HoudiniAssetUtility.destroyGameObject(myParts[i]);
            }
            myParts.Clear();
        }

        if (reload_asset || geo_info.hasGeoChanged)
        {
            // Initialize our geo control.
            init(
                geo_info.nodeId, prGeoId, geo_info.name, (HAPI_GeoType)geo_info.type,
                geo_info.isEditable, geo_info.isDisplayGeo);

            // Set node name.
            geo_node.name = prGeoName;
        }

        if (!geo_info.isDisplayGeo &&
            (geo_info.type != HAPI_GeoType.HAPI_GEOTYPE_CURVE &&
             !myObjectControl.prAsset.prImportTemplatedGeos &&
             geo_info.isTemplated))
        {
            return;
        }

        if (geo_info.type == HAPI_GeoType.HAPI_GEOTYPE_CURVE)
        {
            createAndInitCurve(prNodeId, prObjectId, prGeoId, prIsEditable);
        }
        else
        {
            if (reload_asset || geo_info.hasGeoChanged)
            {
                // Add new geos as needed.
                while (myParts.Count < geo_info.partCount)
                {
                    myParts.Add(createPart(myParts.Count));
                }

                // Remove stale geos.
                while (myParts.Count > geo_info.partCount)
                {
                    HoudiniAssetUtility.destroyGameObject(myParts[geo_info.partCount]);
                    myParts.RemoveAt(geo_info.partCount);
                }
            }

            // Refresh all geos.
            for (int i = 0; i < myParts.Count; ++i)
            {
                myParts[i].GetComponent <HoudiniPartControl>().refresh(
                    reload_asset, geo_info.hasGeoChanged, geo_info.hasMaterialChanged);
            }

            // Handle Edit/Paint Nodes
#if !HAPI_PAINT_SUPPORT
            if (geo_info.type == HAPI_GeoType.HAPI_GEOTYPE_INTERMEDIATE)
            {
                // We are limited to using the first part, always.
                if (myGeoAttributeManager == null && myParts.Count > 0)
                {
                    const int part_id = 0;

                    GameObject         part_gameobject = myParts[part_id];
                    HoudiniPartControl part_control    = part_gameobject.GetComponent <HoudiniPartControl>();
                    MeshFilter         mesh_filter     = part_control.getOrCreateComponent <MeshFilter>();
                    MeshRenderer       mesh_renderer   = part_control.getOrCreateComponent <MeshRenderer>();
                    MeshCollider       mesh_collider   = part_control.getOrCreateComponent <MeshCollider>();
                    Mesh mesh = mesh_filter.sharedMesh;

                    myGeoAttributeManager = ScriptableObject.CreateInstance <HoudiniGeoAttributeManager>();
                    myGeoAttributeManager.init(mesh, mesh_renderer, mesh_collider, part_gameobject.transform);

                    // Fetch all point attributes.
                    string[] point_attribute_names = HoudiniHost.getAttributeNames(
                        prAssetId, prObjectId, prGeoId, part_id, HAPI_AttributeOwner.HAPI_ATTROWNER_POINT);

                    foreach (string point_attribute_name in point_attribute_names)
                    {
                        if (point_attribute_name == "P")
                        {
                            continue;
                        }

                        HAPI_AttributeInfo point_attribute_info = HoudiniHost.getAttributeInfo(
                            prAssetId, prObjectId, prGeoId, part_id, point_attribute_name,
                            HAPI_AttributeOwner.HAPI_ATTROWNER_POINT);

                        if (point_attribute_info.storage == HAPI_StorageType.HAPI_STORAGETYPE_INT)
                        {
                            int[] data = new int[0];
                            HoudiniAssetUtility.getAttribute(
                                prAssetId, prObjectId, prGeoId, part_id,
                                point_attribute_name,
                                ref point_attribute_info,
                                ref data,
                                HoudiniHost.getAttributeIntData);
                            HoudiniGeoAttribute attribute =
                                myGeoAttributeManager.createAttribute(point_attribute_name);
                            attribute.init(
                                mesh, point_attribute_name, HoudiniGeoAttribute.Type.INT,
                                point_attribute_info.tupleSize);
                            attribute.prOriginalAttributeOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_POINT;

                            if (data.Length != attribute.prIntData.Length)
                            {
                                Debug.LogError("Size mis-match in paint tools.");
                            }
                            else
                            {
                                for (int i = 0; i < data.Length; ++i)
                                {
                                    attribute.prIntData[i] = data[i];
                                }
                            }
                        }
                        else if (point_attribute_info.storage == HAPI_StorageType.HAPI_STORAGETYPE_FLOAT)
                        {
                            int     tuple_size = point_attribute_info.tupleSize;
                            float[] data       = new float[0];
                            HoudiniAssetUtility.getAttribute(
                                prAssetId, prObjectId, prGeoId, part_id,
                                point_attribute_name,
                                ref point_attribute_info,
                                ref data,
                                HoudiniHost.getAttributeFloatData);
                            HoudiniGeoAttribute attribute =
                                myGeoAttributeManager.createAttribute(point_attribute_name);
                            attribute.init(
                                mesh, point_attribute_name, HoudiniGeoAttribute.Type.FLOAT,
                                tuple_size);
                            attribute.prOriginalAttributeOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_POINT;

                            // Get Vertex list.
                            HAPI_PartInfo part_info = new HAPI_PartInfo();
                            HoudiniHost.getPartInfo(
                                prAssetId, prObjectId, prGeoId, part_id, out part_info);
                            int[] vertex_list = new int[part_info.vertexCount];
                            HoudiniAssetUtility.getArray4Id(
                                prAssetId, prObjectId, prGeoId, part_id, HoudiniHost.getVertexList,
                                vertex_list, part_info.vertexCount);

                            if (part_info.vertexCount * tuple_size != attribute.prFloatData.Length)
                            {
                                Debug.LogError("Size mis-match in paint tools.");
                            }
                            else
                            {
                                for (int i = 0; i < part_info.vertexCount; ++i)
                                {
                                    for (int tuple = 0; tuple < tuple_size; ++tuple)
                                    {
                                        attribute.prFloatData[i * tuple_size + tuple] =
                                            data[vertex_list[i] * tuple_size + tuple];
                                    }
                                }
                            }
                        }
                        else if (point_attribute_info.storage == HAPI_StorageType.HAPI_STORAGETYPE_STRING)
                        {
                        }
                    }
                }
            }
#endif // !HAPI_PAINT_SUPPORT

            // Handle script attaching.
            if (reload_asset && geo_info.partCount > 0)
            {
                HAPI_AttributeInfo script_attr_info = new HAPI_AttributeInfo("Unity_Script");
                int[] script_attr = new int[0];

                HoudiniAssetUtility.getAttribute(
                    prAssetId, prObjectId, prGeoId, 0, "Unity_Script",
                    ref script_attr_info, ref script_attr, HoudiniHost.getAttributeStringData);

                if (script_attr_info.exists && script_attr_info.owner != HAPI_AttributeOwner.HAPI_ATTROWNER_DETAIL)
                {
                    throw new HoudiniErrorIgnorable("I only understand Unity_Script as detail attributes!");
                }

                if (script_attr_info.exists && script_attr.Length > 0)
                {
                    string script_to_attach = HoudiniHost.getString(script_attr[0]);
                    HoudiniAssetUtility.attachScript(geo_node, script_to_attach);
                }
            }
        }
    }
Ejemplo n.º 8
0
    public bool syncAttributes(int asset_id, int object_id, int geo_id, int part_id, Mesh mesh)
    {
        bool needs_recook = false;

        // Fetch all point attributes.
        string[] point_attribute_names = HoudiniHost.getAttributeNames(
            geo_id, part_id, HAPI_AttributeOwner.HAPI_ATTROWNER_POINT);

        foreach (string point_attribute_name in point_attribute_names)
        {
            if (point_attribute_name == "P")
            {
                continue;
            }

            HAPI_AttributeInfo point_attribute_info = HoudiniHost.getAttributeInfo(
                geo_id, part_id, point_attribute_name,
                HAPI_AttributeOwner.HAPI_ATTROWNER_POINT);

            HoudiniGeoAttribute attribute = null;

            // If we already have an attribute with the same name, sync it with
            // the attribute in Houdini - trying to salvage any data even if the
            // attribute storage type, tuple size, or mesh point count has changed.
            if (hasAttribute(point_attribute_name))
            {
                attribute = getAttribute(point_attribute_name);
            }
            else             // Attribute not found.
            {
                HoudiniGeoAttribute.Type geo_attribute_type = HoudiniGeoAttribute.Type.UNDEFINED;
                switch (point_attribute_info.storage)
                {
                case HAPI_StorageType.HAPI_STORAGETYPE_INT:
                    geo_attribute_type = HoudiniGeoAttribute.Type.INT; break;

                case HAPI_StorageType.HAPI_STORAGETYPE_FLOAT:
                    geo_attribute_type = HoudiniGeoAttribute.Type.FLOAT; break;

                case HAPI_StorageType.HAPI_STORAGETYPE_STRING:
                    geo_attribute_type = HoudiniGeoAttribute.Type.STRING; break;
                }

                attribute = createAttribute(point_attribute_name);
                attribute.init(
                    mesh, point_attribute_name, geo_attribute_type,
                    point_attribute_info.tupleSize);
                attribute.prOriginalAttributeOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_POINT;
            }

            // Sync the values of the Unity attribute with the Houdini attribute.
            needs_recook |= attribute.sync(geo_id, part_id, mesh, point_attribute_info);

            // If the sync updated the values from the asset we need to refresh our mesh.
            if (needs_recook)
            {
                refreshMesh();
            }
        }

        return(needs_recook);
    }
Ejemplo n.º 9
0
	private void addAttribute( HoudiniGeoAttribute new_attribute )
	{
		myAttributes.Add( new_attribute );

		if ( myActiveAttribute == null )
			myActiveAttribute = new_attribute;

		refreshMesh();
	}
Ejemplo n.º 10
0
	public HoudiniGeoAttribute createAttribute( HoudiniGeoAttribute.Preset preset )
	{
		HoudiniGeoAttribute new_attribute = ScriptableObject.CreateInstance< HoudiniGeoAttribute >();
		new_attribute.init( myMesh, preset );
		new_attribute.prName = getUniqueAttributeName( new_attribute.prName );
		addAttribute( new_attribute );
		return new_attribute;
	}