// ignores the Y coordinate of position public void ApplyDamage(Vector3 position, TerrainDamageConfig config, float severity = 1.0f) { Vector3 terrainCell = position; terrainCell -= transform.position; terrainCell.x = (terrainCell.x * terrainData.heightmapResolution) / terrainData.size.x; terrainCell.z = (terrainCell.z * terrainData.heightmapResolution) / terrainData.size.z; // int iCenter = (int)terrainCell.x; // int jCenter = (int)terrainCell.z; // choose what this particular hole is going to look like float holeDepth = Random.Range(config.MinDepth, config.MaxDepth); float holeRadius = Random.Range(config.MinRadius, config.MaxRadius); holeDepth *= severity; holeRadius *= severity; if (config.RemoveEarth) { holeDepth = -holeDepth; } float baseAdjustment = holeDepth / TerrainVerticalScale; float maxHeightmapAdjustment = MaxDeformation / TerrainVerticalScale; int xMin = (int)(terrainCell.x - holeRadius); int xMax = (int)(terrainCell.x + holeRadius); int zMin = (int)(terrainCell.z - holeRadius); int zMax = (int)(terrainCell.z + holeRadius); int iHoleRadius = (int)holeRadius; if (iHoleRadius < 1) { iHoleRadius = 1; } int iHoleRadiusSquaredDivider = iHoleRadius * iHoleRadius * 2; // <WIP> future optimization: pull out just the sub-region that // gets modified and only update those heights rather than all. int dz = -iHoleRadius; for (int z = zMin; z <= zMax; z++, dz++) { int dx = -iHoleRadius; for (int x = xMin; x < xMax; x++, dx++) { if (z >= 0 && z < heightmap.GetLength(0)) { if (x >= 0 && x < heightmap.GetLength(1)) { float fraction = 1.0f; switch (config.HoleShape) { default: case TerrainDamageConfig.ProceduralHoleShape.RECTANGULAR: break; case TerrainDamageConfig.ProceduralHoleShape.INVERTEDCONE: { int offCenter = dx * dx + dz * dz; if (offCenter >= iHoleRadiusSquaredDivider) { offCenter = iHoleRadiusSquaredDivider; } fraction = (iHoleRadiusSquaredDivider - offCenter) / (float)iHoleRadiusSquaredDivider; } break; case TerrainDamageConfig.ProceduralHoleShape.CIRCULAR: { int offCenter = dx * dx + dz * dz; fraction = (offCenter <= iHoleRadiusSquaredDivider / 2) ? 1.0f : 0.0f; } break; } float adjustment = baseAdjustment * fraction; var heightSample = heightmap[z, x] + adjustment; if (heightSample < originalHeightmap[z, x] - maxHeightmapAdjustment) { heightSample = originalHeightmap[z, x] - maxHeightmapAdjustment; } if (heightSample > originalHeightmap[z, x] + maxHeightmapAdjustment) { heightSample = originalHeightmap[z, x] + maxHeightmapAdjustment; } heightmap[z, x] = heightSample; if (z < splatMaps.GetLength(0)) { if (x < splatMaps.GetLength(1)) { for (int k = 0; k < splatMaps.GetLength(2); k++) { if (fraction > 0.5f) { splatMaps[z, x, k] = (k == config.ColorForDamage) ? 1.0f : 0.0f; } } } } } } } } terrainData.SetHeights(0, 0, heightmap); terrainData.SetAlphamaps(0, 0, splatMaps); }
void Start() { config = ScriptableObject.CreateInstance <TerrainDamageConfig>(); }