예제 #1
0
		public static Material LoadUnityMaterial(string materialPath)
		{
			if(materialPath.StartsWith(HEU_Defines.DEFAULT_UNITY_BUILTIN_RESOURCES))
			{
				return HEU_AssetDatabase.LoadUnityAssetFromUniqueAssetPath<Material>(materialPath);
			}

			string relativePath = materialPath;
			if (relativePath.StartsWith(Application.dataPath))
			{
				// If absolute path, change to relative path
				relativePath = HEU_AssetDatabase.GetAssetRelativePath(materialPath);
			}

			Material material = null;

			string mainPath = null;
			string subPath = null;
			HEU_AssetDatabase.GetSubAssetPathFromPath(relativePath, out mainPath, out subPath);
			if(subPath != null)
			{
				// This is a subasset. Need to find it by first loading the main asset.
				Object subObject = HEU_AssetDatabase.LoadSubAssetAtPath(mainPath, subPath);
				if(subObject != null)
				{
					material = subObject as Material;
				}
			}
			else
			{
				// Try loading from Resources first
				material = Resources.Load<Material>(relativePath) as Material;
				if (material == null)
				{
					// If not in Resources, try loading from project
					HEU_AssetDatabase.ImportAsset(relativePath, HEU_AssetDatabase.HEU_ImportAssetOptions.Default);
					material = HEU_AssetDatabase.LoadAssetAtPath(relativePath, typeof(Material)) as Material;
				}
			}

			return material;
		}
예제 #2
0
		public void PopulateInputPreset(HEU_InputPreset inputPreset)
		{
			inputPreset._inputObjectType = _inputObjectType;

			inputPreset._inputAssetName = _inputAsset != null ? _inputAsset.name : "";

			inputPreset._inputIndex = _inputIndex;
			inputPreset._inputName = _inputName;

			inputPreset._keepWorldTransform = _keepWorldTransform;
			inputPreset._packGeometryBeforeMerging = _packGeometryBeforeMerging;

			foreach (HEU_InputObjectInfo inputObject in _inputObjects)
			{
				HEU_InputObjectPreset inputObjectPreset = new HEU_InputObjectPreset();

				if (inputObject._gameObject != null)
				{
					inputObjectPreset._gameObjectName = inputObject._gameObject.name;

					// Tag whether scene or project input object
					inputObjectPreset._isSceneObject = !HEU_GeneralUtility.IsGameObjectInProject(inputObject._gameObject);
					if (!inputObjectPreset._isSceneObject)
					{
						// For inputs in project, use the project path as name
						inputObjectPreset._gameObjectName = HEU_AssetDatabase.GetAssetOrScenePath(inputObject._gameObject);
					}
				}
				else
				{
					inputObjectPreset._gameObjectName = "";
				}

				inputObjectPreset._useTransformOffset = inputObject._useTransformOffset;
				inputObjectPreset._translateOffset = inputObject._translateOffset;
				inputObjectPreset._rotateOffset = inputObject._rotateOffset;
				inputObjectPreset._scaleOffset = inputObject._scaleOffset;

				inputPreset._inputObjectPresets.Add(inputObjectPreset);
			}

		}
예제 #3
0
		/// <summary>
		/// Returns the valid relative path if the given path is under the project Assets/ directory.
		/// If not, it returns the given path as is, but warns the user that the path is outside the project
		/// and therefore not safe to use if the project changes location on another workstation (eg. source control).
		/// </summary>
		/// <param name="inPath">Path to validate.</param>
		/// <returns>Relative path to project Assets/ folder, or just returns the path as is if outside the project.</returns>
		public static string GetValidRelativePath(string inPath)
		{
			// If the selected path is outside the project directory, warn user
			// If inside project, make sure its relative (for version control and multi-user projects)
			if (!HEU_AssetDatabase.IsPathRelativeToAssets(inPath))
			{
				string relativePath = HEU_AssetDatabase.GetAssetRelativePath(inPath);
				if (string.IsNullOrEmpty(relativePath))
				{
					string message = string.Format("Path: {0} is outside the project!\n This is not recommended if using version control or for multi-user projects.",
						inPath);
					Debug.LogWarning(message);
				}
				else
				{
					inPath = relativePath;
				}
			}
			return inPath;
		}
예제 #4
0
		private void DestroyOutputs()
		{
			if (_generatedOutputs != null)
			{
				for (int i = 0; i < _generatedOutputs.Count; ++i)
				{
					HEU_GeneratedOutput.DestroyGeneratedOutput(_generatedOutputs[i]);
					_generatedOutputs[i] = null;
				}
				_generatedOutputs.Clear();
			}

			if (_outputCacheFilePaths != null && _outputCacheFilePaths.Count > 0)
			{
				foreach(string filepath in _outputCacheFilePaths)
				{
					HEU_AssetDatabase.DeleteAssetAtPath(filepath);
				}
				_outputCacheFilePaths.Clear();
			}
		}
		public static void CreateAddObjectInAssetCacheFolder(string assetName, string assetObjectFileName, UnityEngine.Object objectToAdd, ref string bakedAssetPath, ref UnityEngine.Object assetDBObject)
		{
#if UNITY_EDITOR
			if (string.IsNullOrEmpty(bakedAssetPath))
			{
				bakedAssetPath = HEU_AssetDatabase.CreateUniqueBakePath(assetName);
			}

			if (assetDBObject == null)
			{
				HEU_AssetDatabase.CreateObjectInAssetCacheFolder(objectToAdd, bakedAssetPath, assetObjectFileName, objectToAdd.GetType());
				assetDBObject = objectToAdd;
			}
			else
			{
				HEU_AssetDatabase.AddObjectToAsset(objectToAdd, assetDBObject);
			}
#else
			// TODO RUNTIME: AssetDatabase is not supported at runtime. Do we need to support this for runtime?
			Debug.LogWarning(HEU_Defines.HEU_USERMSG_NONEDITOR_NOT_SUPPORTED);
#endif
		}
		/// <summary>
		/// Destroy any terrain components and data on given gameObject.
		/// </summary>
		/// <param name="gameObject"></param>
		public static void DestroyTerrainComponents(GameObject gameObject)
		{
			if(gameObject == null)
			{
				return;
			}

			Terrain terrain = gameObject.GetComponent<Terrain>();
			if(terrain != null)
			{
				if (terrain.terrainData != null)
				{
					HEU_AssetDatabase.DeleteAsset(terrain.terrainData);
					HEU_GeneralUtility.DestroyImmediate(terrain.terrainData, true);
					terrain.terrainData = null;
				}

				DestroyImmediate(terrain);
			}

			DestroyComponent<TerrainCollider>(gameObject);
		}
예제 #7
0
		public static Material LoadUnityMaterial(string materialPath)
		{
			if(materialPath.StartsWith(HEU_Defines.DEFAULT_UNITY_BUILTIN_RESOURCES))
			{
				return HEU_AssetDatabase.LoadUnityAssetFromUniqueAssetPath<Material>(materialPath);
			}

			string relativePath = materialPath;
			if (relativePath.StartsWith(Application.dataPath))
			{
				// If absolute path, change to relative path
				relativePath = HEU_AssetDatabase.GetAssetRelativePath(materialPath);
			}

			// Try loading from Resources first
			Material material = Resources.Load<Material>(relativePath) as Material;
			if(material == null)
			{
				// If not in Resources, try loading from project
				HEU_AssetDatabase.ImportAsset(relativePath, HEU_AssetDatabase.HEU_ImportAssetOptions.Default);
				material = HEU_AssetDatabase.LoadAssetAtPath(relativePath, typeof(Material)) as Material;
			}
			return material;
		}
예제 #8
0
		public static Material GetNewMaterialWithShader(string assetCacheFolderPath, string shaderName, string materialName = "", bool bWriteToFile = true)
		{
			Material material = null;
			Shader shader = FindShader(shaderName);
			if (shader != null)
			{
				material = new Material(shader);
				if (materialName == null || materialName.Length == 0)
				{
					material.name = shaderName;
				}
				else
				{
					material.name = materialName;
				}

				if (bWriteToFile && !string.IsNullOrEmpty(assetCacheFolderPath))
				{
					string materialFileName = materialName + ".mat";
					HEU_AssetDatabase.CreateObjectInAssetCacheFolder(material, assetCacheFolderPath, materialFileName, typeof(Material));
				}
			}
			return material;
		}
예제 #9
0
		/// <summary>
		/// Returns HEU_UploadMeshData with mesh data found on meshGameObject.
		/// </summary>
		/// <param name="meshGameObject">The GameObject to query mesh data from</param>
		/// <returns>A valid HEU_UploadMeshData if mesh data found or null</returns>
		public static HEU_InputDataMesh CreateSingleMeshData(GameObject meshGameObject)
		{
			HEU_InputDataMesh meshData = new HEU_InputDataMesh();

			MeshFilter meshfilter = meshGameObject.GetComponent<MeshFilter>();
			if (meshfilter == null)
			{
				return null;
			}

			if (meshfilter.sharedMesh == null)
			{
				return null;
			}
			meshData._mesh = meshfilter.sharedMesh;
			meshData._numVertices = meshData._mesh.vertexCount;
			meshData._numSubMeshes = meshData._mesh.subMeshCount;

			meshData._meshName = meshGameObject.name;

			meshData._meshPath = HEU_AssetDatabase.GetAssetOrScenePath(meshGameObject);
			if (string.IsNullOrEmpty(meshData._meshPath))
			{
				meshData._meshPath = meshGameObject.name;
			}

			MeshRenderer meshRenderer = meshGameObject.GetComponent<MeshRenderer>();
			if (meshRenderer != null)
			{
				meshData._materials = meshRenderer.sharedMaterials;
			}

			meshData._transform = meshGameObject.transform;

			return meshData;
		}
예제 #10
0
	public static void BakeGameObjectComponents(GameObject sourceGO, GameObject targetGO, string assetName, string outputPath, bool bIsInstancer)
	{
	    UnityEngine.Object assetDBObject = null;
	    Dictionary<Mesh, Mesh> sourceToTargetMeshMap = new Dictionary<Mesh, Mesh>();
	    Dictionary<Material, Material> sourceToCopiedMaterials = new Dictionary<Material, Material>();
	    string newAssetDBObjectFileName = HEU_AssetDatabase.AppendMeshesAssetFileName(assetName);

	    HEU_PartData.BakePartToGameObject(
		    partData: null,
		    srcGO: sourceGO,
		    targetGO: targetGO,
		    assetName: assetName,
		    bIsInstancer: bIsInstancer,
		    bDeleteExistingComponents: false, // Materials might be overwritten if true
		    bDontDeletePersistantResources: false,
		    bWriteMeshesToAssetDatabase: true,
		    bakedAssetPath: ref outputPath,
		    sourceToTargetMeshMap,
		    sourceToCopiedMaterials,
		    assetDBObject: ref assetDBObject,
		    assetObjectFileName: newAssetDBObjectFileName,
		    bReconnectPrefabInstances: false,
		    bKeepPreviousTransformValues: false ); 
	}
예제 #11
0
	public void LoadPreset(HEU_SessionBase session, HEU_InputPreset inputPreset)
	{
	    ResetInputNode(session);

	    ChangeInputType(session, inputPreset._inputObjectType);

	    if (inputPreset._inputObjectType == InputObjectType.UNITY_MESH)
	    {
		bool bSet = false;
		int numObjects = inputPreset._inputObjectPresets.Count;
		for (int i = 0; i < numObjects; ++i)
		{
		    bSet = false;

		    if (!string.IsNullOrEmpty(inputPreset._inputObjectPresets[i]._gameObjectName))
		    {
			GameObject inputGO = null;
			if (inputPreset._inputObjectPresets[i]._isSceneObject)
			{
			    inputGO = HEU_GeneralUtility.GetGameObjectByNameInScene(inputPreset._inputObjectPresets[i]._gameObjectName);
			}
			else
			{
			    // Use the _gameObjectName as path to find in scene
			    inputGO = HEU_AssetDatabase.LoadAssetAtPath(inputPreset._inputObjectPresets[i]._gameObjectName, typeof(GameObject)) as GameObject;
			    if (inputGO == null)
			    {
				Debug.LogErrorFormat("Unable to find input at {0}", inputPreset._inputObjectPresets[i]._gameObjectName);
			    }
			}

			if (inputGO != null)
			{
			    HEU_InputObjectInfo inputObject = InternalAddInputObjectAtEnd(inputGO);
			    bSet = true;

			    inputObject._useTransformOffset = inputPreset._inputObjectPresets[i]._useTransformOffset;
			    inputObject._translateOffset = inputPreset._inputObjectPresets[i]._translateOffset;
			    inputObject._rotateOffset = inputPreset._inputObjectPresets[i]._rotateOffset;
			    inputObject._scaleOffset = inputPreset._inputObjectPresets[i]._scaleOffset;
			}
			else
			{
			    Debug.LogWarningFormat("Gameobject with name {0} not found. Unable to set input object.", inputPreset._inputAssetName);
			}
		    }

		    if (!bSet)
		    {
			// Add dummy spot (user can replace it manually)
			InternalAddInputObjectAtEnd(null);
		    }
		}
	    }
	    else if (inputPreset._inputObjectType == HEU_InputNode.InputObjectType.HDA)
	    {
		bool bSet = false;
		int numInptus = inputPreset._inputAssetPresets.Count;
		for (int i = 0; i < numInptus; ++i)
		{
		    bSet = false;
		    if (!string.IsNullOrEmpty(inputPreset._inputAssetPresets[i]._gameObjectName))
		    {
			bSet = FindAddToInputHDA(inputPreset._inputAssetPresets[i]._gameObjectName);
		    }

		    if (!bSet)
		    {
			// Couldn't add for some reason, so just add dummy spot (user can replace it manually)
			InternalAddInputHDAAtEnd(null);
		    }
		}

		if (numInptus == 0 && !string.IsNullOrEmpty(inputPreset._inputAssetName))
		{
		    // Old preset. Add it to input
		    FindAddToInputHDA(inputPreset._inputAssetName);
		}
	    }

	    KeepWorldTransform = inputPreset._keepWorldTransform;
	    PackGeometryBeforeMerging = inputPreset._packGeometryBeforeMerging;

	    RequiresUpload = true;

	    ClearUICache();
	}
예제 #12
0
		/// <summary>
		/// Upload the given list of mesh data in uploadMeshes into node with inputNodeID.
		/// If the source was a LOD group, then group names are assigned to the geometry.
		/// </summary>
		/// <param name="session">Session to upload to</param>
		/// <param name="inputNodeID">The ID of the input node to upload into</param>
		/// <param name="uploadMeshes">List of mesh data</param>
		/// <param name="bHasLODGroup">Whether the source was a LOD group and therefore treat it specially</param>
		/// <returns></returns>
		public static bool UploadInputMeshData(HEU_SessionBase session, HAPI_NodeId inputNodeID, List<HEU_UploadMeshData> uploadMeshes, bool bHasLODGroup)
		{
			List<Vector3> vertices = new List<Vector3>();
			List<Vector3> normals = new List<Vector3>();
			List<Vector2> uvs = new List<Vector2>();
			List<Color> colors = new List<Color>();

			List<int> triIndexList = new List<int>();

			int numMaterials = 0;

			// Accumulate vertices, normals, uvs, colors, and indices.
			// Keep track of indices start and count for each mesh for later when uploading material assignments and groups.
			// Indices need to be reindexed with vertex offset as we accumulate vertices.
			int numMeshes = uploadMeshes.Count;
			for (int i = 0; i < numMeshes; ++i)
			{
				int vertexOffset = vertices.Count;
				vertices.AddRange(uploadMeshes[i]._mesh.vertices);

				normals.AddRange(uploadMeshes[i]._mesh.normals);
				uvs.AddRange(uploadMeshes[i]._mesh.uv);
				colors.AddRange(uploadMeshes[i]._mesh.colors);

				uploadMeshes[i]._indexStart = new uint[uploadMeshes[i]._numSubMeshes];
				uploadMeshes[i]._indexCount = new uint[uploadMeshes[i]._numSubMeshes];

				for (int j = 0; j < uploadMeshes[i]._numSubMeshes; ++j)
				{
					int indexStart = triIndexList.Count;

					// Indices have to be re-indexed with our own offset
					int[] meshIndices = uploadMeshes[i]._mesh.GetTriangles(j);
					int numIndices = meshIndices.Length;
					for (int k = 0; k < numIndices; ++k)
					{
						triIndexList.Add(vertexOffset + meshIndices[k]);
					}

					uploadMeshes[i]._indexStart[j] = (uint)indexStart;
					uploadMeshes[i]._indexCount[j] = (uint)(triIndexList.Count) - uploadMeshes[i]._indexStart[j];
				}

				numMaterials += uploadMeshes[i]._materials != null ? uploadMeshes[i]._materials.Length : 0;
			}

			// It is possible for some meshes to not have normals/uvs/colors while others do.
			// In the case where an attribute is missing on some meshes, we clear out those attributes so we don't upload
			// partial attribute data.
			int numVertices = vertices.Count;
			if (normals.Count != numVertices)
			{
				normals = null;
			}

			if (uvs.Count != numVertices)
			{
				uvs = null;
			}

			if (colors.Count != numVertices)
			{
				colors = null;
			}

			HAPI_PartInfo partInfo = new HAPI_PartInfo();
			partInfo.faceCount = triIndexList.Count / 3;
			partInfo.vertexCount = triIndexList.Count;
			partInfo.pointCount = vertices.Count;
			partInfo.pointAttributeCount = 1;
			partInfo.vertexAttributeCount = 0;
			partInfo.primitiveAttributeCount = 0;
			partInfo.detailAttributeCount = 0;

			if (normals != null && normals.Count > 0)
			{
				partInfo.vertexAttributeCount++;
			}

			if (uvs != null && uvs.Count > 0)
			{
				partInfo.vertexAttributeCount++;
			}

			if (colors != null && colors.Count > 0)
			{
				partInfo.vertexAttributeCount++;
			}

			if (numMaterials > 0)
			{
				partInfo.primitiveAttributeCount++;
			}

			if (numMeshes > 0)
			{
				partInfo.primitiveAttributeCount++;
			}

			if (bHasLODGroup)
			{
				partInfo.primitiveAttributeCount++;
				partInfo.detailAttributeCount++;
			}

			HAPI_GeoInfo displayGeoInfo = new HAPI_GeoInfo();
			if (!session.GetDisplayGeoInfo(inputNodeID, ref displayGeoInfo))
			{
				return false;
			}

			HAPI_NodeId displayNodeID = displayGeoInfo.nodeId;

			if (!session.SetPartInfo(displayNodeID, 0, ref partInfo))
			{
				return false;
			}

			int[] faceCounts = new int[partInfo.faceCount];
			for (int i = 0; i < partInfo.faceCount; ++i)
			{
				faceCounts[i] = 3;
			}

			int[] triIndices = triIndexList.ToArray();

			if (!HEU_GeneralUtility.SetArray2Arg(displayNodeID, 0, session.SetFaceCount, faceCounts, 0, partInfo.faceCount))
			{
				return false;
			}

			if (!HEU_GeneralUtility.SetArray2Arg(displayNodeID, 0, session.SetVertexList, triIndices, 0, partInfo.vertexCount))
			{
				return false;
			}

			if (!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_POSITION, 3, vertices.ToArray(), ref partInfo, true))
			{
				return false;
			}

			//if(normals != null && !SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_NORMAL, 3, normals, ref partInfo, true))
			if (normals != null && !SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_NORMAL, 3, normals.ToArray(), triIndices, ref partInfo, true))
			{
				return false;
			}

			if (uvs != null && uvs.Count > 0)
			{
				Vector3[] uvs3 = new Vector3[uvs.Count];
				for (int i = 0; i < uvs.Count; ++i)
				{
					uvs3[i][0] = uvs[i][0];
					uvs3[i][1] = uvs[i][1];
					uvs3[i][2] = 0;
				}
				//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_UV, 3, uvs3, ref partInfo, false))
				if (!SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_UV, 3, uvs3, triIndices, ref partInfo, false))
				{
					return false;
				}
			}

			if (colors != null && colors.Count > 0)
			{
				Vector3[] rgb = new Vector3[colors.Count];
				float[] alpha = new float[colors.Count];
				for (int i = 0; i < colors.Count; ++i)
				{
					rgb[i][0] = colors[i].r;
					rgb[i][1] = colors[i].g;
					rgb[i][2] = colors[i].b;

					alpha[i] = colors[i].a;
				}

				//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_COLOR, 3, rgb, ref partInfo, false))
				if (!SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_COLOR, 3, rgb, triIndices, ref partInfo, false))
				{
					return false;
				}

				//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_ALPHA, 1, alpha, ref partInfo, false))
				if (!SetMeshVertexFloatAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_ALPHA, 1, alpha, triIndices, ref partInfo))
				{
					return false;
				}
			}

			// Set material names for round-trip perservation of material assignment
			// Each HEU_UploadMeshData might have a list of submeshes and materials
			// These are all combined into a single mesh, with group names
			if (numMaterials > 0)
			{
				bool bFoundAtleastOneValidMaterial = false;

				string[] materialIDs = new string[partInfo.faceCount];
				for (int g = 0; g < uploadMeshes.Count; ++g)
				{
					if (uploadMeshes[g]._numSubMeshes != uploadMeshes[g]._materials.Length)
					{
						// Number of submeshes should equal number of materials since materials determine submeshes
						continue;
					}

					for (int i = 0; i < uploadMeshes[g]._materials.Length; ++i)
					{
						string materialName = HEU_AssetDatabase.GetAssetPath(uploadMeshes[g]._materials[i]);
						if (materialName == null)
						{
							materialName = "";
						}
						else if (materialName.StartsWith(HEU_Defines.DEFAULT_UNITY_BUILTIN_RESOURCES))
						{
							materialName = HEU_AssetDatabase.GetUniqueAssetPathForUnityAsset(uploadMeshes[g]._materials[i]);
						}

						bFoundAtleastOneValidMaterial |= !string.IsNullOrEmpty(materialName);

						int faceStart = (int)uploadMeshes[g]._indexStart[i] / 3;
						int faceEnd = faceStart + ((int)uploadMeshes[g]._indexCount[i] / 3);
						for (int m = faceStart; m < faceEnd; ++m)
						{
							materialIDs[m] = materialName;
						}
					}
				}

				if (bFoundAtleastOneValidMaterial)
				{
					HAPI_AttributeInfo materialIDAttrInfo = new HAPI_AttributeInfo();
					materialIDAttrInfo.exists = true;
					materialIDAttrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM;
					materialIDAttrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_STRING;
					materialIDAttrInfo.count = partInfo.faceCount;
					materialIDAttrInfo.tupleSize = 1;
					materialIDAttrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

					if (!session.AddAttribute(displayNodeID, 0, HEU_PluginSettings.UnityMaterialAttribName, ref materialIDAttrInfo))
					{
						return false;
					}

					if (!session.SetAttributeStringData(displayNodeID, 0, HEU_PluginSettings.UnityMaterialAttribName, ref materialIDAttrInfo, materialIDs, 0, partInfo.faceCount))
					{
						return false;
					}
				}
			}

			// Set mesh name attribute
			HAPI_AttributeInfo attrInfo = new HAPI_AttributeInfo();
			attrInfo.exists = true;
			attrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM;
			attrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_STRING;
			attrInfo.count = partInfo.faceCount;
			attrInfo.tupleSize = 1;
			attrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

			if (session.AddAttribute(displayNodeID, 0, HEU_PluginSettings.UnityInputMeshAttr, ref attrInfo))
			{
				string[] primitiveNameAttr = new string[partInfo.faceCount];

				for (int g = 0; g < uploadMeshes.Count; ++g)
				{
					for (int i = 0; i < uploadMeshes[g]._numSubMeshes; ++i)
					{
						int faceStart = (int)uploadMeshes[g]._indexStart[i] / 3;
						int faceEnd = faceStart + ((int)uploadMeshes[g]._indexCount[i] / 3);
						for (int m = faceStart; m < faceEnd; ++m)
						{
							primitiveNameAttr[m] = uploadMeshes[g]._meshPath;
						}
					}
				}

				if (!session.SetAttributeStringData(displayNodeID, 0, HEU_PluginSettings.UnityInputMeshAttr, ref attrInfo, primitiveNameAttr, 0, partInfo.faceCount))
				{
					return false;
				}
			}
			else
			{
				return false;
			}

			// Set LOD group membership
			if (bHasLODGroup)
			{
				int[] membership = new int[partInfo.faceCount];

				for (int g = 0; g < uploadMeshes.Count; ++g)
				{
					if (g > 0)
					{
						// Clear array
						for (int m = 0; m < partInfo.faceCount; ++m)
						{
							membership[m] = 0;
						}
					}

					// Set 1 for faces belonging to this group
					for (int s = 0; s < uploadMeshes[g]._numSubMeshes; ++s)
					{
						int faceStart = (int)uploadMeshes[g]._indexStart[s] / 3;
						int faceEnd = faceStart + ((int)uploadMeshes[g]._indexCount[s] / 3);
						for (int m = faceStart; m < faceEnd; ++m)
						{
							membership[m] = 1;
						}
					}

					if (!session.AddGroup(displayNodeID, 0, HAPI_GroupType.HAPI_GROUPTYPE_PRIM, uploadMeshes[g]._meshName))
					{
						return false;
					}

					if (!session.SetGroupMembership(displayNodeID, 0, HAPI_GroupType.HAPI_GROUPTYPE_PRIM, uploadMeshes[g]._meshName, membership, 0, partInfo.faceCount))
					{
						return false;
					}
				}
			}

			return session.CommitGeo(displayNodeID);
		}
예제 #13
0
		private void GenerateTerrain(List<HEU_LoadBufferVolume> terrainBuffers)
		{
			Transform parent = this.gameObject.transform;

			// Directory to store generated terrain files.
			string outputTerrainpath = GetOutputCacheDirectory();
			outputTerrainpath = HEU_Platform.BuildPath(outputTerrainpath, "Terrain");

			int numVolumes = terrainBuffers.Count;
			for(int t = 0; t < numVolumes; ++t)
			{
				if (terrainBuffers[t]._heightMap != null)
				{
					GameObject newGameObject = new GameObject("heightfield_" + terrainBuffers[t]._tileIndex);
					Transform newTransform = newGameObject.transform;
					newTransform.parent = parent;

					HEU_GeneratedOutput generatedOutput = new HEU_GeneratedOutput();
					generatedOutput._outputData._gameObject = newGameObject;

					Terrain terrain = HEU_GeneralUtility.GetOrCreateComponent<Terrain>(newGameObject);
					TerrainCollider collider = HEU_GeneralUtility.GetOrCreateComponent<TerrainCollider>(newGameObject);

					if (!string.IsNullOrEmpty(terrainBuffers[t]._terrainDataPath))
					{
						// Load the source TerrainData, then make a unique copy of it in the cache folder

						TerrainData sourceTerrainData = HEU_AssetDatabase.LoadAssetAtPath(terrainBuffers[t]._terrainDataPath, typeof(TerrainData)) as TerrainData;
						if (sourceTerrainData == null)
						{
							Debug.LogWarningFormat("TerrainData, set via attribute, not found at: {0}", terrainBuffers[t]._terrainDataPath);
						}

						terrain.terrainData = HEU_AssetDatabase.CopyUniqueAndLoadAssetAtAnyPath(sourceTerrainData, outputTerrainpath, typeof(TerrainData)) as TerrainData;
						if (terrain.terrainData != null)
						{
							// Store path so that it can be deleted on clean up
							AddGeneratedOutputFilePath(HEU_AssetDatabase.GetAssetPath(terrain.terrainData));
						}
					}

					if (terrain.terrainData == null)
					{
						terrain.terrainData = new TerrainData();
					}
					TerrainData terrainData = terrain.terrainData;
					collider.terrainData = terrainData;

					HEU_TerrainUtility.SetTerrainMaterial(terrain, terrainBuffers[t]._specifiedTerrainMaterialName);

#if UNITY_2018_3_OR_NEWER
					terrain.allowAutoConnect = true;
					// This has to be set after setting material
					terrain.drawInstanced = true;
#endif

					int heightMapSize = terrainBuffers[t]._heightMapWidth;

					terrainData.heightmapResolution = heightMapSize;
					if (terrainData.heightmapResolution != heightMapSize)
					{
						Debug.LogErrorFormat("Unsupported terrain size: {0}", heightMapSize);
						continue;
					}

					// The terrainData.baseMapResolution is not set here, but rather left to whatever default Unity uses
					// The terrainData.alphamapResolution is set later when setting the alphamaps.

					// 32 is the default for resolutionPerPatch
					const int detailResolution = 1024;
					const int resolutionPerPatch = 32;
					terrainData.SetDetailResolution(detailResolution, resolutionPerPatch);

					terrainData.SetHeights(0, 0, terrainBuffers[t]._heightMap);

					// Note that Unity uses a default height range of 600 when a flat terrain is created.
					// Without a non-zero value for the height range, user isn't able to draw heights.
					// Therefore, set 600 as the value if height range is currently 0 (due to flat heightfield).
					float heightRange = terrainBuffers[t]._heightRange;
					if (heightRange == 0)
					{
						heightRange = 600;
					}

					terrainData.size = new Vector3(terrainBuffers[t]._terrainSizeX, heightRange, terrainBuffers[t]._terrainSizeY);

					terrain.Flush();

					// Set position
					HAPI_Transform hapiTransformVolume = new HAPI_Transform(true);
					hapiTransformVolume.position[0] += terrainBuffers[t]._position[0];
					hapiTransformVolume.position[1] += terrainBuffers[t]._position[1];
					hapiTransformVolume.position[2] += terrainBuffers[t]._position[2];
					HEU_HAPIUtility.ApplyLocalTransfromFromHoudiniToUnity(ref hapiTransformVolume, newTransform);

					// Set layers
					Texture2D defaultTexture = HEU_VolumeCache.LoadDefaultSplatTexture();
					int numLayers = terrainBuffers[t]._splatLayers.Count;

#if UNITY_2018_3_OR_NEWER

					// Create TerrainLayer for each heightfield layer.
					// Note that height and mask layers are ignored (i.e. not created as TerrainLayers).
					// Since height layer is first, only process layers from 2nd index onwards.
					if (numLayers > 1)
					{
						// Keep existing TerrainLayers, and either update or append to them
						TerrainLayer[] existingTerrainLayers = terrainData.terrainLayers;

						// Total layers are existing layers + new alpha maps
						List<TerrainLayer> finalTerrainLayers = new List<TerrainLayer>(existingTerrainLayers);

						for (int m = 1; m < numLayers; ++m)
						{
							TerrainLayer terrainlayer = null;

							int terrainLayerIndex = -1;

							bool bSetTerrainLayerProperties = true;

							HEU_LoadBufferVolumeLayer layer = terrainBuffers[t]._splatLayers[m];

							// Look up TerrainLayer file via attribute if user has set it
							if (!string.IsNullOrEmpty(layer._layerPath))
							{
								terrainlayer = HEU_AssetDatabase.LoadAssetAtPath(layer._layerPath, typeof(TerrainLayer)) as TerrainLayer;
								if (terrainlayer == null)
								{
									Debug.LogWarningFormat("TerrainLayer, set via attribute, not found at: {0}", layer._layerPath);
									continue;
								}
								else
								{
									// Always check if its part of existing list so as not to add it again
									terrainLayerIndex = HEU_TerrainUtility.GetTerrainLayerIndex(terrainlayer, existingTerrainLayers);
								}
							}

							if (terrainlayer == null)
							{
								terrainlayer = new TerrainLayer();
								terrainLayerIndex = finalTerrainLayers.Count;
								finalTerrainLayers.Add(terrainlayer);
							}
							else
							{
								// For existing TerrainLayer, make a copy of it if it has custom layer attributes
								// because we don't want to change the original TerrainLayer.
								if (layer._hasLayerAttributes && terrainLayerIndex >= 0)
								{
									// Copy the TerrainLayer file
									TerrainLayer prevTerrainLayer = terrainlayer;
									terrainlayer = HEU_AssetDatabase.CopyAndLoadAssetAtAnyPath(terrainlayer, outputTerrainpath, typeof(TerrainLayer), true) as TerrainLayer;
									if (terrainlayer != null)
									{
										// Update the TerrainLayer reference in the list with this copy
										finalTerrainLayers[terrainLayerIndex] = terrainlayer;

										// Store path for clean up later
										AddGeneratedOutputFilePath(HEU_AssetDatabase.GetAssetPath(terrainlayer));
									}
									else
									{
										Debug.LogErrorFormat("Unable to copy TerrainLayer '{0}' for generating Terrain. "
											+ "Using original TerrainLayer. Will not be able to set any TerrainLayer properties.", layer._layerName);
										terrainlayer = prevTerrainLayer;
										bSetTerrainLayerProperties = false;
										// Again, continuing on to keep proper indexing.
									}
								}
							}

							if (bSetTerrainLayerProperties)
							{
								if (!string.IsNullOrEmpty(layer._diffuseTexturePath))
								{
									terrainlayer.diffuseTexture = HEU_MaterialFactory.LoadTexture(layer._diffuseTexturePath);
								}
								if (terrainlayer.diffuseTexture == null)
								{
									terrainlayer.diffuseTexture = defaultTexture;
								}

								terrainlayer.diffuseRemapMin = Vector4.zero;
								terrainlayer.diffuseRemapMax = Vector4.one;

								if (!string.IsNullOrEmpty(layer._maskTexturePath))
								{
									terrainlayer.maskMapTexture = HEU_MaterialFactory.LoadTexture(layer._maskTexturePath);
								}

								terrainlayer.maskMapRemapMin = Vector4.zero;
								terrainlayer.maskMapRemapMax = Vector4.one;

								terrainlayer.metallic = layer._metallic;

								if (!string.IsNullOrEmpty(layer._normalTexturePath))
								{
									terrainlayer.normalMapTexture = HEU_MaterialFactory.LoadTexture(layer._normalTexturePath);
								}

								terrainlayer.normalScale = layer._normalScale;

								terrainlayer.smoothness = layer._smoothness;
								terrainlayer.specular = layer._specularColor;
								terrainlayer.tileOffset = layer._tileOffset;

								if (layer._tileSize.magnitude == 0f && terrainlayer.diffuseTexture != null)
								{
									// Use texture size if tile size is 0
									layer._tileSize = new Vector2(terrainlayer.diffuseTexture.width, terrainlayer.diffuseTexture.height);
								}
								terrainlayer.tileSize = layer._tileSize;
							}
						}
						terrainData.terrainLayers = finalTerrainLayers.ToArray();
					}

#else
					// Need to create SplatPrototype for each layer in heightfield, representing the textures.
					SplatPrototype[] splatPrototypes = new SplatPrototype[numLayers];
					for (int m = 0; m < numLayers; ++m)
					{
						splatPrototypes[m] = new SplatPrototype();

						HEU_LoadBufferVolumeLayer layer = terrainBuffers[t]._splatLayers[m];

						Texture2D diffuseTexture = null;
						if (!string.IsNullOrEmpty(layer._diffuseTexturePath))
						{
							diffuseTexture = HEU_MaterialFactory.LoadTexture(layer._diffuseTexturePath);
						}
						if (diffuseTexture == null)
						{
							diffuseTexture = defaultTexture;
						}
						splatPrototypes[m].texture = diffuseTexture;

						splatPrototypes[m].tileOffset = layer._tileOffset;
						if (layer._tileSize.magnitude == 0f && diffuseTexture != null)
						{
							// Use texture size if tile size is 0
							layer._tileSize = new Vector2(diffuseTexture.width, diffuseTexture.height);
						}
						splatPrototypes[m].tileSize = layer._tileSize;

						splatPrototypes[m].metallic = layer._metallic;
						splatPrototypes[m].smoothness = layer._smoothness;

						if (!string.IsNullOrEmpty(layer._normalTexturePath))
						{
							splatPrototypes[m].normalMap = HEU_MaterialFactory.LoadTexture(layer._normalTexturePath);
						}
					}
					terrainData.splatPrototypes = splatPrototypes;
#endif

					// Set the splatmaps
					if (terrainBuffers[t]._splatMaps != null)
					{
						// Set the alphamap size before setting the alphamaps to get correct scaling
						// The alphamap size comes from the first alphamap layer
						int alphamapResolution = terrainBuffers[t]._heightMapWidth;
						if (numLayers > 1)
						{
							alphamapResolution = terrainBuffers[t]._splatLayers[1]._heightMapWidth;
						}
						terrainData.alphamapResolution = alphamapResolution;

						terrainData.SetAlphamaps(0, 0, terrainBuffers[t]._splatMaps);
					}

					// Set the tree scattering
					if (terrainBuffers[t]._scatterTrees != null)
					{
						HEU_TerrainUtility.ApplyScatterTrees(terrainData, terrainBuffers[t]._scatterTrees);
					}

					// Set the detail layers
					if (terrainBuffers[t]._detailPrototypes != null)
					{
						HEU_TerrainUtility.ApplyDetailLayers(terrain, terrainData, terrainBuffers[t]._detailProperties,
							terrainBuffers[t]._detailPrototypes, terrainBuffers[t]._detailMaps);
					}

					terrainBuffers[t]._generatedOutput = generatedOutput;
					_generatedOutputs.Add(generatedOutput);

					SetOutputVisiblity(terrainBuffers[t]);
				}
			}
		}
	/// <summary>
	/// Returns HEU_UploadMeshData with mesh data found on meshGameObject.
	/// </summary>
	/// <param name="meshGameObject">The GameObject to query mesh data from</param>
	/// <returns>A valid HEU_UploadMeshData if mesh data found or null</returns>
	public static HEU_InputDataMesh CreateSingleMeshData(GameObject meshGameObject, bool bExportColliders)
	{
	    HEU_InputDataMesh meshData = new HEU_InputDataMesh();

	    if (meshGameObject == null)
	    {
		return null;
	    }

	    Mesh sharedMesh = GetMeshFromObject(meshGameObject);

	    if (sharedMesh == null)
	    {
		return null;
	    }

	    meshData._mesh = sharedMesh;
	    meshData._numVertices = meshData._mesh.vertexCount;
	    meshData._numSubMeshes = meshData._mesh.subMeshCount;

	    meshData._meshName = meshGameObject.name;

	    // Use project path is not saved in scene, otherwise just use name
	    if (HEU_GeneralUtility.IsGameObjectInProject(meshGameObject))
	    {
		meshData._meshPath = HEU_AssetDatabase.GetAssetOrScenePath(meshGameObject);
		if (string.IsNullOrEmpty(meshData._meshPath))
		{
		    meshData._meshPath = meshGameObject.name;
		}
	    }
	    else
	    {
		meshData._meshPath = meshGameObject.name;
	    }
	    //HEU_Logger.Log("Mesh Path: " + meshData._meshPath);

	    MeshRenderer meshRenderer = meshGameObject.GetComponent<MeshRenderer>();
	    if (meshRenderer != null)
	    {
		meshData._materials = meshRenderer.sharedMaterials;
	    }

	    meshData._transform = meshGameObject.transform;

	    if (bExportColliders && meshGameObject != null)
	    {
		meshData._colliders = new List<HEU_InputDataCollider>();

		Collider[] colliders = meshGameObject.GetComponents<Collider>();
		if (colliders != null)
		{
		    for (int i = 0; i < colliders.Length; i++)
		    {
			Collider collider = colliders[i];

			if (collider == null) continue;

			HEU_InputDataCollider newCollider = new HEU_InputDataCollider();
			newCollider._collider = collider;

			if (collider.GetType() == typeof(BoxCollider))
			{
			    newCollider._colliderType = HEU_InputColliderType.BOX;
			}
			else if (collider.GetType() == typeof(SphereCollider))
			{
			    newCollider._colliderType = HEU_InputColliderType.SPHERE;
			}
			else if (collider.GetType() == typeof(CapsuleCollider))
			{
			    newCollider._colliderType = HEU_InputColliderType.CAPSULE;
			}
			else if (collider.GetType() == typeof(MeshCollider))
			{
			    newCollider._colliderType = HEU_InputColliderType.MESH;
			}
			else
			{
			    HEU_Logger.LogWarningFormat("Collider type not supported: {0}", meshGameObject.name);
			    newCollider._collider = null;
			    newCollider._colliderType = HEU_InputColliderType.NONE;
			}

			if (newCollider._colliderType != HEU_InputColliderType.NONE)
			{
			    meshData._colliders.Add(newCollider);
			}
		    }
		}
	    }


	    return meshData;
	}
예제 #15
0
        private void GenerateInstancesFromNodeIDs(HAPI_NodeId cookNodeId, HEU_LoadBufferInstancer instancerBuffer, Dictionary <HAPI_NodeId, HEU_LoadBufferBase> idBuffersMap,
                                                  Transform instanceRootTransform)
        {
            // For single collision geo override
            GameObject singleCollisionGO = null;

            // For multi collision geo overrides, keep track of loaded objects
            Dictionary <string, GameObject> loadedCollisionObjectMap = new Dictionary <string, GameObject>();

            if (instancerBuffer._collisionAssetPaths != null && instancerBuffer._collisionAssetPaths.Length == 1)
            {
                // Single collision override
                if (!string.IsNullOrEmpty(instancerBuffer._collisionAssetPaths[0]))
                {
                    HEU_AssetDatabase.ImportAsset(instancerBuffer._collisionAssetPaths[0], HEU_AssetDatabase.HEU_ImportAssetOptions.Default);
                    singleCollisionGO = HEU_AssetDatabase.LoadAssetAtPath(instancerBuffer._collisionAssetPaths[0], typeof(GameObject)) as GameObject;
                }

                if (singleCollisionGO == null)
                {
                    // Continue on but log error
                    Debug.LogErrorFormat("Collision asset at path {0} not found for instance {1}.", instancerBuffer._collisionAssetPaths[0], instancerBuffer._name);
                }
            }

            int numInstances = instancerBuffer._instanceNodeIDs.Length;

            for (int i = 0; i < numInstances; ++i)
            {
                HEU_LoadBufferBase sourceBuffer = null;
                if (!idBuffersMap.TryGetValue(instancerBuffer._instanceNodeIDs[i], out sourceBuffer) || sourceBuffer == null)
                {
                    Debug.LogErrorFormat("Part with id {0} is missing. Unable to setup instancer!", instancerBuffer._instanceNodeIDs[i]);
                    return;
                }

                // If the part we're instancing is itself an instancer, make sure it has generated its instances
                if (sourceBuffer._bInstanced && sourceBuffer._generatedOutput == null)
                {
                    HEU_LoadBufferInstancer sourceBufferInstancer = instancerBuffer as HEU_LoadBufferInstancer;
                    if (sourceBufferInstancer != null)
                    {
                        GenerateInstancer(cookNodeId, sourceBufferInstancer, idBuffersMap);
                    }
                }

                GameObject sourceGameObject = sourceBuffer._generatedOutput._outputData._gameObject;
                if (sourceGameObject == null)
                {
                    Debug.LogErrorFormat("Output gameobject is null for source {0}. Unable to instance for {1}.", sourceBuffer._name, instancerBuffer._name);
                    continue;
                }

                GameObject collisionSrcGO = null;
                if (singleCollisionGO != null)
                {
                    // Single collision geo
                    collisionSrcGO = singleCollisionGO;
                }
                else if (instancerBuffer._collisionAssetPaths != null &&
                         (i < instancerBuffer._collisionAssetPaths.Length) &&
                         !string.IsNullOrEmpty(instancerBuffer._collisionAssetPaths[i]))
                {
                    // Mutliple collision geo (one per instance).
                    if (!loadedCollisionObjectMap.TryGetValue(instancerBuffer._collisionAssetPaths[i], out collisionSrcGO))
                    {
                        collisionSrcGO = HEU_AssetDatabase.LoadAssetAtPath(instancerBuffer._collisionAssetPaths[i], typeof(GameObject)) as GameObject;
                        if (collisionSrcGO == null)
                        {
                            Debug.LogErrorFormat("Unable to load collision asset at {0} for instancing!", instancerBuffer._collisionAssetPaths[i]);
                        }
                        else
                        {
                            loadedCollisionObjectMap.Add(instancerBuffer._collisionAssetPaths[i], collisionSrcGO);
                        }
                    }
                }

                int numTransforms = instancerBuffer._instanceTransforms.Length;
                for (int j = 0; j < numTransforms; ++j)
                {
                    CreateNewInstanceFromObject(sourceGameObject, (j + 1), instanceRootTransform, ref instancerBuffer._instanceTransforms[j],
                                                instancerBuffer._instancePrefixes, instancerBuffer._name, collisionSrcGO);
                }
            }
        }
		/// <summary>
		/// Apply the given detail layers and properties to the given terrain.
		/// The detail distance and resolution will be set, along with detail prototypes, and layers.
		/// </summary>
		/// <param name="terrain">The Terrain to set the detail properies on</param>
		/// <param name="terrainData">The TerrainData to apply the layers to</param>
		/// <param name="detailProperties">Container for detail distance and resolution</param>
		/// <param name="heuDetailPrototypes">Data for creating DetailPrototypes</param>
		/// <param name="convertedDetailMaps">The detail maps to set for the detail layers</param>
		public static void ApplyDetailLayers(Terrain terrain, TerrainData terrainData, HEU_DetailProperties detailProperties,
			List<HEU_DetailPrototype> heuDetailPrototypes, List<int[,]> convertedDetailMaps)
		{
#if UNITY_2018_3_OR_NEWER

			if (detailProperties != null)
			{
				if (detailProperties._detailDistance >= 0)
				{
					terrain.detailObjectDistance = detailProperties._detailDistance;
				}

				if (detailProperties._detailDensity >= 0)
				{
					terrain.detailObjectDensity = detailProperties._detailDensity;
				}

				int resPerPath = detailProperties._detailResolutionPerPatch > 0 ?
						detailProperties._detailResolutionPerPatch : terrainData.detailResolutionPerPatch;

				int detailRes = detailProperties._detailResolution > 0 ?
					detailProperties._detailResolution : terrainData.detailResolutionPerPatch;

				if (resPerPath > 0 && detailRes > 0)
				{
					// This should match with half the terrain size
					terrainData.SetDetailResolution(detailRes, resPerPath);
				}
			}

			if (heuDetailPrototypes.Count != convertedDetailMaps.Count)
			{
				Debug.LogError("Number of volume detail layers differs from converted detail maps. Unable to apply detail layers.");
				return;
			}

			// For now, just override existing detail prototypes and layers
			// If user asks for appending/overwriting them, then can use a new index attribute to map them

			List<DetailPrototype> detailPrototypes = new List<DetailPrototype>();

			int numDetailLayers = heuDetailPrototypes.Count;
			for(int i = 0; i < numDetailLayers; ++i)
			{
				DetailPrototype detailPrototype = new DetailPrototype();

				HEU_DetailPrototype heuDetail = heuDetailPrototypes[i];

				if (!string.IsNullOrEmpty(heuDetail._prototypePrefab))
				{
					detailPrototype.prototype = HEU_AssetDatabase.LoadAssetAtPath(heuDetail._prototypePrefab, typeof(GameObject)) as GameObject;
					detailPrototype.usePrototypeMesh = true;
				}
				else if (!string.IsNullOrEmpty(heuDetail._prototypeTexture))
				{
					detailPrototype.prototypeTexture = HEU_MaterialFactory.LoadTexture(heuDetail._prototypeTexture);
					detailPrototype.usePrototypeMesh = false;
				}

				detailPrototype.bendFactor = heuDetail._bendFactor;
				detailPrototype.dryColor = heuDetail._dryColor;
				detailPrototype.healthyColor = heuDetail._healthyColor;
				detailPrototype.maxHeight = heuDetail._maxHeight;
				detailPrototype.maxWidth = heuDetail._maxWidth;
				detailPrototype.minHeight = heuDetail._minHeight;
				detailPrototype.minWidth = heuDetail._minWidth;
				detailPrototype.noiseSpread = heuDetail._noiseSpread;

				detailPrototype.renderMode = (DetailRenderMode)heuDetail._renderMode;

				detailPrototypes.Add(detailPrototype);
			}

			// Set the DetailPrototypes

			if (detailPrototypes.Count > 0)
			{
				terrainData.detailPrototypes = detailPrototypes.ToArray();
			}

			// Set the DetailLayers
			for(int i = 0; i < numDetailLayers; ++i)
			{
				terrainData.SetDetailLayer(0, 0, i, convertedDetailMaps[i]);
			}
#endif
		}
		/// <summary>
		/// Returns true if given gameobjet is in Project only, and not in scene.
		/// </summary>
		/// <param name="go"></param>
		/// <returns></returns>
		public static bool IsGameObjectInProject(GameObject go)
		{
			return HEU_AssetDatabase.ContainsAsset(go);
		}
예제 #18
0
	/// <summary>
	/// Upload the inputData (mesh geometry) into the input node with inputNodeID.
	/// </summary>
	/// <param name="session">Session that the input node exists in</param>
	/// <param name="inputNodeID">ID of the input node</param>
	/// <param name="inputData">Container of the mesh geometry</param>
	/// <returns>True if successfully uploaded data</returns>
	public bool UploadData(HEU_SessionBase session, HAPI_NodeId inputNodeID, HEU_InputData inputData)
	{
	    HEU_InputDataMeshes inputDataMeshes = inputData as HEU_InputDataMeshes;
	    if (inputDataMeshes == null)
	    {
		Debug.LogError("Expected HEU_InputDataMeshes type for inputData, but received unsupported type.");
		return false;
	    }

	    List<Vector3> vertices = new List<Vector3>();
	    List<Vector3> normals = new List<Vector3>();
	    List<Color> colors = new List<Color>();

#if UNITY_2018_2_OR_NEWER
	    const int NumUVSets = 8;
#else
	    const int NumUVSets = 4;
#endif
	    List<Vector3>[] uvs = new List<Vector3>[NumUVSets];
	    for (int u = 0; u < NumUVSets; ++u)
	    {
		uvs[u] = new List<Vector3>();
	    }

	    // Use tempUVs to help with reindexing
	    List<Vector3>[] tempUVs = new List<Vector3>[NumUVSets];
	    for (int u = 0; u < NumUVSets; ++u)
	    {
		tempUVs[u] = new List<Vector3>();
	    }

	    List<int> pointIndexList = new List<int>();
	    List<int> vertIndexList = new List<int>();

	    int numMaterials = 0;

	    int numMeshes = inputDataMeshes._inputMeshes.Count;

	    // Get the parent's world transform, so when there are multiple child meshes,
	    // can merge and apply their local transform after subtracting their parent's world transform
	    Matrix4x4 rootInvertTransformMatrix = Matrix4x4.identity;
	    if (numMeshes > 1)
	    {
		rootInvertTransformMatrix = inputDataMeshes._inputObject.transform.worldToLocalMatrix;
	    }

	    // Always using the first submesh topology. This doesn't support mixed topology (triangles and quads).
	    MeshTopology meshTopology = inputDataMeshes._inputMeshes[0]._mesh.GetTopology(0);

	    int numVertsPerFace = 3;
	    if (meshTopology == MeshTopology.Quads)
	    {
		numVertsPerFace = 4;
	    }

	    // For all meshes:
	    // Accumulate vertices, normals, uvs, colors, and indices.
	    // Keep track of indices start and count for each mesh for later when uploading material assignments and groups.
	    // Find shared vertices, and use unique set of vertices to use as point positions.
	    // Need to reindex indices for both unique vertices, as well as vertex attributes.
	    for (int i = 0; i < numMeshes; ++i)
	    {
		Vector3[] meshVertices = inputDataMeshes._inputMeshes[i]._mesh.vertices;
		Matrix4x4 localToWorld = rootInvertTransformMatrix * inputDataMeshes._inputMeshes[i]._transform.localToWorldMatrix;

		List<Vector3> uniqueVertices = new List<Vector3>();

		// Keep track of old vertex positions (old vertex slot points to new unique vertex slot)
		int[] reindexVertices = new int[meshVertices.Length];
		Dictionary<Vector3, int> reindexMap = new Dictionary<Vector3, int>();

		// For each vertex, check against subsequent vertices for shared positions.
		for (int a = 0; a < meshVertices.Length; ++a)
		{
		    Vector3 va = meshVertices[a];

		    if (!reindexMap.ContainsKey(va))
		    {
			if (numMeshes > 1 && !inputDataMeshes._hasLOD)
			{
			    // For multiple meshes that are not LODs, apply local transform on vertices to get the merged mesh.
			    uniqueVertices.Add(localToWorld.MultiplyPoint(va));
			}
			else
			{
			    uniqueVertices.Add(va);
			}

			// Reindex to point to unique vertex slot
			reindexVertices[a] = uniqueVertices.Count - 1;
			reindexMap[va] = uniqueVertices.Count - 1;
		    }
		    else
		    {
			reindexVertices[a] = reindexMap[va];
		    }
		}

		int vertexOffset = vertices.Count;
		vertices.AddRange(uniqueVertices);

		Vector3[] meshNormals = inputDataMeshes._inputMeshes[i]._mesh.normals;
		Color[] meshColors = inputDataMeshes._inputMeshes[i]._mesh.colors;

		// This is really silly. mesh.GetUVs gives uvs regardless if they exist or not (makes duplicates of
		// first uv if they don't exist), but mesh.uv* gives correct UVs, but in Vector2 format.
		// Since we need to convert to Vector3 later, this checks mesh.uv*, then uses mesh.GetUVs to get in Vector3.
		// Note skipping uv1 as its internally used (i.e. the 2nd uv set is uv2)
		int uindex = 0;
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv, tempUVs[0], uindex++);
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv2, tempUVs[1], uindex++);
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv3, tempUVs[2], uindex++);
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv4, tempUVs[3], uindex++);
#if UNITY_2018_2_OR_NEWER
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv5, tempUVs[4], uindex++);
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv6, tempUVs[5], uindex++);
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv7, tempUVs[6], uindex++);
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv8, tempUVs[7], uindex++);
#endif

		inputDataMeshes._inputMeshes[i]._indexStart = new uint[inputDataMeshes._inputMeshes[i]._numSubMeshes];
		inputDataMeshes._inputMeshes[i]._indexCount = new uint[inputDataMeshes._inputMeshes[i]._numSubMeshes];

		// For each submesh:
		// Generate face to point index -> pointIndexList
		// Generate face to vertex attribute index -> vertIndexList
		for (int j = 0; j < inputDataMeshes._inputMeshes[i]._numSubMeshes; ++j)
		{
		    int indexStart = pointIndexList.Count;
		    int vertIndexStart = vertIndexList.Count;

		    // Indices have to be re-indexed with our own offset 
		    // (using GetIndices to generalize triangles and quad indices)
		    int[] meshIndices = inputDataMeshes._inputMeshes[i]._mesh.GetIndices(j);
		    int numIndices = meshIndices.Length;
		    for (int k = 0; k < numIndices; ++k)
		    {
			int originalIndex = meshIndices[k];
			meshIndices[k] = reindexVertices[originalIndex];

			pointIndexList.Add(vertexOffset + meshIndices[k]);
			vertIndexList.Add(vertIndexStart + k);

			if (meshNormals != null && (originalIndex < meshNormals.Length))
			{
			    normals.Add(meshNormals[originalIndex]);
			}

			for (int u = 0; u < NumUVSets; ++u)
			{
			    if (tempUVs[u].Count > 0)
			    {
				uvs[u].Add(tempUVs[u][originalIndex]);
			    }
			}

			if (meshColors != null && (originalIndex < meshColors.Length))
			{
			    colors.Add(meshColors[originalIndex]);
			}
		    }

		    inputDataMeshes._inputMeshes[i]._indexStart[j] = (uint)indexStart;
		    inputDataMeshes._inputMeshes[i]._indexCount[j] = (uint)(pointIndexList.Count) - inputDataMeshes._inputMeshes[i]._indexStart[j];
		}

		numMaterials += inputDataMeshes._inputMeshes[i]._materials != null ? inputDataMeshes._inputMeshes[i]._materials.Length : 0;
	    }

	    // It is possible for some meshes to not have normals/uvs/colors while others do.
	    // In the case where an attribute is missing on some meshes, we clear out those attributes so we don't upload
	    // partial attribute data.
	    int totalAllVertexCount = vertIndexList.Count;
	    if (normals.Count != totalAllVertexCount)
	    {
		normals = null;
	    }

	    if (colors.Count != totalAllVertexCount)
	    {
		colors = null;
	    }

	    HAPI_PartInfo partInfo = new HAPI_PartInfo();
	    partInfo.faceCount = vertIndexList.Count / numVertsPerFace;
	    partInfo.vertexCount = vertIndexList.Count;
	    partInfo.pointCount = vertices.Count;
	    partInfo.pointAttributeCount = 1;
	    partInfo.vertexAttributeCount = 0;
	    partInfo.primitiveAttributeCount = 0;
	    partInfo.detailAttributeCount = 0;

	    //Debug.LogFormat("Faces: {0}; Vertices: {1}; Verts/Face: {2}", partInfo.faceCount, partInfo.vertexCount, numVertsPerFace);

	    if (normals != null && normals.Count > 0)
	    {
		partInfo.vertexAttributeCount++;
	    }

	    for (int u = 0; u < NumUVSets; ++u)
	    {
		if (uvs[u].Count > 0 && uvs[u].Count == totalAllVertexCount)
		{
		    partInfo.vertexAttributeCount++;
		}
		else
		{
		    uvs[u].Clear();
		}
	    }

	    if (colors != null && colors.Count > 0)
	    {
		partInfo.vertexAttributeCount++;
	    }

	    if (numMaterials > 0)
	    {
		partInfo.primitiveAttributeCount++;
	    }

	    if (numMeshes > 0)
	    {
		partInfo.primitiveAttributeCount++;
	    }

	    if (inputDataMeshes._hasLOD)
	    {
		partInfo.primitiveAttributeCount++;
		partInfo.detailAttributeCount++;
	    }

	    HAPI_GeoInfo displayGeoInfo = new HAPI_GeoInfo();
	    if (!session.GetDisplayGeoInfo(inputNodeID, ref displayGeoInfo))
	    {
		return false;
	    }

	    HAPI_NodeId displayNodeID = displayGeoInfo.nodeId;

	    if (!session.SetPartInfo(displayNodeID, 0, ref partInfo))
	    {
		Debug.LogError("Failed to set input part info. ");
		return false;
	    }

	    int[] faceCounts = new int[partInfo.faceCount];
	    for (int i = 0; i < partInfo.faceCount; ++i)
	    {
		faceCounts[i] = numVertsPerFace;
	    }

	    int[] faceIndices = pointIndexList.ToArray();

	    if (!HEU_GeneralUtility.SetArray2Arg(displayNodeID, 0, session.SetFaceCount, faceCounts, 0, partInfo.faceCount))
	    {
		Debug.LogError("Failed to set input geometry face counts.");
		return false;
	    }

	    if (!HEU_GeneralUtility.SetArray2Arg(displayNodeID, 0, session.SetVertexList, faceIndices, 0, partInfo.vertexCount))
	    {
		Debug.LogError("Failed to set input geometry indices.");
		return false;
	    }

	    if (!HEU_InputMeshUtility.SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_POSITION, 3, vertices.ToArray(), ref partInfo, true))
	    {
		Debug.LogError("Failed to set input geometry position.");
		return false;
	    }

	    int[] vertIndices = vertIndexList.ToArray();

	    //if(normals != null && !SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_NORMAL, 3, normals.ToArray(), ref partInfo, true))
	    if (normals != null && !HEU_InputMeshUtility.SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_NORMAL, 3, normals.ToArray(), vertIndices, ref partInfo, true))
	    {
		Debug.LogError("Failed to set input geometry normals.");
		return false;
	    }

	    for (int u = 0; u < NumUVSets; ++u)
	    {
		if (uvs[u].Count > 0)
		{
		    // Skip uv1 as its used internally. So it goes: uv, uv2, ..., uv8
		    string uvName = u == 0 ? HEU_Defines.HAPI_ATTRIB_UV : string.Format("{0}{1}", HEU_Defines.HAPI_ATTRIB_UV, u + 1);
		    if (!HEU_InputMeshUtility.SetMeshVertexAttribute(session, displayNodeID, 0, uvName, 3, uvs[u].ToArray(), vertIndices, ref partInfo, false))
		    {
			Debug.LogError("Failed to set input geometry UV" + u);
			return false;
		    }
		}
	    }

	    if (colors != null && colors.Count > 0)
	    {
		Vector3[] rgb = new Vector3[colors.Count];
		float[] alpha = new float[colors.Count];
		for (int i = 0; i < colors.Count; ++i)
		{
		    rgb[i][0] = colors[i].r;
		    rgb[i][1] = colors[i].g;
		    rgb[i][2] = colors[i].b;

		    alpha[i] = colors[i].a;
		}

		//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_COLOR, 3, rgb, ref partInfo, false))
		if (!HEU_InputMeshUtility.SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_COLOR, 3, rgb, vertIndices, ref partInfo, false))
		{
		    Debug.LogError("Failed to set input geometry colors.");
		    return false;
		}

		//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_ALPHA, 1, alpha, ref partInfo, false))
		if (!HEU_InputMeshUtility.SetMeshVertexFloatAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_ALPHA, 1, alpha, vertIndices, ref partInfo))
		{
		    Debug.LogError("Failed to set input geometry color alpha.");
		    return false;
		}
	    }

	    // Set material names for round-trip perservation of material assignment
	    // Each HEU_UploadMeshData might have a list of submeshes and materials
	    // These are all combined into a single mesh, with group names
	    if (numMaterials > 0)
	    {
		bool bFoundAtleastOneValidMaterial = false;

		string[] materialIDs = new string[partInfo.faceCount];
		for (int g = 0; g < inputDataMeshes._inputMeshes.Count; ++g)
		{
		    if (inputDataMeshes._inputMeshes[g]._numSubMeshes != inputDataMeshes._inputMeshes[g]._materials.Length)
		    {
			// Number of submeshes should equal number of materials since materials determine submeshes
			continue;
		    }

		    for (int i = 0; i < inputDataMeshes._inputMeshes[g]._materials.Length; ++i)
		    {
			string materialName = HEU_AssetDatabase.GetAssetPathWithSubAssetSupport(inputDataMeshes._inputMeshes[g]._materials[i]);
			if (materialName == null)
			{
			    materialName = "";
			}
			else if (materialName.StartsWith(HEU_Defines.DEFAULT_UNITY_BUILTIN_RESOURCES))
			{
			    materialName = HEU_AssetDatabase.GetUniqueAssetPathForUnityAsset(inputDataMeshes._inputMeshes[g]._materials[i]);
			}

			bFoundAtleastOneValidMaterial |= !string.IsNullOrEmpty(materialName);

			int faceStart = (int)inputDataMeshes._inputMeshes[g]._indexStart[i] / numVertsPerFace;
			int faceEnd = faceStart + ((int)inputDataMeshes._inputMeshes[g]._indexCount[i] / numVertsPerFace);
			for (int m = faceStart; m < faceEnd; ++m)
			{
			    materialIDs[m] = materialName;
			}
		    }
		}

		if (bFoundAtleastOneValidMaterial)
		{
		    HAPI_AttributeInfo materialIDAttrInfo = new HAPI_AttributeInfo();
		    materialIDAttrInfo.exists = true;
		    materialIDAttrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM;
		    materialIDAttrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_STRING;
		    materialIDAttrInfo.count = partInfo.faceCount;
		    materialIDAttrInfo.tupleSize = 1;
		    materialIDAttrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

		    if (!session.AddAttribute(displayNodeID, 0, HEU_PluginSettings.UnityMaterialAttribName, ref materialIDAttrInfo))
		    {
			Debug.LogError("Failed to add input geometry unity material name attribute.");
			return false;
		    }

		    if (!HEU_GeneralUtility.SetAttributeArray(displayNodeID, 0, HEU_PluginSettings.UnityMaterialAttribName, ref materialIDAttrInfo, materialIDs, session.SetAttributeStringData, partInfo.faceCount))
		    {
			Debug.LogError("Failed to set input geometry unity material name.");
			return false;
		    }
		}
	    }

	    // Set mesh name attribute
	    HAPI_AttributeInfo attrInfo = new HAPI_AttributeInfo();
	    attrInfo.exists = true;
	    attrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM;
	    attrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_STRING;
	    attrInfo.count = partInfo.faceCount;
	    attrInfo.tupleSize = 1;
	    attrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

	    if (session.AddAttribute(displayNodeID, 0, HEU_PluginSettings.UnityInputMeshAttr, ref attrInfo))
	    {
		string[] primitiveNameAttr = new string[partInfo.faceCount];

		for (int g = 0; g < inputDataMeshes._inputMeshes.Count; ++g)
		{
		    for (int i = 0; i < inputDataMeshes._inputMeshes[g]._numSubMeshes; ++i)
		    {
			int faceStart = (int)inputDataMeshes._inputMeshes[g]._indexStart[i] / numVertsPerFace;
			int faceEnd = faceStart + ((int)inputDataMeshes._inputMeshes[g]._indexCount[i] / numVertsPerFace);
			for (int m = faceStart; m < faceEnd; ++m)
			{
			    primitiveNameAttr[m] = inputDataMeshes._inputMeshes[g]._meshPath;
			}
		    }
		}

		if (!HEU_GeneralUtility.SetAttributeArray(displayNodeID, 0, HEU_PluginSettings.UnityInputMeshAttr, ref attrInfo, primitiveNameAttr, session.SetAttributeStringData, partInfo.faceCount))
		{
		    Debug.LogError("Failed to set input geometry unity mesh name.");
		    return false;
		}
	    }
	    else
	    {
		return false;
	    }

	    // Set LOD group membership
	    if (inputDataMeshes._hasLOD)
	    {
		int[] membership = new int[partInfo.faceCount];

		for (int g = 0; g < inputDataMeshes._inputMeshes.Count; ++g)
		{
		    if (g > 0)
		    {
			// Clear array
			for (int m = 0; m < partInfo.faceCount; ++m)
			{
			    membership[m] = 0;
			}
		    }

		    // Set 1 for faces belonging to this group
		    for (int s = 0; s < inputDataMeshes._inputMeshes[g]._numSubMeshes; ++s)
		    {
			int faceStart = (int)inputDataMeshes._inputMeshes[g]._indexStart[s] / numVertsPerFace;
			int faceEnd = faceStart + ((int)inputDataMeshes._inputMeshes[g]._indexCount[s] / numVertsPerFace);
			for (int m = faceStart; m < faceEnd; ++m)
			{
			    membership[m] = 1;
			}
		    }

		    if (!session.AddGroup(displayNodeID, 0, HAPI_GroupType.HAPI_GROUPTYPE_PRIM, inputDataMeshes._inputMeshes[g]._meshName))
		    {
			Debug.LogError("Failed to add input geometry LOD group name.");
			return false;
		    }

		    if (!session.SetGroupMembership(displayNodeID, 0, HAPI_GroupType.HAPI_GROUPTYPE_PRIM, inputDataMeshes._inputMeshes[g]._meshName, membership, 0, partInfo.faceCount))
		    {
			Debug.LogError("Failed to set input geometry LOD group name.");
			return false;
		    }
		}
	    }

	    return session.CommitGeo(displayNodeID);
	}
		private void GenerateTerrain(List<HEU_LoadBufferVolume> terrainBuffers)
		{
			Transform parent = this.gameObject.transform;

			int numVolumes = terrainBuffers.Count;
			for(int t = 0; t < numVolumes; ++t)
			{
				if (terrainBuffers[t]._heightMap != null)
				{
					GameObject newGameObject = new GameObject("heightfield_" + terrainBuffers[t]._tileIndex);
					Transform newTransform = newGameObject.transform;
					newTransform.parent = parent;

					HEU_GeneratedOutput generatedOutput = new HEU_GeneratedOutput();
					generatedOutput._outputData._gameObject = newGameObject;

					Terrain terrain = HEU_GeneralUtility.GetOrCreateComponent<Terrain>(newGameObject);
					TerrainCollider collider = HEU_GeneralUtility.GetOrCreateComponent<TerrainCollider>(newGameObject);

					if (!string.IsNullOrEmpty(terrainBuffers[t]._terrainDataPath))
					{
						terrain.terrainData = HEU_AssetDatabase.LoadAssetAtPath(terrainBuffers[t]._terrainDataPath, typeof(TerrainData)) as TerrainData;
						if (terrain.terrainData == null)
						{
							Debug.LogWarningFormat("TerrainData, set via attribute, not found at: {0}", terrainBuffers[t]._terrainDataPath);
						}
					}

					if (terrain.terrainData == null)
					{
						terrain.terrainData = new TerrainData();
					}
					TerrainData terrainData = terrain.terrainData;
					collider.terrainData = terrainData;

					HEU_TerrainUtility.SetTerrainMaterial(terrain);

#if UNITY_2018_3_OR_NEWER
					terrain.allowAutoConnect = true;
					// This has to be set after setting material
					terrain.drawInstanced = true;
#endif

					int heightMapSize = terrainBuffers[t]._heightMapWidth;

					terrainData.heightmapResolution = heightMapSize;
					if (terrainData.heightmapResolution != heightMapSize)
					{
						Debug.LogErrorFormat("Unsupported terrain size: {0}", heightMapSize);
						continue;
					}

					// The terrainData.baseMapResolution is not set here, but rather left to whatever default Unity uses
					// The terrainData.alphamapResolution is set later when setting the alphamaps.

					// 32 is the default for resolutionPerPatch
					const int detailResolution = 1024;
					const int resolutionPerPatch = 32;
					terrainData.SetDetailResolution(detailResolution, resolutionPerPatch);

					terrainData.SetHeights(0, 0, terrainBuffers[t]._heightMap);

					// Note that Unity uses a default height range of 600 when a flat terrain is created.
					// Without a non-zero value for the height range, user isn't able to draw heights.
					// Therefore, set 600 as the value if height range is currently 0 (due to flat heightfield).
					float heightRange = terrainBuffers[t]._heightRange;
					if (heightRange == 0)
					{
						heightRange = 600;
					}

					terrainData.size = new Vector3(terrainBuffers[t]._terrainSizeX, heightRange, terrainBuffers[t]._terrainSizeY);

					terrain.Flush();

					// Set position
					HAPI_Transform hapiTransformVolume = new HAPI_Transform(true);
					hapiTransformVolume.position[0] += terrainBuffers[t]._position[0];
					hapiTransformVolume.position[1] += terrainBuffers[t]._position[1];
					hapiTransformVolume.position[2] += terrainBuffers[t]._position[2];
					HEU_HAPIUtility.ApplyLocalTransfromFromHoudiniToUnity(ref hapiTransformVolume, newTransform);

					// Set layers
					Texture2D defaultTexture = HEU_VolumeCache.LoadDefaultSplatTexture();
					int numLayers = terrainBuffers[t]._layers.Count;

#if UNITY_2018_3_OR_NEWER

					// Create TerrainLayer for each heightfield layer.
					// Note that height and mask layers are ignored (i.e. not created as TerrainLayers).
					// Since height layer is first, only process layers from 2nd index onwards.
					if (numLayers > 1)
					{
						TerrainLayer[] terrainLayers = new TerrainLayer[numLayers - 1];
						for (int m = 1; m < numLayers; ++m)
						{
							TerrainLayer terrainlayer = null;

							HEU_LoadBufferVolumeLayer layer = terrainBuffers[t]._layers[m];

							// Look up TerrainLayer file via attribute if user has set it
							if (!string.IsNullOrEmpty(layer._layerPath))
							{
								terrainlayer = HEU_AssetDatabase.LoadAssetAtPath(layer._layerPath, typeof(TerrainLayer)) as TerrainLayer;
								if (terrainlayer == null)
								{
									Debug.LogWarningFormat("TerrainLayer, set via attribute, not found at: {0}", layer._layerPath);
									continue;
								}
							}

							if (terrainlayer == null)
							{
								terrainlayer = new TerrainLayer();
							}

							if (!string.IsNullOrEmpty(layer._diffuseTexturePath))
							{
								terrainlayer.diffuseTexture = HEU_MaterialFactory.LoadTexture(layer._diffuseTexturePath);
							}
							if (terrainlayer.diffuseTexture == null)
							{
								terrainlayer.diffuseTexture = defaultTexture;
							}

							terrainlayer.diffuseRemapMin = Vector4.zero;
							terrainlayer.diffuseRemapMax = Vector4.one;

							if (!string.IsNullOrEmpty(layer._maskTexturePath))
							{
								terrainlayer.maskMapTexture = HEU_MaterialFactory.LoadTexture(layer._maskTexturePath);
							}

							terrainlayer.maskMapRemapMin = Vector4.zero;
							terrainlayer.maskMapRemapMax = Vector4.one;

							terrainlayer.metallic = layer._metallic;

							if (!string.IsNullOrEmpty(layer._normalTexturePath))
							{
								terrainlayer.normalMapTexture = HEU_MaterialFactory.LoadTexture(layer._normalTexturePath);
							}

							terrainlayer.normalScale = layer._normalScale;

							terrainlayer.smoothness = layer._smoothness;
							terrainlayer.specular = layer._specularColor;
							terrainlayer.tileOffset = layer._tileOffset;

							if (layer._tileSize.magnitude == 0f && terrainlayer.diffuseTexture != null)
							{
								// Use texture size if tile size is 0
								layer._tileSize = new Vector2(terrainlayer.diffuseTexture.width, terrainlayer.diffuseTexture.height);
							}
							terrainlayer.tileSize = layer._tileSize;

							// Note index is m - 1 due to skipping height layer
							terrainLayers[m - 1] = terrainlayer;
						}
						terrainData.terrainLayers = terrainLayers;
					}

#else
					// Need to create SplatPrototype for each layer in heightfield, representing the textures.
					SplatPrototype[] splatPrototypes = new SplatPrototype[numLayers];
					for (int m = 0; m < numLayers; ++m)
					{
						splatPrototypes[m] = new SplatPrototype();

						HEU_LoadBufferVolumeLayer layer = terrainBuffers[t]._layers[m];

						Texture2D diffuseTexture = null;
						if (!string.IsNullOrEmpty(layer._diffuseTexturePath))
						{
							diffuseTexture = HEU_MaterialFactory.LoadTexture(layer._diffuseTexturePath);
						}
						if (diffuseTexture == null)
						{
							diffuseTexture = defaultTexture;
						}
						splatPrototypes[m].texture = diffuseTexture;

						splatPrototypes[m].tileOffset = layer._tileOffset;
						if (layer._tileSize.magnitude == 0f && diffuseTexture != null)
						{
							// Use texture size if tile size is 0
							layer._tileSize = new Vector2(diffuseTexture.width, diffuseTexture.height);
						}
						splatPrototypes[m].tileSize = layer._tileSize;

						splatPrototypes[m].metallic = layer._metallic;
						splatPrototypes[m].smoothness = layer._smoothness;

						if (!string.IsNullOrEmpty(layer._normalTexturePath))
						{
							splatPrototypes[m].normalMap = HEU_MaterialFactory.LoadTexture(layer._normalTexturePath);
						}
					}
					terrainData.splatPrototypes = splatPrototypes;
#endif

					// Set the splatmaps
					if (terrainBuffers[t]._splatMaps != null)
					{
						// Set the alphamap size before setting the alphamaps to get correct scaling
						// The alphamap size comes from the first alphamap layer
						int alphamapResolution = terrainBuffers[t]._heightMapWidth;
						if (numLayers > 1)
						{
							alphamapResolution = terrainBuffers[t]._layers[1]._heightMapWidth;
						}
						terrainData.alphamapResolution = alphamapResolution;

						terrainData.SetAlphamaps(0, 0, terrainBuffers[t]._splatMaps);
					}

					// Set the tree scattering
					if (terrainBuffers[t]._scatterTrees != null)
					{
						HEU_TerrainUtility.ApplyScatter(terrainData, terrainBuffers[t]._scatterTrees);
					}

					terrainBuffers[t]._generatedOutput = generatedOutput;
					_generatedOutputs.Add(generatedOutput);

					SetOutputVisiblity(terrainBuffers[t]);
				}
			}
		}
예제 #20
0
		private bool DrawDetailsGeometry()
		{
			bool bChanged = false;

			EditorGUIUtility.labelWidth = 250;

			{
				bool oldValue = HEU_PluginSettings.Curves_ShowInSceneView;
				bool newValue = HEU_EditorUI.DrawToggleLeft(oldValue, "Show Curves in Scene View");
				if (newValue != oldValue)
				{
					HEU_PluginSettings.Curves_ShowInSceneView = newValue;
					HEU_HoudiniAsset.SetCurvesVisibilityInScene(newValue);
					bChanged = true;
				}
			}
			HEU_EditorUI.DrawSeparator();
			{
				float oldValue = HEU_PluginSettings.NormalGenerationThresholdAngle;
				float newValue = EditorGUILayout.DelayedFloatField("Normal Generation Threshold Angle", oldValue);
				if (newValue != oldValue)
				{
					HEU_PluginSettings.NormalGenerationThresholdAngle = newValue;
					bChanged = true;
				}
			}
			HEU_EditorUI.DrawSeparator();
			{
				string oldValue = HEU_PluginSettings.DefaultTerrainMaterial;
				if (_terrainMaterial == null && !string.IsNullOrEmpty(oldValue))
				{
					//Debug.Log("Loading terrain material at: " + oldValue);
					_terrainMaterial = HEU_MaterialFactory.LoadUnityMaterial(oldValue);
				}

				Material newMaterial = EditorGUILayout.ObjectField("Default Terrain Material", _terrainMaterial, typeof(Material), false) as Material;
				if (newMaterial != _terrainMaterial)
				{
					HEU_PluginSettings.DefaultTerrainMaterial = (newMaterial != null) ? HEU_AssetDatabase.GetAssetPathWithSubAssetSupport(newMaterial) : "";
					_terrainMaterial = newMaterial;
					bChanged = true;
				}
			}
			HEU_EditorUI.DrawSeparator();
			{
				string oldValue = HEU_PluginSettings.TerrainSplatTextureDefault;
				string newValue = EditorGUILayout.DelayedTextField("Default Terrain Splat Texture", oldValue);
				if (!newValue.Equals(oldValue))
				{
					HEU_PluginSettings.TerrainSplatTextureDefault = newValue;
					bChanged = true;
				}
			}
			HEU_EditorUI.DrawSeparator();
			{
				string oldValue = HEU_PluginSettings.DefaultStandardShader;
				string newValue = EditorGUILayout.DelayedTextField("Default Standard Shader", oldValue);
				if (!newValue.Equals(oldValue))
				{
					HEU_PluginSettings.DefaultStandardShader = newValue;
					bChanged = true;
				}
			}
			HEU_EditorUI.DrawSeparator();
			{
				string oldValue = HEU_PluginSettings.DefaultTransparentShader;
				string newValue = EditorGUILayout.DelayedTextField("Default Transparent Shader", oldValue);
				if (!newValue.Equals(oldValue))
				{
					HEU_PluginSettings.DefaultTransparentShader = newValue;
					bChanged = true;
				}
			}
			HEU_EditorUI.DrawSeparator();
			{
				string oldValue = HEU_PluginSettings.DefaultVertexColorShader;
				string newValue = EditorGUILayout.DelayedTextField("Default Vertex Color Shader", oldValue);
				if (!newValue.Equals(oldValue))
				{
					HEU_PluginSettings.DefaultVertexColorShader = newValue;
					bChanged = true;
				}
			}
			HEU_EditorUI.DrawSeparator();
			{
				string oldValue = HEU_PluginSettings.DefaultCurveShader;
				string newValue = EditorGUILayout.DelayedTextField("Default Curve Shader", oldValue);
				if (!newValue.Equals(oldValue))
				{
					HEU_PluginSettings.DefaultCurveShader = newValue;
					bChanged = true;
				}
			}

			HEU_EditorUI.DrawSeparator();

			EditorGUIUtility.labelWidth = 0;

			return bChanged;
		}
예제 #21
0
		private void GenerateInstancesFromAssetPaths(HEU_LoadBufferInstancer instancerBuffer, Transform instanceRootTransform)
	{
			// For single asset, this is set when its impoted
			GameObject singleAssetGO = null;

			// For multi assets, keep track of loaded objects so we only need to load once for each object
			Dictionary<string, GameObject> loadedUnityObjectMap = new Dictionary<string, GameObject>();

			// Temporary empty gameobject in case the specified Unity asset is not found
			GameObject tempGO = null;

			if (instancerBuffer._assetPaths.Length == 1)
			{
				// Single asset path
				if (!string.IsNullOrEmpty(instancerBuffer._assetPaths[0]))
				{
					HEU_AssetDatabase.ImportAsset(instancerBuffer._assetPaths[0], HEU_AssetDatabase.HEU_ImportAssetOptions.Default);
					singleAssetGO = HEU_AssetDatabase.LoadAssetAtPath(instancerBuffer._assetPaths[0], typeof(GameObject)) as GameObject;
				}

				if (singleAssetGO == null)
				{
					Debug.LogErrorFormat("Asset at path {0} not found. Unable to create instances for {1}.", instancerBuffer._assetPaths[0], instancerBuffer._name);
					return;
				}
			}

			int numInstancesCreated = 0;
			int numInstances = instancerBuffer._instanceTransforms.Length;
			for (int i = 0; i < numInstances; ++i)
			{
				// Reset to the single asset for each instance allows which is null if using multi asset
				// therefore forcing the instance asset to be found
				GameObject unitySrcGO = singleAssetGO;

				if (unitySrcGO == null)
				{
					// If not using single asset, then there must be an asset path for each instance

					if (string.IsNullOrEmpty(instancerBuffer._assetPaths[i]))
					{
						continue;
					}

					if (!loadedUnityObjectMap.TryGetValue(instancerBuffer._assetPaths[i], out unitySrcGO))
					{
						// Try loading it
						//HEU_AssetDatabase.ImportAsset(instancerBuffer._assetPaths[i], HEU_AssetDatabase.HEU_ImportAssetOptions.Default);
						unitySrcGO = HEU_AssetDatabase.LoadAssetAtPath(instancerBuffer._assetPaths[i], typeof(GameObject)) as GameObject;

						if (unitySrcGO == null)
						{
							Debug.LogErrorFormat("Unable to load asset at {0} for instancing!", instancerBuffer._assetPaths[i]);

							// Even though the source Unity object is not found, we should create an object instance info to track it
							if (tempGO == null)
							{
								tempGO = new GameObject();
							}
							unitySrcGO = tempGO;
						}

						// Adding to map even if not found so we don't flood the log with the same error message
						loadedUnityObjectMap.Add(instancerBuffer._assetPaths[i], unitySrcGO);
					}
				}

				CreateNewInstanceFromObject(unitySrcGO, (numInstancesCreated + 1), instanceRootTransform, ref instancerBuffer._instanceTransforms[i],
					instancerBuffer._instancePrefixes, instancerBuffer._name);

				numInstancesCreated++;
			}

			if (tempGO != null)
			{
				HEU_GeneralUtility.DestroyImmediate(tempGO, bRegisterUndo: false);
			}
		}
예제 #22
0
		public void LoadPreset(HEU_SessionBase session, HEU_InputPreset inputPreset)
		{
			ResetInputNode(session);

			ChangeInputType(session, inputPreset._inputObjectType);

			if (inputPreset._inputObjectType == HEU_InputNode.InputObjectType.UNITY_MESH)
			{
				int numObjects = inputPreset._inputObjectPresets.Count;
				for (int i = 0; i < numObjects; ++i)
				{
					if (!string.IsNullOrEmpty(inputPreset._inputObjectPresets[i]._gameObjectName))
					{
						GameObject inputGO = null;
						if (inputPreset._inputObjectPresets[i]._isSceneObject)
						{
							inputGO = HEU_GeneralUtility.GetGameObjectByNameInScene(inputPreset._inputObjectPresets[i]._gameObjectName);
						}
						else
						{
							// Use the _gameObjectName as path to find in scene
							inputGO = HEU_AssetDatabase.LoadAssetAtPath(inputPreset._inputObjectPresets[i]._gameObjectName, typeof(GameObject)) as GameObject;
							if(inputGO == null)
							{
								Debug.LogErrorFormat("Unable to find input at {0}", inputPreset._inputObjectPresets[i]._gameObjectName);
							}
						}

						if (inputGO != null)
						{
							HEU_InputObjectInfo inputObject = AddInputObjectAtEnd(inputGO);
							inputObject._useTransformOffset = inputPreset._inputObjectPresets[i]._useTransformOffset;
							inputObject._translateOffset = inputPreset._inputObjectPresets[i]._translateOffset;
							inputObject._rotateOffset = inputPreset._inputObjectPresets[i]._rotateOffset;
							inputObject._scaleOffset = inputPreset._inputObjectPresets[i]._scaleOffset;
						}
						else
						{
							Debug.LogWarningFormat("Gameobject with name {0} not found. Unable to set input object.", inputPreset._inputAssetName);
						}
					}
				}
			}
			else if (inputPreset._inputObjectType == HEU_InputNode.InputObjectType.HDA)
			{
				if (!string.IsNullOrEmpty(inputPreset._inputAssetName))
				{
					GameObject inputAsset = GameObject.Find(inputPreset._inputAssetName);
					if (inputAsset != null)
					{
						HEU_HoudiniAssetRoot inputAssetRoot = inputAsset != null ? inputAsset.GetComponent<HEU_HoudiniAssetRoot>() : null;
						if (inputAssetRoot != null && inputAssetRoot._houdiniAsset != null)
						{
							// Need to reconnect and make sure connected asset is in this session

							_inputAsset = inputAsset;

							if (!inputAssetRoot._houdiniAsset.IsAssetValidInHoudini(session))
							{
								inputAssetRoot._houdiniAsset.RequestCook(true, false, true, true);
							}

							_connectedNodeID = inputAssetRoot._houdiniAsset.AssetID;

							_parentAsset.ConnectToUpstream(inputAssetRoot._houdiniAsset);

							_connectedInputAsset = _inputAsset;
						}
						else
						{
							Debug.LogErrorFormat("Input HDA with name {0} is not a valid asset (missing components). Unable to set input asset.", inputPreset._inputAssetName);
						}
					}
					else
					{
						Debug.LogWarningFormat("Game with name {0} not found. Unable to set input asset.", inputPreset._inputAssetName);
					}
				}
			}

			KeepWorldTransform = inputPreset._keepWorldTransform;
			PackGeometryBeforeMerging = inputPreset._packGeometryBeforeMerging;

			RequiresUpload = true;

			ClearUICache();
		}
		public void GenerateTerrainWithAlphamaps(HEU_SessionBase session, HEU_HoudiniAsset houdiniAsset, bool bRebuild)
		{
			if(_layers == null || _layers.Count == 0)
			{
				Debug.LogError("Unable to generate terrain due to lack of heightfield layers!");
				return;
			}

			HEU_VolumeLayer heightLayer = _layers[0];

			HAPI_VolumeInfo heightVolumeInfo = new HAPI_VolumeInfo();
			bool bResult = session.GetVolumeInfo(_ownerNode.GeoID, heightLayer._part.PartID, ref heightVolumeInfo);
			if (!bResult)
			{
				Debug.LogErrorFormat("Unable to get volume info for height layer: {0}!", heightLayer._layerName);
				return;
			}

			// Special handling of volume cache presets. It is applied here (if exists) because it might pertain to TerrainData that exists
			// in the AssetDatabase. If we don't apply here but rather create a new one, the existing file will get overwritten.
			// Applying the preset here for terrain ensures the TerrainData is reused.
			// Get the volume preset for this part
			HEU_VolumeCachePreset volumeCachePreset = houdiniAsset.GetVolumeCachePreset(_ownerNode.ObjectNode.ObjectName, _ownerNode.GeoName, TileIndex);
			if (volumeCachePreset != null)
			{
				ApplyPreset(volumeCachePreset);

				// Remove it so that it doesn't get applied when doing the recook step
				houdiniAsset.RemoveVolumeCachePreset(volumeCachePreset);
			}

			// The TerrainData and TerrainLayer files needs to be saved out if we create them. This creates the relative folder
			// path from the Asset's cache folder: {assetCache}/{geo name}/Terrain/Tile{tileIndex}/...
			string relativeFolderPath = HEU_Platform.BuildPath(_ownerNode.GeoName, HEU_Defines.HEU_FOLDER_TERRAIN, HEU_Defines.HEU_FOLDER_TILE + TileIndex);

			if (bRebuild)
			{
				// For full rebuild, re-create the TerrainData instead of using previous
				_terrainData = null;
			}

			//Debug.Log("Generating Terrain with AlphaMaps: " + (_terrainData != null ? _terrainData.name : "NONE"));
			TerrainData terrainData = _terrainData;
			Vector3 terrainOffsetPosition = Vector3.zero;

			// Look up TerrainData file via attribute if user has set it
			string terrainDataFile = HEU_GeneralUtility.GetAttributeStringValueSingle(session, _ownerNode.GeoID, heightLayer._part.PartID,
				HEU_Defines.DEFAULT_UNITY_HEIGHTFIELD_TERRAINDATA_FILE_ATTR, HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM);
			if (!string.IsNullOrEmpty(terrainDataFile))
			{
				TerrainData loadedTerrainData = HEU_AssetDatabase.LoadAssetAtPath(terrainDataFile, typeof(TerrainData)) as TerrainData;
				if (loadedTerrainData == null)
				{
					Debug.LogWarningFormat("TerrainData, set via attribute, not found at: {0}", terrainDataFile);
				}
				else
				{
					// In the case that the specified TerrainData belongs to another Terrain (i.e. input Terrain), 
					// make a copy of it and store it in our cache. Note that this overwrites existing TerrainData in our cache
					// because the workflow is such that attributes will always override local setting.
					string bakedTerrainPath = houdiniAsset.GetValidAssetCacheFolderPath();
					bakedTerrainPath = HEU_Platform.BuildPath(bakedTerrainPath, relativeFolderPath);
					terrainData = HEU_AssetDatabase.CopyAndLoadAssetAtAnyPath(loadedTerrainData, bakedTerrainPath, typeof(TerrainData), true) as TerrainData;
					if (terrainData == null)
					{
						Debug.LogErrorFormat("Unable to copy TerrainData from {0} for generating Terrain.", terrainDataFile);
					}
				}
			}

			// Generate the terrain and terrain data from the height layer. This applies height values.
			bResult = HEU_TerrainUtility.GenerateTerrainFromVolume(session, ref heightVolumeInfo, heightLayer._part.ParentGeoNode.GeoID,
				heightLayer._part.PartID, heightLayer._part.OutputGameObject, ref terrainData, out terrainOffsetPosition);
			if (!bResult || terrainData == null)
			{
				return;
			}

			if (_terrainData != terrainData)
			{
				_terrainData = terrainData;
				heightLayer._part.SetTerrainData(terrainData, relativeFolderPath);
			}

			heightLayer._part.SetTerrainOffsetPosition(terrainOffsetPosition);

			int terrainSize = terrainData.heightmapResolution;

			// Now process TerrainLayers and alpha maps

			// First, preprocess all layers to get heightfield arrays, converted to proper size
			List<float[]> heightFields = new List<float[]>();
			// Corresponding list of HF volume layers to process as splatmaps
			List<HEU_VolumeLayer> volumeLayersToProcess = new List<HEU_VolumeLayer>();

			int numLayers = _layers.Count;
			float minHeight = 0;
			float maxHeight = 0;
			float  heightRange = 0;
			// This skips the height layer, and processes all other layers.
			// Note that mask shouldn't be part of _layers at this point.
			for(int i = 1; i < numLayers; ++i)
			{
				float[] normalizedHF = HEU_TerrainUtility.GetNormalizedHeightmapFromPartWithMinMax(session, _ownerNode.GeoID, _layers[i]._part.PartID, 
					_layers[i]._xLength, _layers[i]._yLength, ref minHeight, ref maxHeight, ref heightRange);
				if (normalizedHF != null && normalizedHF.Length > 0)
				{
					heightFields.Add(normalizedHF);
					volumeLayersToProcess.Add(_layers[i]);
				}
			}

			int numVolumeLayers = volumeLayersToProcess.Count;

			HAPI_NodeId geoID;
			HAPI_PartId partID;

			Texture2D defaultTexture = LoadDefaultSplatTexture();

#if UNITY_2018_3_OR_NEWER

			// Create or update the terrain layers based on heightfield layers.

			// Keep existing TerrainLayers, and either update or append to them
			TerrainLayer[] existingTerrainLayers = terrainData.terrainLayers;

			// Total layers are existing layers + new alpha maps
			List<TerrainLayer> finalTerrainLayers = new List<TerrainLayer>(existingTerrainLayers);

			// This holds the alpha map indices for each layer that will be added to the TerrainData.
			// The alpha maps could be a mix of existing and new values, so need to know which to use
			// Initially set to use existing alpha maps, then override later on if specified via HF layers
			List<int> alphaMapIndices = new List<int>();
			for (int a = 0; a < existingTerrainLayers.Length; ++a)
			{
				// Negative indices for existing alpha map (offset by -1)
				alphaMapIndices.Add(-a - 1);
			}

			bool bNewTerrainLayer = false;
			HEU_VolumeLayer layer = null;
			TerrainLayer terrainLayer = null;
			bool bSetTerrainLayerProperties = true;
			for (int m = 0; m < numVolumeLayers; ++m)
			{
				bNewTerrainLayer = false;
				bSetTerrainLayerProperties = true;

				layer = volumeLayersToProcess[m];

				geoID = _ownerNode.GeoID;
				partID = layer._part.PartID;

				terrainLayer = null;

				int terrainLayerIndex = -1;

				// The TerrainLayer attribute overrides existing TerrainLayer. So if its set, load and use it.
				string terrainLayerFile = HEU_GeneralUtility.GetAttributeStringValueSingle(session, geoID, partID,
						HEU_Defines.DEFAULT_UNITY_HEIGHTFIELD_TERRAINLAYER_FILE_ATTR, HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM);
				if (!string.IsNullOrEmpty(terrainLayerFile))
				{
					terrainLayer = HEU_AssetDatabase.LoadAssetAtPath(terrainLayerFile, typeof(TerrainLayer)) as TerrainLayer;
					if (terrainLayer == null)
					{
						Debug.LogWarningFormat("TerrainLayer, set via attribute, not found at: {0}", terrainLayerFile);
						// Not earlying out or skipping this layer due to error because we want to keep proper indexing
						// by creating a new TerrainLayer.
					}
					else
					{
						// TerrainLayer loaded from attribute. 
						// It could be an existing TerrainLayer that is already part of finalTerrainLayers 
						// or could be a new one which needs to be added.

						// If its a different TerrainLayer than existing, update the finalTerrainLayers, and index.
						if (layer._terrainLayer != null && layer._terrainLayer != terrainLayer)
						{
							terrainLayerIndex = HEU_TerrainUtility.GetTerrainLayerIndex(layer._terrainLayer, existingTerrainLayers);
							if (terrainLayerIndex >= 0)
							{
								finalTerrainLayers[terrainLayerIndex] = terrainLayer;
							}
						}

						if (terrainLayerIndex == -1)
						{
							// Always check if its part of existing list so as not to add it again
							terrainLayerIndex = HEU_TerrainUtility.GetTerrainLayerIndex(terrainLayer, existingTerrainLayers);
						}
					}
				}

				// No terrain layer specified, so try using existing if we have it
				if (terrainLayer == null)
				{
					terrainLayerIndex = HEU_TerrainUtility.GetTerrainLayerIndex(layer._terrainLayer, existingTerrainLayers);
					if (terrainLayerIndex >= 0)
					{
						// Note the terrainLayerIndex is same for finalTerrainLayers as existingTerrainLayers
						terrainLayer = existingTerrainLayers[terrainLayerIndex];
					}
				}

				// Still not found, so just create a new one
				if (terrainLayer == null)
				{
					terrainLayer = new TerrainLayer();
					terrainLayer.name = layer._layerName;
					//Debug.LogFormat("Created new TerrainLayer with name: {0} ", terrainLayer.name);
					bNewTerrainLayer = true;
				}

				if (terrainLayerIndex == -1)
				{
					// Adding to the finalTerrainLayers if this is indeed a newly created or loaded TerrainLayer
					// (i.e. isn't already part of the TerrainLayers for this Terrain).
					// Save this layer's index for later on if we make a copy.
					terrainLayerIndex = finalTerrainLayers.Count;
					finalTerrainLayers.Add(terrainLayer);

					// Positive index for alpha map from heightfield (starting at 1)
					alphaMapIndices.Add(m + 1);
				}
				else
				{
					// Positive index for alpha map from heightfield (starting at 1)
					alphaMapIndices[terrainLayerIndex] = m + 1;
				}

				// For existing TerrainLayer, make a copy of it if it has custom layer attributes
				// because we don't want to change the original TerrainLayer.
				if (!bNewTerrainLayer && layer._hasLayerAttributes)
				{
					string bakedTerrainPath = houdiniAsset.GetValidAssetCacheFolderPath();
					bakedTerrainPath = HEU_Platform.BuildPath(bakedTerrainPath, relativeFolderPath);
					TerrainLayer prevTerrainLayer = terrainLayer;
					terrainLayer = HEU_AssetDatabase.CopyAndLoadAssetAtAnyPath(terrainLayer, bakedTerrainPath, typeof(TerrainLayer), true) as TerrainLayer;
					if (terrainLayer != null)
					{
						// Update the TerrainLayer reference in the list with this copy
						finalTerrainLayers[terrainLayerIndex] = terrainLayer;
					}
					else
					{
						Debug.LogErrorFormat("Unable to copy TerrainLayer '{0}' for generating Terrain. "
							+ "Using original TerrainLayer. Will not be able to set any TerrainLayer properties.", layer._layerName);
						terrainLayer = prevTerrainLayer;
						bSetTerrainLayerProperties = false;
						// Again, continuing on to keep proper indexing.
					}
				}

				// Now override layer properties if they have been set via attributes
				if (bSetTerrainLayerProperties)
				{
					LoadLayerPropertiesFromAttributes(session, geoID, partID, terrainLayer, bNewTerrainLayer, defaultTexture);
				}

				if (bNewTerrainLayer)
				{
					// In order to retain the new TerrainLayer, it must be saved to the AssetDatabase.
					Object savedObject = null;
					string layerFileNameWithExt = terrainLayer.name;
					if (!layerFileNameWithExt.EndsWith(HEU_Defines.HEU_EXT_TERRAINLAYER))
					{
						layerFileNameWithExt += HEU_Defines.HEU_EXT_TERRAINLAYER;
					}
					houdiniAsset.AddToAssetDBCache(layerFileNameWithExt, terrainLayer, relativeFolderPath, ref savedObject);
				}

				// Store reference
				layer._terrainLayer = terrainLayer;
			}

			// Get existing alpha maps so we can reuse the values if needed
			float[,,] existingAlphaMaps = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight);

			terrainData.terrainLayers = finalTerrainLayers.ToArray();

			int numTotalAlphaMaps = finalTerrainLayers.Count;

#else
			// Create or update the SplatPrototype based on heightfield layers.

			// Need to create or reuse SplatPrototype for each layer in heightfield, representing the textures.
			SplatPrototype[] existingSplats = terrainData.splatPrototypes;

			// A full rebuild clears out existing splats, but a regular cook keeps them.
			List<SplatPrototype> finalSplats = new List<SplatPrototype>(existingSplats);

			// This holds the alpha map indices for each layer that will be added to the TerrainData
			// The alpha maps could be a mix of existing and new values, so need to know which to use
			List<int> alphaMapIndices = new List<int>();

			// Initially set to use existing alpha maps, then override later on if specified via HF layers.
			for (int a = 0; a < existingSplats.Length; ++a)
			{
				// Negative indices for existing alpha map (offset by -1)
				alphaMapIndices.Add(-a - 1);
			}

			bool bNewSplat = false;
			HEU_VolumeLayer layer = null;
			SplatPrototype splatPrototype = null;

			for (int m = 0; m < numVolumeLayers; ++m)
			{
				bNewSplat = false;

				layer = volumeLayersToProcess[m];

				geoID = _ownerNode.GeoID;
				partID = layer._part.PartID;

				// Try to find existing SplatPrototype for reuse. But not for full rebuild.
				splatPrototype = null;
				if (layer._splatPrototypeIndex >= 0 && layer._splatPrototypeIndex < existingSplats.Length)
				{
					splatPrototype = existingSplats[layer._splatPrototypeIndex];

					// Positive index for alpha map from heightfield (starting at 1)
					alphaMapIndices[layer._splatPrototypeIndex] = m + 1;
				}

				if (splatPrototype == null)
				{
					splatPrototype = new SplatPrototype();
					layer._splatPrototypeIndex = finalSplats.Count;
					finalSplats.Add(splatPrototype);

					// Positive index for alpha map from heightfield (starting at 1)
					alphaMapIndices.Add(m + 1);
				}

				// Now override splat properties if they have been set via attributes
				LoadLayerPropertiesFromAttributes(session, geoID, partID, splatPrototype, bNewSplat, defaultTexture);
			}

			// On regular cook, get existing alpha maps so we can reuse the values if needed.
			float[,,] existingAlphaMaps = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight);

			terrainData.splatPrototypes = finalSplats.ToArray();

			int numTotalAlphaMaps = finalSplats.Count;
#endif

			// Set alpha maps by combining with existing alpha maps, and appending new heightfields

			float[,,] alphamap = null;
			if (numTotalAlphaMaps > 0 && volumeLayersToProcess.Count > 0)
			{
				// Convert the heightfields into alpha maps with layer strengths
				float[] strengths = new float[volumeLayersToProcess.Count];
				for (int m = 0; m < volumeLayersToProcess.Count; ++m)
				{
					strengths[m] = volumeLayersToProcess[m]._strength;
				}

				alphamap = HEU_TerrainUtility.AppendConvertedHeightFieldToAlphaMap(
					volumeLayersToProcess[0]._xLength, volumeLayersToProcess[0]._yLength, existingAlphaMaps,
					heightFields, strengths, alphaMapIndices);

				// Update the alphamap resolution to the actual size of the first 
				// heightfield layer used for the alphamaps.
				// Setting the size before setting the alphamas applies proper scaling.
				int alphamapResolution = volumeLayersToProcess[0]._xLength;
				terrainData.alphamapResolution = alphamapResolution;

				terrainData.SetAlphamaps(0, 0, alphamap);
			}

			// Tree instances for scattering
			HEU_TerrainUtility.ApplyScatter(terrainData, _scatterTrees);

			// If the layers were writen out, this saves the asset DB. Otherwise user has to save it themselves.
			// Not 100% sure this is needed, but without this the editor doesn't know the terrain asset has been updated
			// and therefore doesn't import and show the terrain layer.
			HEU_AssetDatabase.SaveAssetDatabase();
		}
예제 #24
0
 /// <summary>
 /// For the given object, returns its file path if it exists.
 /// </summary>
 /// <param name="inObject">Object to get the path for.</param>
 /// <returns>Valid path or null if none found.</returns>
 public static string LocateValidFilePath(UnityEngine.Object inObject)
 {
     return(inObject != null?HEU_AssetDatabase.GetAssetPath(inObject) : null);
 }
예제 #25
0
		private bool DrawDetailsGeometry()
		{
			bool bChanged = false;

			EditorGUIUtility.labelWidth = 250;

			{
				bool oldValue = HEU_PluginSettings.Curves_ShowInSceneView;
				bool newValue = HEU_EditorUI.DrawToggleLeft(oldValue, "Show Curves in Scene View");
				if (newValue != oldValue)
				{
					HEU_PluginSettings.Curves_ShowInSceneView = newValue;
					HEU_HoudiniAsset.SetCurvesVisibilityInScene(newValue);
					bChanged = true;
				}
			}
			HEU_EditorUI.DrawSeparator();
			{
				int oldValue = HEU_PluginSettings.MaxVerticesPerPrimitive;
				int newValue = EditorGUILayout.DelayedIntField("Max Vertices Per Primitive", oldValue);
				if (newValue != oldValue)
				{
					if (newValue == 3 || newValue == 4)
					{
						HEU_PluginSettings.MaxVerticesPerPrimitive = newValue;
						bChanged = true;
					}
					else
					{
						Debug.LogWarningFormat("Plugin only supports 3 (triangles) or 4 (quads) max vertices values.");
					}
				}
			}
			HEU_EditorUI.DrawSeparator();
			{
				float oldValue = HEU_PluginSettings.NormalGenerationThresholdAngle;
				float newValue = EditorGUILayout.DelayedFloatField("Normal Generation Threshold Angle", oldValue);
				if (newValue != oldValue)
				{
					HEU_PluginSettings.NormalGenerationThresholdAngle = newValue;
					bChanged = true;
				}
			}
			HEU_EditorUI.DrawSeparator();
			{
				string oldValue = HEU_PluginSettings.DefaultTerrainMaterial;
				if (_terrainMaterial == null && !string.IsNullOrEmpty(oldValue))
				{
					//Debug.Log("Loading terrain material at: " + oldValue);
					_terrainMaterial = HEU_MaterialFactory.LoadUnityMaterial(oldValue);
				}

				Material newMaterial = EditorGUILayout.ObjectField("Default Terrain Material", _terrainMaterial, typeof(Material), false) as Material;
				if (newMaterial != _terrainMaterial)
				{
					string materialPath = "";
					if (newMaterial != null)
					{
						materialPath = HEU_AssetDatabase.GetAssetPathWithSubAssetSupport(newMaterial);
						if (!string.IsNullOrEmpty(materialPath) && (materialPath.StartsWith(HEU_Defines.DEFAULT_UNITY_BUILTIN_RESOURCES)))
						{
							// Default materials need to be specially handled
							materialPath = HEU_AssetDatabase.GetUniqueAssetPathForUnityAsset(newMaterial);
							newMaterial = HEU_AssetDatabase.LoadUnityAssetFromUniqueAssetPath<Material>(materialPath);
						}
					}

					HEU_PluginSettings.DefaultTerrainMaterial = materialPath;
					_terrainMaterial = newMaterial;
					bChanged = true;
				}
			}
			HEU_EditorUI.DrawSeparator();
			{
				string oldValue = HEU_PluginSettings.TerrainSplatTextureDefault;
				string newValue = EditorGUILayout.DelayedTextField("Default Terrain Splat Texture", oldValue);
				if (!newValue.Equals(oldValue))
				{
					HEU_PluginSettings.TerrainSplatTextureDefault = newValue;
					bChanged = true;
				}
			}
			HEU_EditorUI.DrawSeparator();
			{
				string oldValue = HEU_PluginSettings.DefaultStandardShader;
				string newValue = EditorGUILayout.DelayedTextField("Default Standard Shader", oldValue);
				if (!newValue.Equals(oldValue))
				{
					HEU_PluginSettings.DefaultStandardShader = newValue;
					bChanged = true;
				}
			}
			HEU_EditorUI.DrawSeparator();
			{
				string oldValue = HEU_PluginSettings.DefaultTransparentShader;
				string newValue = EditorGUILayout.DelayedTextField("Default Transparent Shader", oldValue);
				if (!newValue.Equals(oldValue))
				{
					HEU_PluginSettings.DefaultTransparentShader = newValue;
					bChanged = true;
				}
			}
			HEU_EditorUI.DrawSeparator();
			{
				string oldValue = HEU_PluginSettings.DefaultVertexColorShader;
				string newValue = EditorGUILayout.DelayedTextField("Default Vertex Color Shader", oldValue);
				if (!newValue.Equals(oldValue))
				{
					HEU_PluginSettings.DefaultVertexColorShader = newValue;
					bChanged = true;
				}
			}
			HEU_EditorUI.DrawSeparator();
			{
				string oldValue = HEU_PluginSettings.DefaultCurveShader;
				string newValue = EditorGUILayout.DelayedTextField("Default Curve Shader", oldValue);
				if (!newValue.Equals(oldValue))
				{
					HEU_PluginSettings.DefaultCurveShader = newValue;
					bChanged = true;
				}
			}

			HEU_EditorUI.DrawSeparator();

			EditorGUIUtility.labelWidth = 0;

			return bChanged;
		}
		public static void WriteMaterialToAssetCache(Material material, string assetCacheFolderPath, string materialName)
		{
			string materialFileName = materialName + HEU_Defines.HEU_EXT_MAT;
			//Debug.LogFormat("Writing material {0} out to {1}", materialFileName, assetCacheFolderPath);
			HEU_AssetDatabase.CreateObjectInAssetCacheFolder(material, assetCacheFolderPath, HEU_Defines.HEU_FOLDER_MATERIALS, materialFileName, typeof(Material));
		}
예제 #27
0
	public void PopulateInputPreset(HEU_InputPreset inputPreset)
	{
	    inputPreset._inputObjectType = _inputObjectType;

	    // Deprecated and replaced with _inputAssetPresets. Leaving it in for backwards compatibility.
	    //inputPreset._inputAssetName = _inputAsset != null ? _inputAsset.name : "";

	    inputPreset._inputIndex = _inputIndex;
	    inputPreset._inputName = _inputName;

	    inputPreset._keepWorldTransform = _keepWorldTransform;
	    inputPreset._packGeometryBeforeMerging = _packGeometryBeforeMerging;

	    foreach (HEU_InputObjectInfo inputObject in _inputObjects)
	    {
		HEU_InputObjectPreset inputObjectPreset = new HEU_InputObjectPreset();

		if (inputObject._gameObject != null)
		{
		    inputObjectPreset._gameObjectName = inputObject._gameObject.name;

		    // Tag whether scene or project input object
		    inputObjectPreset._isSceneObject = !HEU_GeneralUtility.IsGameObjectInProject(inputObject._gameObject);
		    if (!inputObjectPreset._isSceneObject)
		    {
			// For inputs in project, use the project path as name
			inputObjectPreset._gameObjectName = HEU_AssetDatabase.GetAssetOrScenePath(inputObject._gameObject);
		    }
		}
		else
		{
		    inputObjectPreset._gameObjectName = "";
		}

		inputObjectPreset._useTransformOffset = inputObject._useTransformOffset;
		inputObjectPreset._translateOffset = inputObject._translateOffset;
		inputObjectPreset._rotateOffset = inputObject._rotateOffset;
		inputObjectPreset._scaleOffset = inputObject._scaleOffset;

		inputPreset._inputObjectPresets.Add(inputObjectPreset);
	    }

	    foreach (HEU_InputHDAInfo hdaInfo in _inputAssetInfos)
	    {
		HEU_InputAssetPreset inputAssetPreset = new HEU_InputAssetPreset();

		if (hdaInfo._connectedGO != null)
		{
		    if (!HEU_GeneralUtility.IsGameObjectInProject(hdaInfo._connectedGO))
		    {
			inputAssetPreset._gameObjectName = hdaInfo._connectedGO.name;
		    }
		    else
		    {
			inputAssetPreset._gameObjectName = "";
		    }

		    inputPreset._inputAssetPresets.Add(inputAssetPreset);
		}
	    }
	}
		public static bool DoesMaterialExistInAssetCache(Material material)
		{
			return !string.IsNullOrEmpty(HEU_AssetDatabase.GetAssetPath(material));
		}
예제 #29
0
		/// <summary>
		/// Upload the inputData (mesh geometry) into the input node with inputNodeID.
		/// </summary>
		/// <param name="session">Session that the input node exists in</param>
		/// <param name="inputNodeID">ID of the input node</param>
		/// <param name="inputData">Container of the mesh geometry</param>
		/// <returns>True if successfully uploaded data</returns>
		public bool UploadData(HEU_SessionBase session, HAPI_NodeId inputNodeID, HEU_InputData inputData)
		{
			HEU_InputDataMeshes inputDataMeshes = inputData as HEU_InputDataMeshes;
			if (inputDataMeshes == null)
			{
				Debug.LogError("Expected HEU_InputDataMeshes type for inputData, but received unsupported type.");
				return false;
			}

			List<Vector3> vertices = new List<Vector3>();
			List<Vector3> normals = new List<Vector3>();
			List<Vector2> uvs = new List<Vector2>();
			List<Color> colors = new List<Color>();

			List<int> pointIndexList = new List<int>();
			List<int> vertIndexList = new List<int>();

			int numMaterials = 0;

			int numMeshes = inputDataMeshes._inputMeshes.Count;

			// Get the parent's world transform, so when there are multiple child meshes,
			// can merge and apply their local transform after subtracting their parent's world transform
			Matrix4x4 rootInvertTransformMatrix = Matrix4x4.identity;
			if (numMeshes > 1)
			{
				rootInvertTransformMatrix = inputDataMeshes._inputObject.transform.worldToLocalMatrix;
			}

			// For all meshes:
			// Accumulate vertices, normals, uvs, colors, and indices.
			// Keep track of indices start and count for each mesh for later when uploading material assignments and groups.
			// Find shared vertices, and use unique set of vertices to use as point positions.
			// Need to reindex indices for both unique vertices, as well as vertex attributes.
			for (int i = 0; i < numMeshes; ++i)
			{
				Vector3[] meshVertices = inputDataMeshes._inputMeshes[i]._mesh.vertices;
				Matrix4x4 localToWorld = inputDataMeshes._inputMeshes[i]._transform.localToWorldMatrix * rootInvertTransformMatrix;

				List<Vector3> uniqueVertices = new List<Vector3>();

				// Keep track of old vertex positions (old vertex slot points to new unique vertex slot)
				int[] reindexVertices = new int[meshVertices.Length];

				for (int j = 0; j < meshVertices.Length; ++j)
				{
					reindexVertices[j] = -1;
				}

				// For each vertex, check against subsequent vertices for shared positions.
				for (int a = 0; a < meshVertices.Length; ++a)
				{
					Vector3 va = meshVertices[a];

					if (reindexVertices[a] == -1)
					{
						if (numMeshes > 1 && !inputDataMeshes._hasLOD)
						{
							// For multiple meshes that are not LODs, apply local transform on vertices to get the merged mesh.
							uniqueVertices.Add(localToWorld.MultiplyPoint(va));
						}
						else
						{
							uniqueVertices.Add(va);
						}

						// Reindex to point to unique vertex slot
						reindexVertices[a] = uniqueVertices.Count - 1;
					}

					for (int b = a + 1; b < meshVertices.Length; ++b)
					{
						if (va == meshVertices[b])
						{
							// Shared vertex -> reindex to point to unique vertex slot
							reindexVertices[b] = reindexVertices[a];
						}
					}
				}

				int vertexOffset = vertices.Count;
				vertices.AddRange(uniqueVertices);

				Vector3[] meshNormals = inputDataMeshes._inputMeshes[i]._mesh.normals;
				Vector2[] meshUVs = inputDataMeshes._inputMeshes[i]._mesh.uv;
				Color[] meshColors = inputDataMeshes._inputMeshes[i]._mesh.colors;

				inputDataMeshes._inputMeshes[i]._indexStart = new uint[inputDataMeshes._inputMeshes[i]._numSubMeshes];
				inputDataMeshes._inputMeshes[i]._indexCount = new uint[inputDataMeshes._inputMeshes[i]._numSubMeshes];

				// For each submesh:
				// Generate face to point index -> pointIndexList
				// Generate face to vertex attribute index -> vertIndexList
				for (int j = 0; j < inputDataMeshes._inputMeshes[i]._numSubMeshes; ++j)
				{
					int indexStart = pointIndexList.Count;
					int vertIndexStart = vertIndexList.Count;

					// Indices have to be re-indexed with our own offset
					int[] meshIndices = inputDataMeshes._inputMeshes[i]._mesh.GetTriangles(j);
					int numIndices = meshIndices.Length;
					for (int k = 0; k < numIndices; ++k)
					{
						int originalIndex = meshIndices[k];
						meshIndices[k] = reindexVertices[originalIndex];

						pointIndexList.Add(vertexOffset + meshIndices[k]);
						vertIndexList.Add(vertIndexStart + k);

						if (meshNormals != null && (originalIndex < meshNormals.Length))
						{
							normals.Add(meshNormals[originalIndex]);
						}

						if (meshUVs != null && (originalIndex < meshUVs.Length))
						{
							uvs.Add(meshUVs[originalIndex]);
						}

						if (meshColors != null && (originalIndex < meshColors.Length))
						{
							colors.Add(meshColors[originalIndex]);
						}
					}

					inputDataMeshes._inputMeshes[i]._indexStart[j] = (uint)indexStart;
					inputDataMeshes._inputMeshes[i]._indexCount[j] = (uint)(pointIndexList.Count) - inputDataMeshes._inputMeshes[i]._indexStart[j];
				}

				numMaterials += inputDataMeshes._inputMeshes[i]._materials != null ? inputDataMeshes._inputMeshes[i]._materials.Length : 0;
			}

			// It is possible for some meshes to not have normals/uvs/colors while others do.
			// In the case where an attribute is missing on some meshes, we clear out those attributes so we don't upload
			// partial attribute data.
			int totalAllVertexCount = vertIndexList.Count;
			if (normals.Count != totalAllVertexCount)
			{
				normals = null;
			}

			if (uvs.Count != totalAllVertexCount)
			{
				uvs = null;
			}

			if (colors.Count != totalAllVertexCount)
			{
				colors = null;
			}

			HAPI_PartInfo partInfo = new HAPI_PartInfo();
			partInfo.faceCount = vertIndexList.Count / 3;
			partInfo.vertexCount = vertIndexList.Count;
			partInfo.pointCount = vertices.Count;
			partInfo.pointAttributeCount = 1;
			partInfo.vertexAttributeCount = 0;
			partInfo.primitiveAttributeCount = 0;
			partInfo.detailAttributeCount = 0;

			if (normals != null && normals.Count > 0)
			{
				partInfo.vertexAttributeCount++;
			}

			if (uvs != null && uvs.Count > 0)
			{
				partInfo.vertexAttributeCount++;
			}

			if (colors != null && colors.Count > 0)
			{
				partInfo.vertexAttributeCount++;
			}

			if (numMaterials > 0)
			{
				partInfo.primitiveAttributeCount++;
			}

			if (numMeshes > 0)
			{
				partInfo.primitiveAttributeCount++;
			}

			if (inputDataMeshes._hasLOD)
			{
				partInfo.primitiveAttributeCount++;
				partInfo.detailAttributeCount++;
			}

			HAPI_GeoInfo displayGeoInfo = new HAPI_GeoInfo();
			if (!session.GetDisplayGeoInfo(inputNodeID, ref displayGeoInfo))
			{
				return false;
			}

			HAPI_NodeId displayNodeID = displayGeoInfo.nodeId;

			if (!session.SetPartInfo(displayNodeID, 0, ref partInfo))
			{
				Debug.LogError("Failed to set input part info. ");
				return false;
			}

			int[] faceCounts = new int[partInfo.faceCount];
			for (int i = 0; i < partInfo.faceCount; ++i)
			{
				faceCounts[i] = 3;
			}

			int[] triIndices = pointIndexList.ToArray();

			if (!HEU_GeneralUtility.SetArray2Arg(displayNodeID, 0, session.SetFaceCount, faceCounts, 0, partInfo.faceCount))
			{
				Debug.LogError("Failed to set input geometry face counts.");
				return false;
			}

			if (!HEU_GeneralUtility.SetArray2Arg(displayNodeID, 0, session.SetVertexList, triIndices, 0, partInfo.vertexCount))
			{
				Debug.LogError("Failed to set input geometry indices.");
				return false;
			}

			if (!HEU_InputMeshUtility.SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_POSITION, 3, vertices.ToArray(), ref partInfo, true))
			{
				Debug.LogError("Failed to set input geometry position.");
				return false;
			}

			int[] vertIndices = vertIndexList.ToArray();

			//if(normals != null && !SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_NORMAL, 3, normals.ToArray(), ref partInfo, true))
			if (normals != null && !HEU_InputMeshUtility.SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_NORMAL, 3, normals.ToArray(), vertIndices, ref partInfo, true))
			{
				Debug.LogError("Failed to set input geometry normals.");
				return false;
			}

			if (uvs != null && uvs.Count > 0)
			{
				Vector3[] uvs3 = new Vector3[uvs.Count];
				for (int i = 0; i < uvs.Count; ++i)
				{
					uvs3[i][0] = uvs[i][0];
					uvs3[i][1] = uvs[i][1];
					uvs3[i][2] = 0;
				}
				//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_UV, 3, uvs3, ref partInfo, false))
				if (!HEU_InputMeshUtility.SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_UV, 3, uvs3, vertIndices, ref partInfo, false))
				{
					Debug.LogError("Failed to set input geometry UVs.");
					return false;
				}
			}

			if (colors != null && colors.Count > 0)
			{
				Vector3[] rgb = new Vector3[colors.Count];
				float[] alpha = new float[colors.Count];
				for (int i = 0; i < colors.Count; ++i)
				{
					rgb[i][0] = colors[i].r;
					rgb[i][1] = colors[i].g;
					rgb[i][2] = colors[i].b;

					alpha[i] = colors[i].a;
				}

				//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_COLOR, 3, rgb, ref partInfo, false))
				if (!HEU_InputMeshUtility.SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_COLOR, 3, rgb, vertIndices, ref partInfo, false))
				{
					Debug.LogError("Failed to set input geometry colors.");
					return false;
				}

				//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_ALPHA, 1, alpha, ref partInfo, false))
				if (!HEU_InputMeshUtility.SetMeshVertexFloatAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_ALPHA, 1, alpha, vertIndices, ref partInfo))
				{
					Debug.LogError("Failed to set input geometry color alpha.");
					return false;
				}
			}

			// Set material names for round-trip perservation of material assignment
			// Each HEU_UploadMeshData might have a list of submeshes and materials
			// These are all combined into a single mesh, with group names
			if (numMaterials > 0)
			{
				bool bFoundAtleastOneValidMaterial = false;

				string[] materialIDs = new string[partInfo.faceCount];
				for (int g = 0; g < inputDataMeshes._inputMeshes.Count; ++g)
				{
					if (inputDataMeshes._inputMeshes[g]._numSubMeshes != inputDataMeshes._inputMeshes[g]._materials.Length)
					{
						// Number of submeshes should equal number of materials since materials determine submeshes
						continue;
					}

					for (int i = 0; i < inputDataMeshes._inputMeshes[g]._materials.Length; ++i)
					{
						string materialName = HEU_AssetDatabase.GetAssetPathWithSubAssetSupport(inputDataMeshes._inputMeshes[g]._materials[i]);
						if (materialName == null)
						{
							materialName = "";
						}
						else if (materialName.StartsWith(HEU_Defines.DEFAULT_UNITY_BUILTIN_RESOURCES))
						{
							materialName = HEU_AssetDatabase.GetUniqueAssetPathForUnityAsset(inputDataMeshes._inputMeshes[g]._materials[i]);
						}

						bFoundAtleastOneValidMaterial |= !string.IsNullOrEmpty(materialName);

						int faceStart = (int)inputDataMeshes._inputMeshes[g]._indexStart[i] / 3;
						int faceEnd = faceStart + ((int)inputDataMeshes._inputMeshes[g]._indexCount[i] / 3);
						for (int m = faceStart; m < faceEnd; ++m)
						{
							materialIDs[m] = materialName;
						}
					}
				}

				if (bFoundAtleastOneValidMaterial)
				{
					HAPI_AttributeInfo materialIDAttrInfo = new HAPI_AttributeInfo();
					materialIDAttrInfo.exists = true;
					materialIDAttrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM;
					materialIDAttrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_STRING;
					materialIDAttrInfo.count = partInfo.faceCount;
					materialIDAttrInfo.tupleSize = 1;
					materialIDAttrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

					if (!session.AddAttribute(displayNodeID, 0, HEU_PluginSettings.UnityMaterialAttribName, ref materialIDAttrInfo))
					{
						Debug.LogError("Failed to add input geometry unity material name attribute.");
						return false;
					}

					if (!HEU_GeneralUtility.SetAttributeArray(displayNodeID, 0, HEU_PluginSettings.UnityMaterialAttribName, ref materialIDAttrInfo, materialIDs, session.SetAttributeStringData, partInfo.faceCount))
					{
						Debug.LogError("Failed to set input geometry unity material name.");
						return false;
					}
				}
			}

			// Set mesh name attribute
			HAPI_AttributeInfo attrInfo = new HAPI_AttributeInfo();
			attrInfo.exists = true;
			attrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM;
			attrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_STRING;
			attrInfo.count = partInfo.faceCount;
			attrInfo.tupleSize = 1;
			attrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

			if (session.AddAttribute(displayNodeID, 0, HEU_PluginSettings.UnityInputMeshAttr, ref attrInfo))
			{
				string[] primitiveNameAttr = new string[partInfo.faceCount];

				for (int g = 0; g < inputDataMeshes._inputMeshes.Count; ++g)
				{
					for (int i = 0; i < inputDataMeshes._inputMeshes[g]._numSubMeshes; ++i)
					{
						int faceStart = (int)inputDataMeshes._inputMeshes[g]._indexStart[i] / 3;
						int faceEnd = faceStart + ((int)inputDataMeshes._inputMeshes[g]._indexCount[i] / 3);
						for (int m = faceStart; m < faceEnd; ++m)
						{
							primitiveNameAttr[m] = inputDataMeshes._inputMeshes[g]._meshPath;
						}
					}
				}

				if (!HEU_GeneralUtility.SetAttributeArray(displayNodeID, 0, HEU_PluginSettings.UnityInputMeshAttr, ref attrInfo, primitiveNameAttr, session.SetAttributeStringData, partInfo.faceCount))
				{
					Debug.LogError("Failed to set input geometry unity mesh name.");
					return false;
				}
			}
			else
			{
				return false;
			}

			// Set LOD group membership
			if (inputDataMeshes._hasLOD)
			{
				int[] membership = new int[partInfo.faceCount];

				for (int g = 0; g < inputDataMeshes._inputMeshes.Count; ++g)
				{
					if (g > 0)
					{
						// Clear array
						for (int m = 0; m < partInfo.faceCount; ++m)
						{
							membership[m] = 0;
						}
					}

					// Set 1 for faces belonging to this group
					for (int s = 0; s < inputDataMeshes._inputMeshes[g]._numSubMeshes; ++s)
					{
						int faceStart = (int)inputDataMeshes._inputMeshes[g]._indexStart[s] / 3;
						int faceEnd = faceStart + ((int)inputDataMeshes._inputMeshes[g]._indexCount[s] / 3);
						for (int m = faceStart; m < faceEnd; ++m)
						{
							membership[m] = 1;
						}
					}

					if (!session.AddGroup(displayNodeID, 0, HAPI_GroupType.HAPI_GROUPTYPE_PRIM, inputDataMeshes._inputMeshes[g]._meshName))
					{
						Debug.LogError("Failed to add input geometry LOD group name.");
						return false;
					}

					if (!session.SetGroupMembership(displayNodeID, 0, HAPI_GroupType.HAPI_GROUPTYPE_PRIM, inputDataMeshes._inputMeshes[g]._meshName, membership, 0, partInfo.faceCount))
					{
						Debug.LogError("Failed to set input geometry LOD group name.");
						return false;
					}
				}
			}

			return session.CommitGeo(displayNodeID);
		}
		public static void DeleteAssetMaterial(Material material)
		{
			HEU_AssetDatabase.DeleteAsset(material);
		}