grass-rendering-prototype/Assets/Scripts/GrassField.cs
2024-09-26 22:41:42 +02:00

94 lines
3.4 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;
public class GrassField : MonoBehaviour {
public int size = 100;
public int numChunks = 5;
public GrassChunk chunkPrefab;
private struct BladeData {
public Vector3 rootPosition;
public Vector3 tipPosition;
}
public void GenerateGrassField() {
Debug.Log("Generating grass field... ");
var blades = GenerateBlades();
CreateChunks(blades);
Debug.Log("Generating grass field done");
}
private BladeData[] GenerateBlades() {
var blades = new BladeData[size * size];
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++) {
var i = x + y * size;
blades[i].rootPosition = new Vector3(x + 0.5f, 0.0f, y + 0.5f);
blades[i].tipPosition = blades[i].rootPosition + new Vector3(0.0f, 1.0f, 0.0f);
}
return blades;
}
private void CreateChunks(BladeData[] blades) {
GameObject chunks;
// If a child called "Chunks" exists, destroy it -> children are also destroyed
var chunksTransform = gameObject.transform.Find("Chunks");
if (chunksTransform != null) {
// Destroy(obj) does not work in edit mode
DestroyImmediate(chunksTransform.gameObject);
}
// create GameObject "Chunks" as a container for all GrassChunk objects
chunks = new GameObject("Chunks");
chunks.transform.SetParent(this.transform, false);
var chunkSize = ((float)size) / numChunks;
for (int x = 0; x < numChunks; x++)
for (int y = 0; y < numChunks; y++) {
var chunkPos = new Vector3(x, 0.0f, y) * chunkSize;
// bounds in local space of grass field
var bounds = new Bounds(
new Vector3(0.5f * chunkSize, 0.5f, 0.5f * chunkSize),
new Vector3(chunkSize, 1.01f, chunkSize)
);
List<Vector3> rootPositions = new();
List<Vector3> tipPositions = new();
List<int> indices = new();
foreach (var blade in blades) {
var localRootPos = blade.rootPosition - chunkPos;
if (bounds.Contains(localRootPos)) {
rootPositions.Add(localRootPos);
var localTipPos = blade.tipPosition - chunkPos;
tipPositions.Add(localTipPos);
indices.Add(rootPositions.Count - 1);
}
}
var mesh = new Mesh();
// 16 bit (default) supports 65536 vertices, 32 bit supports 4 billion
// mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
mesh.name = "grass_chunk[" + x + "," + y + "]";
mesh.SetVertices(rootPositions);
// do not calculate bounding box - will be set manually
mesh.SetIndices(indices, MeshTopology.Points, 0, false);
// Vector3 UVs are possible
mesh.SetUVs(0, tipPositions);
var chunk = Instantiate(chunkPrefab, chunks.transform);
chunk.name = "Chunk [" + x + ", " + y +"]";
chunk.transform.localPosition = chunkPos;
var meshFilter = chunk.GetComponent<MeshFilter>();
meshFilter.sharedMesh = mesh;
var meshRenderer = chunk.GetComponent<MeshRenderer>();
meshRenderer.localBounds = bounds;
}
}
}