/// <summary> /// Initialise the extension /// </summary> public override void Initialise() { m_textureHM = new UnityHeightMap(m_grassMask); if (m_normaliseMask && m_textureHM.HasData()) { m_textureHM.Normalise(); } if (m_invertMask && m_textureHM.HasData()) { m_textureHM.Invert(); } if (m_flipMask && m_textureHM.HasData()) { m_textureHM.Flip(); } }
/// <summary> /// Called after the spawn is complete /// </summary> /// <param name="spawnRule">The rule that generated this call</param> /// <param name="spawnInfo">The spawninfo structure for this call</param> public override void PostSpawn(SpawnRule spawnRule, ref SpawnInfo spawnInfo) { //See if we can load the texture if (m_textureHM == null || !m_textureHM.HasData()) { return; } //Get the terrain Terrain t = Gaia.TerrainHelper.GetTerrain(spawnInfo.m_hitLocationWU); if (t == null) { return; } //Get the cached detail maps List <HeightMap> detailMaps = spawnInfo.m_spawner.GetDetailMaps(spawnInfo.m_hitTerrain.GetInstanceID()); if (detailMaps == null || m_grassIndex >= detailMaps.Count) { return; } //Make some speedy calculations float widthWU = spawnInfo.m_hitTerrain.terrainData.size.x; float depthWU = spawnInfo.m_hitTerrain.terrainData.size.z; float radiusWU = spawnRule.GetMaxScaledRadius(ref spawnInfo) * m_scaleMask; float xStartWU = spawnInfo.m_hitLocationWU.x - (radiusWU / 2f); float zStartWU = spawnInfo.m_hitLocationWU.z - (radiusWU / 2f); float xEndWU = xStartWU + radiusWU; float zEndWU = zStartWU + radiusWU; float stepWU = 0.5f; Vector3 locationWU = Vector3.zero; float xRotNU = 0f, zRotNU = 0f; float grassRange = (float)(m_maxGrassStrength - m_minGrassStrenth); for (float x = xStartWU; x < xEndWU; x += stepWU) { for (float z = zStartWU; z < zEndWU; z += stepWU) { //Need to rotate x,z around the pivot by the rotation angle locationWU = new Vector3(x, spawnInfo.m_hitLocationWU.y, z); locationWU = Gaia.Utils.RotatePointAroundPivot(locationWU, spawnInfo.m_hitLocationWU, new Vector3(0f, spawnInfo.m_spawnRotationY, 0f)); //Now normalise the result xRotNU = (locationWU.x / widthWU) + 0.5f; zRotNU = (locationWU.z / depthWU) + 0.5f; //Drop out if out of bounds if (xRotNU < 0f || xRotNU >= 1f || zRotNU < 0f || zRotNU > 1f) { continue; } detailMaps[m_grassIndex][zRotNU, xRotNU] = Mathf.Clamp((m_textureHM[(x - xStartWU) / radiusWU, (z - zStartWU) / radiusWU] * grassRange) + m_minGrassStrenth, 0f, 15f); } } }
/// <summary> /// Call this to get the degree of completion in range 0..1. /// </summary> /// <param name="spawner">The spawner this is for</param> /// <param name="objSpawned">The object that was spawned in the spawn step (if relevant)</param> /// <returns>Return the completion in range of 0 (not started) .. 1 (completed)</returns> public override void PostSpawn(SpawnRule spawnRule, ref SpawnInfo spawnInfo) { //See if we can load the texture if (m_textureHM == null || !m_textureHM.HasData()) { return; } //Get the terrain Terrain t = Gaia.TerrainHelper.GetTerrain(spawnInfo.m_hitLocationWU); if (t == null) { return; } //Get the cached texture maps List <HeightMap> txtMaps = spawnInfo.m_spawner.GetTextureMaps(spawnInfo.m_hitTerrain.GetInstanceID()); if (txtMaps == null || m_textureIndex >= txtMaps.Count) { return; } //Make some speedy calculations float widthWU = spawnInfo.m_hitTerrain.terrainData.size.x; float depthWU = spawnInfo.m_hitTerrain.terrainData.size.z; float radiusWU = spawnRule.GetMaxScaledRadius(ref spawnInfo) * m_scaleMask; float xStartWU = spawnInfo.m_hitLocationWU.x - (radiusWU / 2f); float zStartWU = spawnInfo.m_hitLocationWU.z - (radiusWU / 2f); float xEndWU = xStartWU + radiusWU; float zEndWU = zStartWU + radiusWU; float stepWU = 0.5f; Vector3 locationWU = Vector3.zero; float xRotNU = 0f, zRotNU = 0f; float currStrength = 0f, newStrength = 1f; for (float x = xStartWU; x < xEndWU; x += stepWU) { for (float z = zStartWU; z < zEndWU; z += stepWU) { //Need to rotate x,z around the pivot by the rotation angle locationWU = new Vector3(x, spawnInfo.m_hitLocationWU.y, z); locationWU = Gaia.GaiaUtils.RotatePointAroundPivot(locationWU, spawnInfo.m_hitLocationWU, new Vector3(0f, spawnInfo.m_spawnRotationY, 0f)); //Now normalise the result xRotNU = (locationWU.x / widthWU) + 0.5f; zRotNU = (locationWU.z / depthWU) + 0.5f; //Drop out if out of bounds if (xRotNU < 0f || xRotNU >= 1f || zRotNU < 0f || zRotNU > 1f) { continue; } //Only interested in increasing values currStrength = txtMaps[m_textureIndex][zRotNU, xRotNU]; newStrength = m_textureHM[(x - xStartWU) / radiusWU, (z - zStartWU) / radiusWU]; if (newStrength > currStrength) { float delta = newStrength - currStrength; float theRest = 1f - currStrength; float adjustment = 0f; if (theRest != 0f) { adjustment = 1f - (delta / theRest); } for (int idx = 0; idx < txtMaps.Count; idx++) { if (idx == m_textureIndex) { txtMaps[idx][zRotNU, xRotNU] = newStrength; } else { txtMaps[idx][zRotNU, xRotNU] *= adjustment; } } } } } spawnInfo.m_spawner.SetTextureMapsDirty(); }