grass-rendering-prototype/Assets/Scripts/GrassChunk.cs

154 lines
4.4 KiB
C#

using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Serialization;
[RequireComponent(typeof(MeshRenderer)), RequireComponent(typeof(MeshFilter))]
public class GrassChunk : MonoBehaviour {
[SerializeField] private Material materialLOD0;
public Material MaterialLOD0 {
get { return materialLOD0; }
set {
materialLOD0 = value;
UpdateLODAssets();
}
}
[SerializeField] private Mesh meshLOD0;
public Mesh MeshLOD0 {
get { return meshLOD0; }
set {
meshLOD0 = value;
UpdateLODAssets();
UpdateLOD(); // a new mesh may change the AABB which may affect the LOD
}
}
[SerializeField] private bool enableShadowsLOD0;
public bool EnableShadowsLOD0 {
get { return enableShadowsLOD0; }
set {
enableShadowsLOD0 = value;
UpdateLODAssets();
}
}
[SerializeField] private Material materialLOD1;
public Material MaterialLOD1 {
get { return materialLOD1; }
set {
materialLOD1 = value;
UpdateLODAssets();
}
}
[SerializeField] private Mesh meshLOD1;
public Mesh MeshLOD1 {
get { return meshLOD1; }
set {
meshLOD1 = value;
UpdateLODAssets();
UpdateLOD(); // a new mesh may change the AABB which may affect the LOD
}
}
[SerializeField] private bool enableShadowsLOD1;
public bool EnableShadowsLOD1 {
get { return enableShadowsLOD1; }
set {
enableShadowsLOD1 = value;
UpdateLODAssets();
}
}
[SerializeField] private Material materialLOD2;
public Material MaterialLOD2 {
get { return materialLOD2; }
set {
materialLOD2 = value;
UpdateLODAssets();
}
}
[SerializeField] private Mesh meshLOD2;
public Mesh MeshLOD2 {
get { return meshLOD2; }
set {
meshLOD2 = value;
UpdateLODAssets();
UpdateLOD(); // a new mesh may change the AABB which may affect the LOD
}
}
[SerializeField] private bool enableShadowsLOD2;
public bool EnableShadowsLOD2 {
get { return enableShadowsLOD2; }
set {
enableShadowsLOD2 = value;
UpdateLODAssets();
}
}
private int lod = -1; // set to -1 so LOD.set does not exit early when initially called with 0
public int LOD {
get { return lod; }
set {
if (lod == value) return;
lod = value;
UpdateLODAssets();
}
}
private void Update() {
UpdateLOD();
}
public void UpdateLOD() {
var meshRenderer = GetComponent<MeshRenderer>();
if (Camera.main) {
// using meshRenderer.bounds may cause a loop where LOD switches constantly
var sqrCamDist = meshRenderer.bounds.SqrDistance(Camera.main.transform.position);
if (sqrCamDist > 20f * 20f) {
LOD = 2;
}
else if (sqrCamDist > 5f * 5f) {
LOD = 1;
}
else {
LOD = 0;
}
}
}
private void UpdateLODAssets() {
var meshRenderer = GetComponent<MeshRenderer>();
var meshFilter = GetComponent<MeshFilter>();
switch (lod) {
case 0:
meshRenderer.sharedMaterial = materialLOD0;
meshRenderer.shadowCastingMode = EnableShadowsLOD0 ? ShadowCastingMode.On : ShadowCastingMode.Off;
meshFilter.sharedMesh = meshLOD0;
break;
case 1:
meshRenderer.sharedMaterial = materialLOD1;
meshRenderer.shadowCastingMode = EnableShadowsLOD1 ? ShadowCastingMode.On : ShadowCastingMode.Off;
meshFilter.sharedMesh = meshLOD1;
break;
case 2:
meshRenderer.sharedMaterial = materialLOD2;
meshRenderer.shadowCastingMode = EnableShadowsLOD2 ? ShadowCastingMode.On : ShadowCastingMode.Off;
meshFilter.sharedMesh = meshLOD2;
break;
}
}
private void OnDrawGizmos() {
Gizmos.color = new Color(1f, 0.7f, 0f, 0.5f);
var meshRenderer = GetComponent<MeshRenderer>();
var bounds = meshRenderer.bounds;
Gizmos.DrawWireCube(bounds.center, bounds.size);
}
}