Files
2024-11-20 15:21:28 +01:00

2586 lines
87 KiB
C#

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Rendering;
#if VEGETATION_STUDIO
using AwesomeTechnologies;
using AwesomeTechnologies.VegetationStudio;
#endif
#if VEGETATION_STUDIO_PRO
using AwesomeTechnologies.VegetationSystem.Biomes;
#endif
#if UNITY_EDITOR
using UnityEditor;
#endif
[RequireComponent(typeof(MeshFilter))]
public class RamSpline : MonoBehaviour
{
public SplineProfile currentProfile;
public SplineProfile oldProfile;
public List<RamSpline> beginnigChildSplines = new List<RamSpline>();
public List<RamSpline> endingChildSplines = new List<RamSpline>();
public RamSpline beginningSpline;
public RamSpline endingSpline;
public int beginningConnectionID;
public int endingConnectionID;
public float beginningMinWidth = 0.5f;
public float beginningMaxWidth = 1f;
public float endingMinWidth = 0.5f;
public float endingMaxWidth = 1f;
public int toolbarInt = 0;
public bool invertUVDirection = false;
public bool uvRotation = true;
public MeshFilter meshfilter;
public List<Vector4> controlPoints = new List<Vector4>();
public List<Quaternion> controlPointsRotations = new List<Quaternion>();
public List<Quaternion> controlPointsOrientation = new List<Quaternion>();
public List<Vector3> controlPointsUp = new List<Vector3>();
public List<Vector3> controlPointsDown = new List<Vector3>();
public List<float> controlPointsSnap = new List<float>();
public AnimationCurve meshCurve = new AnimationCurve(new Keyframe[] { new Keyframe(0, 0), new Keyframe(1, 0) });
public List<AnimationCurve> controlPointsMeshCurves = new List<AnimationCurve>();
public bool normalFromRaycast = false;
public bool snapToTerrain = false;
public LayerMask snapMask = 1;
public List<Vector3> points = new List<Vector3>();
public List<Vector3> pointsUp = new List<Vector3>();
public List<Vector3> pointsDown = new List<Vector3>();
public List<Vector3> points2 = new List<Vector3>();
public List<Vector3> verticesBeginning = new List<Vector3>();
public List<Vector3> verticesEnding = new List<Vector3>();
public List<Vector3> normalsBeginning = new List<Vector3>();
public List<Vector3> normalsEnding = new List<Vector3>();
public List<float> widths = new List<float>();
public List<float> snaps = new List<float>();
public List<float> lerpValues = new List<float>();
public List<Quaternion> orientations = new List<Quaternion>();
public List<Vector3> tangents = new List<Vector3>();
public List<Vector3> normalsList = new List<Vector3>();
public Color[] colors;
public List<Vector2> colorsFlowMap = new List<Vector2>();
public List<Vector3> verticeDirection = new List<Vector3>();
public float floatSpeed = 10;
public bool generateOnStart = false;
public float minVal = 0.5f;
public float maxVal = 0.5f;
public float width = 4;
public int vertsInShape = 3;
public float traingleDensity = 0.2f;
public float uvScale = 3;
public Material oldMaterial;
public bool showVertexColors;
public bool showFlowMap;
public bool overrideFlowMap = false;
public bool drawOnMesh = false;
public bool drawOnMeshFlowMap = false;
public bool uvScaleOverride = false;
public bool debug = false;
public bool debugNormals = false;
public bool debugTangents = false;
public bool debugBitangent = false;
public bool debugFlowmap = false;
public bool debugPoints = false;
public bool debugPointsConnect = false;
public bool debugMesh = true;
public float distanceToDebug = 5;
public Color drawColor = Color.black;
public bool drawColorR = true;
public bool drawColorG = true;
public bool drawColorB = true;
public bool drawColorA = true;
public bool drawOnMultiple = false;
public float flowSpeed = 1f;
public float flowDirection = 0f;
public AnimationCurve flowFlat = new AnimationCurve(new Keyframe[] {
new Keyframe (0, 0.025f),
new Keyframe (0.5f, 0.05f),
new Keyframe (1, 0.025f)
});
public AnimationCurve flowWaterfall = new AnimationCurve(new Keyframe[] {
new Keyframe (0, 0.25f),
new Keyframe (1, 0.25f)
});
public bool noiseflowMap = false;
public float noiseMultiplierflowMap = 0.1f;
public float noiseSizeXflowMap = 2f;
public float noiseSizeZflowMap = 2f;
public float opacity = 0.1f;
public float drawSize = 1f;
public float length = 0;
public float fulllength = 0;
public float uv3length;
public float minMaxWidth;
public float uvWidth;
public float uvBeginning;
public bool receiveShadows = false;
public ShadowCastingMode shadowCastingMode = ShadowCastingMode.Off;
//Part meshes
public bool generateMeshParts = false;
public int meshPartsCount = 3;
public List<Transform> meshesPartTransforms = new List<Transform>();
//Simulate mesh
public float simulatedRiverLength = 100;
public int simulatedRiverPoints = 10;
public float simulatedMinStepSize = 1f;
public bool simulatedNoUp = false;
public bool simulatedBreakOnUp = true;
//Terrain Change
public int detailTerrain = 100;
public int detailTerrainForward = 100;
public float terrainAdditionalWidth = 2;
public float terrainSmoothMultiplier = 5;
public bool overrideRiverRender = false;
public bool noiseWidth = false;
public float noiseMultiplierWidth = 4f;
public float noiseSizeWidth = 0.5f;
public bool noiseCarve = false;
public float noiseMultiplierInside = 1f;
public float noiseMultiplierOutside = 0.25f;
public float noiseSizeX = 0.2f;
public float noiseSizeZ = 0.2f;
public bool noisePaint = false;
public float noiseMultiplierInsidePaint = 0.25f;
public float noiseMultiplierOutsidePaint = 0.25f;
public float noiseSizeXPaint = 0.2f;
public float noiseSizeZPaint = 0.2f;
public LayerMask maskCarve = 1;
public AnimationCurve terrainCarve = new AnimationCurve(new Keyframe[] { new Keyframe(0, 0.5f), new Keyframe(10, -4) });
public float distSmooth = 5;
public float distSmoothStart = 1;
public AnimationCurve terrainPaintCarve = new AnimationCurve(new Keyframe[] { new Keyframe(0, 0), new Keyframe(1, 1) });
public int currentSplatMap = 1;
public bool mixTwoSplatMaps = false;
public int secondSplatMap = 1;
public bool addCliffSplatMap = false;
public int cliffSplatMap = 1;
public float cliffAngle = 45;
public float cliffBlend = 1;
public int cliffSplatMapOutside = 1;
public float cliffAngleOutside = 45;
public float cliffBlendOutside = 1;
public float distanceClearFoliage = 1;
public float distanceClearFoliageTrees = 1;
#if VEGETATION_STUDIO_PRO
public float biomMaskResolution = 0.5f;
public float vegetationMaskSize = 3;
public float vegetationBlendDistance = 1f;
public BiomeMaskArea biomeMaskArea;
public bool refreshMask = false;
#endif
#if VEGETATION_STUDIO
public float vegetationMaskPerimeter = 5;
public VegetationMaskArea vegetationMaskArea;
#endif
public GameObject meshGO;
public void Start()
{
if (generateOnStart)
GenerateSpline();
}
/// <summary>
/// Creates spline
/// </summary>
/// <param name="splineMaterial">Material of the spline</param>
/// <param name="positions">Positions to add to the spline</param>
/// <returns></returns>
public static RamSpline CreateSpline(Material splineMaterial = null, List<Vector4> positions = null, string name = "RamSpline")
{
GameObject gameobject = new GameObject(name);
gameobject.layer = LayerMask.NameToLayer("Water");
RamSpline spline = gameobject.AddComponent<RamSpline>();
MeshRenderer meshRenderer = gameobject.AddComponent<MeshRenderer>();
meshRenderer.receiveShadows = false;
meshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
if (splineMaterial != null)
meshRenderer.sharedMaterial = splineMaterial;
if (positions != null)
for (int i = 0; i < positions.Count; i++)
{
spline.AddPoint(positions[i]);
}
#if UNITY_EDITOR
Undo.RegisterCreatedObjectUndo(gameobject, "Create river");
#endif
return spline;
}
/// <summary>
/// Add point at end of spline
/// </summary>
/// <param name="position">New point position</param>
public void AddPoint(Vector4 position)
{
if (position.w == 0)
{
if (controlPoints.Count > 0)
position.w = controlPoints[controlPoints.Count - 1].w;
else
position.w = width;
}
controlPointsRotations.Add(Quaternion.identity);
controlPoints.Add(position);
controlPointsSnap.Add(0);
controlPointsMeshCurves.Add(new AnimationCurve(new Keyframe[] { new Keyframe(0, 0), new Keyframe(1, 0) }));
}
/// <summary>
/// Add point in the middle of the spline
/// </summary>
/// <param name="i">Point id</param>
public void AddPointAfter(int i)
{
Vector4 position;
if (i == -1)
{
position = controlPoints[0];
}
else
position = controlPoints[i];
if (i < controlPoints.Count - 1 && controlPoints.Count > i + 1)
{
Vector4 positionSecond = controlPoints[i + 1];
if (Vector3.Distance((Vector3)positionSecond, (Vector3)position) > 0)
position = (position + positionSecond) * 0.5f;
else
position.x += 1;
}
else if (controlPoints.Count > 1 && i == controlPoints.Count - 1)
{
Vector4 positionSecond = controlPoints[i - 1];
if (Vector3.Distance((Vector3)positionSecond, (Vector3)position) > 0)
position = position + (position - positionSecond);
else
position.x += 1;
}
else
{
position.x += 1;
}
controlPoints.Insert(i + 1, position);
controlPointsRotations.Insert(i + 1, Quaternion.identity);
controlPointsSnap.Insert(i + 1, 0);
controlPointsMeshCurves.Insert(i + 1, new AnimationCurve(new Keyframe[] {
new Keyframe (0, 0),
new Keyframe (1, 0)
}));
}
/// <summary>
/// Changes point position, if new position doesn't have width old width will be taken
/// </summary>
/// <param name="i">Point id</param>
/// <param name="position">New position</param>
public void ChangePointPosition(int i, Vector3 position)
{
ChangePointPosition(i, new Vector4(position.x, position.y, position.z, 0));
}
/// <summary>
/// Changes point position, if new position doesn't have width old width will be taken
/// </summary>
/// <param name="i">Point id</param>
/// <param name="position">New position</param>
public void ChangePointPosition(int i, Vector4 position)
{
Vector4 oldPos = controlPoints[i];
if (position.w == 0)
position.w = oldPos.w;
controlPoints[i] = position;
}
/// <summary>
/// Removes point in spline
/// </summary>
/// <param name="i"></param>
public void RemovePoint(int i)
{
if (i < controlPoints.Count)
{
controlPoints.RemoveAt(i);
controlPointsRotations.RemoveAt(i);
controlPointsMeshCurves.RemoveAt(i);
controlPointsSnap.RemoveAt(i);
}
}
/// <summary>
/// Removes points from point id forward
/// </summary>
/// <param name="fromID">Point id</param>
public void RemovePoints(int fromID = -1)
{
int pointsCount = controlPoints.Count - 1;
for (int i = pointsCount; i > fromID; i--)
{
RemovePoint(i);
}
}
public void GenerateBeginningParentBased()
{
vertsInShape = (int)Mathf.Round((beginningSpline.vertsInShape - 1) * (beginningMaxWidth - beginningMinWidth) + 1);
if (vertsInShape < 1)
vertsInShape = 1;
beginningConnectionID = beginningSpline.points.Count - 1;
Vector4 pos = beginningSpline.controlPoints[beginningSpline.controlPoints.Count - 1];
float width = pos.w;
width *= beginningMaxWidth - beginningMinWidth;
pos = Vector3.Lerp(beginningSpline.pointsDown[beginningConnectionID], beginningSpline.pointsUp[beginningConnectionID], beginningMinWidth + (beginningMaxWidth - beginningMinWidth) * 0.5f)
+ beginningSpline.transform.position - transform.position;
pos.w = width;
controlPoints[0] = pos;
if (!uvScaleOverride)
uvScale = beginningSpline.uvScale;
}
public void GenerateEndingParentBased()
{
if (beginningSpline == null)
{
vertsInShape = (int)Mathf.Round((endingSpline.vertsInShape - 1) * (endingMaxWidth - endingMinWidth) + 1);
if (vertsInShape < 1)
vertsInShape = 1;
}
endingConnectionID = 0;
Vector4 pos = endingSpline.controlPoints[0];
float width = pos.w;
width *= endingMaxWidth - endingMinWidth;
pos = Vector3.Lerp(endingSpline.pointsDown[endingConnectionID], endingSpline.pointsUp[endingConnectionID], endingMinWidth + (endingMaxWidth - endingMinWidth) * 0.5f) + endingSpline.transform.position - transform.position;
pos.w = width;
controlPoints[controlPoints.Count - 1] = pos;
}
public void GenerateSpline(List<RamSpline> generatedSplines = null)
{
generatedSplines = new List<RamSpline>();
if (beginningSpline != null && beginningSpline.endingSpline != null)
{
Debug.LogError("River can't be ending spline and have beginning spline");
return;
}
if (endingSpline != null && endingSpline.beginningSpline != null)
{
Debug.LogError("River can't be begining spline and have ending spline");
return;
}
if (beginningSpline)
{
GenerateBeginningParentBased();
}
if (endingSpline)
{
GenerateEndingParentBased();
}
List<Vector4> pointsChecked = new List<Vector4>();
for (int i = 0; i < controlPoints.Count; i++)
{
if (i > 0)
{
if (Vector3.Distance((Vector3)controlPoints[i], (Vector3)controlPoints[i - 1]) > 0)
pointsChecked.Add(controlPoints[i]);
}
else
pointsChecked.Add(controlPoints[i]);
}
Mesh mesh = new Mesh();
meshfilter = GetComponent<MeshFilter>();
if (pointsChecked.Count < 2)
{
mesh.Clear();
meshfilter.mesh = mesh;
return;
}
controlPointsOrientation = new List<Quaternion>();
lerpValues.Clear();
snaps.Clear();
points.Clear();
pointsUp.Clear();
pointsDown.Clear();
orientations.Clear();
tangents.Clear();
normalsList.Clear();
widths.Clear();
controlPointsUp.Clear();
controlPointsDown.Clear();
verticesBeginning.Clear();
verticesEnding.Clear();
normalsBeginning.Clear();
normalsEnding.Clear();
if (beginningSpline != null && beginningSpline.controlPointsRotations.Count > 0)
controlPointsRotations[0] = Quaternion.identity;
if (endingSpline != null && endingSpline.controlPointsRotations.Count > 0)
controlPointsRotations[controlPointsRotations.Count - 1] = Quaternion.identity;
for (int i = 0; i < pointsChecked.Count; i++)
{
if (i > pointsChecked.Count - 2)
{
continue;
}
CalculateCatmullRomSideSplines(pointsChecked, i);
}
if (beginningSpline != null && beginningSpline.controlPointsRotations.Count > 0)
controlPointsRotations[0] = Quaternion.Inverse(controlPointsOrientation[0]) * (beginningSpline.controlPointsOrientation[beginningSpline.controlPointsOrientation.Count - 1]);
if (endingSpline != null && endingSpline.controlPointsRotations.Count > 0)
controlPointsRotations[controlPointsRotations.Count - 1] = Quaternion.Inverse(controlPointsOrientation[controlPointsOrientation.Count - 1]) * (endingSpline.controlPointsOrientation[0]);// * endingSpline.controlPointsRotations [0]);
controlPointsOrientation = new List<Quaternion>();
controlPointsUp.Clear();
controlPointsDown.Clear();
for (int i = 0; i < pointsChecked.Count; i++)
{
if (i > pointsChecked.Count - 2)
{
continue;
}
CalculateCatmullRomSideSplines(pointsChecked, i);
}
for (int i = 0; i < pointsChecked.Count; i++)
{
if (i > pointsChecked.Count - 2)
{
continue;
}
CalculateCatmullRomSplineParameters(pointsChecked, i);
}
for (int i = 0; i < controlPointsUp.Count; i++)
{
if (i > controlPointsUp.Count - 2)
{
continue;
}
CalculateCatmullRomSpline(controlPointsUp, i, ref pointsUp);
}
for (int i = 0; i < controlPointsDown.Count; i++)
{
if (i > controlPointsDown.Count - 2)
{
continue;
}
CalculateCatmullRomSpline(controlPointsDown, i, ref pointsDown);
}
GenerateMesh(ref mesh);
if (generatedSplines != null)
{
generatedSplines.Add(this);
foreach (var item in beginnigChildSplines)
{
if (item != null && !generatedSplines.Contains(item))
{
if (item.beginningSpline == this || item.endingSpline == this)
{
item.GenerateSpline(generatedSplines);
}
}
}
foreach (var item in endingChildSplines)
{
if (item != null && !generatedSplines.Contains(item))
{
if (item.beginningSpline == this || item.endingSpline == this)
{
item.GenerateSpline(generatedSplines);
}
}
}
}
}
void CalculateCatmullRomSideSplines(List<Vector4> controlPoints, int pos)
{
Vector3 p0 = controlPoints[pos];
Vector3 p1 = controlPoints[pos];
Vector3 p2 = controlPoints[ClampListPos(pos + 1)];
Vector3 p3 = controlPoints[ClampListPos(pos + 1)];
if (pos > 0)
p0 = controlPoints[ClampListPos(pos - 1)];
if (pos < controlPoints.Count - 2)
p3 = controlPoints[ClampListPos(pos + 2)];
int tValueMax = 0;
if (pos == controlPoints.Count - 2)
{
tValueMax = 1;
}
for (int tValue = 0; tValue <= tValueMax; tValue++)
{
Vector3 newPos = GetCatmullRomPosition(tValue, p0, p1, p2, p3);
Vector3 tangent = GetCatmullRomTangent(tValue, p0, p1, p2, p3).normalized;
Vector3 normal = CalculateNormal(tangent, Vector3.up).normalized;
Quaternion orientation;
if (normal == tangent && normal == Vector3.zero)
orientation = Quaternion.identity;
else
orientation = Quaternion.LookRotation(tangent, normal);
orientation *= Quaternion.Lerp(controlPointsRotations[pos], controlPointsRotations[ClampListPos(pos + 1)], tValue);
// if (beginningSpline && pos == 0) {
//
// int lastId = beginningSpline.controlPointsOrientation.Count - 1;
// //orientation = beginningSpline.controlPointsOrientation [lastId];
//
// }
//
// if (endingSpline && pos == controlPoints.Count - 2 && tValue == 1) {
//
// //orientation = endingSpline.controlPointsOrientation [0];
//
// }
controlPointsOrientation.Add(orientation);
Vector3 posUp = newPos + orientation * (0.5f * controlPoints[pos + tValue].w * Vector3.right);
Vector3 posDown = newPos + orientation * (0.5f * controlPoints[pos + tValue].w * Vector3.left);
controlPointsUp.Add(posUp);
controlPointsDown.Add(posDown);
}
}
void CalculateCatmullRomSplineParameters(List<Vector4> controlPoints, int pos, bool initialPoints = false)
{
Vector3 p0 = controlPoints[pos];
Vector3 p1 = controlPoints[pos];
Vector3 p2 = controlPoints[ClampListPos(pos + 1)];
Vector3 p3 = controlPoints[ClampListPos(pos + 1)];
if (pos > 0)
p0 = controlPoints[ClampListPos(pos - 1)];
if (pos < controlPoints.Count - 2)
p3 = controlPoints[ClampListPos(pos + 2)];
int loops = Mathf.FloorToInt(1f / traingleDensity);
float i = 1;
float start = 0;
if (pos > 0)
start = 1;
for (i = start; i <= loops; i++)
{
float t = i * traingleDensity;
CalculatePointParameters(controlPoints, pos, p0, p1, p2, p3, t);
}
if (i < loops)
{
i = loops;
float t = i * traingleDensity;
CalculatePointParameters(controlPoints, pos, p0, p1, p2, p3, t);
}
}
void CalculateCatmullRomSpline(List<Vector3> controlPoints, int pos, ref List<Vector3> points)
{
Vector3 p0 = controlPoints[pos];
Vector3 p1 = controlPoints[pos];
Vector3 p2 = controlPoints[ClampListPos(pos + 1)];
Vector3 p3 = controlPoints[ClampListPos(pos + 1)];
if (pos > 0)
p0 = controlPoints[ClampListPos(pos - 1)];
if (pos < controlPoints.Count - 2)
p3 = controlPoints[ClampListPos(pos + 2)];
int loops = Mathf.FloorToInt(1f / traingleDensity);
float i = 1;
float start = 0;
if (pos > 0)
start = 1;
for (i = start; i <= loops; i++)
{
float t = i * traingleDensity;
CalculatePointPosition(controlPoints, pos, p0, p1, p2, p3, t, ref points);
}
if (i < loops)
{
i = loops;
float t = i * traingleDensity;
CalculatePointPosition(controlPoints, pos, p0, p1, p2, p3, t, ref points);
}
}
void CalculatePointPosition(List<Vector3> controlPoints, int pos, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t, ref List<Vector3> points)
{
Vector3 newPos = GetCatmullRomPosition(t, p0, p1, p2, p3);
points.Add(newPos);
Vector3 tangent = GetCatmullRomTangent(t, p0, p1, p2, p3).normalized;
Vector3 normal = CalculateNormal(tangent, Vector3.up).normalized;
}
void CalculatePointParameters(List<Vector4> controlPoints, int pos, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
{
Vector3 newPos = GetCatmullRomPosition(t, p0, p1, p2, p3);
widths.Add(Mathf.Lerp(controlPoints[pos].w, controlPoints[ClampListPos(pos + 1)].w, t));
if (controlPointsSnap.Count > pos + 1)
snaps.Add(Mathf.Lerp(controlPointsSnap[pos], controlPointsSnap[ClampListPos(pos + 1)], t));
else
snaps.Add(0);
lerpValues.Add(pos + t);
points.Add(newPos);
Vector3 tangent = GetCatmullRomTangent(t, p0, p1, p2, p3).normalized;
Vector3 normal = CalculateNormal(tangent, Vector3.up).normalized;
// Debug.Log(tangent + " CalculatePointParameters: " + normal);
Quaternion orientation;
if (normal == tangent && normal == Vector3.zero)
orientation = Quaternion.identity;
else
orientation = Quaternion.LookRotation(tangent, normal);
orientation *= Quaternion.Lerp(controlPointsRotations[pos], controlPointsRotations[ClampListPos(pos + 1)], t);
orientations.Add(orientation);
tangents.Add(tangent);
if (normalsList.Count > 0 && Vector3.Angle(normalsList[normalsList.Count - 1], normal) > 90)
{
normal *= -1;
}
normalsList.Add(normal);
}
int ClampListPos(int pos)
{
if (pos < 0)
{
pos = controlPoints.Count - 1;
}
if (pos > controlPoints.Count)
{
pos = 1;
}
else if (pos > controlPoints.Count - 1)
{
pos = 0;
}
return pos;
}
Vector3 GetCatmullRomPosition(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
{
Vector3 a = 2f * p1;
Vector3 b = p2 - p0;
Vector3 c = 2f * p0 - 5f * p1 + 4f * p2 - p3;
Vector3 d = -p0 + 3f * p1 - 3f * p2 + p3;
Vector3 pos = 0.5f * (a + (b * t) + (c * t * t) + (d * t * t * t));
return pos;
}
Vector3 GetCatmullRomTangent(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
{
return 0.5f * ((-p0 + p2) + 2f * (2f * p0 - 5f * p1 + 4f * p2 - p3) * t + 3f * (-p0 + 3f * p1 - 3f * p2 + p3) * t * t);
}
Vector3 CalculateNormal(Vector3 tangent, Vector3 up)
{
Vector3 binormal = Vector3.Cross(up, tangent);
return Vector3.Cross(tangent, binormal);
}
void GenerateMesh(ref Mesh mesh)
{
MeshRenderer meshRenderer = gameObject.GetComponent<MeshRenderer>();
if (meshRenderer != null)
{
meshRenderer.receiveShadows = receiveShadows;
meshRenderer.shadowCastingMode = shadowCastingMode;
}
foreach (var item in meshesPartTransforms)
{
if (item != null)
{
if (Application.isPlaying)
Destroy(item.gameObject);
else
DestroyImmediate(item.gameObject);
Destroy(item.gameObject);
}
}
int segments = points.Count - 1;
int edgeLoops = points.Count;
int vertCount = vertsInShape * edgeLoops;
List<int> triangleIndices = new List<int>();
Vector3[] vertices = new Vector3[vertCount];
Vector3[] normals = new Vector3[vertCount];
Vector2[] uvs = new Vector2[vertCount];
Vector2[] uvs3 = new Vector2[vertCount];
Vector2[] uvs4 = new Vector2[vertCount];
if (colors == null || colors.Length != vertCount)
{
colors = new Color[vertCount];
for (int i = 0; i < colors.Length; i++)
{
colors[i] = Color.black;
}
}
if (colorsFlowMap.Count != vertCount)
colorsFlowMap.Clear();
length = 0;
fulllength = 0;
if (beginningSpline != null)
length = beginningSpline.length;
minMaxWidth = 1;
uvWidth = 1;
uvBeginning = 0;
if (beginningSpline != null)
{
minMaxWidth = beginningMaxWidth - beginningMinWidth;
uvWidth = minMaxWidth * beginningSpline.uvWidth;
uvBeginning = beginningSpline.uvWidth * beginningMinWidth + beginningSpline.uvBeginning;
}
else if (endingSpline != null)
{
minMaxWidth = endingMaxWidth - endingMinWidth;
uvWidth = minMaxWidth * endingSpline.uvWidth;
uvBeginning = endingSpline.uvWidth * endingMinWidth + endingSpline.uvBeginning;
}
for (int i = 0; i < pointsDown.Count; i++)
{
float width = widths[i];
if (i > 0)
fulllength += uvWidth * Vector3.Distance(pointsDown[i], pointsDown[i - 1]) / (float)(uvScale * width);
}
float roundEnding = Mathf.Round(fulllength);
for (int i = 0; i < pointsDown.Count; i++)
{
float width = widths[i];
int offset = i * vertsInShape;
if (i > 0)
{
length += (uvWidth * Vector3.Distance(pointsDown[i], pointsDown[i - 1]) / (float)(uvScale * width)) / fulllength * roundEnding;
}
float u = 0;
float u3 = 0;
for (int j = 0; j < vertsInShape; j++)
{
int id = offset + j;
//VERTICES
float pos = j / (float)(vertsInShape - 1);
if (pos < 0.5f)
pos *= minVal * 2;
else
pos = ((pos - 0.5f) * (1 - maxVal) + 0.5f * maxVal) * 2;
if (i == 0 && beginningSpline != null && beginningSpline.verticesEnding != null && beginningSpline.normalsEnding != null)
{
int pos2 = (int)(beginningSpline.vertsInShape * beginningMinWidth);
vertices[id] = beginningSpline.verticesEnding[Mathf.Clamp(j + pos2, 0, beginningSpline.verticesEnding.Count - 1)] + beginningSpline.transform.position - transform.position;
//if (beginningSpline.normalsEnding.Count > 0)
// normals [id] = beginningSpline.normalsEnding [Mathf.Clamp (j + pos2, 0, beginningSpline.normalsEnding.Count - 1)];
}
else if (i == pointsDown.Count - 1 && endingSpline != null && endingSpline.verticesBeginning != null && endingSpline.verticesBeginning.Count > 0 && endingSpline.normalsBeginning != null)
{
int pos2 = (int)(endingSpline.vertsInShape * endingMinWidth);
vertices[id] = endingSpline.verticesBeginning[Mathf.Clamp(j + pos2, 0, endingSpline.verticesBeginning.Count - 1)] + endingSpline.transform.position - transform.position;
//if (endingSpline.normalsBeginning.Count > 0)
// normals [id] = endingSpline.normalsBeginning [Mathf.Clamp (j + pos2, 0, endingSpline.normalsBeginning.Count - 1)];
}
else
{
vertices[id] = Vector3.Lerp(pointsDown[i], pointsUp[i], pos);
RaycastHit hit;
if (Physics.Raycast(vertices[id] + transform.position + Vector3.up * 5, Vector3.down, out hit, 1000, snapMask.value))
{
vertices[id] = Vector3.Lerp(vertices[id], hit.point - transform.position + new Vector3(0, 0.1f, 0), (Mathf.Sin(Mathf.PI * snaps[i] - Mathf.PI * 0.5f) + 1) * 0.5f);
}
if (normalFromRaycast)
{
RaycastHit hit2;
if (Physics.Raycast(points[i] + transform.position + Vector3.up * 5, Vector3.down, out hit2, 1000, snapMask.value))
{
normals[id] = hit2.normal;
}
}
vertices[id].y += Mathf.Lerp(controlPointsMeshCurves[Mathf.FloorToInt(lerpValues[i])].Evaluate(pos),
controlPointsMeshCurves[Mathf.CeilToInt(lerpValues[i])].Evaluate(pos),
lerpValues[i] - Mathf.Floor(lerpValues[i]));
}
if (i > 0 && i < 5 && beginningSpline != null && beginningSpline.verticesEnding != null)
{
vertices[id].y = (vertices[id].y + vertices[id - vertsInShape].y) * 0.5f;
}
if (i == pointsDown.Count - 1 && endingSpline != null && endingSpline.verticesBeginning != null)
{
for (int k = 1; k < 5; k++)
{
vertices[id - vertsInShape * k].y = (vertices[id - vertsInShape * (k - 1)].y + vertices[id - vertsInShape * k].y) * 0.5f;
}
}
if (i == 0)
verticesBeginning.Add(vertices[id]);
if (i == pointsDown.Count - 1)
verticesEnding.Add(vertices[id]);
//NORMALS
if (!normalFromRaycast)
// if ((i > 0 || beginningSpline == null) && (i < pointsDown.Count - 1 || endingSpline == null))
normals[id] = orientations[i] * Vector3.up;
//if (beginningSpline != null && i == 1)
// normals [id] = (normals [id] + normals [id - vertsInShape]) * 0.5f;
//
//if (i == pointsDown.Count - 2 && endingSpline != null && endingSpline.normalsBeginning != null && endingSpline.normalsBeginning.Count > 0) {
//
// int pos2 = (int)(endingSpline.vertsInShape * endingMinWidth);
// normals [id] = (normals [id] + endingSpline.normalsBeginning [Mathf.Clamp (j + pos2, 0, endingSpline.normalsBeginning.Count - 1)]) * 0.5f;
//
//}
if (i == 0)
normalsBeginning.Add(normals[id]);
if (i == pointsDown.Count - 1)
normalsEnding.Add(normals[id]);
//UVS
if (j > 0)
{
u = (pos) * uvWidth;
u3 = pos;
}
if (beginningSpline != null || endingSpline != null)
{
u += uvBeginning;
}
u = u / uvScale;
float uv4u = FlowCalculate(u3, normals[id].y, vertices[id]);
int lerpDistance = 10;
if (beginnigChildSplines.Count > 0 && i <= lerpDistance)
{
float lerpUv4u = 0;
foreach (var item in beginnigChildSplines)
{
if (item == null)
continue;
if (Mathf.CeilToInt(item.endingMaxWidth * (vertsInShape - 1)) >= j && j >= Mathf.CeilToInt(item.endingMinWidth * (vertsInShape - 1)))
{
lerpUv4u = (j - Mathf.CeilToInt(item.endingMinWidth * (vertsInShape - 1)))
/ (float)(Mathf.CeilToInt(item.endingMaxWidth * (vertsInShape - 1)) - Mathf.CeilToInt(item.endingMinWidth * (vertsInShape - 1)));
lerpUv4u = FlowCalculate(lerpUv4u, normals[id].y, vertices[id]);
}
}
if (i > 0)
uv4u = Mathf.Lerp(uv4u, lerpUv4u, 1 - (i / (float)lerpDistance));
else
uv4u = lerpUv4u;
}
if (i >= pointsDown.Count - lerpDistance - 1 && endingChildSplines.Count > 0)
{
float lerpUv4u = 0;
foreach (var item in endingChildSplines)
{
if (item == null)
continue;
if (Mathf.CeilToInt(item.beginningMaxWidth * (vertsInShape - 1)) >= j && j >= Mathf.CeilToInt(item.beginningMinWidth * (vertsInShape - 1)))
{
lerpUv4u = (j - Mathf.CeilToInt(item.beginningMinWidth * (vertsInShape - 1)))
/ (float)(Mathf.CeilToInt(item.beginningMaxWidth * (vertsInShape - 1)) - Mathf.CeilToInt(item.beginningMinWidth * (vertsInShape - 1)));
lerpUv4u = FlowCalculate(lerpUv4u, normals[id].y, vertices[id]);
}
}
if (i < pointsDown.Count - 1)
uv4u = Mathf.Lerp(uv4u, lerpUv4u, (i - (pointsDown.Count - lerpDistance - 1)) / (float)lerpDistance);
else
uv4u = lerpUv4u;
}
float uv4v = -(u3 - 0.5f) * 0.01f;
uv3length = length / (float)fulllength;
if (beginningSpline != null)
{
uv3length = (length - beginningSpline.length) / (float)fulllength + beginningSpline.uv3length;
// Debug.Log(uv3length + " " + beginningSpline.uv3length + " " + length + " " + fulllength);
}
if (beginnigChildSplines != null && beginnigChildSplines.Count > 0)
{
uv3length = (length) / (float)fulllength + beginnigChildSplines[0].uv3length;
}
if (uvRotation)
{
if (!invertUVDirection)
{
uvs[id] = new Vector2(1 - length, u);
uvs3[id] = new Vector2(1 - uv3length, u3);
uvs4[id] = new Vector2(uv4u, uv4v);
}
else
{
uvs[id] = new Vector2(1 + length, u);
uvs3[id] = new Vector2(1 + uv3length, u3);
uvs4[id] = new Vector2(uv4u, uv4v);
}
}
else
{
if (!invertUVDirection)
{
uvs[id] = new Vector2(u, 1 - length);
uvs3[id] = new Vector2(u3, 1 - uv3length);
uvs4[id] = new Vector2(uv4v, uv4u);
}
else
{
uvs[id] = new Vector2(u, 1 + length);
uvs3[id] = new Vector2(u3, 1 + uv3length);
uvs4[id] = new Vector2(uv4v, uv4u);
}
}
float tempRound = (int)(uvs4[id].x * 100);
uvs4[id].x = tempRound * 0.01f;
tempRound = (int)(uvs4[id].y * 100);
uvs4[id].y = tempRound * 0.01f;
if (colorsFlowMap.Count <= id)
colorsFlowMap.Add(uvs4[id]);
else if (!overrideFlowMap)
colorsFlowMap[id] = uvs4[id];
}
}
//TRIANGLES
for (int i = 0; i < segments; i++)
{
int offset = i * vertsInShape;
for (int l = 0; l < vertsInShape - 1; l += 1)
{
int a = offset + l;
int b = offset + l + vertsInShape;
int c = offset + l + 1 + vertsInShape;
int d = offset + l + 1;
triangleIndices.Add(a);
triangleIndices.Add(b);
triangleIndices.Add(c);
triangleIndices.Add(c);
triangleIndices.Add(d);
triangleIndices.Add(a);
}
}
verticeDirection.Clear();
for (int i = 0; i < vertices.Length - vertsInShape; i++)
{
Vector3 dir = (vertices[i + vertsInShape] - vertices[i]).normalized;
if (uvRotation)
dir = new Vector3(dir.z, 0, -dir.x);
verticeDirection.Add(dir);
}
for (int i = vertices.Length - vertsInShape; i < vertices.Length; i++)
{
Vector3 dir = (vertices[i] - vertices[i - vertsInShape]).normalized;
if (uvRotation)
dir = new Vector3(dir.z, 0, -dir.x);
verticeDirection.Add(dir);
}
mesh = new Mesh();
mesh.Clear();
mesh.vertices = vertices;
mesh.normals = normals;
mesh.uv = uvs;
mesh.uv3 = uvs3;
mesh.uv4 = colorsFlowMap.ToArray();
mesh.triangles = triangleIndices.ToArray();
mesh.colors = colors;
mesh.RecalculateTangents();
meshfilter.mesh = mesh;
GetComponent<MeshRenderer>().enabled = true;
if (generateMeshParts)
GenerateMeshParts(mesh);
}
public void GenerateMeshParts(Mesh baseMesh)
{
foreach (var item in meshesPartTransforms)
{
if (item != null)
DestroyImmediate(item.gameObject);
}
Vector3[] vertices = baseMesh.vertices;
Vector3[] normals = baseMesh.normals;
Vector2[] uvs = baseMesh.uv;
Vector2[] uvs3 = baseMesh.uv3;
GetComponent<MeshRenderer>().enabled = false;
int verticesLinesPart = Mathf.RoundToInt((vertices.Length / vertsInShape) / (float)meshPartsCount);
int verticesInPart = verticesLinesPart * vertsInShape;
for (int i = 0; i < meshPartsCount; i++)
{
GameObject go = new GameObject(gameObject.name + "- Mesh part " + i);
go.transform.SetParent(gameObject.transform, false);
go.transform.localPosition = Vector3.zero;
go.transform.localEulerAngles = Vector3.zero;
go.transform.localScale = Vector3.one;
meshesPartTransforms.Add(go.transform);
MeshRenderer meshRendererPart = go.AddComponent<MeshRenderer>();
meshRendererPart.sharedMaterial = GetComponent<MeshRenderer>().sharedMaterial;
meshRendererPart.receiveShadows = receiveShadows;
meshRendererPart.shadowCastingMode = shadowCastingMode;
MeshFilter mf = go.AddComponent<MeshFilter>();
Mesh meshPart = new Mesh();
meshPart.Clear();
List<Vector3> verticesPart = new List<Vector3>();
List<Vector3> normalsPart = new List<Vector3>();
List<Vector2> uvPart = new List<Vector2>();
List<Vector2> uv3Part = new List<Vector2>();
List<Vector2> uv4Part = new List<Vector2>();
List<Color> colorsPart = new List<Color>();
List<int> trianglesPart = new List<int>();
for (int j = verticesInPart * i + (i > 0 ? -vertsInShape : 0); (j < verticesInPart * (i + 1) && j < vertices.Length) || (i == meshPartsCount - 1 && j < vertices.Length); j++)
{
verticesPart.Add(vertices[j]);
normalsPart.Add(normals[j]);
uvPart.Add(uvs[j]);
uv3Part.Add(uvs3[j]);
uv4Part.Add(colorsFlowMap[j]);
colorsPart.Add(colors[j]);
}
if (verticesPart.Count > 0)
{
Vector3 pivotChange = verticesPart[0];
for (int j = 0; j < verticesPart.Count; j++)
{
verticesPart[j] = verticesPart[j] - pivotChange;
}
for (int k = 0; k < verticesPart.Count / vertsInShape - 1; k++)
{
int offset = k * vertsInShape;
for (int l = 0; l < vertsInShape - 1; l += 1)
{
int a = offset + l;
int b = offset + l + vertsInShape;
int c = offset + l + 1 + vertsInShape;
int d = offset + l + 1;
trianglesPart.Add(a);
trianglesPart.Add(b);
trianglesPart.Add(c);
trianglesPart.Add(c);
trianglesPart.Add(d);
trianglesPart.Add(a);
}
}
go.transform.position += pivotChange;
meshPart.vertices = verticesPart.ToArray();
meshPart.triangles = trianglesPart.ToArray();
meshPart.normals = normalsPart.ToArray();
meshPart.uv = uvPart.ToArray();
meshPart.uv3 = uv3Part.ToArray();
meshPart.uv4 = uv4Part.ToArray();
meshPart.colors = colorsPart.ToArray();
meshPart.RecalculateTangents();
mf.mesh = meshPart;
//MeshCollider meshCollider = go.AddComponent<MeshCollider>();
//meshCollider.cookingOptions = MeshColliderCookingOptions.InflateConvexMesh | MeshColliderCookingOptions.CookForFasterSimulation | MeshColliderCookingOptions.EnableMeshCleaning | MeshColliderCookingOptions.WeldColocatedVertices;
//meshCollider.skinWidth = 0.1f;
//meshCollider.convex = true;
//meshCollider.isTrigger = true;
}
}
}
public void AddNoiseToWidths()
{
for (int i = 0; i < controlPoints.Count; i++)
{
Vector4 controlPoint = controlPoints[i];
controlPoint.w = controlPoint.w + (noiseWidth ? noiseMultiplierWidth * (Mathf.PerlinNoise(noiseSizeWidth * i, 0) - 0.5f) : 0);
if (controlPoint.w < 0)
{
controlPoint.w = 0;
}
controlPoints[i] = controlPoint;
}
}
public void SimulateRiver(bool generate = true)
{
if (meshGO != null)
{
if (Application.isEditor)
DestroyImmediate(meshGO);
else
Destroy(meshGO);
}
if (controlPoints.Count == 0)
{
Debug.Log("Add one point to start Simulating River");
return;
}
Ray ray = new Ray();
RaycastHit hit;
Vector3 lastPosition = transform.TransformPoint((Vector3)controlPoints[controlPoints.Count - 1]);
List<Vector3> positionsGenerated = new List<Vector3>();
if (controlPoints.Count > 1)
{
positionsGenerated.Add(transform.TransformPoint((Vector3)controlPoints[controlPoints.Count - 2]));
positionsGenerated.Add(lastPosition);
}
List<Vector3> samplePositionsGenerated = new List<Vector3>();
samplePositionsGenerated.Add(lastPosition);
//Debug.DrawRay(lastPosition + new Vector3(0, 3, 0), Vector3.down * 20, Color.white, 3);
float length = 0;
int i = -1;
int added = 0;
bool end = false;
float widthNew = 0;
if (controlPoints.Count > 0)
widthNew = controlPoints[controlPoints.Count - 1].w;
else
widthNew = width;
do
{
i++;
if (i > 0)
{
Vector3 maxPosition = Vector3.zero;
float max = float.MinValue;
bool foundNextPositon = false;
for (float j = simulatedMinStepSize; j < 10; j += 0.1f)
{
for (int angle = 0; angle < 36; angle++)
{
float x = j * Mathf.Cos(angle);
float z = j * Mathf.Sin(angle);
ray.origin = lastPosition + new Vector3(0, 1000, 0) + new Vector3(x, 0, z);
ray.direction = Vector3.down;
if (Physics.Raycast(ray, out hit, 10000))
{
if (hit.distance > max)
{
bool goodPoint = true;
foreach (var item in positionsGenerated)
{
if (Vector3.Distance(item, lastPosition) > Vector3.Distance(item, hit.point) + 0.5f)
{
goodPoint = false;
break;
}
}
if (goodPoint)
{
foundNextPositon = true;
max = hit.distance;
maxPosition = hit.point;
}
}
//else
// Debug.DrawRay(ray.origin, ray.direction * 10000, Color.red, 3);
}
}
if (foundNextPositon)
break;
}
if (!foundNextPositon)
break;
if (maxPosition.y > lastPosition.y)
{
if (simulatedNoUp)
maxPosition.y = lastPosition.y;
if (simulatedBreakOnUp)
end = true;
//Debug.DrawRay(maxPosition + new Vector3(0, 5, 0), ray.direction * 10, Color.red, 3);
}
// else
// Debug.DrawRay(maxPosition + new Vector3(0, 5, 0), ray.direction * 10, Color.blue, 3);
length += Vector3.Distance(maxPosition, lastPosition);
if (i % simulatedRiverPoints == 0 || simulatedRiverLength <= length || end)
{
//Debug.DrawRay(maxPosition + new Vector3(0, 5, 0), ray.direction * 20, Color.white, 3);
samplePositionsGenerated.Add(maxPosition);
if (generate)
{
added++;
Vector4 newPosition = maxPosition - transform.position;
newPosition.w = widthNew + (noiseWidth ? noiseMultiplierWidth * (Mathf.PerlinNoise(noiseSizeWidth * added, 0) - 0.5f) : 0);
controlPointsRotations.Add(Quaternion.identity);
controlPoints.Add(newPosition);
controlPointsSnap.Add(0);
controlPointsMeshCurves.Add(new AnimationCurve(meshCurve.keys));
}
}
else
{
//samplePositionsGenerated.Add(maxPosition);
//Debug.DrawRay(maxPosition + new Vector3(0, 3, 0), ray.direction * 20, Color.Lerp(Color.red, Color.green, i / (float)spline.simulatedRiverLength), 3);
}
positionsGenerated.Add(lastPosition);
lastPosition = maxPosition;
}
} while (simulatedRiverLength > length && !end);
if (!generate)
{
if (controlPoints.Count > 0)
widthNew = controlPoints[controlPoints.Count - 1].w;
else
widthNew = width;
float widthNoise = 0;
List<List<Vector4>> positionArray = new List<List<Vector4>>();
Vector3 v1 = new Vector3();
for (i = 0; i < samplePositionsGenerated.Count - 1; i++)
{
widthNoise = widthNew + (noiseWidth ? noiseMultiplierWidth * (Mathf.PerlinNoise(noiseSizeWidth * i, 0) - 0.5f) : 0);
//Debug.DrawLine(samplePositionsGenerated[i], samplePositionsGenerated[i + 1], Color.white, 3);
v1 = Vector3.Cross(samplePositionsGenerated[i + 1] - samplePositionsGenerated[i], Vector3.up).normalized;
if (i > 0)
{
Vector3 v2 = Vector3.Cross(samplePositionsGenerated[i] - samplePositionsGenerated[i - 1], Vector3.up).normalized;
v1 = (v1 + v2).normalized;
}
//Vector3 v2 = Vector3.Cross(samplePositionsGenerated[i + 1] - samplePositionsGenerated[i], v1).normalized;
//Debug.DrawLine(samplePositionsGenerated[i] - v1 * widthNew * 0.5f, samplePositionsGenerated[i] + v1 * widthNew * 0.5f, Color.blue, 3);
List<Vector4> positionRow = new List<Vector4>();
positionRow.Add(samplePositionsGenerated[i] + v1 * widthNoise * 0.5f);
positionRow.Add(samplePositionsGenerated[i] - v1 * widthNoise * 0.5f);
positionArray.Add(positionRow);
}
widthNoise = widthNew + (noiseWidth ? noiseMultiplierWidth * (Mathf.PerlinNoise(noiseSizeWidth * i, 0) - 0.5f) : 0);
List<Vector4> positionRowLast = new List<Vector4>();
positionRowLast.Add(samplePositionsGenerated[i] + v1 * widthNoise * 0.5f);
positionRowLast.Add(samplePositionsGenerated[i] - v1 * widthNoise * 0.5f);
positionArray.Add(positionRowLast);
Mesh meshTerrain = new Mesh();
meshTerrain.indexFormat = IndexFormat.UInt32;
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
// List<Vector2> uv = new List<Vector2>();
foreach (var positionRow in positionArray)
{
foreach (var vert in positionRow)
{
vertices.Add(vert);
}
}
for (i = 0; i < positionArray.Count - 1; i++)
{
int count = positionArray[i].Count;
for (int j = 0; j < count - 1; j++)
{
triangles.Add(j + i * count);
triangles.Add(j + (i + 1) * count);
triangles.Add((j + 1) + i * count);
triangles.Add((j + 1) + i * count);
triangles.Add(j + (i + 1) * count);
triangles.Add((j + 1) + (i + 1) * count);
}
}
meshTerrain.SetVertices(vertices);
meshTerrain.SetTriangles(triangles, 0);
// meshTerrain.SetUVs(0, uv);
meshTerrain.RecalculateNormals();
meshTerrain.RecalculateTangents();
meshTerrain.RecalculateBounds();
meshGO = new GameObject("TerrainMesh");
meshGO.hideFlags = HideFlags.HideAndDontSave;
meshGO.AddComponent<MeshFilter>();
meshGO.transform.parent = transform;
MeshRenderer meshRenderer = meshGO.AddComponent<MeshRenderer>();
meshRenderer.sharedMaterial = new Material(Shader.Find("Debug Terrain Carve"));
meshRenderer.sharedMaterial.color = new Color(0, 0.5f, 0);
meshGO.transform.position = Vector3.zero;
meshGO.GetComponent<MeshFilter>().sharedMesh = meshTerrain;
}
}
#region Terrain
public void ShowTerrainCarve(float differentSize = 0)
{
if (Application.isEditor && meshGO == null)
{
Transform meshGoTrans = transform.Find("TerrainMesh");
if (meshGoTrans != null)
meshGO = meshGoTrans.gameObject;
}
if (meshGO != null)
{
if (Application.isEditor)
DestroyImmediate(meshGO);
else
Destroy(meshGO);
}
Mesh mesh = meshfilter.sharedMesh;
RaycastHit hit;
Vector3 rayPointDown;
Vector3 rayPointUp;
Vector3 point;
detailTerrainForward = 2;
detailTerrain = 10;
if (differentSize == 0)
terrainAdditionalWidth = distSmooth + distSmoothStart;
else
terrainAdditionalWidth = differentSize;
List<List<Vector4>> positionArray = new List<List<Vector4>>();
float noise = 0;
for (int i = 0; i < pointsDown.Count - 1; i++)
{
for (int tf = 0; tf <= detailTerrainForward; tf++)
{
List<Vector4> positionArrayRow = new List<Vector4>();
rayPointDown = Vector3.Lerp(pointsDown[i], pointsDown[i + 1], tf / (float)detailTerrainForward);
rayPointUp = Vector3.Lerp(pointsUp[i], pointsUp[i + 1], tf / (float)detailTerrainForward);
Vector3 diff = rayPointDown - rayPointUp;
float diffMagintude = diff.magnitude;
rayPointDown += diff * 0.05f;
rayPointUp -= diff * 0.05f;
diff.Normalize();
Vector3 rayPointDownNew = rayPointDown + diff * terrainAdditionalWidth * 0.5f;
Vector3 rayPointUpNew = rayPointUp - diff * terrainAdditionalWidth * 0.5f;
if (terrainAdditionalWidth > 0)
{
for (int t = 0; t < detailTerrain; t++)
{
point = Vector3.Lerp(rayPointDownNew, rayPointDown, t / (float)detailTerrain) + transform.position;
if (Physics.Raycast(point + Vector3.up * 500, Vector3.down, out hit, 10000, maskCarve.value))
{
if (noiseCarve)
noise = Mathf.PerlinNoise(point.x * noiseSizeX, point.z * noiseSizeZ) * noiseMultiplierOutside - noiseMultiplierOutside * 0.5f;
else
noise = 0;
float evaluate = 1 - t / (float)detailTerrain;
evaluate *= terrainAdditionalWidth;
float height = point.y + terrainCarve.Evaluate(-evaluate) + terrainCarve.Evaluate(-evaluate) * noise;
float smoothValue = t / (float)detailTerrain;
smoothValue = Mathf.Pow(smoothValue, terrainSmoothMultiplier);
height = Mathf.Lerp(hit.point.y, height, smoothValue);
Vector4 newPos = new Vector4(hit.point.x, height, hit.point.z, -evaluate);
positionArrayRow.Add(newPos);
}
else
positionArrayRow.Add(point);
}
}
for (int t = 0; t <= detailTerrain; t++)
{
point = Vector3.Lerp(rayPointDown, rayPointUp, t / (float)detailTerrain) + transform.position;
if (Physics.Raycast(point + Vector3.up * 500, Vector3.down, out hit, 10000, maskCarve.value))
{
if (noiseCarve)
noise = Mathf.PerlinNoise(point.x * noiseSizeX, point.z * noiseSizeZ) * noiseMultiplierInside - noiseMultiplierInside * 0.5f;
else
noise = 0;
float evaluate = diffMagintude * (0.5f - Mathf.Abs(0.5f - t / (float)detailTerrain));
float height = point.y + terrainCarve.Evaluate(evaluate) + terrainCarve.Evaluate(evaluate) * noise;
float smoothValue = 1 - 2 * Mathf.Abs(t / (float)detailTerrain - 0.5f);
smoothValue = Mathf.Pow(smoothValue, terrainSmoothMultiplier);
height = Mathf.Lerp(hit.point.y, height, 1);
Vector4 newPos = new Vector4(hit.point.x, height, hit.point.z, evaluate);
positionArrayRow.Add(newPos);
}
else
positionArrayRow.Add(point);
}
if (terrainAdditionalWidth > 0)
{
for (int t = 1; t <= detailTerrain; t++)
{
point = Vector3.Lerp(rayPointUp, rayPointUpNew, t / (float)detailTerrain) + transform.position;
if (Physics.Raycast(point + Vector3.up * 50, Vector3.down, out hit, 10000, maskCarve.value))
{
if (noiseCarve)
noise = Mathf.PerlinNoise(point.x * noiseSizeX, point.z * noiseSizeZ) * noiseMultiplierOutside - noiseMultiplierOutside * 0.5f;
else
noise = 0;
float evaluate = t / (float)detailTerrain;
evaluate *= terrainAdditionalWidth;
float height = point.y + terrainCarve.Evaluate(-evaluate) + terrainCarve.Evaluate(-evaluate) * noise;
float smoothValue = 1 - t / (float)detailTerrain;
smoothValue = Mathf.Pow(smoothValue, terrainSmoothMultiplier);
height = Mathf.Lerp(hit.point.y, height, smoothValue);
Vector4 newPos = new Vector4(hit.point.x, height, hit.point.z, -evaluate);
positionArrayRow.Add(newPos);
}
else
positionArrayRow.Add(point);
}
}
positionArray.Add(positionArrayRow);
}
}
Mesh meshTerrain = new Mesh();
meshTerrain.indexFormat = IndexFormat.UInt32;
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
List<Vector2> uv = new List<Vector2>();
foreach (var positionRow in positionArray)
{
foreach (var vert in positionRow)
{
vertices.Add(vert);
}
}
for (int i = 0; i < positionArray.Count - 1; i++)
{
int count = positionArray[i].Count;
for (int j = 0; j < count - 1; j++)
{
triangles.Add(j + i * count);
triangles.Add(j + (i + 1) * count);
triangles.Add((j + 1) + i * count);
triangles.Add((j + 1) + i * count);
triangles.Add(j + (i + 1) * count);
triangles.Add((j + 1) + (i + 1) * count);
}
}
foreach (var positionRow in positionArray)
{
foreach (var vert in positionRow)
{
uv.Add(new Vector2(vert.w, 0));
}
}
meshTerrain.SetVertices(vertices);
meshTerrain.SetTriangles(triangles, 0);
meshTerrain.SetUVs(0, uv);
meshTerrain.RecalculateNormals();
meshTerrain.RecalculateTangents();
meshTerrain.RecalculateBounds();
//if (meshGO == null)
//{
meshGO = new GameObject("TerrainMesh");
meshGO.transform.parent = transform;
meshGO.hideFlags = HideFlags.HideAndDontSave;
meshGO.AddComponent<MeshFilter>();
meshGO.transform.parent = transform;
MeshRenderer meshRenderer = meshGO.AddComponent<MeshRenderer>();
meshRenderer.sharedMaterial = new Material(Shader.Find("Debug Terrain Carve"));
meshRenderer.sharedMaterial.color = new Color(0, 0.5f, 0);
// }
meshGO.transform.position = Vector3.zero;
meshGO.GetComponent<MeshFilter>().sharedMesh = meshTerrain;
if (overrideRiverRender)
meshGO.GetComponent<MeshRenderer>().sharedMaterial.renderQueue = 5000;
else
meshGO.GetComponent<MeshRenderer>().sharedMaterial.renderQueue = 2980;
}
public void TerrainCarve()
{
bool debugLines = false;
bool savedAutoSyncTransforms = Physics.autoSyncTransforms;
Physics.autoSyncTransforms = false;
foreach (Terrain terrain in Terrain.activeTerrains)
{
TerrainData terrainData = terrain.terrainData;
float posY = terrain.transform.position.y;
float sizeX = terrain.terrainData.size.x;
float sizeY = terrain.terrainData.size.y;
float sizeZ = terrain.terrainData.size.z;
float terrainTowidth = (1 / (float)sizeZ * (terrainData.heightmapResolution - 1));
float terrainToheight = (1 / (float)sizeX * (terrainData.heightmapResolution - 1));
float minX;
float maxX;
float minZ;
float maxZ;
#if UNITY_EDITOR
Undo.RegisterCompleteObjectUndo(terrainData, "River curve");
#endif
MeshCollider meshCollider = meshGO.gameObject.AddComponent<MeshCollider>();
List<Vector3> transformPointUp = new List<Vector3>();
List<Vector3> transformPointDown = new List<Vector3>();
int pointsCount = 5;
int pointsStart = 0;//pointsUp.Count
//List<Vector2> done = new List<Vector2>();
//List<Vector3> positionArray = new List<Vector3>();
Vector3 pointOne = Vector3.zero;
Vector3 pointTwo = Vector3.zero;
for (pointsStart = 0; pointsStart < pointsUp.Count; pointsStart = Mathf.Clamp(pointsStart + pointsCount - 1, 0, pointsUp.Count))
{
int end = Mathf.Min(pointsStart + pointsCount, pointsUp.Count);
//int currentCount = Mathf.Min(pointsCount, pointsUp.Count - pointsStart);
transformPointUp.Clear();
transformPointDown.Clear();
for (int i = pointsStart; i < end; i++)
{
transformPointUp.Add(transform.TransformPoint(pointsUp[i]));
transformPointDown.Add(transform.TransformPoint(pointsDown[i]));
}
minX = float.MaxValue;
maxX = float.MinValue;
minZ = float.MaxValue;
maxZ = float.MinValue;
for (int i = 0; i < transformPointUp.Count; i++)
{
Vector3 point = transformPointUp[i];
if (minX > point.x)
minX = point.x;
if (maxX < point.x)
maxX = point.x;
if (minZ > point.z)
minZ = point.z;
if (maxZ < point.z)
maxZ = point.z;
}
for (int i = 0; i < transformPointDown.Count; i++)
{
Vector3 point = transformPointDown[i];
if (minX > point.x)
minX = point.x;
if (maxX < point.x)
maxX = point.x;
if (minZ > point.z)
minZ = point.z;
if (maxZ < point.z)
maxZ = point.z;
}
minX -= terrain.transform.position.x + distSmooth;
maxX -= terrain.transform.position.x - distSmooth;
minZ -= terrain.transform.position.z + distSmooth;
maxZ -= terrain.transform.position.z - distSmooth;
minX = minX * terrainToheight;
maxX = maxX * terrainToheight;
minZ = minZ * terrainTowidth;
maxZ = maxZ * terrainTowidth;
maxX = Mathf.Ceil(Mathf.Clamp(maxX + 1, 0, (terrainData.heightmapResolution)));
minZ = Mathf.Floor(Mathf.Clamp(minZ, 0, (terrainData.heightmapResolution)));
maxZ = Mathf.Ceil(Mathf.Clamp(maxZ + 1, 0, (terrainData.heightmapResolution)));
minX = Mathf.Floor(Mathf.Clamp(minX, 0, (terrainData.heightmapResolution)));
float[,] heightmapData = terrainData.GetHeights((int)minX, (int)minZ, (int)(maxX - minX), (int)(maxZ - minZ));
Vector3 position = Vector3.zero;
Vector3 pointMin = Vector3.zero;
for (int x = 0; x < heightmapData.GetLength(0); x++)
{
for (int z = 0; z < heightmapData.GetLength(1); z++)
{
position.x = (z + minX) / (float)terrainToheight + terrain.transform.position.x;
position.z = (x + minZ) / (float)terrainTowidth + terrain.transform.position.z;
Ray ray = new Ray(position + Vector3.up * 3000, Vector3.down);
RaycastHit hit;
if (meshCollider.Raycast(ray, out hit, 10000))
{
float height = hit.point.y - posY;
heightmapData[x, z] = height / (float)sizeY;
if (debugLines)
{
Debug.DrawLine(hit.point, hit.point + Vector3.up * 0.5f, Color.magenta, 10);
}
}
}
}
terrainData.SetHeights((int)minX, (int)minZ, heightmapData);
}
DestroyImmediate(meshCollider);
terrain.Flush();
}
Physics.autoSyncTransforms = savedAutoSyncTransforms;
if (meshGO != null)
DestroyImmediate(meshGO);
}
public void TerrainPaintMeshBased()
{
bool savedAutoSyncTransforms = Physics.autoSyncTransforms;
Physics.autoSyncTransforms = false;
foreach (Terrain terrain in Terrain.activeTerrains)
{
TerrainData terrainData = terrain.terrainData;
float sizeX = terrain.terrainData.size.x;
float sizeY = terrain.terrainData.size.y;
float sizeZ = terrain.terrainData.size.z;
float terrainTowidth = (1 / (float)sizeZ * (terrainData.alphamapWidth - 1));
float terrainToheight = (1 / (float)sizeX * (terrainData.alphamapHeight - 1));
#if UNITY_EDITOR
Undo.RegisterCompleteObjectUndo(terrainData, "Paint river");
Undo.RegisterCompleteObjectUndo(terrain, "Terrain draw texture");
Undo.RegisterCompleteObjectUndo(terrainData.alphamapTextures, "alpha");
#endif
float minX;
float maxX;
float minZ;
float maxZ;
MeshCollider meshCollider = meshGO.gameObject.AddComponent<MeshCollider>();
List<Vector3> transformPointUp = new List<Vector3>();
List<Vector3> transformPointDown = new List<Vector3>();
int pointsCount = 5;
int pointsStart = 0;//pointsUp.Count
//List<Vector2> done = new List<Vector2>();
//List<Vector3> positionArray = new List<Vector3>();
Vector3 pointOne = Vector3.zero;
Vector3 pointTwo = Vector3.zero;
for (pointsStart = 0; pointsStart < pointsUp.Count; pointsStart = Mathf.Clamp(pointsStart + pointsCount - 1, 0, pointsUp.Count))
{
int end = Mathf.Min(pointsStart + pointsCount, pointsUp.Count);
//int currentCount = Mathf.Min(pointsCount, pointsUp.Count - pointsStart);
transformPointUp.Clear();
transformPointDown.Clear();
for (int i = pointsStart; i < end; i++)
{
transformPointUp.Add(transform.TransformPoint(pointsUp[i]));
transformPointDown.Add(transform.TransformPoint(pointsDown[i]));
}
minX = float.MaxValue;
maxX = float.MinValue;
minZ = float.MaxValue;
maxZ = float.MinValue;
for (int i = 0; i < transformPointUp.Count; i++)
{
Vector3 point = transformPointUp[i];
if (minX > point.x)
minX = point.x;
if (maxX < point.x)
maxX = point.x;
if (minZ > point.z)
minZ = point.z;
if (maxZ < point.z)
maxZ = point.z;
}
for (int i = 0; i < transformPointDown.Count; i++)
{
Vector3 point = transformPointDown[i];
if (minX > point.x)
minX = point.x;
if (maxX < point.x)
maxX = point.x;
if (minZ > point.z)
minZ = point.z;
if (maxZ < point.z)
maxZ = point.z;
}
minX -= terrain.transform.position.x + distSmooth;
maxX -= terrain.transform.position.x - distSmooth;
minZ -= terrain.transform.position.z + distSmooth;
maxZ -= terrain.transform.position.z - distSmooth;
minX = minX * terrainToheight;
maxX = maxX * terrainToheight;
minZ = minZ * terrainTowidth;
maxZ = maxZ * terrainTowidth;
minX = Mathf.Floor(Mathf.Clamp(minX, 0, (terrainData.alphamapWidth)));
maxX = Mathf.Ceil(Mathf.Clamp(maxX + 1, 0, (terrainData.alphamapWidth)));
minZ = Mathf.Floor(Mathf.Clamp(minZ, 0, (terrainData.alphamapHeight)));
maxZ = Mathf.Ceil(Mathf.Clamp(maxZ + 1, 0, (terrainData.alphamapHeight)));
float[,,] alphamapData = terrainData.GetAlphamaps((int)minX, (int)minZ, (int)(maxX - minX), (int)(maxZ - minZ));
Vector3 position = Vector3.zero;
Vector3 pointMin = Vector3.zero;
float noise = 0;
for (int x = 0; x < alphamapData.GetLength(0); x++)
{
for (int z = 0; z < alphamapData.GetLength(1); z++)
{
position.x = (z + minX) / (float)terrainToheight + terrain.transform.position.x;
position.z = (x + minZ) / (float)terrainTowidth + terrain.transform.position.z;
Ray ray = new Ray(position + Vector3.up * 3000, Vector3.down);
RaycastHit hit;
if (meshCollider.Raycast(ray, out hit, 10000))
{
float minDist = hit.textureCoord.x;
if (!mixTwoSplatMaps)
{
if (noisePaint)
{
if (minDist >= 0)
noise = Mathf.PerlinNoise(hit.point.x * noiseSizeXPaint, hit.point.z * noiseSizeZPaint) * noiseMultiplierInsidePaint - noiseMultiplierInsidePaint * 0.5f;
else
noise = Mathf.PerlinNoise(hit.point.x * noiseSizeXPaint, hit.point.z * noiseSizeZPaint) * noiseMultiplierOutsidePaint - noiseMultiplierOutsidePaint * 0.5f;
}
else
noise = 0;
// Debug.Log(x + " " + z + " " + currentSplatMap);
float oldValue = alphamapData[x, z, currentSplatMap];
alphamapData[x, z, currentSplatMap] = Mathf.Clamp01(Mathf.Lerp(alphamapData[x, z, currentSplatMap], 1, terrainPaintCarve.Evaluate(minDist) + terrainPaintCarve.Evaluate(minDist) * noise));
for (int l = 0; l < terrainData.terrainLayers.Length; l++)
{
if (l != currentSplatMap)
{
alphamapData[x, z, l] = oldValue == 1 ? 0 : Mathf.Clamp01(alphamapData[x, z, l] * ((1 - alphamapData[x, z, currentSplatMap]) / (1 - oldValue)));
}
}
}
else
{
if (minDist >= 0)
noise = Mathf.PerlinNoise(hit.point.x * noiseSizeXPaint, hit.point.z * noiseSizeZPaint) * noiseMultiplierInsidePaint - noiseMultiplierInsidePaint * 0.5f;
else
noise = Mathf.PerlinNoise(hit.point.x * noiseSizeXPaint, hit.point.z * noiseSizeZPaint) * noiseMultiplierOutsidePaint - noiseMultiplierOutsidePaint * 0.5f;
float oldValue = alphamapData[x, z, currentSplatMap];
alphamapData[x, z, currentSplatMap] = Mathf.Clamp01(Mathf.Lerp(alphamapData[x, z, currentSplatMap], 1, terrainPaintCarve.Evaluate(minDist)));
for (int l = 0; l < terrainData.terrainLayers.Length; l++)
{
if (l != currentSplatMap)
{
alphamapData[x, z, l] = oldValue == 1 ? 0 : Mathf.Clamp01(alphamapData[x, z, l] * ((1 - alphamapData[x, z, currentSplatMap]) / (1 - oldValue)));
}
}
if (noise > 0)
{
oldValue = alphamapData[x, z, secondSplatMap];
alphamapData[x, z, secondSplatMap] = Mathf.Clamp01(Mathf.Lerp(alphamapData[x, z, secondSplatMap], 1, noise));
for (int l = 0; l < terrainData.terrainLayers.Length; l++)
{
if (l != secondSplatMap)
{
alphamapData[x, z, l] = oldValue == 1 ? 0 : Mathf.Clamp01(alphamapData[x, z, l] * ((1 - alphamapData[x, z, secondSplatMap]) / (1 - oldValue)));
}
}
}
}
if (addCliffSplatMap)
{
if (minDist >= 0)
{
float angle = Vector3.Angle(hit.normal, Vector3.up);
if (angle > cliffAngle)
{
float oldValue = alphamapData[x, z, cliffSplatMap];
alphamapData[x, z, cliffSplatMap] = cliffBlend;
for (int l = 0; l < terrainData.terrainLayers.Length; l++)
{
if (l != cliffSplatMap)
{
alphamapData[x, z, l] = oldValue == 1 ? 0 : Mathf.Clamp01(alphamapData[x, z, l] * ((1 - alphamapData[x, z, cliffSplatMap]) / (1 - oldValue)));
}
}
}
}
else
{
float angle = Vector3.Angle(hit.normal, Vector3.up);
if (angle > cliffAngleOutside)
{
float oldValue = alphamapData[x, z, cliffSplatMapOutside];
alphamapData[x, z, cliffSplatMapOutside] = cliffBlendOutside;
for (int l = 0; l < terrainData.terrainLayers.Length; l++)
{
if (l != cliffSplatMapOutside)
{
alphamapData[x, z, l] = oldValue == 1 ? 0 : Mathf.Clamp01(alphamapData[x, z, l] * ((1 - alphamapData[x, z, cliffSplatMapOutside]) / (1 - oldValue)));
}
}
}
}
}
}
}
}
terrainData.SetAlphamaps((int)minX, (int)minZ, alphamapData);
}
DestroyImmediate(meshCollider);
terrain.Flush();
}
Physics.autoSyncTransforms = savedAutoSyncTransforms;
if (meshGO != null)
DestroyImmediate(meshGO);
}
public void TerrainClearFoliage(bool details = true)
{
//Debug.Log("TerrainClearFoliage");
bool savedAutoSyncTransforms = Physics.autoSyncTransforms;
Physics.autoSyncTransforms = false;
foreach (Terrain terrain in Terrain.activeTerrains)
{
//Debug.Log("tarrain: " + terrain.name);
TerrainData terrainData = terrain.terrainData;
Transform transformTerrain = terrain.transform;
float posY = terrain.transform.position.y;
float sizeX = terrain.terrainData.size.x;
float sizeY = terrain.terrainData.size.y;
float sizeZ = terrain.terrainData.size.z;
float terrainTowidth = (1 / (float)sizeZ * (terrainData.detailWidth));
float terrainToheight = (1 / (float)sizeX * (terrainData.detailHeight));
#if UNITY_EDITOR
Undo.RegisterCompleteObjectUndo(terrainData, "Paint river");
Undo.RegisterCompleteObjectUndo(terrain, "Terrain draw texture");
#endif
float minX;
float maxX;
float minZ;
float maxZ;
MeshCollider meshCollider = meshGO.gameObject.AddComponent<MeshCollider>();
List<Vector3> transformPointUp = new List<Vector3>();
List<Vector3> transformPointDown = new List<Vector3>();
int pointsCount = 5;
int pointsStart = 0;//pointsUp.Count
//List<Vector2> done = new List<Vector2>();
//List<Vector3> positionArray = new List<Vector3>();
Vector3 pointOne = Vector3.zero;
Vector3 pointTwo = Vector3.zero;
Vector3 position = Vector3.zero;
if (details)
{
//Debug.Log("details");
for (pointsStart = 0; pointsStart < pointsUp.Count; pointsStart = Mathf.Clamp(pointsStart + pointsCount - 1, 0, pointsUp.Count))
{
int end = Mathf.Min(pointsStart + pointsCount, pointsUp.Count);
int currentCount = Mathf.Min(pointsCount, pointsUp.Count - pointsStart);
//Debug.Log("Current count " + currentCount + " " + pointsStart);
transformPointUp.Clear();
transformPointDown.Clear();
for (int i = pointsStart; i < end; i++)
{
transformPointUp.Add(transform.TransformPoint(pointsUp[i]));
transformPointDown.Add(transform.TransformPoint(pointsDown[i]));
}
minX = float.MaxValue;
maxX = float.MinValue;
minZ = float.MaxValue;
maxZ = float.MinValue;
for (int i = 0; i < transformPointUp.Count; i++)
{
Vector3 point = transformPointUp[i];
//Debug.DrawLine(transformPointUp[i], transformPointUp[i] + Vector3.up * 10, Color.black, 5);
if (minX > point.x)
minX = point.x;
if (maxX < point.x)
maxX = point.x;
if (minZ > point.z)
minZ = point.z;
if (maxZ < point.z)
maxZ = point.z;
}
for (int i = 0; i < transformPointDown.Count; i++)
{
Vector3 point = transformPointDown[i];
// Debug.DrawLine(transformPointDown[i], transformPointDown[i] + Vector3.up * 10, Color.blue, 5);
if (minX > point.x)
minX = point.x;
if (maxX < point.x)
maxX = point.x;
if (minZ > point.z)
minZ = point.z;
if (maxZ < point.z)
maxZ = point.z;
}
//Debug.DrawLine(new Vector3(minX, 0, minZ), new Vector3(minX, 0, minZ) + Vector3.up * 100, Color.magenta, 10);
//Debug.DrawLine(new Vector3(minX, 0, maxZ), new Vector3(minX, 0, maxZ) + Vector3.up * 100, Color.magenta, 10);
//Debug.DrawLine(new Vector3(maxX, 0, minZ), new Vector3(maxX, 0, minZ) + Vector3.up * 100, Color.cyan, 10);
//Debug.DrawLine(new Vector3(maxX, 0, maxZ), new Vector3(maxX, 0, maxZ) + Vector3.up * 100, Color.cyan, 10);
minX -= transformTerrain.position.x + distanceClearFoliage;
maxX -= transformTerrain.position.x - distanceClearFoliage;
minZ -= transformTerrain.position.z + distanceClearFoliage;
maxZ -= transformTerrain.position.z - distanceClearFoliage;
minX = minX * terrainToheight;
maxX = maxX * terrainToheight;
minZ = minZ * terrainTowidth;
maxZ = maxZ * terrainTowidth;
minX = Mathf.Floor(Mathf.Clamp(minX, 0, (terrainData.detailWidth)));
maxX = Mathf.Ceil(Mathf.Clamp(maxX + 1, 0, (terrainData.detailWidth)));
minZ = Mathf.Floor(Mathf.Clamp(minZ, 0, (terrainData.detailHeight)));
maxZ = Mathf.Ceil(Mathf.Clamp(maxZ + 1, 0, (terrainData.detailHeight)));
int[,] detailLayer;
if (maxX - minX > 0 && maxZ - minZ > 0)
{
//Debug.Log("DetailLayers");
for (int l = 0; l < terrainData.detailPrototypes.Length; l++)
{
detailLayer = terrainData.GetDetailLayer((int)minX, (int)minZ, (int)(maxX - minX), (int)(maxZ - minZ), l);
//Debug.Log("DetailLayer " + l);
for (int x = 0; x < detailLayer.GetLength(0); x++)
{
for (int z = 0; z < detailLayer.GetLength(1); z++)
{
position.x = (z + minX) / (float)terrainToheight + terrain.transform.position.x;
position.z = (x + minZ) / (float)terrainTowidth + terrain.transform.position.z;
Ray ray = new Ray(position + Vector3.up * 3000, Vector3.down);
// Debug.DrawRay(position + Vector3.up * 10, ray.direction * 20, Color.red, 3);
RaycastHit hit;
if (meshCollider.Raycast(ray, out hit, 10000))
{
detailLayer[x, z] = 0;
}
}
}
terrainData.SetDetailLayer((int)minX, (int)minZ, l, detailLayer);
}
}
}
}
else
{
List<TreeInstance> newTrees = new List<TreeInstance>();
TreeInstance[] oldTrees = terrainData.treeInstances;
foreach (var tree in oldTrees)
{
//Debug.DrawRay(new Vector3(, 0, tree.position.z * sizeZ) + terrain.transform.position, Vector3.up * 5, Color.red, 3);
position.x = tree.position.x * sizeX + transformTerrain.position.x;//, polygonHeight
position.z = tree.position.z * sizeZ + transformTerrain.position.z;
Ray ray = new Ray(position + Vector3.up * 3000, Vector3.down);
RaycastHit hit;
if (!meshCollider.Raycast(ray, out hit, 10000))
{
newTrees.Add(tree);
}
}
terrainData.treeInstances = newTrees.ToArray();
}
DestroyImmediate(meshCollider);
terrain.Flush();
}
Physics.autoSyncTransforms = savedAutoSyncTransforms;
if (meshGO != null)
DestroyImmediate(meshGO);
}
#endregion
float FlowCalculate(float u, float normalY, Vector3 vertice)
{
float noise = (noiseflowMap ? Mathf.PerlinNoise(vertice.x * noiseSizeXflowMap, vertice.z * noiseSizeZflowMap) * noiseMultiplierflowMap - noiseMultiplierflowMap * 0.5f : 0) * Mathf.Pow(Mathf.Clamp(normalY, 0, 1), 5);
return Mathf.Lerp(flowWaterfall.Evaluate(u), flowFlat.Evaluate(u) + noise, Mathf.Clamp(normalY, 0, 1));
}
}