959e80cf72
assets upload description.
337 lines
11 KiB
C#
337 lines
11 KiB
C#
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!
|
|
}
|
|
}
|
|
}
|