I began messing with some terrain code, but I ran into a few problems.
Code: Select all
using UnityEngine;
using System.Collections;
using DaggerfallWorkshop.Game.Utility.ModSupport;
using DaggerfallWorkshop.Game;
using DaggerfallWorkshop.Game.Utility.ModSupport.ModSettings;
public class TerrainTool : MonoBehaviour
{
public static Mod mod;
public static TerrainTool TerrainToolInstance;
static ModSettings settings;
public bool TestWithMouse = true;
public Terrain myTerrain;
public int SmoothArea;
private int xResolution;
private int zResolution;
private float[,] heights;
private float[,] heightMapBackup;
protected const float DEPTH_METER_CONVERT = 0.05f;
protected const float TEXTURE_SIZE_MULTIPLIER = 1.25f;
public int DeformationTextureNum = 1;
protected int alphaMapWidth;
protected int alphaMapHeight;
protected int numOfAlphaLayers;
private float[,,] alphaMapBackup;
private bool terrainGrabbed;
//starts mod manager on game begin. Grabs mod initializing paramaters.
//ensures SateTypes is set to .Start for proper save data restore values.
[Invoke(StateManager.StateTypes.Game, 0)]
public static void Init(InitParams initParams)
{
//Below code blocks set up instances of class/script/mod.\\
//sets up and runs this script file as the main mod file, so it can setup all the other scripts for the mod.
GameObject TerrainTool = new GameObject("TerrainToolMod");
TerrainToolInstance = TerrainTool.AddComponent<TerrainTool>();
Debug.Log("TERRAIN TOOL STARTED");
//initiates mod paramaters for class/script.
mod = initParams.Mod;
//loads mods settings.
settings = mod.GetSettings();
//assets = mod.LoadAllAssetsFromBundle();
//initiates save paramaters for class/script.
//mod.SaveDataInterface = instance;
//after finishing, set the mod's IsReady flag to true.
mod.IsReady = true;
}
void OnApplicationQuit()
{
if (Debug.isDebugBuild)
{
myTerrain.terrainData.SetHeights(0, 0, heightMapBackup);
myTerrain.terrainData.SetAlphamaps(0, 0, alphaMapBackup);
}
}
void Update()
{
// This is just for testing with mouse!
// Point mouse to the Terrain. Left mouse button
// raises and right mouse button lowers terrain.
if (TestWithMouse == true)
{
if (Input.GetMouseButtonDown(0))
{
myTerrain = Terrain.activeTerrain;
xResolution = myTerrain.terrainData.heightmapWidth;
zResolution = myTerrain.terrainData.heightmapHeight;
alphaMapWidth = myTerrain.terrainData.alphamapWidth;
alphaMapHeight = myTerrain.terrainData.alphamapHeight;
numOfAlphaLayers = myTerrain.terrainData.alphamapLayers;
Debug.Log("SAMPLING TERRAIN");
RaycastHit hit;
Ray ray = new Ray(GameManager.Instance.MainCamera.transform.position, GameManager.Instance.MainCamera.transform.forward);
Debug.DrawRay(ray.origin, ray.direction, Color.red,3);
if (Physics.Raycast(ray, out hit))
{
// area middle point x and z, area width, area height, smoothing distance, area height adjust
raiselowerTerrainArea(hit.point, 10, 10, SmoothArea, 0.01f);
// area middle point x and z, area size, texture ID from terrain textures
TextureDeformation(hit.point, 10 * 2f, DeformationTextureNum);
}
}
if (Input.GetMouseButtonDown(1))
{
Debug.Log("SAMPLING TERRAIN");
myTerrain = Terrain.activeTerrain;
xResolution = myTerrain.terrainData.heightmapWidth;
zResolution = myTerrain.terrainData.heightmapHeight;
alphaMapWidth = myTerrain.terrainData.alphamapWidth;
alphaMapHeight = myTerrain.terrainData.alphamapHeight;
numOfAlphaLayers = myTerrain.terrainData.alphamapLayers;
RaycastHit hit;
Ray ray = new Ray(GameManager.Instance.MainCamera.transform.position, GameManager.Instance.MainCamera.transform.forward * 10f);
Debug.DrawRay(ray.origin, ray.direction, Color.red,3);
if (Physics.Raycast(ray, out hit))
{
// area middle point x and z, area width, area height, smoothing distance, area height adjust
raiselowerTerrainArea(hit.point, 10, 10, SmoothArea, -0.01f);
// area middle point x and z, area size, texture ID from terrain textures
TextureDeformation(hit.point, 10 * 2f, 0);
}
}
}
}
private void raiselowerTerrainArea(Vector3 point, int lenx, int lenz, int smooth, float incdec)
{
int areax;
int areaz;
smooth += 1;
float smoothing;
int terX = (int)((point.x / myTerrain.terrainData.size.x) * xResolution);
int terZ = (int)((point.z / myTerrain.terrainData.size.z) * zResolution);
lenx += smooth;
lenz += smooth;
terX -= (lenx / 2);
terZ -= (lenz / 2);
if (terX < 0) terX = 0;
if (terX > xResolution) terX = xResolution;
if (terZ < 0) terZ = 0;
if (terZ > zResolution) terZ = zResolution;
float[,] heights = myTerrain.terrainData.GetHeights(terX, terZ, lenx, lenz);
float y = heights[lenx / 2, lenz / 2];
y += incdec;
for (smoothing = 1; smoothing < smooth + 1; smoothing++)
{
float multiplier = smoothing / smooth;
for (areax = (int)(smoothing / 2); areax < lenx - (smoothing / 2); areax++)
{
for (areaz = (int)(smoothing / 2); areaz < lenz - (smoothing / 2); areaz++)
{
if ((areax > -1) && (areaz > -1) && (areax < xResolution) && (areaz < zResolution))
{
heights[areax, areaz] = Mathf.Clamp((float)y * multiplier, 0, 1);
}
}
}
}
myTerrain.terrainData.SetHeights(terX, terZ, heights);
}
private void raiselowerTerrainPoint(Vector3 point, float incdec)
{
int terX = (int)((point.x / myTerrain.terrainData.size.x) * xResolution);
int terZ = (int)((point.z / myTerrain.terrainData.size.z) * zResolution);
float y = heights[terX, terZ];
y += incdec;
float[,] height = new float[1, 1];
height[0, 0] = Mathf.Clamp(y, 0, 1);
heights[terX, terZ] = Mathf.Clamp(y, 0, 1);
myTerrain.terrainData.SetHeights(terX, terZ, height);
}
protected void TextureDeformation(Vector3 pos, float craterSizeInMeters, int textureIDnum)
{
Vector3 alphaMapTerrainPos = GetRelativeTerrainPositionFromPos(pos, myTerrain, alphaMapWidth, alphaMapHeight);
int alphaMapCraterWidth = (int)(craterSizeInMeters * (alphaMapWidth / myTerrain.terrainData.size.x));
int alphaMapCraterLength = (int)(craterSizeInMeters * (alphaMapHeight / myTerrain.terrainData.size.z));
int alphaMapStartPosX = (int)(alphaMapTerrainPos.x - (alphaMapCraterWidth / 2));
int alphaMapStartPosZ = (int)((alphaMapTerrainPos.z * -1) - (alphaMapCraterLength / 2));
Debug.Log(alphaMapTerrainPos + " | " + alphaMapCraterWidth + " | " + alphaMapCraterLength + " | " + alphaMapStartPosX + " | " + alphaMapStartPosZ);
float[,,] alphas = myTerrain.terrainData.GetAlphamaps(alphaMapStartPosX, alphaMapStartPosZ, alphaMapCraterWidth, alphaMapCraterLength);
float circlePosX;
float circlePosY;
float distanceFromCenter;
for (int i = 0; i < alphaMapCraterLength; i++) //width
{
for (int j = 0; j < alphaMapCraterWidth; j++) //height
{
circlePosX = (j - (alphaMapCraterWidth / 2)) / (alphaMapWidth / myTerrain.terrainData.size.x);
circlePosY = (i - (alphaMapCraterLength / 2)) / (alphaMapHeight / myTerrain.terrainData.size.z);
distanceFromCenter = Mathf.Abs(Mathf.Sqrt(circlePosX * circlePosX + circlePosY * circlePosY));
if (distanceFromCenter < (craterSizeInMeters / 2.0f))
{
for (int layerCount = 0; layerCount < numOfAlphaLayers; layerCount++)
{
//could add blending here in the future
if (layerCount == textureIDnum)
{
alphas[i, j, layerCount] = 1;
}
else
{
alphas[i, j, layerCount] = 0;
}
}
}
}
}
myTerrain.terrainData.SetAlphamaps(alphaMapStartPosX, alphaMapStartPosZ, alphas);
}
protected Vector3 GetNormalizedPositionRelativeToTerrain(Vector3 pos, Terrain terrain)
{
Vector3 tempCoord = (pos - terrain.gameObject.transform.position);
Vector3 coord;
coord.x = tempCoord.x / myTerrain.terrainData.size.x;
coord.y = tempCoord.y / myTerrain.terrainData.size.y;
coord.z = tempCoord.z / myTerrain.terrainData.size.z;
return coord;
}
protected Vector3 GetRelativeTerrainPositionFromPos(Vector3 pos, Terrain terrain, int mapWidth, int mapHeight)
{
Vector3 coord = GetNormalizedPositionRelativeToTerrain(pos, terrain);
return new Vector3((coord.x * mapWidth), 0, (coord.z * mapHeight));
}
}
The first issue is this line of code.
Code: Select all
float[,,] alphas = myTerrain.terrainData.GetAlphamaps(alphaMapStartPosX, alphaMapStartPosZ, alphaMapCraterWidth, alphaMapCraterLength);
DFU terrain width values are coming out as negatives for some reason, and this does not seem to like a negative input. I can turn the negative into a positive and it seems to stop this error.
However, once I turn the value positive, despite seeing no errors in the log, it doesn't work. The terrain doesn't change at all on mouse click; maybe it is, and maybe it is doing it somewhere else and i'm messing up the math/positioning. The debug message shows the ray is clearly hitting the terrain and activating the deformation code. However, this is where the math gets way above my head.
Anyone who understands the math behind this and how the code is working in precise terms can help me?