Example #1
0
    private void cacheNumInstances()
    {
        HAPI_ObjectInfo object_info = prAsset.prObjects[prObjectId];

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

        HoudiniHost.getGeoInfo(prAsset.prAssetId, prObjectId, 0, out geo_info);
        if (geo_info.partCount == 0)
        {
            return;
        }

        HAPI_PartInfo part_info = new HAPI_PartInfo();

        HoudiniHost.getPartInfo(prAsset.prAssetId, prObjectId, 0, 0, out part_info);
        if (prAsset.prEnableLogging)
        {
            Debug.Log("Instancer #" + prObjectId + " (" + object_info.name + "): "
                      + "points: " + part_info.pointCount);
        }

        if (part_info.pointCount > 65000)
        {
            throw new HoudiniError("Point count (" + part_info.pointCount + ") above limit (" + 65000 + ")!");
        }

        myNumInstances = part_info.pointCount;
    }
Example #2
0
    private void cacheNumInstances()
    {
        var             obj_idx     = prAsset.findObjectByNodeId(prObjectId);
        HAPI_ObjectInfo object_info = prAsset.prObjects[obj_idx];

        // Get Detail info.
        HAPI_GeoInfo geo_info = HoudiniHost.getDisplayGeoInfo(prObjectId);

        if (geo_info.partCount == 0)
        {
            return;
        }

        HAPI_PartInfo part_info = HoudiniHost.getPartInfo(geo_info.nodeId, 0);

        if (prAsset.prEnableLogging)
        {
            Debug.Log("Instancer #" + prObjectId + " (" + object_info.name + "): "
                      + "points: " + part_info.pointCount);
        }

        if (part_info.pointCount > 65000)
        {
            throw new HoudiniError("Point count (" + part_info.pointCount + ") above limit (" + 65000 + ")!");
        }

        myNumInstances = part_info.pointCount;
    }
    /// <summary>
    /// Query object nodes in the Asset. An object node represents a Houdini transform node.
    /// Each object might have any number of SOP geometry containers and a transform.
    /// <param name="houdiniAsset">The HEU_HoudiniAsset of the loaded asset</param>
    /// </summary>
    public static void QueryObjects(HEU_HoudiniAsset houdiniAsset)
    {
        // Get access to the Houdini Engine session used by this asset.
        // This gives access to call Houdini Engine APIs directly.
        HEU_SessionBase session = houdiniAsset.GetAssetSession(true);

        if (session == null || !session.IsSessionValid())
        {
            Debug.LogWarningFormat("Invalid Houdini Engine session! Try restarting session.");
            return;
        }

        HAPI_ObjectInfo[] objectInfos      = null;
        HAPI_Transform[]  objectTransforms = null;
        HAPI_NodeInfo     assetNodeInfo    = houdiniAsset.NodeInfo;

        // Fill in object infos and transforms based on node type and number of child objects.
        // This the hiearchy of the HDA when loaded in Houdini Engine. It can contain subnets with
        // multiple objects containing multiple geometry, or a single object containting any number of geometry.
        // This automatically handles object-level HDAs and geometry (SOP) HDAs.
        if (!HEU_HAPIUtility.GetObjectInfos(session, houdiniAsset.AssetID, ref assetNodeInfo, out objectInfos, out objectTransforms))
        {
            return;
        }

        // For each object, get the display and editable geometries contained inside.
        for (int i = 0; i < objectInfos.Length; ++i)
        {
            // Get display SOP geo info
            HAPI_GeoInfo displayGeoInfo = new HAPI_GeoInfo();
            if (!session.GetDisplayGeoInfo(objectInfos[i].nodeId, ref displayGeoInfo))
            {
                return;
            }

            QueryGeoParts(session, ref displayGeoInfo);

            // Optional: Get editable nodes, cook em, then create geo nodes for them
            HAPI_NodeId[] editableNodes = null;
            HEU_SessionManager.GetComposedChildNodeList(session, objectInfos[i].nodeId, (int)HAPI_NodeType.HAPI_NODETYPE_SOP, (int)HAPI_NodeFlags.HAPI_NODEFLAGS_EDITABLE, true, out editableNodes);
            if (editableNodes != null)
            {
                foreach (HAPI_NodeId editNodeID in editableNodes)
                {
                    if (editNodeID != displayGeoInfo.nodeId)
                    {
                        session.CookNode(editNodeID, HEU_PluginSettings.CookTemplatedGeos);

                        HAPI_GeoInfo editGeoInfo = new HAPI_GeoInfo();
                        if (session.GetGeoInfo(editNodeID, ref editGeoInfo))
                        {
                            QueryGeoParts(session, ref editGeoInfo);
                        }
                    }
                }
            }
        }
    }
    /// <summary>
    /// Query each geometry container's parts to get the actual geometry data.
    /// A HAPI_GeoInfo represents a SOP geometry container that might have one or more
    /// HAPI_PartInfos.A geometry containing more than one part could mean different
    /// geometry types merged together, or different layers in a heightfield volume.
    /// </summary>
    /// <param name="session">Houdini Engine session</param>
    /// <param name="geoInfo">The HEU_GeoInfo pertaining to the geometry to query</param>
    public static void QueryGeoParts(HEU_SessionBase session, ref HAPI_GeoInfo geoInfo)
    {
        int numParts = geoInfo.partCount;

        for (int i = 0; i < numParts; ++i)
        {
            HAPI_PartInfo partInfo = new HAPI_PartInfo();
            if (!session.GetPartInfo(geoInfo.nodeId, 0, ref partInfo))
            {
                continue;
            }

            StringBuilder sb = new StringBuilder();

            // Process each geometry by its type
            if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_MESH)
            {
                // Meshes
                sb.AppendLine(string.Format("Mesh part at {0} with vertex count {1}, point count {2}, and primitive count {3}",
                                            i, partInfo.vertexCount, partInfo.pointCount, partInfo.faceCount));
            }
            else if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_VOLUME)
            {
                // Heightfield / terrain
                sb.AppendLine(string.Format("Volume part at {0}", i));
            }
            else if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_CURVE)
            {
                // Curves
                sb.AppendLine(string.Format("Curve part at {0}", i));
            }
            else if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_INSTANCER)
            {
                // Instancer
                sb.AppendLine(string.Format("Instancer part at {0}", i));
            }
            else if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_INVALID)
            {
                // Not valid Houdini Engine type - ignore
                sb.AppendLine(string.Format("Invalid part at {0}", i));
            }

            // Query attributes for each part
            QueryPartAttributeByOwner(session, geoInfo.nodeId, i, HAPI_AttributeOwner.HAPI_ATTROWNER_DETAIL, partInfo.detailAttributeCount, sb);
            QueryPartAttributeByOwner(session, geoInfo.nodeId, i, HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM, partInfo.primitiveAttributeCount, sb);
            QueryPartAttributeByOwner(session, geoInfo.nodeId, i, HAPI_AttributeOwner.HAPI_ATTROWNER_POINT, partInfo.pointAttributeCount, sb);
            QueryPartAttributeByOwner(session, geoInfo.nodeId, i, HAPI_AttributeOwner.HAPI_ATTROWNER_VERTEX, partInfo.vertexAttributeCount, sb);

            Debug.Log("Part: \n" + sb.ToString());
        }
    }
Example #5
0
    private void getInstanceAndNameAttrs(out int[] instance_attr, out int[] name_attr)
    {
        instance_attr = new int[0];
        name_attr     = new int[0];

        HAPI_GeoInfo geo_info = HoudiniHost.getDisplayGeoInfo(prObjectId);

        HAPI_AttributeInfo instance_attr_info = new HAPI_AttributeInfo("instance");

        Utility.getAttribute(
            geo_info.nodeId, 0, "instance", ref instance_attr_info,
            ref instance_attr, HoudiniHost.getAttributeStringData);

        if (!instance_attr_info.exists)
        {
            return;
        }

        if (instance_attr_info.exists && instance_attr_info.owner != HAPI_AttributeOwner.HAPI_ATTROWNER_POINT)
        {
            throw new HoudiniErrorIgnorable("I only understand instance as point attributes!");
        }

        if (instance_attr_info.exists && instance_attr.Length != myNumInstances)
        {
            throw new HoudiniError(
                      "Unexpected instance_hint array length found for asset: " + prAsset.prAssetId + "!");
        }

        HAPI_AttributeInfo name_attr_info = new HAPI_AttributeInfo("name");

        Utility.getAttribute(
            geo_info.nodeId, 0, "name", ref name_attr_info,
            ref name_attr, HoudiniHost.getAttributeStringData);

        if (name_attr_info.exists && name_attr_info.owner != HAPI_AttributeOwner.HAPI_ATTROWNER_POINT)
        {
            throw new HoudiniErrorIgnorable("I only understand name as point attributes!");
        }

        if (name_attr_info.exists && name_attr.Length != myNumInstances)
        {
            throw new HoudiniError(
                      "Unexpected name array length found for asset: " + prAsset.prAssetId + "!");
        }
    }
    public bool refresh(bool reload_asset, HAPI_ObjectInfo object_info)
    {
        bool needs_recook = false;

        if (reload_asset)
        {
            for (int i = 0; i < myGeos.Count; ++i)
            {
                if (myGeos[i])
                {
                    HoudiniAssetUtility.destroyGameObject(myGeos[i]);
                }
            }
            myGeos.Clear();
        }

        if (reload_asset || object_info.haveGeosChanged)
        {
            // TODO: Add back support for templated geos and curve SOPs.
            HAPI_GeoInfo geo_info = HoudiniHost.getDisplayGeoInfo(prObjectId);
            object_info.geoCount = 1;

            // Add new geos as needed.
            while (myGeos.Count < object_info.geoCount)
            {
                myGeos.Add(createGeo(geo_info.nodeId));
            }

            // Remove stale geos.
            while (myGeos.Count > object_info.geoCount)
            {
                HoudiniAssetUtility.destroyGameObject(myGeos[object_info.geoCount]);
                myGeos.RemoveAt(object_info.geoCount);
            }

            // Refresh all geos.
            for (int i = 0; i < myGeos.Count; ++i)
            {
                needs_recook |= myGeos[i].GetComponent <HoudiniGeoControl>().refresh(reload_asset);
            }
        }

        return(needs_recook);
    }
Example #7
0
    protected override bool buildCreateObjects(bool reload_asset, ref HoudiniProgressBar progress_bar)
    {
        try
        {
            prCurve.syncPointsWithParm();

            HAPI_GeoInfo  geo_info      = HoudiniHost.getDisplayGeoInfo(prCurve.prControl.prAssetId);
            HAPI_NodeInfo geo_node_info = HoudiniHost.getNodeInfo(geo_info.nodeId);
            prCurve.createObject(geo_node_info.parentId, geo_info.nodeId);

            HoudiniHost.repaint();
        }
        catch (HoudiniError)
        {
            // Per-object errors are not re-thrown so that the rest of the asset has a chance to load.
            //Debug.LogWarning( error.ToString() );
        }

        return(false);
    }
Example #8
0
    public void bakeAnimation(float curr_time, GameObject parent_object)
    {
        try
        {
            HAPI_GeoInfo geo_info = HoudiniHost.getDisplayGeoInfo(prObjectId);

            HAPI_Transform[] instance_transforms = new HAPI_Transform[myNumInstances];
            Utility.getArray2Id(
                geo_info.nodeId, HAPI_RSTOrder.HAPI_SRT,
                HoudiniHost.getInstanceTransforms, instance_transforms, myNumInstances);

            Matrix4x4 parent_xform_inverse = Matrix4x4.identity;

            if (parent_object != null)
            {
                parent_xform_inverse = parent_object.transform.localToWorldMatrix.inverse;
            }

            for (int ii = 0; ii < myNumInstances; ++ii)
            {
                Vector3 pos = new Vector3();

                // Apply object transforms.
                //
                // Axis and Rotation conversions:
                // Note that Houdini's X axis points in the opposite direction that Unity's does.  Also, Houdini's
                // rotation is right handed, whereas Unity is left handed.  To account for this, we need to invert
                // the x coordinate of the translation, and do the same for the rotations (except for the x rotation,
                // which doesn't need to be flipped because the change in handedness AND direction of the left x axis
                // causes a double negative - yeah, I know).

                pos[0] = -instance_transforms[ii].position[0];
                pos[1] = instance_transforms[ii].position[1];
                pos[2] = instance_transforms[ii].position[2];

                Quaternion quat = new Quaternion(instance_transforms[ii].rotationQuaternion[0],
                                                 instance_transforms[ii].rotationQuaternion[1],
                                                 instance_transforms[ii].rotationQuaternion[2],
                                                 instance_transforms[ii].rotationQuaternion[3]);

                Vector3 euler = quat.eulerAngles;
                euler.y = -euler.y;
                euler.z = -euler.z;

                quat = Quaternion.Euler(euler);

                Vector3 scale = new Vector3(instance_transforms[ii].scale[0],
                                            instance_transforms[ii].scale[1],
                                            instance_transforms[ii].scale[2]);

                if (parent_object != null)
                {
                    Matrix4x4 world_mat = Matrix4x4.identity;
                    world_mat.SetTRS(pos, quat, scale);
                    Matrix4x4 local_mat = parent_xform_inverse * world_mat;

                    quat  = HoudiniAssetUtility.getQuaternion(local_mat);
                    scale = HoudiniAssetUtility.getScale(local_mat);
                    pos   = HoudiniAssetUtility.getPosition(local_mat);
                }

                HoudiniCurvesCollection curves = myCurvesCollection[ii];

                HoudiniAssetUtility.addKeyToCurve(curr_time, pos[0], curves.tx);
                HoudiniAssetUtility.addKeyToCurve(curr_time, pos[1], curves.ty);
                HoudiniAssetUtility.addKeyToCurve(curr_time, pos[2], curves.tz);
                HoudiniAssetUtility.addKeyToCurve(curr_time, quat.x, curves.qx);
                HoudiniAssetUtility.addKeyToCurve(curr_time, quat.y, curves.qy);
                HoudiniAssetUtility.addKeyToCurve(curr_time, quat.z, curves.qz);
                HoudiniAssetUtility.addKeyToCurve(curr_time, quat.w, curves.qw);
                HoudiniAssetUtility.addKeyToCurve(curr_time, scale.x, curves.sx);
                HoudiniAssetUtility.addKeyToCurve(curr_time, scale.y, curves.sy);
                HoudiniAssetUtility.addKeyToCurve(curr_time, scale.z, curves.sz);
            }
        }
        catch (HoudiniError error)
        {
            Debug.LogWarning(error.ToString());
            return;
        }
    }
 HAPI_GetGeoInfo(
     ref HAPI_Session session,
     HAPI_AssetId asset_id, HAPI_ObjectId object_id, HAPI_GeoId geo_id,
     out HAPI_GeoInfo geo_info);
Example #10
0
	public bool refresh( bool reload_asset )
	{
		bool needs_recook = false;

		if ( prObjectControl == null )
		{
			Debug.LogError( "Why is my object control null on a refresh?" );
			return needs_recook;
		}

		GameObject geo_node = gameObject;

		// Get Geo info.
		HAPI_GeoInfo geo_info = new HAPI_GeoInfo();
		try
		{
			// If templated geos are off this will error out for templated
			// geos because they woudn't have cooked. But we still need to
			// get the geo info to see that this is a templated geo and skip it.
			HoudiniHost.getGeoInfo( prAssetId, prObjectId, prGeoId, out geo_info );
		}
		catch ( HoudiniErrorInvalidArgument ) {}

		if ( geo_info.type == HAPI_GeoType.HAPI_GEOTYPE_INPUT )
			return needs_recook;

		if ( geo_info.isTemplated && !prAsset.prImportTemplatedGeos && !geo_info.isEditable )
			return needs_recook;

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

		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 needs_recook;
		}

		if ( geo_info.type == HAPI_GeoType.HAPI_GEOTYPE_CURVE )
		{
			createAndInitCurve( prNodeId, prObjectId, prGeoId, prIsEditable );
			needs_recook = true;
		}
		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 ( geo_info.type == HAPI_GeoType.HAPI_GEOTYPE_INTERMEDIATE )
			{
				// Currently, we only support painting on the first part.
				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;

				// We are limited to using the first part, always.
				if ( myGeoAttributeManager == null && myParts.Count > 0 )
				{
					if ( prAsset.prGeoAttributeManagerMap.contains( getRelativePath() ) )
					{
						myGeoAttributeManager = prAsset.prGeoAttributeManagerMap.get( getRelativePath() );
						myGeoAttributeManager.name = getAbsolutePath() + "/GeoAttributeManager";
						myGeoAttributeManager.reInit( mesh, mesh_renderer, mesh_collider, part_gameobject.transform );
					}
					else
					{
						myGeoAttributeManager = ScriptableObject.CreateInstance< HoudiniGeoAttributeManager >();
						myGeoAttributeManager.name = getAbsolutePath() + "/GeoAttributeManager";
						myGeoAttributeManager.init( mesh, mesh_renderer, mesh_collider, part_gameobject.transform );
						prAsset.prGeoAttributeManagerMap.add( getRelativePath(), myGeoAttributeManager );
					}

					// Sync the attributes and see if we need a recook.
					if ( myGeoAttributeManager.syncAttributes( prAssetId, prObjectId, prGeoId, part_id, mesh ) )
					{
						HoudiniAssetUtility.setMesh(
							prAssetId, prObjectId, prGeoId,
							ref mesh, part_control, myGeoAttributeManager );
						needs_recook = true;
					}
				}
				else
				{
					// Just sync the attributes but don't recook. Setting needs_recook to true here would
					// cause infinite cooking.
					myGeoAttributeManager.syncAttributes( prAssetId, prObjectId, prGeoId, part_id, mesh );
				}
			}

			// 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 );
				}
			}
		}

		return needs_recook;
	}
Example #11
0
	// GEOMETRY GETTERS -----------------------------------------------------------------------------------------

	public static void getGeoInfo(
		HAPI_AssetId asset_id, HAPI_ObjectId object_id, HAPI_GeoId geo_id,
		out HAPI_GeoInfo geo_info )
	{
#if ( UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || ( UNITY_METRO && UNITY_EDITOR ) )
		HAPI_Result status_code = HAPI_GetGeoInfo( ref mySession, asset_id, object_id, geo_id, out geo_info );
		processStatusCode( status_code );
#else
		throw new HoudiniErrorUnsupportedPlatform();
#endif
	}
Example #12
0
	public static string[] getGroupNames(
		HAPI_AssetId asset_id, HAPI_ObjectId object_id, HAPI_GeoId geo_id,
		HAPI_GroupType group_type )
	{
#if ( UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || ( UNITY_METRO && UNITY_EDITOR ) )
		HAPI_GeoInfo geo_info = new HAPI_GeoInfo();
		HAPI_Result status_code = HAPI_GetGeoInfo( ref mySession, asset_id, object_id, geo_id, out geo_info );
		processStatusCode( status_code );

		int count = geo_info.getGroupCountByType( group_type );

		int[] names = new int[ count ];
		status_code = HAPI_GetGroupNames(
			ref mySession, asset_id, object_id, geo_id, group_type, names, count );
		processStatusCode( status_code );

		string[] name_strings = new string[ count ];
		for ( int i = 0; i < count; ++i )
			name_strings[ i ] = getString( names[ i ] );

		return name_strings;
#else
		throw new HoudiniErrorUnsupportedPlatform();
#endif
	}
Example #13
0
	HAPI_SetGeoInfo(
		ref HAPI_Session session,
		HAPI_AssetId asset_id, HAPI_ObjectId object_id, HAPI_GeoId geo_id,
		ref HAPI_GeoInfo geo_info );
Example #14
0
    private static extern HAPI_Result HAPI_SetGeoInfo(
		ref HAPI_Session session,
		HAPI_AssetId asset_id, HAPI_ObjectId object_id, HAPI_GeoId geo_id,
		ref HAPI_GeoInfo geo_info );
Example #15
0
    public void instanceObjects(HoudiniProgressBar progress_bar)
    {
        try
        {
            destroyChildren();

            HAPI_ObjectInfo object_info = HoudiniHost.getObjectInfo(prObjectId);

            // Get Detail info.
            HAPI_GeoInfo geo_info = HoudiniHost.getDisplayGeoInfo(prObjectId);
            if (geo_info.partCount == 0)
            {
                return;
            }

            cacheNumInstances();

            HAPI_Transform[] instance_transforms = new HAPI_Transform[myNumInstances];
            Utility.getArray2Id(
                geo_info.nodeId, HAPI_RSTOrder.HAPI_SRT,
                HoudiniHost.getInstanceTransforms, instance_transforms, myNumInstances);

            // Get scale point attributes.
            HAPI_AttributeInfo scale_attr_info = new HAPI_AttributeInfo("scale");
            float[]            scale_attr      = new float[0];
            Utility.getAttribute(
                geo_info.nodeId, 0, "scale", ref scale_attr_info, ref scale_attr, HoudiniHost.getAttributeFloatData);

            if (scale_attr_info.exists && scale_attr_info.owner != HAPI_AttributeOwner.HAPI_ATTROWNER_POINT)
            {
                throw new HoudiniErrorIgnorable("I only understand scale as point attributes!");
            }

            if (scale_attr_info.exists && scale_attr.Length != myNumInstances * 3)
            {
                throw new HoudiniError(
                          "Unexpected scale array length found for asset: " + prAsset.prAssetId + "!\n" +
                          "Expected length of: " + myNumInstances * 3 + " but given: " + scale_attr.Length);
            }

            HAPI_AttributeInfo script_attr_info = new HAPI_AttributeInfo("Unity_Script");
            int[] script_attr = new int[0];
            Utility.getAttribute(
                geo_info.nodeId, 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_POINT)
            {
                throw new HoudiniErrorIgnorable("I only understand Unity_Script as point attributes!");
            }

            if (script_attr_info.exists && script_attr.Length != myNumInstances)
            {
                throw new HoudiniError("Unexpected Unity_Script array length found for asset: " + prAsset.prAssetId + "!");
            }

            int[] instance_attr = null;
            int[] name_attr     = null;
            getInstanceAndNameAttrs(out instance_attr, out name_attr);

            progress_bar.prTotal = myNumInstances;

            List <int> exclusion_list = new List <int>();
            instanceOverriddenObjects(myNumInstances, exclusion_list);

            List <string> unique_instantiated_names        = new List <string>();
            HoudiniInstancerPersistentData persistent_data = prPersistentData;
            if (persistent_data.variationChoice.Count != myNumInstances)
            {
                if (myNumInstances > persistent_data.variationChoice.Count)
                {
                    int difference = myNumInstances - persistent_data.variationChoice.Count;
                    for (int ii = 0; ii < difference; ii++)
                    {
                        persistent_data.variationChoice.Add(-1);
                    }
                }
                else
                {
                    int difference = persistent_data.variationChoice.Count - myNumInstances;
                    persistent_data.variationChoice.RemoveRange(
                        persistent_data.variationChoice.Count - difference, difference);
                }
            }

            bool liveTransformPropagationSetting = false;
            bool syncAssetTransformSetting       = false;
            bool enableCooking = true;
            for (int i = 0; i < myNumInstances; ++i)
            {
                if (exclusion_list.Contains(i))
                {
                    continue;
                }

                GameObject obj_to_instance = null;

                if (instance_attr.Length > 0 || name_attr.Length > 0)
                {
                    if (name_attr.Length > 0)
                    {
                        string obj_name     = HoudiniHost.getString(name_attr[i]);
                        int    object_index = prAsset.findObjectByName(obj_name);

                        if (object_index >= 0)
                        {
                            obj_to_instance = prAsset.prGameObjects[object_index];
                        }
                        else
                        {
                            obj_to_instance = prAsset.findPartByName(obj_name, true);
                        }

                        if (obj_to_instance == null)
                        {
                            obj_to_instance = GameObject.Find(obj_name);
                        }
                    }
                    else
                    {
                        string    instanceObjectPath = HoudiniHost.getString(instance_attr[i]);
                        string [] pathItems          = instanceObjectPath.Split('/');
                        string    instanceObjectName = pathItems[pathItems.Length - 1];

                        int objectIndex = prAsset.findObjectByName(instanceObjectName);
                        if (objectIndex >= 0)
                        {
                            obj_to_instance = prAsset.prGameObjects[objectIndex];
                        }
                        else
                        {
                            obj_to_instance = GameObject.Find(instanceObjectName);
                        }
                    }

                    if (obj_to_instance != null)
                    {
                        HoudiniAsset hapi_asset = obj_to_instance.GetComponent <HoudiniAsset>();
                        if (hapi_asset != null)
                        {
                            liveTransformPropagationSetting = hapi_asset.prTransformChangeTriggersCooks;
                            syncAssetTransformSetting       = hapi_asset.prPushUnityTransformToHoudini;
                            enableCooking = hapi_asset.prEnableCooking;
                            hapi_asset.prTransformChangeTriggersCooks = false;
                            hapi_asset.prPushUnityTransformToHoudini  = false;
                            hapi_asset.prEnableCooking = false;
                        }
                    }
                }
                else if (object_info.objectToInstanceId >= 0)
                {
                    int object_to_instance_idx = prAsset.findObjectByNodeId(object_info.objectToInstanceId);
                    if (object_to_instance_idx >= 0)
                    {
                        obj_to_instance = prAsset.prGameObjects[object_to_instance_idx];
                    }
                }

                if (obj_to_instance != null)
                {
                    // Set progress bar information.
                    progress_bar.prCurrentValue = i;
                    progress_bar.prMessage      = "Instancing: " + obj_to_instance.name + " (" + i + " of " + myNumInstances + ")";
                    progress_bar.displayProgressBar();

                    if (!unique_instantiated_names.Contains(obj_to_instance.name))
                    {
                        unique_instantiated_names.Add(obj_to_instance.name);
                    }

                    Vector3 pos = new Vector3();

                    // Apply object transforms.
                    //
                    // Axis and Rotation conversions:
                    // Note that Houdini's X axis points in the opposite direction that Unity's does.  Also, Houdini's
                    // rotation is right handed, whereas Unity is left handed.  To account for this, we need to invert
                    // the x coordinate of the translation, and do the same for the rotations (except for the x rotation,
                    // which doesn't need to be flipped because the change in handedness AND direction of the left x axis
                    // causes a double negative - yeah, I know).

                    pos[0] = -instance_transforms[i].position[0];
                    pos[1] = instance_transforms[i].position[1];
                    pos[2] = instance_transforms[i].position[2];

                    Quaternion quat = new Quaternion(instance_transforms[i].rotationQuaternion[0],
                                                     instance_transforms[i].rotationQuaternion[1],
                                                     instance_transforms[i].rotationQuaternion[2],
                                                     instance_transforms[i].rotationQuaternion[3]);

                    Vector3 euler = quat.eulerAngles;
                    euler.y = -euler.y;
                    euler.z = -euler.z;

                    Vector3 scale = new Vector3(instance_transforms[i].scale[0],
                                                instance_transforms[i].scale[1],
                                                instance_transforms[i].scale[2]);



                    Matrix4x4 local_mat = new Matrix4x4();
                    local_mat.SetTRS(pos, Quaternion.Euler(euler), scale);

                    // TODO: Now this *should* be the transform.localToWorldMatrix
                    // but for some reason, after a scene load, we pick up compensating
                    // factors in the local transform that cancel out the transform on the
                    // asset.  For now just use the asset's transform as the parent matrix.
                    Matrix4x4 parent_mat = prAsset.transform.localToWorldMatrix;
                    Matrix4x4 global_mat = parent_mat * local_mat;


                    euler = HoudiniAssetUtility.getQuaternion(global_mat).eulerAngles;
                    pos   = HoudiniAssetUtility.getPosition(global_mat);
                    scale = HoudiniAssetUtility.getScale(global_mat);


                    //mat.SetTRS( pos,

                    string script_to_attach = "";
                    if (script_attr_info.exists)
                    {
                        script_to_attach = HoudiniHost.getString(script_attr[i]);
                    }
                    instanceObject(obj_to_instance,
                                   pos,
                                   euler,
                                   i,
                                   scale_attr_info.exists,
                                   scale,
                                   script_attr_info.exists,
                                   script_to_attach);


                    HoudiniAsset hapi_asset = obj_to_instance.GetComponent <HoudiniAsset>();
                    if (hapi_asset != null)
                    {
                        hapi_asset.prTransformChangeTriggersCooks = liveTransformPropagationSetting;
                        hapi_asset.prPushUnityTransformToHoudini  = syncAssetTransformSetting;
                        hapi_asset.prEnableCooking = enableCooking;
                    }
                }
            }

            updateUniqueInstantiatedNames(unique_instantiated_names);
        }
        catch (HoudiniError error)
        {
            Debug.LogWarning(error.ToString());
            return;
        }
    }
Example #16
0
 HAPI_GetGeoInfo(
     HAPI_AssetId asset_id, HAPI_ObjectId object_id, HAPI_GeoId geo_id,
     out HAPI_GeoInfo geo_info);
Example #17
0
	public void instanceObjects( HoudiniProgressBar progress_bar )
	{
		try
		{
			destroyChildren();
			
			HAPI_ObjectInfo object_info = prAsset.prObjects[ prObjectId ];
			
			// Get Detail info.
			HAPI_GeoInfo geo_info = new HAPI_GeoInfo();
			HoudiniHost.getGeoInfo( prAsset.prAssetId, prObjectId, 0, out geo_info );
			if ( geo_info.partCount == 0 )
				return;
			
			cacheNumInstances();
											
			HAPI_Transform[] instance_transforms = new HAPI_Transform[ myNumInstances ];
			Utility.getArray4Id( prAsset.prAssetId, prObjectId, 0, HAPI_RSTOrder.HAPI_SRT, 
								 HoudiniHost.getInstanceTransforms, instance_transforms, myNumInstances );
			
			// Get scale point attributes.
			HAPI_AttributeInfo scale_attr_info = new HAPI_AttributeInfo( "scale" );
			float[] scale_attr = new float[ 0 ];
			Utility.getAttribute( prAsset.prAssetId, prObjectId, 0, 0, "scale",
								  ref scale_attr_info, ref scale_attr, HoudiniHost.getAttributeFloatData );
			
			if ( scale_attr_info.exists && scale_attr_info.owner != HAPI_AttributeOwner.HAPI_ATTROWNER_POINT )
				throw new HoudiniErrorIgnorable( "I only understand scale as point attributes!" );
			
			if ( scale_attr_info.exists && scale_attr.Length != myNumInstances * 3 )
				throw new HoudiniError( 
					"Unexpected scale array length found for asset: " + prAsset.prAssetId + "!\n" +
					"Expected length of: " + myNumInstances * 3 + " but given: " + scale_attr.Length );
			
						
			HAPI_AttributeInfo script_attr_info = new HAPI_AttributeInfo( "Unity_Script" );
			int[] script_attr = new int[ 0 ];
			Utility.getAttribute( prAsset.prAssetId, prObjectId, 0, 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_POINT )
				throw new HoudiniErrorIgnorable( "I only understand Unity_Script as point attributes!" );
			
			if ( script_attr_info.exists && script_attr.Length != myNumInstances )
				throw new HoudiniError( "Unexpected Unity_Script array length found for asset: " + prAsset.prAssetId + "!" );
						
			
			int[] instance_attr = null;
			int[] name_attr = null;
			getInstanceAndNameAttrs(out instance_attr,out name_attr );
			
			progress_bar.prTotal = myNumInstances;
			
			List <int> exclusion_list = new List<int>();
			instanceOverriddenObjects( myNumInstances, exclusion_list );

			List < string > unique_instantiated_names = new List< string >();
			HoudiniInstancerPersistentData persistent_data = prPersistentData;
			if( persistent_data.variationChoice.Count != myNumInstances )
			{
				if( myNumInstances > persistent_data.variationChoice.Count )
				{
					int difference = myNumInstances - persistent_data.variationChoice.Count;
					for( int ii = 0; ii < difference; ii++ )
					{
						persistent_data.variationChoice.Add( -1 );
					}
				}
				else
				{
					int difference = persistent_data.variationChoice.Count - myNumInstances;
					persistent_data.variationChoice.RemoveRange(
						persistent_data.variationChoice.Count - difference, difference );
				}
			}

			bool liveTransformPropagationSetting	= false;
			bool syncAssetTransformSetting			= false;
			bool enableCooking						= true;
			for ( int ii = 0; ii < myNumInstances; ++ii )
			{
				if ( exclusion_list.Contains( ii ) )
					continue;
				
				GameObject objToInstantiate = null;
				
				if ( instance_attr.Length > 0 || name_attr.Length > 0 )
				{					
					if( name_attr.Length > 0 )
					{
						string obj_name	= HoudiniHost.getString( name_attr[ ii ] );
						int object_index = prAsset.findObjectByName( obj_name );
						if ( object_index >= 0 )
						{
							objToInstantiate = prAsset.prGameObjects[ object_index ];
						}
						else
						{
							objToInstantiate = prAsset.findPartByName( obj_name, true );
						}

						if( objToInstantiate == null )
						{
							objToInstantiate = GameObject.Find( obj_name );
						}
					}
					else 
					{
						string instanceObjectPath	= HoudiniHost.getString( instance_attr[ ii ] );
						string[] pathItems			= instanceObjectPath.Split('/');
						string instanceObjectName	= pathItems[ pathItems.Length - 1 ];
																																		
						int objectIndex = prAsset.findObjectByName( instanceObjectName );
						if ( objectIndex >= 0 )
							objToInstantiate = prAsset.prGameObjects[ objectIndex ];
						else
							objToInstantiate = GameObject.Find( instanceObjectName );
					}

					if ( objToInstantiate != null )
					{
						HoudiniAsset hapi_asset = objToInstantiate.GetComponent< HoudiniAsset >();
						if ( hapi_asset != null )
						{
							liveTransformPropagationSetting				= hapi_asset.prTransformChangeTriggersCooks;
							syncAssetTransformSetting					= hapi_asset.prPushUnityTransformToHoudini;
							enableCooking								= hapi_asset.prEnableCooking;
							hapi_asset.prTransformChangeTriggersCooks	= false;
							hapi_asset.prPushUnityTransformToHoudini	= false;
							hapi_asset.prEnableCooking					= false;
						}
					}
				}
				else if ( object_info.objectToInstanceId >= 0 )
					objToInstantiate = prAsset.prGameObjects[ object_info.objectToInstanceId ];

				if ( objToInstantiate != null )
				{
					// Set progress bar information.
					progress_bar.prCurrentValue = ii;
					progress_bar.prMessage = "Instancing: " + objToInstantiate.name + " (" + ii + " of " + myNumInstances + ")";
					progress_bar.displayProgressBar();

					if ( !unique_instantiated_names.Contains( objToInstantiate.name ) )
					{
						unique_instantiated_names.Add( objToInstantiate.name );
					}
	
					Vector3 pos = new Vector3();
					
					// Apply object transforms.
					//
					// Axis and Rotation conversions:
					// Note that Houdini's X axis points in the opposite direction that Unity's does.  Also, Houdini's 
					// rotation is right handed, whereas Unity is left handed.  To account for this, we need to invert
					// the x coordinate of the translation, and do the same for the rotations (except for the x rotation,
					// which doesn't need to be flipped because the change in handedness AND direction of the left x axis
					// causes a double negative - yeah, I know).
					
					pos[ 0 ] = -instance_transforms[ ii ].position[ 0 ];
					pos[ 1 ] =  instance_transforms[ ii ].position[ 1 ];
					pos[ 2 ] =  instance_transforms[ ii ].position[ 2 ];
					
					Quaternion quat = new Quaternion( 	instance_transforms[ ii ].rotationQuaternion[ 0 ],
														instance_transforms[ ii ].rotationQuaternion[ 1 ],
														instance_transforms[ ii ].rotationQuaternion[ 2 ],
														instance_transforms[ ii ].rotationQuaternion[ 3 ] );
					
					Vector3 euler = quat.eulerAngles;
					euler.y = -euler.y;
					euler.z = -euler.z;
					
					Vector3 scale = new Vector3 ( instance_transforms[ ii ].scale[ 0 ],
												  instance_transforms[ ii ].scale[ 1 ],
												  instance_transforms[ ii ].scale[ 2 ] );
					
					
					
					Matrix4x4 local_mat = new Matrix4x4();
					local_mat.SetTRS( pos, Quaternion.Euler( euler ), scale );

					// TODO: Now this *should* be the transform.localToWorldMatrix
					// but for some reason, after a scene load, we pick up compensating
					// factors in the local transform that cancel out the transform on the
					// asset.  For now just use the asset's transform as the parent matrix.
					Matrix4x4 parent_mat = prAsset.transform.localToWorldMatrix;
					Matrix4x4 global_mat = parent_mat * local_mat;

					
					euler = HoudiniAssetUtility.getQuaternion( global_mat ).eulerAngles;
					pos = HoudiniAssetUtility.getPosition( global_mat );
					scale = HoudiniAssetUtility.getScale( global_mat );
					
						
					//mat.SetTRS( pos, 
					
					string script_to_attach = "";
					if( script_attr_info.exists )
						script_to_attach = HoudiniHost.getString( script_attr[ ii ] );
					instanceObject( objToInstantiate, 
								 	pos,
									euler,									
								 	ii,
									scale_attr_info.exists,
									scale,
									script_attr_info.exists,
									script_to_attach );
						

					HoudiniAsset hapi_asset = objToInstantiate.GetComponent< HoudiniAsset >();
					if ( hapi_asset != null )
					{
						hapi_asset.prTransformChangeTriggersCooks	= liveTransformPropagationSetting;
						hapi_asset.prPushUnityTransformToHoudini			= syncAssetTransformSetting;
						hapi_asset.prEnableCooking				= enableCooking;
					}

				}
			}

			updateUniqueInstantiatedNames( unique_instantiated_names );


		}
		catch ( HoudiniError error )
		{
			Debug.LogWarning( error.ToString() );
			return;
		}
	}
Example #18
0
	private void cacheNumInstances()
	{
		HAPI_ObjectInfo object_info = prAsset.prObjects[ prObjectId ];
			
		// Get Detail info.
		HAPI_GeoInfo geo_info = new HAPI_GeoInfo();
		HoudiniHost.getGeoInfo( prAsset.prAssetId, prObjectId, 0, out geo_info );
		if ( geo_info.partCount == 0 )
			return;
		
		HAPI_PartInfo part_info = new HAPI_PartInfo();
		HoudiniHost.getPartInfo( prAsset.prAssetId, prObjectId, 0, 0, out part_info );
		if ( prAsset.prEnableLogging )
			Debug.Log( "Instancer #" + prObjectId + " (" + object_info.name + "): "
					   + "points: " + part_info.pointCount );
				
		if ( part_info.pointCount > 65000 )
			throw new HoudiniError( "Point count (" + part_info.pointCount + ") above limit (" + 65000 + ")!" );
		
		myNumInstances = part_info.pointCount;
	}
Example #19
0
 HAPI_SetGeoInfo(
     HAPI_AssetId asset_id, HAPI_ObjectId object_id, HAPI_GeoId geo_id,
     ref HAPI_GeoInfo geo_info);
Example #20
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);
                }
            }
        }
    }
    public bool refresh(bool reload_asset, HAPI_ObjectInfo object_info)
    {
        bool needs_recook = false;

        if (reload_asset)
        {
            for (int i = 0; i < myGeos.Count; ++i)
            {
                if (myGeos[i])
                {
                    HoudiniAssetUtility.destroyGameObject(myGeos[i]);
                }
            }
            myGeos.Clear();
        }

        if (reload_asset || object_info.haveGeosChanged)
        {
            // Get the GeoInfos of the display geo node
            HAPI_GeoInfo display_geo_info = HoudiniHost.getDisplayGeoInfo(prObjectId);
            int          GeoCount         = object_info.geoCount = 1;

            // Add new geos as needed.
            while (myGeos.Count < GeoCount)
            {
                myGeos.Add(createGeo(display_geo_info.nodeId));
            }

            int node_id = object_info.nodeId;
            if (prAsset.prNodeInfo.type == HAPI_NodeType.HAPI_NODETYPE_SOP)
            {
                node_id = display_geo_info.nodeId;
            }

            // Look for editable nodes inside the network/the object
            const bool recursive         = true;
            int[]      editable_networks = HoudiniHost.getChildNodeList(
                node_id,
                (int)HAPI_NodeType.HAPI_NODETYPE_SOP,
                (int)HAPI_NodeFlags.HAPI_NODEFLAGS_EDITABLE,
                recursive);

            // Add the editable nodes to it
            for (int n = 0; n < editable_networks.Length; n++)
            {
                // The editable node has to be cooked first
                HoudiniHost.cookNode(editable_networks[n]);

                HAPI_GeoInfo editGeoInfo = HoudiniHost.getGeoInfo(editable_networks[n]);
                myGeos.Add(createGeo(editGeoInfo.nodeId));
                GeoCount++;
            }

            // Remove stale geos.
            while (myGeos.Count > GeoCount)
            {
                HoudiniAssetUtility.destroyGameObject(myGeos[GeoCount]);
                myGeos.RemoveAt(GeoCount);
            }

            // Refresh all geos.
            for (int i = 0; i < myGeos.Count; ++i)
            {
                needs_recook |= myGeos[i].GetComponent <HoudiniGeoControl>().refresh(reload_asset);
            }
        }

        return(needs_recook);
    }