/// <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); } //HEU_Logger.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)) { //HEU_Logger.Log("Mask layer found! Skipping creating the HF."); bMaskSet = true; bMaskLayer = true; alphaLayerID = idt._maskNodeID; float[,] heights = idt._terrainData.GetHeights(0, 0, idt._terrainData.heightmapResolution, idt._terrainData.heightmapResolution); int heightsSizeX = heights.GetLength(0); int heightsSizeY = heights.GetLength(1); alphaMapsConverted[m] = HEU_TerrainUtility.ResampleData(alphaMapsConverted[m], sizeX, sizeY, heightsSizeX, heightsSizeY); } 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; HEU_Logger.LogError("Failed to create input volume node for layer " + layerName); break; } } //HEU_Logger.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; HEU_Logger.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; HEU_Logger.LogError("Unable to connect new volume node for layer " + layerName); break; } inputLayerIndex++; } } return(bResult); }
/// <summary> /// Upload the base height layer into heightfield network. /// </summary> /// <param name="session"></param> /// <param name="idt"></param> /// <returns></returns> public bool UploadHeightValuesWithTransform(HEU_SessionBase session, HEU_InputDataTerrain idt, ref HAPI_VolumeInfo volumeInfo) { // Get Geo, Part, and Volume infos HAPI_GeoInfo geoInfo = new HAPI_GeoInfo(); if (!session.GetGeoInfo(idt._heightNodeID, ref geoInfo)) { HEU_Logger.LogError("Unable to get geo info from heightfield node!"); return(false); } HAPI_PartInfo partInfo = new HAPI_PartInfo(); if (!session.GetPartInfo(geoInfo.nodeId, 0, ref partInfo)) { HEU_Logger.LogError("Unable to get part info from heightfield node!"); return(false); } volumeInfo = new HAPI_VolumeInfo(); if (!session.GetVolumeInfo(idt._heightNodeID, 0, ref volumeInfo)) { HEU_Logger.LogError("Unable to get volume info from heightfield node!"); return(false); } if ((volumeInfo.xLength - 1) != Mathf.RoundToInt(idt._numPointsX / idt._voxelSize) || (volumeInfo.yLength - 1) != Mathf.RoundToInt(idt._numPointsY / idt._voxelSize) || idt._terrainData.heightmapResolution != volumeInfo.xLength || idt._terrainData.heightmapResolution != volumeInfo.yLength) { HEU_Logger.LogWarning("Created heightfield in Houdini differs in voxel size from input terrain! Terrain may require resampling."); } // Update volume infos, and set it. This is required. volumeInfo.tileSize = 1; volumeInfo.type = HAPI_VolumeType.HAPI_VOLUMETYPE_HOUDINI; volumeInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_FLOAT; volumeInfo.transform = idt._transform; volumeInfo.minX = 0; volumeInfo.minY = 0; volumeInfo.minZ = 0; volumeInfo.tupleSize = 1; volumeInfo.tileSize = 1; volumeInfo.hasTaper = false; volumeInfo.xTaper = 0f; volumeInfo.yTaper = 0f; if (!session.SetVolumeInfo(idt._heightNodeID, partInfo.id, ref volumeInfo)) { HEU_Logger.LogError("Unable to set volume info on input heightfield node!"); return(false); } // Now set the height data float[,] heights = idt._terrainData.GetHeights(0, 0, idt._terrainData.heightmapResolution, idt._terrainData.heightmapResolution); int sizeX = heights.GetLength(0); int sizeY = heights.GetLength(1); int totalSize = sizeX * sizeY; // Convert to single array float[] heightsArr = new float[totalSize]; for (int j = 0; j < sizeY; j++) { for (int i = 0; i < sizeX; i++) { // Flip for coordinate system change float h = heights[i, (sizeY - j - 1)]; heightsArr[i + j * sizeX] = h * idt._heightScale; } } if (volumeInfo.xLength != volumeInfo.yLength) { HEU_Logger.LogError("Error: Houdini heightmap must be square!"); return(false); } if (idt._terrainData.heightmapResolution != volumeInfo.xLength) { // Resize heightsArr to idt._terrainData.heightmapResolution HEU_Logger.LogWarningFormat("Attempting to resize landscape from ({0}x{1}) to ({2}x{3})", idt._terrainData.heightmapResolution, idt._terrainData.heightmapResolution, volumeInfo.xLength, volumeInfo.xLength); heightsArr = HEU_TerrainUtility.ResampleData(heightsArr, idt._terrainData.heightmapResolution, idt._terrainData.heightmapResolution, volumeInfo.xLength, volumeInfo.xLength); sizeX = volumeInfo.xLength; sizeY = volumeInfo.yLength; totalSize = sizeX * sizeY; } // Set the base height layer if (!session.SetHeightFieldData(idt._heightNodeID, 0, HEU_Defines.HAPI_HEIGHTFIELD_LAYERNAME_HEIGHT, heightsArr, 0, totalSize)) { HEU_Logger.LogError("Unable to set height values on input heightfield node!"); return(false); } SetTerrainDataAttributesToHeightField(session, geoInfo.nodeId, 0, idt._terrainData); SetTreePrototypes(session, geoInfo.nodeId, 0, idt._terrainData); if (!session.CommitGeo(idt._heightNodeID)) { HEU_Logger.LogError("Unable to commit geo on input heightfield node!"); return(false); } return(true); }