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; }
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()); } }
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); }
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); }
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);
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; }
// 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 }
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 }
HAPI_SetGeoInfo( ref HAPI_Session session, HAPI_AssetId asset_id, HAPI_ObjectId object_id, HAPI_GeoId geo_id, ref HAPI_GeoInfo geo_info );
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 );
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; } }
HAPI_GetGeoInfo( HAPI_AssetId asset_id, HAPI_ObjectId object_id, HAPI_GeoId geo_id, out HAPI_GeoInfo geo_info);
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; } }
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; }
HAPI_SetGeoInfo( HAPI_AssetId asset_id, HAPI_ObjectId object_id, HAPI_GeoId geo_id, ref HAPI_GeoInfo geo_info);
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); }