/// <summary> /// Connect the input to the merge object node /// </summary> /// <param name="session"></param> private void ConnectToMergeObject(HEU_SessionBase session) { if (_inputNodeType == InputNodeType.PARAMETER) { if (string.IsNullOrEmpty(_paramName)) { Debug.LogErrorFormat("Invalid parameter name for input node of parameter type!"); return; } if (!session.SetParamNodeValue(_nodeID, _paramName, _connectedNodeID)) { Debug.LogErrorFormat("Unable to connect to input node!"); return; } //Debug.LogFormat("Setting input connection for parameter {0} with {1} connecting to {2}", _paramName, _nodeID, _connectedNodeID); } else { if (!session.ConnectNodeInput(_nodeID, _inputIndex, _connectedNodeID)) { Debug.LogErrorFormat("Unable to connect to input node!"); return; } } }
private void ConnectInputNode(HEU_SessionBase session) { // Connect node input if (_inputNodeType == InputNodeType.PARAMETER) { if (string.IsNullOrEmpty(_paramName)) { Debug.LogErrorFormat("Invalid parameter name for input node of parameter type!"); return; } if (!session.SetParamNodeValue(_nodeID, _paramName, _connectedNodeID)) { Debug.LogErrorFormat("Unable to connect to input node!"); return; } //Debug.LogFormat("Setting input connection for parameter {0} with {1} connecting to {2}", _paramName, _nodeID, _connectedNodeID); } else { if(!session.ConnectNodeInput(_nodeID, _inputIndex, _connectedNodeID)) { Debug.LogErrorFormat("Unable to connect to input node!"); return; } } // This ensures that the input node's own object merge Keep World Transform // plays nicely with the connected object merge's Keep World Transform SetInputNodeObjectMergeKeepTransform(session, false); }
private void ConnectInputNode(HEU_SessionBase session) { // Connect node input if (_inputNodeType == InputNodeType.PARAMETER) { if (string.IsNullOrEmpty(_paramName)) { Debug.LogErrorFormat("Invalid parameter name for input node of parameter type!"); return; } if (!session.SetParamNodeValue(_nodeID, _paramName, _connectedNodeID)) { Debug.LogErrorFormat("Unable to connect to input node!"); return; } } else { if(!session.ConnectNodeInput(_nodeID, _inputIndex, _connectedNodeID)) { Debug.LogErrorFormat("Unable to connect to input node!"); return; } } }
public static bool CreateInputNodeWithMultiObjects(HEU_SessionBase session, HAPI_NodeId assetID, ref HAPI_NodeId connectedAssetID, ref List<HEU_InputObjectInfo> inputObjects, ref List<HAPI_NodeId> inputObjectsConnectedAssetIDs, bool bKeepWorldTransform) { // Create the merge SOP node. if (!session.CreateNode(-1, "SOP/merge", null, true, out connectedAssetID)) { Debug.LogErrorFormat("Unable to create merge SOP node for connecting input assets."); return false; } int numObjects = inputObjects.Count; for (int i = 0; i < numObjects; ++i) { HAPI_NodeId meshNodeID = HEU_Defines.HEU_INVALID_NODE_ID; inputObjectsConnectedAssetIDs.Add(meshNodeID); // Skipping null gameobjects. Though if this causes issues, can always let it continue // to create input node, but not upload mesh data if (inputObjects[i]._gameObject == null) { continue; } bool bResult = CreateInputNodeWithGeoData(session, assetID, inputObjects[i]._gameObject, out meshNodeID); if (!bResult || meshNodeID == HEU_Defines.HEU_INVALID_NODE_ID) { string errorMsg = string.Format("Input at index {0} is not valid", i); if (inputObjects[i]._gameObject.GetComponent<HEU_HoudiniAssetRoot>() != null) { errorMsg += " because it is an HDA. Change the Input Type to HDA."; } else if (inputObjects[i]._gameObject.GetComponent<MeshFilter>() == null || inputObjects[i]._gameObject.GetComponent<MeshFilter>().sharedMesh == null) { errorMsg += " because it does not have a valid Mesh. Make sure the GameObject has a MeshFilter component with a valid mesh."; } else { errorMsg += ". Unable to create input node."; } Debug.LogErrorFormat(errorMsg); // Skipping this and continuing input processing since this isn't a deal breaker continue; } inputObjectsConnectedAssetIDs[i] = meshNodeID; if (!session.ConnectNodeInput(connectedAssetID, i, meshNodeID)) { Debug.LogErrorFormat("Unable to connect input nodes!"); return false; } UploadInputObjectTransform(session, inputObjects[i], meshNodeID, bKeepWorldTransform); } return true; }
internal static bool CreateInputNodeWithMultiAssets(HEU_SessionBase session, HEU_HoudiniAsset parentAsset, ref HAPI_NodeId connectMergeID, ref List<HEU_InputHDAInfo> inputAssetInfos, bool bKeepWorldTransform, HAPI_NodeId mergeParentID = -1) { // Create the merge SOP node that the input nodes are going to connect to. if (!session.CreateNode(mergeParentID, "SOP/merge", null, true, out connectMergeID)) { HEU_Logger.LogErrorFormat("Unable to create merge SOP node for connecting input assets."); return false; } int numInputs = inputAssetInfos.Count; for (int i = 0; i < numInputs; ++i) { inputAssetInfos[i]._connectedInputNodeID = HEU_Defines.HEU_INVALID_NODE_ID; if (inputAssetInfos[i]._pendingGO == null) { continue; } // ID of the asset that will be connected HAPI_NodeId inputAssetID = HEU_Defines.HEU_INVALID_NODE_ID; HEU_HoudiniAssetRoot inputAssetRoot = inputAssetInfos[i]._pendingGO.GetComponent<HEU_HoudiniAssetRoot>(); if (inputAssetRoot != null && inputAssetRoot._houdiniAsset != null) { if (!inputAssetRoot._houdiniAsset.IsAssetValidInHoudini(session)) { // Force a recook if its not valid (in case it hasn't been loaded into the session) inputAssetRoot._houdiniAsset.RequestCook(true, false, true, true); } inputAssetID = inputAssetRoot._houdiniAsset.AssetID; } if (inputAssetID == HEU_Defines.HEU_INVALID_NODE_ID) { continue; } if (!session.ConnectNodeInput(connectMergeID, i, inputAssetID)) { HEU_Logger.LogErrorFormat("Unable to connect input nodes!"); return false; } inputAssetInfos[i]._connectedInputNodeID = inputAssetID; inputAssetInfos[i]._connectedGO = inputAssetInfos[i]._pendingGO; inputAssetInfos[i]._connectedMergeNodeID = connectMergeID; parentAsset.ConnectToUpstream(inputAssetRoot._houdiniAsset); } return true; }
/// <summary> /// Create an input node network and upload the given set of input objects. /// This creates a SOP/merge node, and input nodes for each object in inputObjects /// which are then connected to the merge node. /// It finds the input interface that supports each object in inputObjects for creating /// the input node and uploading the data based on the type of data. /// </summary> /// <param name="session">Session to create the input node in</param> /// <param name="assetID">Main asset ID</param> /// <param name="connectMergeID">Created SOP/merge node ID</param> /// <param name="inputObjects">List of input objects to upload</param> /// <param name="inputObjectsConnectedAssetIDs">List of input node IDs for the input nodes created</param> /// <param name="bKeepWorldTransform">Whether to use world transform for the input nodes</param> /// <returns>True if successfully uploading input nodes</returns> public static bool CreateInputNodeWithMultiObjects(HEU_SessionBase session, HAPI_NodeId assetID, ref HAPI_NodeId connectMergeID, ref List<HEU_InputObjectInfo> inputObjects, ref List<HAPI_NodeId> inputObjectsConnectedAssetIDs, bool bKeepWorldTransform) { // Create the merge SOP node that the input nodes are going to connect to. if (!session.CreateNode(-1, "SOP/merge", null, true, out connectMergeID)) { Debug.LogErrorFormat("Unable to create merge SOP node for connecting input assets."); return false; } int numObjects = inputObjects.Count; for (int i = 0; i < numObjects; ++i) { HAPI_NodeId newConnectInputID = HEU_Defines.HEU_INVALID_NODE_ID; inputObjectsConnectedAssetIDs.Add(newConnectInputID); // Skipping null gameobjects. Though if this causes issues, can always let it continue // to create input node, but not upload mesh data if (inputObjects[i]._gameObject == null) { continue; } HEU_InputInterface inputInterface = GetInputInterface(inputObjects[i]); if (inputInterface == null) { Debug.LogWarningFormat("No input interface found for gameobject: {0}. Skipping upload!", inputObjects[i]._gameObject.name); continue; } bool bResult = inputInterface.CreateInputNodeWithDataUpload(session, connectMergeID, inputObjects[i]._gameObject, out newConnectInputID); if (!bResult || newConnectInputID == HEU_Defines.HEU_INVALID_NODE_ID) { Debug.LogError("Failed to upload input."); continue; } inputObjectsConnectedAssetIDs[i] = newConnectInputID; if (!session.ConnectNodeInput(connectMergeID, i, newConnectInputID)) { Debug.LogErrorFormat("Unable to connect input nodes!"); return false; } UploadInputObjectTransform(session, inputObjects[i], newConnectInputID, bKeepWorldTransform); } return true; }
/// <summary> /// Upload the alphamaps (terrain layers) into heightfield network. /// Note that this skips the base layer. /// </summary> /// <param name="session"></param> /// <param name="idt"></param> /// <returns></returns> public bool UploadAlphaMaps(HEU_SessionBase session, HEU_InputDataTerrain idt) { bool bResult = true; int alphaLayers = idt._terrainData.alphamapLayers; // Skip the base layer if (alphaLayers < 1) { return true; } int sizeX = idt._terrainData.alphamapWidth; int sizeY = idt._terrainData.alphamapHeight; int totalSize = sizeX * sizeY; float[,,] alphaMaps = idt._terrainData.GetAlphamaps(0, 0, sizeX, sizeY); float[][] alphaMapsConverted = new float[alphaLayers - 1][]; // Convert the alphamap layers to double arrays. // Note that we're skipping the base alpha map. for (int m = 0; m < alphaLayers - 1; ++m) { alphaMapsConverted[m] = new float[totalSize]; for (int j = 0; j < sizeY; j++) { for (int i = 0; i < sizeX; i++) { // Flip for coordinate system change float h = alphaMaps[i, (sizeY - j - 1), m + 1]; alphaMapsConverted[m][i + j * sizeX] = h; } } } // Create volume layers for all non-base alpha maps and upload values. for (int m = 0; m < alphaLayers - 1; ++m) { string layerName = "unity_alphamap_" + m + 1; HAPI_NodeId alphaLayerID = HEU_Defines.HEU_INVALID_NODE_ID; if (!session.CreateHeightfieldInputVolumeNode(idt._heightfieldNodeID, out alphaLayerID, layerName, Mathf.RoundToInt(sizeX * idt._voxelSize), Mathf.RoundToInt(sizeY * idt._voxelSize), idt._voxelSize)) { bResult = false; Debug.LogError("Failed to create input volume node for layer " + layerName); break; } if (!SetHeightFieldData(session, alphaLayerID, 0, alphaMapsConverted[m], layerName)) { bResult = false; break; } if (!session.CommitGeo(alphaLayerID)) { bResult = false; Debug.LogError("Failed to commit volume layer " + layerName); break; } // Connect to the merge node but starting from index 1 since index 0 is height layer if (!session.ConnectNodeInput(idt._mergeNodeID, m + 2, alphaLayerID, 0)) { bResult = false; Debug.LogError("Unable to connect new volume node for layer " + layerName); break; } } return bResult; }
/// <summary> /// Creates a mesh input node and uploads the mesh data from inputObject. /// </summary> /// <param name="session">Session that connectNodeID exists in</param> /// <param name="connectNodeID">The node to connect the network to. Most likely a SOP/merge node</param> /// <param name="inputObject">The gameobject containing the mesh components</param> /// <param name="inputNodeID">The created input node ID</param> /// <returns>True if created network and uploaded mesh data.</returns> public override bool CreateInputNodeWithDataUpload(HEU_SessionBase session, HAPI_NodeId connectNodeID, GameObject inputObject, out HAPI_NodeId inputNodeID) { inputNodeID = HEU_Defines.HEU_INVALID_NODE_ID; // Create input node, cook it, then upload the geometry data if (!HEU_HAPIUtility.IsNodeValidInHoudini(session, connectNodeID)) { HEU_Logger.LogError("Connection node is invalid."); return false; } bool bExportColliders = settings != null && settings.ExportColliders == true; // Get upload meshes from input object HEU_InputDataMeshes inputMeshes = GenerateMeshDatasFromGameObject(inputObject, bExportColliders); if (inputMeshes == null || inputMeshes._inputMeshes == null || inputMeshes._inputMeshes.Count == 0) { HEU_Logger.LogError("No valid meshes found on input objects."); return false; } string inputName = null; HAPI_NodeId newNodeID = HEU_Defines.HEU_INVALID_NODE_ID; session.CreateInputNode(out newNodeID, inputName); if (newNodeID == HEU_Defines.HEU_INVALID_NODE_ID || !HEU_HAPIUtility.IsNodeValidInHoudini(session, newNodeID)) { HEU_Logger.LogError("Failed to create new input node in Houdini session!"); return false; } inputNodeID = newNodeID; if (!UploadData(session, inputNodeID, inputMeshes)) { if (!session.CookNode(inputNodeID, false)) { HEU_Logger.LogError("New input node failed to cook!"); return false; } return false; } bool createMergeNode = false; HAPI_NodeId mergeNodeId = HEU_Defines.HEU_INVALID_NODE_ID; if (bExportColliders) { createMergeNode = true; } if (!createMergeNode) { return true; } HAPI_NodeId parentId = HEU_HAPIUtility.GetParentNodeID(session, newNodeID); if (!session.CreateNode(parentId, "merge", null, false, out mergeNodeId)) { HEU_Logger.LogErrorFormat("Unable to create merge SOP node for connecting input assets."); return false; } if (!session.ConnectNodeInput(mergeNodeId, 0, newNodeID)) { HEU_Logger.LogErrorFormat("Unable to connect to input node!"); return false; } if (!session.SetNodeDisplay(mergeNodeId, 1)) { HEU_Logger.LogWarningFormat("Unable to set display flag!"); } inputNodeID = mergeNodeId; if (bExportColliders) { if (!UploadColliderData(session, mergeNodeId, inputMeshes, parentId)) { return false; } } if (!session.CookNode(inputNodeID, false)) { HEU_Logger.LogError("New input node failed to cook!"); return false; } return true; }
internal bool UploadCapsuleColliderData(HEU_SessionBase session, CapsuleCollider collider, int inputIndex, HAPI_NodeId parentNodeID, out HAPI_NodeId inputNodeID) { inputNodeID = HEU_Defines.HEU_INVALID_NODE_ID; if (!collider) return false; // Copied from Unreal FKSphylElem::GetElemSolid because exact Unity capsule source code is not available Vector3 sphereCenter = collider.center; float sphereRadius = collider.radius; float sphereLength = collider.height; // Height in Unreal is only the line segment. Height in Unity is the total length, so to get the line length, subtract 2 * rad sphereLength = Mathf.Max(sphereLength - 2 * sphereRadius, 0); int direction = collider.direction; // 0 = X, 1 = Y, 2 = Z. Default is Y // Unreal Y -> Unity X, Unreal Z -> Unity Y int numSides = 6; int numRings = (numSides / 2) + 1; int numVerts = (numSides + 1) * (numRings + 1); // Calculate the vertices for one arc Vector3[] arcVertices = new Vector3[numRings + 1]; for (int ringIdx = 0; ringIdx < numRings + 1; ringIdx++) { float angle; float zOffset; if (ringIdx <= numSides / 4) { angle = ((float) ringIdx / (numRings - 1)) * Mathf.PI; zOffset = 0.5f * sphereLength; } else { angle = ((float)(ringIdx - 1) / (numRings - 1) ) * Mathf.PI; zOffset = -0.5f * sphereLength; } // Note- unit sphere, so position always has mag of one. We can just use it for normal! Vector3 spherePos = new Vector3(); spherePos.x = sphereRadius * Mathf.Sin(angle); spherePos.y = sphereRadius * Mathf.Cos(angle); spherePos.z = 0; arcVertices[ringIdx] = spherePos + new Vector3(0, zOffset, 0); } Vector3 directionRotationEuler = Vector3.zero; if (direction == 1) { // Y axis - This is the default after Unity unit conversion directionRotationEuler = Vector3.zero; } else if (direction == 0) { // X axis - Rotate around Z directionRotationEuler = new Vector3(0, 0, 90); } else if (direction == 2) { // Z axis - Rotate around X directionRotationEuler = new Vector3(90, 0, 0); } Quaternion directionRotation = Quaternion.Euler(directionRotationEuler); // Get the transform matrix for the rotation // Get the capsule vertices by rotating the arc NumSides+1 times float[] vertices = new float[numVerts * 3]; for (int sideIdx = 0; sideIdx < numSides + 1; sideIdx++) { Vector3 arcEuler = new Vector3(0, 360.0f *((float)sideIdx / (float)numSides), 0); Quaternion arcRot = Quaternion.Euler(arcEuler); for (int vertIdx = 0; vertIdx < numRings + 1; vertIdx++) { int vIx = (numRings + 1) * sideIdx + vertIdx; Vector3 arcVertex = arcRot * arcVertices[vertIdx]; arcVertex = directionRotation * arcVertex; Vector3 curPosition = sphereCenter + arcVertex; HEU_HAPIUtility.ConvertPositionUnityToHoudini(curPosition, out vertices[vIx * 3 + 0], out vertices[vIx * 3 + 1], out vertices[vIx * 3 + 2]); } } int numIndices = numSides * numRings * 6; int[] indices = new int[numIndices]; int curIndex = 0; for (int sideIdx = 0; sideIdx < numSides; sideIdx++) { int a0start = (sideIdx + 0) * (numRings + 1); int a1start = (sideIdx + 1) * (numRings + 1); for (int ringIdx = 0; ringIdx < numRings; ringIdx++) { // First tri (reverse winding) indices[curIndex+0] = a0start + ringIdx + 0; indices[curIndex+2] = a1start + ringIdx + 0; indices[curIndex+1] = a0start + ringIdx + 1; curIndex += 3; // Second Tri (reverse winding) indices[curIndex+0] = a1start + ringIdx + 0; indices[curIndex+2] = a1start + ringIdx + 1; indices[curIndex+1] = a0start + ringIdx + 1; curIndex += 3; } } HAPI_NodeId sphereNodeID = -1; string sphereName = string.Format("Sphyl{0}", inputIndex); if (!CreateInputNodeForCollider(session, out sphereNodeID, parentNodeID, inputIndex, sphereName, vertices, indices)) return false; if (!session.CookNode(sphereNodeID, false)) return false; HAPI_NodeId groupNodeID = HEU_Defines.HEU_INVALID_NODE_ID; string groupName = string.Format("group{0}", inputIndex); if (!session.CreateNode(parentNodeID, "groupcreate", groupName, false, out groupNodeID)) { HEU_Logger.LogErrorFormat("Unable to create group SOP node for connecting input assets."); return false; } HAPI_NodeId groupParmID = HEU_Defines.HEU_INVALID_NODE_ID; if (!session.GetParmIDFromName(groupNodeID, "groupname", out groupParmID) || groupParmID == HEU_Defines.HEU_INVALID_NODE_ID) return false; string baseGroupName = GetColliderGroupBaseName(collider, bIsConvex: false, bIsSimple: true); string groupNameStr = string.Format("{0}_capsule{1}", baseGroupName, inputIndex); if (!session.SetParamStringValue(groupNodeID, groupNameStr, groupParmID, 0)) return false; if (!session.ConnectNodeInput(groupNodeID, 0, sphereNodeID)) return false; inputNodeID = groupNodeID; return true; }
internal bool UploadSphereColliderData(HEU_SessionBase session, SphereCollider collider, int inputIndex, HAPI_NodeId parentNodeID, out HAPI_NodeId inputNodeID) { inputNodeID = HEU_Defines.HEU_INVALID_NODE_ID; if (!collider) return false; Vector3 center = HEU_HAPIUtility.ConvertPositionUnityToHoudini(collider.center); float radius = collider.radius; HAPI_NodeId sphereNodeID = HEU_Defines.HEU_INVALID_NODE_ID; string name = string.Format("Sphere{0}", inputIndex); if (!session.CreateNode(parentNodeID, "sphere", null, false, out sphereNodeID)) { HEU_Logger.LogErrorFormat("Unable to create merge box node for connecting input assets."); return false; } string radParamName = "rad"; if (!session.SetParamFloatValue(sphereNodeID, radParamName, 0, radius)) return false; if (!session.SetParamFloatValue(sphereNodeID, radParamName, 1, radius)) return false; if (!session.SetParamFloatValue(sphereNodeID, radParamName, 2, radius)) return false; string transformParamName = "t"; if (!session.SetParamFloatValue(sphereNodeID, transformParamName, 0, center.x)) return false; if (!session.SetParamFloatValue(sphereNodeID, transformParamName, 1, center.y)) return false; if (!session.SetParamFloatValue(sphereNodeID, transformParamName, 2, center.z)) return false; string typeParamName = "type"; if (!session.SetParamIntValue(sphereNodeID, typeParamName, 0, 1)) return false; if (!session.CookNode(sphereNodeID, false)) return false; HAPI_NodeId groupNodeID = HEU_Defines.HEU_INVALID_NODE_ID; string groupName = string.Format("group{0}", inputIndex); if (!session.CreateNode(parentNodeID, "groupcreate", groupName, false, out groupNodeID)) { HEU_Logger.LogErrorFormat("Unable to create group SOP node for connecting input assets."); return false; } HAPI_NodeId groupParmID = HEU_Defines.HEU_INVALID_NODE_ID; if (!session.GetParmIDFromName(groupNodeID, "groupname", out groupParmID) || groupParmID == HEU_Defines.HEU_INVALID_NODE_ID) return false; string baseGroupName = GetColliderGroupBaseName(collider, bIsConvex: false, bIsSimple: true); string groupNameStr = string.Format("{0}_sphere{1}", baseGroupName, inputIndex); if (!session.SetParamStringValue(groupNodeID, groupNameStr, groupParmID, 0)) return false; if (!session.ConnectNodeInput(groupNodeID, 0, sphereNodeID)) return false; inputNodeID = groupNodeID; return true; }
internal bool UploadBoxColliderData(HEU_SessionBase session, BoxCollider collider, int inputIndex, HAPI_NodeId parentNodeID, out HAPI_NodeId inputNodeID) { inputNodeID = HEU_Defines.HEU_INVALID_NODE_ID; if (!collider) return false; HAPI_NodeId boxNodeID = HEU_Defines.HEU_INVALID_NODE_ID; string name = string.Format("Box{0}", inputIndex); Vector3 center = HEU_HAPIUtility.ConvertPositionUnityToHoudini(collider.center); Vector3 size = HEU_HAPIUtility.ConvertScaleUnityToHoudini(collider.size); if (!session.CreateNode(parentNodeID, "box", null, false, out boxNodeID)) { HEU_Logger.LogErrorFormat("Unable to create merge box node for connecting input assets."); return false; } string sizeParamName = "size"; if (!session.SetParamFloatValue(boxNodeID, sizeParamName, 0, size.x)) return false; if (!session.SetParamFloatValue(boxNodeID, sizeParamName, 1, size.y)) return false; if (!session.SetParamFloatValue(boxNodeID, sizeParamName, 2, size.z)) return false; string transformParamName = "t"; if (!session.SetParamFloatValue(boxNodeID, transformParamName, 0, center.x)) return false; if (!session.SetParamFloatValue(boxNodeID, transformParamName, 1, center.y)) return false; if (!session.SetParamFloatValue(boxNodeID, transformParamName, 2, center.z)) return false; if (!session.CookNode(boxNodeID, false)) return false; HAPI_NodeId groupNodeID = HEU_Defines.HEU_INVALID_NODE_ID; string groupName = string.Format("group{0}", inputIndex); if (!session.CreateNode(parentNodeID, "groupcreate", groupName, false, out groupNodeID)) { HEU_Logger.LogErrorFormat("Unable to create group SOP node for connecting input assets."); return false; } HAPI_NodeId groupParmID = HEU_Defines.HEU_INVALID_NODE_ID; if (!session.GetParmIDFromName(groupNodeID, "groupname", out groupParmID) || groupParmID == HEU_Defines.HEU_INVALID_NODE_ID) return false; string baseGroupName = GetColliderGroupBaseName(collider, bIsConvex: false, bIsSimple: true); string groupNameStr = string.Format("{0}_box{1}", baseGroupName, inputIndex); if (!session.SetParamStringValue(groupNodeID, groupNameStr, groupParmID, 0)) return false; if (!session.ConnectNodeInput(groupNodeID, 0, boxNodeID)) return false; inputNodeID = groupNodeID; return true; }
internal bool UploadColliderData(HEU_SessionBase session, HAPI_NodeId mergeNodeID, HEU_InputDataMeshes inputData, HAPI_NodeId parentNodeId) { // The input to put on int inputIndex = 1; foreach (HEU_InputDataMesh inputMesh in inputData._inputMeshes) { if (inputMesh == null || inputMesh._colliders == null) { continue; } foreach (HEU_InputDataCollider colliderData in inputMesh._colliders) { if (colliderData == null || colliderData._collider == null || colliderData._colliderType == HEU_InputColliderType.NONE) { continue; } HAPI_NodeId newInputNodeID = HEU_Defines.HEU_INVALID_NODE_ID; switch (colliderData._colliderType) { case HEU_InputColliderType.BOX: BoxCollider boxCollider = colliderData._collider as BoxCollider; if (!boxCollider || !UploadBoxColliderData(session, boxCollider, inputIndex, parentNodeId, out newInputNodeID)) { HEU_Logger.LogWarning("Invalid collider input!"); continue; } break; case HEU_InputColliderType.SPHERE: SphereCollider sphereCollider = colliderData._collider as SphereCollider; if (!sphereCollider || !UploadSphereColliderData(session, sphereCollider, inputIndex, parentNodeId, out newInputNodeID)) { HEU_Logger.LogWarning("Invalid collider input!"); continue; } break; case HEU_InputColliderType.CAPSULE: CapsuleCollider capsuleCollider = colliderData._collider as CapsuleCollider; if (!capsuleCollider || !UploadCapsuleColliderData(session, capsuleCollider, inputIndex, parentNodeId, out newInputNodeID)) { HEU_Logger.LogWarning("Invalid collider input!"); return false; } break; case HEU_InputColliderType.MESH: MeshCollider meshCollider = colliderData._collider as MeshCollider; if (!meshCollider || !UploadMeshColliderData(session, meshCollider, inputIndex, parentNodeId, out newInputNodeID)) { HEU_Logger.LogWarning("Invalid collider input!"); return false; } break; default: HEU_Logger.LogWarning("Invalid collider type!"); return false; } if (newInputNodeID == HEU_Defines.HEU_INVALID_NODE_ID) continue; if (!session.ConnectNodeInput(mergeNodeID, inputIndex, newInputNodeID)) { HEU_Logger.LogErrorFormat("Unable to connect to input node!"); return false; } inputIndex++; } } return true; }
internal bool UploadMeshColliderData(HEU_SessionBase session, MeshCollider collider, int inputIndex, HAPI_NodeId parentNodeID, out HAPI_NodeId inputNodeID) { inputNodeID = HEU_Defines.HEU_INVALID_NODE_ID; if (!collider) return false; Mesh mesh = collider.sharedMesh; Vector3[] vertices = mesh.vertices; int numSubmeshes = mesh.subMeshCount; List<int> indices = new List<int>(); for (int i = 0; i < numSubmeshes; i++) { int[] indicesForSubmesh = mesh.GetIndices(i); indices.AddRange(indicesForSubmesh); } int[] indicesArr = indices.ToArray(); float[] verticesArr = new float[vertices.Length * 3]; for (int i = 0; i < vertices.Length; i++) { HEU_HAPIUtility.ConvertPositionUnityToHoudini(vertices[i], out verticesArr[i * 3 + 0], out verticesArr[i * 3 + 1], out verticesArr[i * 3 + 2]); } HAPI_NodeId meshNodeID = -1; string meshName = string.Format("MeshCollider{0}", inputIndex); if (!CreateInputNodeForCollider(session, out meshNodeID, parentNodeID, inputIndex, meshName, verticesArr, indicesArr)) return false; if (!session.CookNode(meshNodeID, false)) return false; HAPI_NodeId groupNodeID = HEU_Defines.HEU_INVALID_NODE_ID; string groupName = string.Format("group{0}", inputIndex); if (!session.CreateNode(parentNodeID, "groupcreate", groupName, false, out groupNodeID)) { HEU_Logger.LogErrorFormat("Unable to create group SOP node for connecting input assets."); return false; } HAPI_NodeId groupParmID = HEU_Defines.HEU_INVALID_NODE_ID; if (!session.GetParmIDFromName(groupNodeID, "groupname", out groupParmID) || groupParmID == HEU_Defines.HEU_INVALID_NODE_ID) return false; bool isConvex = collider.convex; string baseGroupName = GetColliderGroupBaseName(collider, bIsConvex: isConvex, bIsSimple: false); string groupNameStr = string.Format("{0}_mesh{1}", baseGroupName, inputIndex); if (!session.SetParamStringValue(groupNodeID, groupNameStr, groupParmID, 0)) return false; if (!session.ConnectNodeInput(groupNodeID, 0, meshNodeID)) return false; inputNodeID = groupNodeID; return true; }
/// <summary> /// Upload the alphamaps (TerrainLayers) into heightfield network. /// </summary> /// <param name="session"></param> /// <param name="idt"></param> /// <param name="baseVolumeInfo">The valid base height HAPI_VolumeInfo</param> /// <param name="bMaskSet">This is set to true if a mask layer was uploaded</param> /// <returns>True if successfully uploaded all layers</returns> public bool UploadAlphaMaps(HEU_SessionBase session, HEU_InputDataTerrain idt, ref HAPI_VolumeInfo baseVolumeInfo, out bool bMaskSet) { bool bResult = true; bMaskSet = false; int alphaLayers = idt._terrainData.alphamapLayers; if (alphaLayers < 1) { return(bResult); } int sizeX = idt._terrainData.alphamapWidth; int sizeY = idt._terrainData.alphamapHeight; int totalSize = sizeX * sizeY; float[,,] alphaMaps = idt._terrainData.GetAlphamaps(0, 0, sizeX, sizeY); float[][] alphaMapsConverted = new float[alphaLayers][]; // Convert the alphamap layers to double arrays. for (int m = 0; m < alphaLayers; ++m) { alphaMapsConverted[m] = new float[totalSize]; for (int j = 0; j < sizeY; j++) { for (int i = 0; i < sizeX; i++) { // Flip for coordinate system change float h = alphaMaps[i, (sizeY - j - 1), m]; alphaMapsConverted[m][i + j * sizeX] = h; } } } // Create volume layers for all alpha maps and upload values. bool bMaskLayer = false; int inputLayerIndex = 1; for (int m = 0; m < alphaLayers; ++m) { #if UNITY_2018_3_OR_NEWER string layerName = idt._terrainData.terrainLayers[m].name; #else string layerName = "unity_alphamap_" + m + 1; #endif // The Unity layer name could contain '.terrainlayer' and spaces. Remove them because Houdini doesn't allow // spaces, and the extension isn't necessary. layerName = layerName.Replace(" ", "_"); int extIndex = layerName.LastIndexOf(HEU_Defines.HEU_EXT_TERRAINLAYER); if (extIndex > 0) { layerName = layerName.Remove(extIndex); } //Debug.Log("Processing terrain layer: " + layerName); HAPI_NodeId alphaLayerID = HEU_Defines.HEU_INVALID_NODE_ID; if (layerName.Equals(HEU_Defines.HAPI_HEIGHTFIELD_LAYERNAME_HEIGHT)) { // Skip height (base) layer (since it has been uploaded already) continue; } else if (layerName.Equals(HEU_Defines.HAPI_HEIGHTFIELD_LAYERNAME_MASK)) { //Debug.Log("Mask layer found! Skipping creating the HF."); bMaskSet = true; bMaskLayer = true; alphaLayerID = idt._maskNodeID; } else { bMaskLayer = false; if (!session.CreateHeightfieldInputVolumeNode(idt._heightfieldNodeID, out alphaLayerID, layerName, Mathf.RoundToInt(sizeX * idt._voxelSize), Mathf.RoundToInt(sizeY * idt._voxelSize), idt._voxelSize)) { bResult = false; Debug.LogError("Failed to create input volume node for layer " + layerName); break; } } //Debug.Log("Uploading terrain layer: " + layerName); if (!SetHeightFieldData(session, alphaLayerID, 0, alphaMapsConverted[m], layerName, ref baseVolumeInfo)) { bResult = false; break; } #if UNITY_2018_3_OR_NEWER SetTerrainLayerAttributesToHeightField(session, alphaLayerID, 0, idt._terrainData.terrainLayers[m]); #endif if (!session.CommitGeo(alphaLayerID)) { bResult = false; Debug.LogError("Failed to commit volume layer " + layerName); break; } if (!bMaskLayer) { // Connect to the merge node but starting from index 1 since index 0 is height layer if (!session.ConnectNodeInput(idt._mergeNodeID, inputLayerIndex + 1, alphaLayerID, 0)) { bResult = false; Debug.LogError("Unable to connect new volume node for layer " + layerName); break; } inputLayerIndex++; } } return(bResult); }