Exemple #1
0
        // TRANSFORMS -------------------------------------------------------------------------------------------------

        /// <summary>
        /// Apply Houdini Engine world transform to Unity's transform object.
        /// This assumes given HAPI transform is in world space.
        /// </summary>
        /// <param name="hapiTransform">Houdini Engine transform to get data from</param>
        /// <param name="unityTransform">The Unity transform to apply data to</param>
        public static void ApplyWorldTransfromFromHoudiniToUnity(HAPI_Transform hapiTransform, Transform unityTransform)
        {
            // Houdini uses right-handed coordinate system, while Unity uses left-handed.
            // Note: we always use global transform space when communicating with Houdini

            // Invert the X for position
            unityTransform.position = new Vector3(-hapiTransform.position[0], hapiTransform.position[1], hapiTransform.position[2]);

            // Invert Y and Z for rotation
            Quaternion quaternion = new Quaternion(hapiTransform.rotationQuaternion[0], hapiTransform.rotationQuaternion[1], hapiTransform.rotationQuaternion[2], hapiTransform.rotationQuaternion[3]);
            Vector3    euler      = quaternion.eulerAngles;

            euler.y = -euler.y;
            euler.z = -euler.z;
            unityTransform.rotation = Quaternion.Euler(euler);

            // No inversion required for scale
            // We can't directly set global scale in Unity, but the proper workaround is to unparent, set scale, then reparent
            Vector3 scale = new Vector3(hapiTransform.scale[0], hapiTransform.scale[1], hapiTransform.scale[2]);

            if (unityTransform.parent != null)
            {
                Transform parent = unityTransform.parent;
                unityTransform.parent     = null;
                unityTransform.localScale = scale;
                unityTransform.parent     = parent;
            }
            else
            {
                unityTransform.localScale = scale;
            }
        }
 /// <summary>
 /// Apply the given HAPI transform to all parts of this node.
 /// </summary>
 /// <param name="hapiTransform">HAPI transform to apply</param>
 public void ApplyHAPITransform(ref HAPI_Transform hapiTransform)
 {
     foreach (HEU_PartData part in _parts)
     {
         part.ApplyHAPITransform(ref hapiTransform);
     }
 }
Exemple #3
0
		private void CreateNewInstanceFromObject(GameObject sourceObject, int instanceIndex, Transform parentTransform, 
			ref HAPI_Transform hapiTransform, string[] instancePrefixes, string instanceName)
		{
			GameObject newInstanceGO = null;

			if (HEU_EditorUtility.IsPrefabAsset(sourceObject))
			{
				newInstanceGO = HEU_EditorUtility.InstantiatePrefab(sourceObject) as GameObject;
				newInstanceGO.transform.parent = parentTransform;
			}
			else
			{
				newInstanceGO = HEU_EditorUtility.InstantiateGameObject(sourceObject, parentTransform, false, false);
			}

			// To get the instance output name, we pass in the instance index. The actual name will be +1 from this.
			newInstanceGO.name = HEU_GeometryUtility.GetInstanceOutputName(instanceName, instancePrefixes, instanceIndex);
			newInstanceGO.isStatic = sourceObject.isStatic;

			Transform instanceTransform = newInstanceGO.transform;
			HEU_HAPIUtility.ApplyLocalTransfromFromHoudiniToUnityForInstance(ref hapiTransform, instanceTransform);

			// When cloning, the instanced part might have been made invisible, so re-enable renderer to have the cloned instance display it.
			HEU_GeneralUtility.SetGameObjectRenderVisiblity(newInstanceGO, true);
			HEU_GeneralUtility.SetGameObjectChildrenRenderVisibility(newInstanceGO, true);
			HEU_GeneralUtility.SetGameObjectColliderState(newInstanceGO, true);
			HEU_GeneralUtility.SetGameObjectChildrenColliderState(newInstanceGO, true);
		}
Exemple #4
0
        /// <summary>
        /// Returns Unity 4x4 matrix corresponding to the given HAPI_Transform.
        /// Converts from Houdini to Unity coordinate system.
        /// </summary>
        /// <param name="hapiTransform">HAPI transform to get values from</param>
        /// <returns>Matrix4x4 in Unity coordinate system</returns>
        public static Matrix4x4 GetMatrixFromHAPITransform(ref HAPI_Transform hapiTransform, bool bConvertToUnity = true)
        {
            float invert = bConvertToUnity ? -1f : 1f;

            // TODO: Refactor this so as to use a common function to get these values
            // Invert the X for position
            Vector3 position = new Vector3(invert * hapiTransform.position[0], hapiTransform.position[1], hapiTransform.position[2]);

            // Invert Y and Z for rotation
            Quaternion quaternion = new Quaternion(hapiTransform.rotationQuaternion[0], hapiTransform.rotationQuaternion[1], hapiTransform.rotationQuaternion[2], hapiTransform.rotationQuaternion[3]);
            Vector3    euler      = quaternion.eulerAngles;

            euler.y = invert * euler.y;
            euler.z = invert * euler.z;
            Quaternion rotation = Quaternion.Euler(euler);

            // No inversion required for scale
            // We can't directly set global scale in Unity, but the proper workaround is to unparent, set scale, then reparent
            Vector3 scale = new Vector3(hapiTransform.scale[0], hapiTransform.scale[1], hapiTransform.scale[2]);

            Matrix4x4 matrix = new Matrix4x4();

            matrix.SetTRS(position, rotation, scale);
            return(matrix);
        }
Exemple #5
0
		public void Initialize(HEU_SessionBase session, HAPI_ObjectInfo objectInfo, HAPI_Transform objectTranform, HEU_HoudiniAsset parentAsset)
		{
			_objectInfo = objectInfo;
			_objectTransform = objectTranform;
			_parentAsset = parentAsset;

			SyncWithObjectInfo(session);

			// Translate transform to Unity (TODO)

			List<HAPI_GeoInfo> geoInfos = new List<HAPI_GeoInfo>();

			// Get display geo info
			HAPI_GeoInfo displayGeoInfo = new HAPI_GeoInfo();
			if(!session.GetDisplayGeoInfo(_objectInfo.nodeId, ref displayGeoInfo))
			{
				return;
			}
			//Debug.LogFormat("Found geoinfo with name {0} and id {1}", HEU_SessionManager.GetString(displayGeoInfo.nameSH, session), displayGeoInfo.nodeId);
			geoInfos.Add(displayGeoInfo);
			
			// TODO: The following editable node query also retrieves geo nodes for terrain with visualization nodes. Need to review to check if we're using the
			// correct query flags, and handling returned nodes correctly.
			// Get editable nodes, cook em, then create geo nodes for them
			HAPI_NodeId[] editableNodes = null;
			HEU_SessionManager.GetComposedChildNodeList(session, _objectInfo.nodeId, (int)HAPI_NodeType.HAPI_NODETYPE_SOP, (int)HAPI_NodeFlags.HAPI_NODEFLAGS_EDITABLE, true, out editableNodes); 
			if(editableNodes != null)
			{
				foreach(HAPI_NodeId editNodeID in editableNodes)
				{
					if (editNodeID != displayGeoInfo.nodeId)
					{
						session.CookNode(editNodeID, HEU_PluginSettings.CookTemplatedGeos);

						HAPI_GeoInfo editGeoInfo = new HAPI_GeoInfo();
						if (session.GetGeoInfo(editNodeID, ref editGeoInfo))
						{
							geoInfos.Add(editGeoInfo);
						}
					}
				}
			}
			
			//Debug.LogFormat("Object id={5}, name={0}, isInstancer={1}, isInstanced={2}, instancePath={3}, instanceId={4}", 
			//	HEU_SessionManager.GetString(objectInfo.nameSH, session), objectInfo.isInstancer, objectInfo.isInstanced, 
			//	HEU_SessionManager.GetString(objectInfo.objectInstancePathSH, session), objectInfo.objectToInstanceId, objectInfo.nodeId);

			// Go through geo infos to create geometry
			int numGeoInfos = geoInfos.Count;
			for(int i = 0; i < numGeoInfos; ++i)
			{
				// Create GeoNode for each
				_geoNodes.Add(CreateGeoNode(session, geoInfos[i]));
			}

			// This has been moved to GenerateGeometry but kept here just in case.
			//ApplyObjectTransformToGeoNodes();
		}
	public void Reset()
	{
	    _objName = "";

	    _parentAsset = null;
	    _objectInfo = new HAPI_ObjectInfo();
	    _geoNodes = new List<HEU_GeoNode>();
	    _objectTransform = new HAPI_Transform(true);
	}
Exemple #7
0
		/// <summary>
		/// Copy src HAPI_Transfrom to dest HAPI_Transform.
		/// </summary>
		public static void CopyHAPITransform(ref HAPI_Transform src, ref HAPI_Transform dest)
		{
			src.position.CopyToWithResize<float>(ref dest.position);
			src.rotationQuaternion.CopyToWithResize<float>(ref dest.rotationQuaternion);
			src.scale.CopyToWithResize<float>(ref dest.scale);
			src.shear.CopyToWithResize<float>(ref dest.shear);

			dest.rstOrder = src.rstOrder;
		}
Exemple #8
0
	internal void Initialize(HEU_SessionBase session, HAPI_ObjectInfo objectInfo, HAPI_Transform objectTranform, HEU_HoudiniAsset parentAsset, bool bUseOutputNodes)
	{
	    _objectInfo = objectInfo;
	    _objectTransform = objectTranform;
	    _parentAsset = parentAsset;

	    SyncWithObjectInfo(session);

	    // Translate transform to Unity (TODO)
	    List<HAPI_GeoInfo> geoInfos = new List<HAPI_GeoInfo>();

	    HEU_HAPIUtility.GatherAllAssetGeoInfos(session, parentAsset.AssetInfo, objectInfo, bUseOutputNodes, ref geoInfos);
	    int numGeoInfos = geoInfos.Count;
	    for (int i = 0; i < numGeoInfos; ++i)
	    {
		// Create GeoNode for each
		_geoNodes.Add(CreateGeoNode(session, geoInfos[i]));
	    }
	}
Exemple #9
0
		private HEU_LoadBufferInstancer GeneratePartsInstancerBuffer(HEU_SessionBase session, HAPI_NodeId geoID, HAPI_PartId partID, string partName, HAPI_PartInfo partInfo)
		{
			// Get the instance node IDs to get the geometry to be instanced.
			// Get the instanced count to all the instances. These will end up being mesh references to the mesh from instance node IDs.

			// Get each instance's transform
			HAPI_Transform[] instanceTransforms = new HAPI_Transform[partInfo.instanceCount];
			if (!HEU_GeneralUtility.GetArray3Arg(geoID, partID, HAPI_RSTOrder.HAPI_SRT, session.GetInstancerPartTransforms, instanceTransforms, 0, partInfo.instanceCount))
			{
				SetLog(HEU_LoadData.LoadStatus.ERROR, string.Format("Unable to get instance transforms for part {0}", partName));
				return null;
			}

			// Get part IDs for the parts being instanced
			HAPI_NodeId[] instanceNodeIDs = new HAPI_NodeId[partInfo.instancedPartCount];
			if (!HEU_GeneralUtility.GetArray2Arg(geoID, partID, session.GetInstancedPartIds, instanceNodeIDs, 0, partInfo.instancedPartCount))
			{
				SetLog(HEU_LoadData.LoadStatus.ERROR, string.Format("Unable to get instance node IDs for part {0}", partName));
				return null;
			}

			// Get instance names if set
			string[] instancePrefixes = null;
			HAPI_AttributeInfo instancePrefixAttrInfo = new HAPI_AttributeInfo();
			HEU_GeneralUtility.GetAttributeInfo(session, geoID, partID, HEU_Defines.DEFAULT_INSTANCE_PREFIX_ATTR, ref instancePrefixAttrInfo);
			if (instancePrefixAttrInfo.exists)
			{
				instancePrefixes = HEU_GeneralUtility.GetAttributeStringData(session, geoID, partID, HEU_Defines.DEFAULT_INSTANCE_PREFIX_ATTR, ref instancePrefixAttrInfo);
			}

			HEU_LoadBufferInstancer instancerBuffer = new HEU_LoadBufferInstancer();
			instancerBuffer.InitializeBuffer(partID, partName, partInfo.isInstanced, true);

			instancerBuffer._instanceTransforms = instanceTransforms;
			instancerBuffer._instanceNodeIDs = instanceNodeIDs;
			instancerBuffer._instancePrefixes = instancePrefixes;

			return instancerBuffer;
		}
        /// <summary>
        /// Gets the object infos and transforms for given asset.
        /// </summary>
        /// <param name="assetID">ID of the asset</param>
        /// <param name="nodeInfo">HAPI_NodeInfo of the asset</param>
        /// <param name="objectInfos">Array of retrieved object infos</param>
        /// <param name="objectTransforms">Array of retrieved object transforms</param>
        /// <returns>True if succesfully retrieved object infos and transforms</returns>
        public static bool GetObjectInfos(HEU_SessionBase session, HAPI_NodeId assetID, ref HAPI_NodeInfo nodeInfo, out HAPI_ObjectInfo[] objectInfos, out HAPI_Transform[] objectTransforms)
        {
            objectInfos      = new HAPI_ObjectInfo[0];
            objectTransforms = new HAPI_Transform[0];

            if (nodeInfo.type == HAPI_NodeType.HAPI_NODETYPE_SOP)
            {
                // For SOP assets, we use the parent IDs to get the object info and geo info

                objectInfos = new HAPI_ObjectInfo[1];
                if (!session.GetObjectInfo(nodeInfo.parentId, ref objectInfos[0]))
                {
                    return(false);
                }

                // Identity transform will be used for SOP assets, so not querying transform
                objectTransforms    = new HAPI_Transform[1];
                objectTransforms[0] = new HAPI_Transform(true);
            }
            else if (nodeInfo.type == HAPI_NodeType.HAPI_NODETYPE_OBJ)
            {
                int objectCount = 0;
                if (!session.ComposeObjectList(assetID, out objectCount))
                {
                    return(false);
                }

                if (objectCount <= 0)
                {
                    // Since this asset is an object type and has 0 object as children, we use the object itself

                    objectInfos = new HAPI_ObjectInfo[1];
                    if (!session.GetObjectInfo(nodeInfo.id, ref objectInfos[0]))
                    {
                        return(false);
                    }

                    // Identity transform will be used for single object assets, so not querying transform
                    objectTransforms    = new HAPI_Transform[1];
                    objectTransforms[0] = new HAPI_Transform(true);
                }
                else
                {
                    // This object has children, so use GetComposedObjectList to get list of HAPI_ObjectInfos

                    objectInfos = new HAPI_ObjectInfo[objectCount];
                    if (!session.GetComposedObjectList(nodeInfo.parentId, objectInfos, 0, objectCount))
                    {
                        return(false);
                    }

                    // Now get the object transforms
                    objectTransforms = new HAPI_Transform[objectCount];
                    if (!HEU_SessionManager.GetComposedObjectTransformsMemorySafe(session, nodeInfo.parentId, HAPI_RSTOrder.HAPI_SRT, objectTransforms, 0, objectCount))
                    {
                        return(false);
                    }
                }
            }
            else
            {
                Debug.LogWarningFormat(HEU_Defines.HEU_NAME + ": Unsupported node type {0}", nodeInfo.type);
                return(false);
            }

            return(true);
        }
Exemple #11
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]);
				}
			}
		}
		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]);
				}
			}
		}
Exemple #13
0
		private HEU_LoadBufferInstancer GeneratePointAttributeInstancerBuffer(HEU_SessionBase session, HAPI_NodeId geoID, HAPI_PartId partID, 
			string partName, HAPI_PartInfo partInfo)
		{
			int numInstances = partInfo.pointCount;
			if (numInstances <= 0)
			{
				return null;
			}

			// Find type of instancer
			string instanceAttrName = HEU_PluginSettings.InstanceAttr;
			string unityInstanceAttrName = HEU_PluginSettings.UnityInstanceAttr;
			string instancePrefixAttrName = HEU_Defines.DEFAULT_INSTANCE_PREFIX_ATTR;

			HAPI_AttributeInfo instanceAttrInfo = new HAPI_AttributeInfo();
			HAPI_AttributeInfo unityInstanceAttrInfo = new HAPI_AttributeInfo();
			HAPI_AttributeInfo instancePrefixAttrInfo = new HAPI_AttributeInfo();

			HEU_GeneralUtility.GetAttributeInfo(session, geoID, partID, instanceAttrName, ref instanceAttrInfo);
			HEU_GeneralUtility.GetAttributeInfo(session, geoID, partID, unityInstanceAttrName, ref unityInstanceAttrInfo);

			if (unityInstanceAttrInfo.exists)
			{
				// Object instancing via existing Unity object (path from point attribute)

				HAPI_Transform[] instanceTransforms = new HAPI_Transform[numInstances];
				if (!HEU_GeneralUtility.GetArray3Arg(geoID, partID, HAPI_RSTOrder.HAPI_SRT, session.GetInstanceTransformsOnPart, instanceTransforms, 0, numInstances))
				{
					return null;
				}

				string[] instancePrefixes = null;
				HEU_GeneralUtility.GetAttributeInfo(session, geoID, partID, instancePrefixAttrName, ref instancePrefixAttrInfo);
				if (instancePrefixAttrInfo.exists)
				{
					instancePrefixes = HEU_GeneralUtility.GetAttributeStringData(session, geoID, partID, instancePrefixAttrName, ref instancePrefixAttrInfo);
				}

				string[] assetPaths = null;

				// Attribute owner type determines whether to use single (detail) or multiple (point) asset(s) as source
				if (unityInstanceAttrInfo.owner == HAPI_AttributeOwner.HAPI_ATTROWNER_POINT || unityInstanceAttrInfo.owner == HAPI_AttributeOwner.HAPI_ATTROWNER_DETAIL)
				{

					assetPaths = HEU_GeneralUtility.GetAttributeStringData(session, geoID, partID, unityInstanceAttrName, ref unityInstanceAttrInfo);
				}
				else
				{
					// Other attribute owned types are unsupported
					SetLog(HEU_LoadData.LoadStatus.ERROR, string.Format("Unsupported attribute owner {0} for attribute {1}", 
						unityInstanceAttrInfo.owner, unityInstanceAttrName));
					return null;
				}

				if (assetPaths == null)
				{
					SetLog(HEU_LoadData.LoadStatus.ERROR, "Unable to get instanced asset path from attribute!");
					return null;
				}

				HEU_LoadBufferInstancer instancerBuffer = new HEU_LoadBufferInstancer();
				instancerBuffer.InitializeBuffer(partID, partName, partInfo.isInstanced, true);

				instancerBuffer._instanceTransforms = instanceTransforms;
				instancerBuffer._instancePrefixes = instancePrefixes;
				instancerBuffer._assetPaths = assetPaths;

				return instancerBuffer;
			}
			else if (instanceAttrInfo.exists)
			{
				// Object instancing via internal object path is not supported
				SetLog(HEU_LoadData.LoadStatus.ERROR, string.Format("Object instancing is not supported (part {0})!", partName));
			}
			else
			{
				// Standard object instancing via single Houdini object is not supported
				SetLog(HEU_LoadData.LoadStatus.ERROR, string.Format("Object instancing is not supported (part {0})!", partName));
			}

			return null;
		}
		// <summary>
		/// Get the transform of an OBJ node.
		/// </summary>
		/// <param name="nodeID">The object node ID</param>
		/// <param name="relativeToNodeID">The object node ID of the object to which the returned transform will be relative to. -1 if want object's local transform</param>
		/// <param name="rstOrder">The transform order</param>
		/// <param name="hapiTransform">Transform info to populate</param>
		/// <returns>True if successfully queried transform info</returns>
		public virtual bool GetObjectTransform(HAPI_NodeId nodeID, HAPI_NodeId relativeToNodeID, HAPI_RSTOrder rstOrder, ref HAPI_Transform hapiTransform)
		{
			return false;
		}
	/// <summary>
	/// Retrieves object info from Houdini session and updates internal state.
	/// New geo nodes are created, unused geo nodes are destroyed.
	/// Geo nodes are then refreshed to be in sync with Houdini session.
	/// </summary>
	/// <returns>True if internal state has changed (including geometry).</returns>
	public void UpdateObject(HEU_SessionBase session, bool bForceUpdate)
	{
	    // Update the geo info
	    if (!session.GetObjectInfo(ObjectID, ref _objectInfo))
	    {
		return;
	    }
	    SyncWithObjectInfo(session);

	    // Update the object transform
	    _objectTransform = ParentAsset.GetObjectTransform(session, ObjectID);

	    // Container for existing geo nodes that are still in use
	    List<HEU_GeoNode> geoNodesToKeep = new List<HEU_GeoNode>();

	    // Container for new geo infos that need to be created
	    List<HAPI_GeoInfo> newGeoInfosToCreate = new List<HAPI_GeoInfo>();

	    if (_objectInfo.haveGeosChanged || bForceUpdate)
	    {
		// Indicates that the geometry nodes have changed
		//Debug.Log("Geos have changed!");

		// Form a list of geo infos that are now present after cooking
		List<HAPI_GeoInfo> postCookGeoInfos = new List<HAPI_GeoInfo>();

		// Get the display geo info
		HAPI_GeoInfo displayGeoInfo = new HAPI_GeoInfo();
		if (session.GetDisplayGeoInfo(_objectInfo.nodeId, ref displayGeoInfo, false))
		{
		    postCookGeoInfos.Add(displayGeoInfo);
		}
		else
		{
		    displayGeoInfo.nodeId = HEU_Defines.HEU_INVALID_NODE_ID;
		}

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

			    HAPI_GeoInfo editGeoInfo = new HAPI_GeoInfo();
			    if (session.GetGeoInfo(editNodeID, ref editGeoInfo))
			    {
				postCookGeoInfos.Add(editGeoInfo);
			    }
			}
		    }
		}

		// Now for each geo node that are present after cooking, we check if its
		// new or whether we already have it prior to cooking.
		int numPostCookGeoInfos = postCookGeoInfos.Count;
		for (int i = 0; i < numPostCookGeoInfos; i++)
		{
		    bool bFound = false;
		    for (int j = 0; j < _geoNodes.Count; j++)
		    {
			string geoName = HEU_SessionManager.GetString(postCookGeoInfos[i].nameSH, session);
			if (geoName.Equals(_geoNodes[j].GeoName))
			{
			    _geoNodes[j].SetGeoInfo(postCookGeoInfos[i]);

			    geoNodesToKeep.Add(_geoNodes[j]);
			    _geoNodes.RemoveAt(j);

			    bFound = true;
			    break;
			}
		    }

		    if (!bFound)
		    {
			newGeoInfosToCreate.Add(postCookGeoInfos[i]);
		    }
		}

		// Whatever is left in _geoNodes is no longer needed so clean up
		int numCurrentGeos = _geoNodes.Count;
		for (int i = 0; i < numCurrentGeos; ++i)
		{
		    _geoNodes[i].DestroyAllData();
		}
	    }
	    else
	    {
		Debug.Assert(_objectInfo.geoCount == _geoNodes.Count, "Expected same number of geometry nodes.");
	    }

	    // Go through the old geo nodes that are still in use and update if necessary.
	    foreach (HEU_GeoNode geoNode in geoNodesToKeep)
	    {
		// Get geo info and check if geo changed
		bool bGeoChanged = bForceUpdate || geoNode.HasGeoNodeChanged(session);
		if (bGeoChanged)
		{
		    geoNode.UpdateGeo(session);
		}
		else
		{
		    if (_objectInfo.haveGeosChanged)
		    {
			// Clear object instances since the object info has changed.
			// Without this, the object instances were never getting updated
			// if only the inputs changed but not outputs (of instancers).
			geoNode.ClearObjectInstances();
		    }

		    // Visiblity might have changed, so update that
		    geoNode.CalculateVisiblity(IsVisible());
		    geoNode.CalculateColliderState();
		}
	    }

	    // Create the new geo infos and add to our keep list
	    foreach (HAPI_GeoInfo newGeoInfo in newGeoInfosToCreate)
	    {
		geoNodesToKeep.Add(CreateGeoNode(session, newGeoInfo));
	    }

	    // Overwrite the old list with new
	    _geoNodes = geoNodesToKeep;

	    // Updating the trasform is done in GenerateGeometry
	}
Exemple #16
0
		private void GenerateTerrain(List<HEU_LoadBufferVolume> terrainBuffers)
		{
			Transform parent = this.gameObject.transform;

			int numVolues = terrainBuffers.Count;
			for(int t = 0; t < numVolues; ++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);

					terrain.terrainData = new TerrainData();
					TerrainData terrainData = terrain.terrainData;
					collider.terrainData = terrainData;

					int heightMapSize = terrainBuffers[t]._heightMapSize;

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

					terrainData.baseMapResolution = heightMapSize;
					terrainData.alphamapResolution = heightMapSize;

					const int resolutionPerPatch = 128;
					terrainData.SetDetailResolution(resolutionPerPatch, resolutionPerPatch);

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

					terrainData.size = new Vector3(terrainBuffers[t]._terrainSizeX, terrainBuffers[t]._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 at time of this implementation the new Unity terrain
					// is still in beta. Therefore, the following layer creation is subject
					// to change.

					TerrainLayer[] terrainLayers = new TerrainLayer[numLayers];
					for (int m = 0; m < numLayers; ++m)
					{
						terrainLayers[m] = new TerrainLayer();

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

						if (!string.IsNullOrEmpty(layer._diffuseTexturePath))
						{
							// Using Resources.Load is much faster than AssetDatabase.Load
							//terrainLayers[m].diffuseTexture = HEU_MaterialFactory.LoadTexture(layer._diffuseTexturePath);
							terrainLayers[m].diffuseTexture = Resources.Load<Texture2D>(layer._diffuseTexturePath);
						}
						if (terrainLayers[m].diffuseTexture == null)
						{
							terrainLayers[m].diffuseTexture = defaultTexture;
						}

						terrainLayers[m].diffuseRemapMin = Vector4.zero;
						terrainLayers[m].diffuseRemapMax = Vector4.one;

						if (!string.IsNullOrEmpty(layer._maskTexturePath))
						{
							// Using Resources.Load is much faster than AssetDatabase.Load
							//terrainLayers[m].maskMapTexture = HEU_MaterialFactory.LoadTexture(layer._maskTexturePath);
							terrainLayers[m].maskMapTexture = Resources.Load<Texture2D>(layer._maskTexturePath);
						}

						terrainLayers[m].maskMapRemapMin = Vector4.zero;
						terrainLayers[m].maskMapRemapMax = Vector4.one;

						terrainLayers[m].metallic = layer._metallic;

						if (!string.IsNullOrEmpty(layer._normalTexturePath))
						{
							terrainLayers[m].normalMapTexture = HEU_MaterialFactory.LoadTexture(layer._normalTexturePath);
						}

						terrainLayers[m].normalScale = layer._normalScale;

						terrainLayers[m].smoothness = layer._smoothness;
						terrainLayers[m].specular = layer._specularColor;
						terrainLayers[m].tileOffset = layer._tileOffset;

						if (layer._tileSize.magnitude == 0f && terrainLayers[m].diffuseTexture != null)
						{
							// Use texture size if tile size is 0
							layer._tileSize = new Vector2(terrainLayers[m].diffuseTexture.width, terrainLayers[m].diffuseTexture.height);
						}
						terrainLayers[m].tileSize = layer._tileSize;
					}
					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

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

					//string assetPath = HEU_AssetDatabase.CreateAssetCacheFolder("terrainData");
					//AssetDatabase.CreateAsset(terrainData, assetPath);
					//Debug.Log("Created asset data at " + assetPath);

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

					SetOutputVisiblity(terrainBuffers[t]);
				}
			}
		}
Exemple #17
0
	/// <summary>
	/// Retrieves object info from Houdini session and updates internal state.
	/// New geo nodes are created, unused geo nodes are destroyed.
	/// Geo nodes are then refreshed to be in sync with Houdini session.
	/// </summary>
	/// <returns>True if internal state has changed (including geometry).</returns>
	internal void UpdateObject(HEU_SessionBase session, bool bForceUpdate)
	{
	    if (ParentAsset == null)
	    {
		return;
	    }

	    // Update the geo info
	    if (!session.GetObjectInfo(ObjectID, ref _objectInfo))
	    {
		return;
	    }
	    SyncWithObjectInfo(session);

	    // Update the object transform
	    _objectTransform = ParentAsset.GetObjectTransform(session, ObjectID);

	    // Container for existing geo nodes that are still in use
	    List<HEU_GeoNode> geoNodesToKeep = new List<HEU_GeoNode>();

	    // Container for new geo infos that need to be created
	    List<HAPI_GeoInfo> newGeoInfosToCreate = new List<HAPI_GeoInfo>();

	    if (_objectInfo.haveGeosChanged || bForceUpdate)
	    {
		// Indicates that the geometry nodes have changed
		//HEU_Logger.Log("Geos have changed!");

		// Form a list of geo infos that are now present after cooking
		List<HAPI_GeoInfo> postCookGeoInfos = new List<HAPI_GeoInfo>();


		bool useOutputNodes = true;
		if (ParentAsset) useOutputNodes = ParentAsset.UseOutputNodes;

		HEU_HAPIUtility.GatherAllAssetGeoInfos(session, ParentAsset.AssetInfo, _objectInfo, useOutputNodes, ref postCookGeoInfos);

		// Now for each geo node that are present after cooking, we check if its
		// new or whether we already have it prior to cooking.
		int numPostCookGeoInfos = postCookGeoInfos.Count;
		for (int i = 0; i < numPostCookGeoInfos; i++)
		{
		    bool bFound = false;
		    for (int j = 0; j < _geoNodes.Count; j++)
		    {
			string geoName = HEU_SessionManager.GetString(postCookGeoInfos[i].nameSH, session);
			if (geoName.Equals(_geoNodes[j].GeoName))
			{
			    _geoNodes[j].SetGeoInfo(postCookGeoInfos[i]);

			    geoNodesToKeep.Add(_geoNodes[j]);
			    _geoNodes.RemoveAt(j);

			    bFound = true;
			    break;
			}
		    }

		    if (!bFound)
		    {
			newGeoInfosToCreate.Add(postCookGeoInfos[i]);
		    }
		}

		// Whatever is left in _geoNodes is no longer needed so clean up
		int numCurrentGeos = _geoNodes.Count;
		for (int i = 0; i < numCurrentGeos; ++i)
		{
		    _geoNodes[i].DestroyAllData();
		}
	    }
	    else
	    {
		Debug.Assert(_objectInfo.geoCount == _geoNodes.Count, "Expected same number of geometry nodes.");
	    }

	    // Go through the old geo nodes that are still in use and update if necessary.
	    foreach (HEU_GeoNode geoNode in geoNodesToKeep)
	    {
		// Get geo info and check if geo changed
		bool bGeoChanged = bForceUpdate || geoNode.HasGeoNodeChanged(session);
		if (bGeoChanged)
		{
		    geoNode.UpdateGeo(session);
		}
		else
		{
		    if (_objectInfo.haveGeosChanged)
		    {
			// Clear object instances since the object info has changed.
			// Without this, the object instances were never getting updated
			// if only the inputs changed but not outputs (of instancers).
			geoNode.ClearObjectInstances();
		    }

		    // Visiblity might have changed, so update that
		    geoNode.CalculateVisiblity(IsVisible());
		    geoNode.CalculateColliderState();
		}
	    }

	    // Create the new geo infos and add to our keep list
	    foreach (HAPI_GeoInfo newGeoInfo in newGeoInfosToCreate)
	    {
		geoNodesToKeep.Add(CreateGeoNode(session, newGeoInfo));
	    }

	    // Overwrite the old list with new
	    _geoNodes = geoNodesToKeep;

	    // Updating the trasform is done in GenerateGeometry
	}