Firstborn/Assets/AwesomeTechnologies/VegetationStudioPro/Runtime/GrassSystem/GrassPatch/ProceduralGrassPlane.cs

337 lines
11 KiB
C#
Raw Permalink Normal View History

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace AwesomeTechnologies.Grass
{
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
[System.Serializable]
public class ProceduralGrassPlane : MonoBehaviour
{
public enum AnchorPoint
{
TopLeft,
TopHalf,
TopRight,
RightHalf,
BottomRight,
BottomHalf,
BottomLeft,
LeftHalf,
Center
}
public int widthSegments = 5;
public int heightSegments = 4;
public float width = 1.0f;
public float height = 0.5f;
public AnchorPoint anchor = AnchorPoint.Center;
private UnityEngine.Vector2 anchorOffset;
public int Index = 0;
//private string anchorId;
public float Offset1 = 0.3f;
public float Offset2 = 0.15f;
public float MinimumBendHeight = 0.25f;
public float CurveOffset = 0.25f;
public int LODLevel = 0;
public Material Material;
public bool BakePhase;
public bool BakeBend;
public bool BakeAO;
public float Phase;
public AnimationCurve BendCurve;
public AnimationCurve AmbientOcclusionCurve;
public bool GenerateBackside = true;
void Start()
{
}
void SetAncorPoints()
{
switch (anchor)
{
case AnchorPoint.TopLeft:
anchorOffset = new UnityEngine.Vector2(-width / 2.0f, height / 2.0f);
//anchorId = "TL";
break;
case AnchorPoint.TopHalf:
anchorOffset = new UnityEngine.Vector2(0.0f, height / 2.0f);
//anchorId = "TH";
break;
case AnchorPoint.TopRight:
anchorOffset = new UnityEngine.Vector2(width / 2.0f, height / 2.0f);
//anchorId = "TR";
break;
case AnchorPoint.RightHalf:
anchorOffset = new UnityEngine.Vector2(width / 2.0f, 0.0f);
//anchorId = "RH";
break;
case AnchorPoint.BottomRight:
anchorOffset = new UnityEngine.Vector2(width / 2.0f, -height / 2.0f);
//anchorId = "BR";
break;
case AnchorPoint.BottomHalf:
anchorOffset = new UnityEngine.Vector2(0.0f, -height / 2.0f);
//anchorId = "BH";
break;
case AnchorPoint.BottomLeft:
anchorOffset = new UnityEngine.Vector2(-width / 2.0f, -height / 2.0f);
//anchorId = "BL";
break;
case AnchorPoint.LeftHalf:
anchorOffset = new UnityEngine.Vector2(-width / 2.0f, 0.0f);
//anchorId = "LH";
break;
case AnchorPoint.Center:
default:
anchorOffset = UnityEngine.Vector2.zero;
//anchorId = "C";
break;
}
}
void ApplyPhaseAndBend(Mesh mesh, int currentLOD)
{
Color[] meshColors;
Vector3[] vertex = mesh.vertices;
if (mesh.colors.Length == 0)
{
meshColors = new Color[mesh.vertexCount];
}
else
{
meshColors = mesh.colors;
}
byte phaseByte = 255;
byte bendByte = 255;
byte ambientByte = 255;
if (BakePhase)
{
phaseByte = (byte)(Phase * 255);
}
for (int i = 0; i <= meshColors.Length -1; i++)
{
float vertexHeight = (vertex[i].y + height / 2f) / height;
vertexHeight = Mathf.Clamp(vertexHeight, 0, 1);
if (BakeBend)
{
float bendCurveOutput = BendCurve.Evaluate(vertexHeight);
bendCurveOutput = Mathf.Clamp(bendCurveOutput,0f,1f);
bendByte = (byte)(bendCurveOutput * 255);
}
if (BakeAO)
{
float ambientOcculsionCurveOutput = AmbientOcclusionCurve.Evaluate(vertexHeight);
ambientOcculsionCurveOutput = Mathf.Clamp(ambientOcculsionCurveOutput, 0f, 1f);
ambientByte = (byte)(ambientOcculsionCurveOutput * 255);
}
meshColors[i] = new Color32(ambientByte, phaseByte, bendByte, bendByte);
}
mesh.colors = meshColors;
// float fadeOutPlane = 0;
//
// switch (currentLOD)
// {
// case 0:
// if (Index % 2 != 1)
// {
// fadeOutPlane = 1;
// }
// break;
// case 1:
// if (Index % 4 != 1)
// {
// fadeOutPlane = 1;
// }
// break;
// }
// Vector2[] uv2s;
// if (mesh.uv2.Length == 0)
// {
// uv2s = new Vector2[mesh.vertexCount];
// }
// else
// {
// uv2s = mesh.uv2;
// }
//
// for (int i = 0; i <= uv2s.Length - 1; i++)
// {
// uv2s[i] = new Vector2(fadeOutPlane, currentLOD);
// }
//
// mesh.uv2 = uv2s;
}
public void CreateGrassPlane(int currentLOD)
{
SetAncorPoints();
// You can change that line to provide another MeshFilter
MeshFilter filter = gameObject.GetComponent<MeshFilter>();
if (filter == null)
{
filter = gameObject.AddComponent<MeshFilter>();
}
Mesh m = filter.sharedMesh;
if (m == null) m = new Mesh();
m.Clear();
int hCount2 = widthSegments + 1;
int vCount2 = heightSegments + 1;
int numTriangles = widthSegments * heightSegments * 6;
int numVertices = hCount2 * vCount2;
Vector3[] vertices = new Vector3[numVertices];
UnityEngine.Vector2[] uvs = new UnityEngine.Vector2[numVertices];
int[] triangles = new int[numTriangles];
Vector4[] tangents = new Vector4[numVertices];
Vector4 tangent = new Vector4(1f, 0f, 0f, -1f);
int index = 0;
float uvFactorX = 1.0f / widthSegments;
float uvFactorY = 1.0f / heightSegments;
float scaleX = width / widthSegments;
float scaleY = height / heightSegments;
for (float y = 0.0f; y < vCount2; y++)
{
for (float x = 0.0f; x < hCount2; x++)
{
float NormalizedX = x * uvFactorX;
float CurrentOffset = Mathf.Lerp(Offset1, Offset2, x * uvFactorX);
float ZOffset = Mathf.Lerp(0, CurrentOffset, y * uvFactorY);
if ((y * scaleY) <= MinimumBendHeight)
{
ZOffset = 0;
}
float zCurveoffset = 0;
if (NormalizedX <= 0.5f)
{
zCurveoffset = Mathf.Lerp(CurveOffset,0,NormalizedX *2);
}
else
{
zCurveoffset = Mathf.Lerp(0, CurveOffset, (NormalizedX*2) - 0.5f);
}
vertices[index] = new Vector3(x * scaleX - width / 2f - anchorOffset.x, y * scaleY - height / 2f - anchorOffset.y, ZOffset + zCurveoffset);
tangents[index] = tangent;
uvs[index++] = new UnityEngine.Vector2(x * uvFactorX, y * uvFactorY);
}
}
index = 0;
for (int y = 0; y < heightSegments; y++)
{
for (int x = 0; x < widthSegments; x++)
{
triangles[index] = (y * hCount2) + x;
triangles[index + 1] = ((y + 1) * hCount2) + x;
triangles[index + 2] = (y * hCount2) + x + 1;
triangles[index + 3] = ((y + 1) * hCount2) + x;
triangles[index + 4] = ((y + 1) * hCount2) + x + 1;
triangles[index + 5] = (y * hCount2) + x + 1;
index += 6;
}
}
m.vertices = vertices;
m.uv = uvs;
m.triangles = triangles;
m.tangents = tangents;
m.RecalculateNormals();
if (GenerateBackside)
{
BuildBackside(m);
m.RecalculateNormals();
}
filter.sharedMesh = m;
m.RecalculateBounds();
//if (material == null)
//{
// material = (Material)Resources.Load("GrassPlaneMaterial", typeof(Material));
//}
MeshRenderer meshRenderer = this.gameObject.GetComponent<MeshRenderer>();
if (meshRenderer)
{
meshRenderer.sharedMaterial = Material;
}
if (BakePhase || BakeBend) ApplyPhaseAndBend(m,currentLOD);
}
void BuildBackside(Mesh mesh)
{
var vertices = mesh.vertices;
var uv = mesh.uv;
var normals = mesh.normals;
var szV = vertices.Length;
var newVerts = new Vector3[szV * 2];
var newUv = new UnityEngine.Vector2[szV * 2];
var newNorms = new Vector3[szV * 2];
for (var j = 0; j < szV; j++)
{
// duplicate vertices and uvs:
newVerts[j] = newVerts[j + szV] = vertices[j];
newUv[j] = newUv[j + szV] = uv[j];
// copy the original normals...
newNorms[j] = normals[j];
// and revert the new ones
newNorms[j + szV] = -normals[j];
}
var triangles = mesh.triangles;
var szT = triangles.Length;
var newTris = new int[szT * 2]; // double the triangles
for (var i = 0; i < szT; i += 3)
{
// copy the original triangle
newTris[i] = triangles[i];
newTris[i + 1] = triangles[i + 1];
newTris[i + 2] = triangles[i + 2];
// save the new reversed triangle
var j = i + szT;
newTris[j] = triangles[i] + szV;
newTris[j + 2] = triangles[i + 1] + szV;
newTris[j + 1] = triangles[i + 2] + szV;
}
mesh.vertices = newVerts;
mesh.uv = newUv;
mesh.normals = newNorms;
mesh.triangles = newTris; // assign triangles last!
}
}
}