Smooth LOD transition setup (only color) + Material variants + more stuff lol
This commit is contained in:
parent
794125696f
commit
f5de2988d0
31
Assets/Materials/Grass LOD 0.mat
Normal file
31
Assets/Materials/Grass LOD 0.mat
Normal file
@ -0,0 +1,31 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Grass LOD 0
|
||||
m_Shader: {fileID: 4800000, guid: eebe2969663fc40449d6052c661a6c2e, type: 3}
|
||||
m_Parent: {fileID: 2100000, guid: 1cd7df4d77cf1ae40ad59a15c2769be9, type: 2}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _LOD_LOD_0
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs: []
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _LOD: 0
|
||||
m_Colors: []
|
||||
m_BuildTextureStacks: []
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7693e3a8eaaa814480ba4085681ed02
|
||||
guid: d979d9bbf3760d948a452ba192cbf563
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
31
Assets/Materials/Grass LOD 1.mat
Normal file
31
Assets/Materials/Grass LOD 1.mat
Normal file
@ -0,0 +1,31 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Grass LOD 1
|
||||
m_Shader: {fileID: 4800000, guid: eebe2969663fc40449d6052c661a6c2e, type: 3}
|
||||
m_Parent: {fileID: 2100000, guid: 1cd7df4d77cf1ae40ad59a15c2769be9, type: 2}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _LOD_LOD_1
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs: []
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _LOD: 1
|
||||
m_Colors: []
|
||||
m_BuildTextureStacks: []
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 826d52a86cbdbd148ac471a227237ffe
|
||||
guid: 91fb1ec3cf2133a4b931798a8822d055
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
31
Assets/Materials/Grass LOD 2.mat
Normal file
31
Assets/Materials/Grass LOD 2.mat
Normal file
@ -0,0 +1,31 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Grass LOD 2
|
||||
m_Shader: {fileID: 4800000, guid: eebe2969663fc40449d6052c661a6c2e, type: 3}
|
||||
m_Parent: {fileID: 2100000, guid: 1cd7df4d77cf1ae40ad59a15c2769be9, type: 2}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _LOD_LOD_2
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs: []
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _LOD: 2
|
||||
m_Colors: []
|
||||
m_BuildTextureStacks: []
|
||||
8
Assets/Materials/Grass LOD 2.mat.meta
Normal file
8
Assets/Materials/Grass LOD 2.mat.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad7fd76c0f67ff04e8f51f21faf1739d
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
36
Assets/Materials/Grass.mat
Normal file
36
Assets/Materials/Grass.mat
Normal file
@ -0,0 +1,36 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Grass
|
||||
m_Shader: {fileID: 4800000, guid: eebe2969663fc40449d6052c661a6c2e, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _LOD_LOD_0
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs: []
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _BendStrength: 1
|
||||
- _BladeWidth: 0.03
|
||||
- _LOD: 0
|
||||
m_Colors:
|
||||
- _Color0: {r: 0.5882353, g: 1, b: 0.5882353, a: 1}
|
||||
- _Color1: {r: 1, g: 0.8209069, b: 0.495283, a: 1}
|
||||
- _Color2: {r: 1, g: 0.49831352, b: 0.21226418, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
@ -1,72 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: GrassLOD0
|
||||
m_Shader: {fileID: 4800000, guid: eebe2969663fc40449d6052c661a6c2e, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _LOD_LOD_0
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BladeWidthTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _FrabVarianz:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _HeightMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MaskMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _WindTextur:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AOStrength: 1
|
||||
- _BendStrength: 1
|
||||
- _BladeBow: 0.3
|
||||
- _BladeWidth: 0.0325
|
||||
- _ExtraSawnOnCutGras: 6
|
||||
- _FieldSize: 5
|
||||
- _LOD: 0
|
||||
- _Metallic: 0
|
||||
- _NumSegments_LOD_0: 11
|
||||
- _NumSegments_LOD_1: 5
|
||||
- _NumSegments_LOD_2: 1
|
||||
- _Roughness: 0.3
|
||||
- _SSSStrength: 1
|
||||
- _SegmentsMinusOne: 11
|
||||
- _Translucency: 1
|
||||
m_Colors:
|
||||
- _BoxSize: {r: 0, g: 0, b: 0, a: 0}
|
||||
- _BoxWorldCenter: {r: 0, g: 0, b: 0, a: 0}
|
||||
- _Braun: {r: 0.33999997, g: 0.85, b: 0.92, a: 1}
|
||||
- _Farbe: {r: 0.33999997, g: 0.85, b: 0.92, a: 1}
|
||||
- _InnerColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _SpecularColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _WindOffset: {r: 0, g: 0, b: 0, a: 0}
|
||||
m_BuildTextureStacks: []
|
||||
@ -1,72 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: GrassLOD1
|
||||
m_Shader: {fileID: 4800000, guid: eebe2969663fc40449d6052c661a6c2e, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _LOD_LOD_1
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BladeWidthTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _FrabVarianz:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _HeightMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MaskMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _WindTextur:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AOStrength: 1
|
||||
- _BendStrength: 1
|
||||
- _BladeBow: 0.3
|
||||
- _BladeWidth: 0.0276
|
||||
- _ExtraSawnOnCutGras: 6
|
||||
- _FieldSize: 5
|
||||
- _LOD: 1
|
||||
- _Metallic: 0
|
||||
- _NumSegments_LOD_0: 11
|
||||
- _NumSegments_LOD_1: 3
|
||||
- _NumSegments_LOD_2: 1
|
||||
- _Roughness: 0.3
|
||||
- _SSSStrength: 1
|
||||
- _SegmentsMinusOne: 11
|
||||
- _Translucency: 1
|
||||
m_Colors:
|
||||
- _BoxSize: {r: 0, g: 0, b: 0, a: 0}
|
||||
- _BoxWorldCenter: {r: 0, g: 0, b: 0, a: 0}
|
||||
- _Braun: {r: 0.33999997, g: 0.85, b: 0.92, a: 1}
|
||||
- _Farbe: {r: 0.33999997, g: 0.85, b: 0.92, a: 1}
|
||||
- _InnerColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _SpecularColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _WindOffset: {r: 0, g: 0, b: 0, a: 0}
|
||||
m_BuildTextureStacks: []
|
||||
@ -1,72 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: GrassLOD2
|
||||
m_Shader: {fileID: 4800000, guid: eebe2969663fc40449d6052c661a6c2e, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _LOD_LOD_2
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BladeWidthTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _FrabVarianz:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _HeightMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MaskMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _WindTextur:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AOStrength: 1
|
||||
- _BendStrength: 1
|
||||
- _BladeBow: 0.3
|
||||
- _BladeWidth: 0.047
|
||||
- _ExtraSawnOnCutGras: 6
|
||||
- _FieldSize: 5
|
||||
- _LOD: 2
|
||||
- _Metallic: 0
|
||||
- _NumSegments_LOD_0: 11
|
||||
- _NumSegments_LOD_1: 5
|
||||
- _NumSegments_LOD_2: 1
|
||||
- _Roughness: 0.3
|
||||
- _SSSStrength: 1
|
||||
- _SegmentsMinusOne: 11
|
||||
- _Translucency: 1
|
||||
m_Colors:
|
||||
- _BoxSize: {r: 0, g: 0, b: 0, a: 0}
|
||||
- _BoxWorldCenter: {r: 0, g: 0, b: 0, a: 0}
|
||||
- _Braun: {r: 0.33999997, g: 0.85, b: 0.92, a: 1}
|
||||
- _Farbe: {r: 0.33999997, g: 0.85, b: 0.92, a: 1}
|
||||
- _InnerColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _SpecularColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _WindOffset: {r: 0, g: 0, b: 0, a: 0}
|
||||
m_BuildTextureStacks: []
|
||||
File diff suppressed because one or more lines are too long
9
Assets/Scripts/Editor/Startup.cs
Normal file
9
Assets/Scripts/Editor/Startup.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
[InitializeOnLoad]
|
||||
public class Startup {
|
||||
static Startup() {
|
||||
Shader.EnableKeyword("UNITY_EDITOR");
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Editor/Startup.cs.meta
Normal file
11
Assets/Scripts/Editor/Startup.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6a6c758bb82b2040ad5ca8a7c20f0b1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
[RequireComponent(typeof(MeshRenderer)), RequireComponent(typeof(MeshFilter))]
|
||||
public class GrassChunk : MonoBehaviour {
|
||||
@ -139,8 +137,8 @@ public class GrassChunk : MonoBehaviour {
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDrawGizmos() {
|
||||
Gizmos.color = new Color(1f, 0.7f, 0f, 0.5f);
|
||||
private void OnDrawGizmosSelected() {
|
||||
Gizmos.color = new Color(1f, 0.7f, 0f, 0.2f);
|
||||
var meshRenderer = GetComponent<MeshRenderer>();
|
||||
var bounds = meshRenderer.bounds;
|
||||
Gizmos.DrawWireCube(bounds.center, bounds.size);
|
||||
|
||||
@ -4,7 +4,7 @@ using UnityEngine;
|
||||
|
||||
public class GrassField : MonoBehaviour {
|
||||
public int size = 100;
|
||||
public int numChunks = 5;
|
||||
public int numChunks = 10;
|
||||
public int bladesPerMeter = 100;
|
||||
public GrassChunk chunkPrefab;
|
||||
public bool ignoreHeightForLOD = true;
|
||||
@ -13,15 +13,19 @@ public class GrassField : MonoBehaviour {
|
||||
[Range(0f, 1f)] public float densityLOD0 = 1f;
|
||||
public bool enableShadowsLOD0 = true;
|
||||
[Header("LOD 1")]
|
||||
public float distanceLOD1 = 7.5f;
|
||||
public float distanceLOD1 = 5f;
|
||||
public Material grassMaterialLOD1;
|
||||
[Range(0f, 1f)] public float densityLOD1 = 0.5f;
|
||||
public bool enableShadowsLOD1 = true;
|
||||
[Header("LOD 2")]
|
||||
public float distanceLOD2 = 7.5f + Mathf.Sqrt(2 * ((100f / 10f) * (100f / 10f))) + 5f;
|
||||
public float distanceLOD2 = 5f + (100f / 10f) * SQRT_2 + 3f;
|
||||
public Material grassMaterialLOD2;
|
||||
[Range(0f, 1f)] public float densityLOD2 = 0.2f;
|
||||
public bool enableShadowsLOD2 = false;
|
||||
|
||||
private const float SQRT_2 = 1.4142135623730f;
|
||||
private static readonly int pId_WorldSpaceCameraPosEditor = Shader.PropertyToID("_WorldSpaceCameraPosEditor");
|
||||
private static readonly int pId_TransitionRange = Shader.PropertyToID("_TransitionRange");
|
||||
|
||||
// a 2D array would be cleaner, but it can't be serialized
|
||||
// serialize it, because the chunks are generated offline and used during runtime
|
||||
@ -30,8 +34,9 @@ public class GrassField : MonoBehaviour {
|
||||
// ReSharper disable Unity.PerformanceAnalysis
|
||||
public void GenerateGrassField() {
|
||||
Debug.Log("Generating grass field... ");
|
||||
|
||||
var bladesLOD0 = GrassMeshGeneration.GenerateBladesRandom(size, size * size * (int)(bladesPerMeter * densityLOD0));
|
||||
var bladesLOD0 = GrassMeshGeneration.GenerateBladesRandom(
|
||||
size, size * size * (int)(bladesPerMeter * densityLOD0)
|
||||
);
|
||||
// var bladesLOD1 = GenerateBladesRandom(size, size * size * (int)(bladesPerMeter * densityLOD1));
|
||||
// var bladesLOD2 = GenerateBladesRandom(size, size * size * (int)(bladesPerMeter * densityLOD2));
|
||||
var bladesLOD1 = GrassMeshGeneration.GenerateBladesReduced(bladesLOD0, densityLOD1);
|
||||
@ -42,7 +47,8 @@ public class GrassField : MonoBehaviour {
|
||||
}
|
||||
|
||||
private void OnEnable() {
|
||||
var minDistLOD2 = distanceLOD1 + Mathf.Sqrt( 2 * Mathf.Pow( (float)size / numChunks, 2f ) );
|
||||
var chunkSize = ((float)size) / numChunks;
|
||||
var minDistLOD2 = distanceLOD1 + chunkSize * SQRT_2;
|
||||
if (distanceLOD2 < minDistLOD2) {
|
||||
Debug.LogWarning("It is recommended that minDistLOD2 is greater than " + minDistLOD2 + ".");
|
||||
}
|
||||
@ -53,17 +59,31 @@ public class GrassField : MonoBehaviour {
|
||||
}
|
||||
}
|
||||
|
||||
private void Update() {
|
||||
UpdateLODs(false);
|
||||
private void OnDisable() {
|
||||
var camPosWorld = Camera.main ? Camera.main.transform.position : Vector3.zero;
|
||||
UpdateMaterials(camPosWorld);
|
||||
UpdateLODs(camPosWorld);
|
||||
}
|
||||
|
||||
private void UpdateLODs(bool forceCompleteCheck = true) {
|
||||
private void OnValidate() {
|
||||
var camPosWorld = Camera.main ? Camera.main.transform.position : Vector3.zero;
|
||||
UpdateMaterials(camPosWorld);
|
||||
}
|
||||
|
||||
private void Update() {
|
||||
var cam = Camera.main;
|
||||
if (!cam) return;
|
||||
var camPosWorld = cam.transform.position;
|
||||
#if UNITY_EDITOR
|
||||
UpdateMaterials(camPosWorld);
|
||||
#endif
|
||||
|
||||
if (_chunks.Length != numChunks * numChunks) return;
|
||||
UpdateLODs(camPosWorld, false); // while the game is running, only the chunks near the camera are updated
|
||||
}
|
||||
|
||||
var camPos = cam.transform.position - transform.position; // cam position relative to grass field
|
||||
private void UpdateLODs(Vector3 camPosWorld, bool forceCompleteCheck = true) {
|
||||
var camPos = camPosWorld - transform.position; // cam position relative to grass field
|
||||
if (ignoreHeightForLOD) {
|
||||
camPos.y = 0;
|
||||
}
|
||||
@ -125,6 +145,26 @@ public class GrassField : MonoBehaviour {
|
||||
return range;
|
||||
}
|
||||
|
||||
private void UpdateMaterials(Vector3 camPosWorld) {
|
||||
var chunkSize = ((float)size) / numChunks;
|
||||
var chunkDiagonalLength = chunkSize * SQRT_2;
|
||||
|
||||
var transition0From = 0f;
|
||||
var transition0To = distanceLOD1;
|
||||
var transition1From = transition0To + chunkDiagonalLength;
|
||||
var transition1To = distanceLOD2;
|
||||
grassMaterialLOD0.SetVector(pId_TransitionRange, new Vector2(transition0From, transition0To));
|
||||
grassMaterialLOD1.SetVector(pId_TransitionRange, new Vector2(transition1From, transition1To));
|
||||
#if UNITY_EDITOR
|
||||
if (ignoreHeightForLOD) {
|
||||
camPosWorld.y = 0;
|
||||
}
|
||||
grassMaterialLOD0.SetVector(pId_WorldSpaceCameraPosEditor, camPosWorld);
|
||||
grassMaterialLOD1.SetVector(pId_WorldSpaceCameraPosEditor, camPosWorld);
|
||||
grassMaterialLOD2.SetVector(pId_WorldSpaceCameraPosEditor, camPosWorld);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void CreateChunks(BladeData[] bladesLOD0, BladeData[] bladesLOD1, BladeData[] bladesLOD2) {
|
||||
GameObject chunksContainer;
|
||||
// If a child called "Chunks" exists, destroy it -> children are also destroyed
|
||||
@ -169,7 +209,9 @@ public class GrassField : MonoBehaviour {
|
||||
_chunks[x + y * numChunks] = chunk;
|
||||
}
|
||||
|
||||
UpdateLODs();
|
||||
var camPosWorld = Camera.main ? Camera.main.transform.position : Vector3.zero;
|
||||
UpdateLODs(camPosWorld);
|
||||
UpdateMaterials(camPosWorld);
|
||||
}
|
||||
|
||||
private Mesh GenerateChunkMesh(Vector3 chunkPos, Bounds chunkBounds, BladeData[] blades, string meshName) {
|
||||
@ -237,12 +279,12 @@ public class GrassField : MonoBehaviour {
|
||||
Gizmos.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, 0.001f, 1f));
|
||||
}
|
||||
|
||||
Gizmos.color = new Color(1.0f, 0.0f, 1.0f, 1f);
|
||||
Gizmos.color = new Color(0f, 0.3f, 1f, 1f);
|
||||
Gizmos.DrawWireSphere(center, distanceLOD1);
|
||||
Gizmos.DrawWireSphere(center, distanceLOD2);
|
||||
|
||||
Gizmos.color = new Color(1.0f, 1.0f, 0.0f, 1f);
|
||||
var minDistLOD2 = distanceLOD1 + Mathf.Sqrt( 2 * Mathf.Pow( (float)size / numChunks, 2f ) );
|
||||
var minDistLOD2 = distanceLOD1 + chunkSize * SQRT_2;
|
||||
Gizmos.DrawWireSphere(center, minDistLOD2);
|
||||
|
||||
Gizmos.matrix = oldMatrix;
|
||||
|
||||
@ -1,8 +1,12 @@
|
||||
Shader "Grass/GrassBlade" {
|
||||
Properties {
|
||||
[KeywordEnum(LOD 0, LOD 1, LOD 2)] _LOD("Level of Detail", int) = 0
|
||||
_BladeWidth("Breite", Range(0.003, .1)) = 0.01
|
||||
|
||||
_BladeWidth("Blade Width", Range(0.003, .1)) = 0.01
|
||||
_BendStrength("Bend Strength", Range(0, 1)) = 1
|
||||
_Color0("Color LOD 0", Color) = (0.3, 1.0, 0.3, 1.0)
|
||||
_Color1("Color LOD 1", Color) = (1.0, 0.7, 0.3, 1.0)
|
||||
_Color2("Color LOD 2", Color) = (1.0, 0.3, 0.1, 1.0)
|
||||
}
|
||||
SubShader {
|
||||
LOD 100
|
||||
@ -19,6 +23,7 @@
|
||||
#pragma multi_compile _ SHADOWS_SCREEN
|
||||
// shader_feature is very similar to multi_compile. Use multi_compile for keywords that are set from code.
|
||||
#pragma shader_feature _LOD_LOD_0 _LOD_LOD_1 _LOD_LOD_2
|
||||
#pragma shader_feature UNITY_EDITOR
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
#include "UnityPBSLighting.cginc"
|
||||
@ -45,6 +50,7 @@
|
||||
#pragma geometry geom
|
||||
|
||||
#pragma shader_feature _LOD_LOD_0 _LOD_LOD_1 _LOD_LOD_2
|
||||
#pragma shader_feature UNITY_EDITOR
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
// Material Properties
|
||||
float _BladeWidth, _BendStrength;
|
||||
int _NumSegments_LOD_0, _NumSegments_LOD_1, _NumSegments_LOD_2;
|
||||
float4 _Color0, _Color1, _Color2;
|
||||
|
||||
float2 _TransitionRange;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
float3 _WorldSpaceCameraPosEditor;
|
||||
#endif
|
||||
|
||||
struct MeshData {
|
||||
float4 vertex : POSITION;
|
||||
@ -15,6 +22,7 @@ struct g2f {
|
||||
#ifdef IS_IN_BASE_PASS
|
||||
float2 uv : TEXCOORD0; // bottom left 0.0 top right 1.1 (values converge - 0 and 1 meet at the tip)
|
||||
SHADOW_COORDS(1) // put shadows data into TEXCOORD1
|
||||
float3 worldPos : TEXCOORD2;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -25,7 +33,13 @@ v2g vert (MeshData v) {
|
||||
return o;
|
||||
}
|
||||
|
||||
const int ns = 11;
|
||||
float getCameraDistance(float3 pos) {
|
||||
#if UNITY_EDITOR
|
||||
return distance(_WorldSpaceCameraPosEditor, pos);
|
||||
#else
|
||||
return distance(_WorldSpaceCameraPos, pos);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if _LOD_LOD_0
|
||||
[MaxVertexCount(4 + ( 11 - 1 ) * 2)]
|
||||
@ -44,7 +58,8 @@ void geom(point v2g IN[1], inout TriangleStream<g2f> triStream) {
|
||||
// if (!isInFrustum(basePosClipSpace, 0.1) && !isInFrustum(tipPosClipSpace, 0.1)) return;
|
||||
|
||||
const float3 basePosWS = mul(unity_ObjectToWorld, float4(basePos.xyz, 1.0)).xyz;
|
||||
const float cameraDistance = distance(_WorldSpaceCameraPos, basePosWS);
|
||||
|
||||
const float cameraDistance = getCameraDistance(basePosWS);
|
||||
|
||||
// randomly cull grass blades
|
||||
// float randoVal = N21(basePos);
|
||||
@ -88,30 +103,34 @@ void geom(point v2g IN[1], inout TriangleStream<g2f> triStream) {
|
||||
const float3 vertRightTip = segmentCenterTip - widthOffset * 0.4;
|
||||
|
||||
o.pos = UnityObjectToClipPos(vertLeftBase);
|
||||
#ifdef IS_IN_BASE_PASS
|
||||
#ifdef IS_IN_BASE_PASS
|
||||
o.uv = float2(0, 0);
|
||||
TRANSFER_SHADOW(o)
|
||||
o.worldPos = mul(unity_ObjectToWorld, float4(basePos, 1.0));
|
||||
#endif
|
||||
triStream.Append(o);
|
||||
|
||||
o.pos = UnityObjectToClipPos(vertRightBase);
|
||||
#ifdef IS_IN_BASE_PASS
|
||||
#ifdef IS_IN_BASE_PASS
|
||||
o.uv = float2(1, 0);
|
||||
TRANSFER_SHADOW(o)
|
||||
o.worldPos = mul(unity_ObjectToWorld, float4(basePos, 1.0));
|
||||
#endif
|
||||
triStream.Append(o);
|
||||
|
||||
o.pos = UnityObjectToClipPos(vertLeftTip);
|
||||
#ifdef IS_IN_BASE_PASS
|
||||
#ifdef IS_IN_BASE_PASS
|
||||
o.uv = float2(0, 1);
|
||||
TRANSFER_SHADOW(o)
|
||||
o.worldPos = mul(unity_ObjectToWorld, float4(basePos, 1.0));
|
||||
#endif
|
||||
triStream.Append(o);
|
||||
|
||||
o.pos = UnityObjectToClipPos(vertRightTip);
|
||||
#ifdef IS_IN_BASE_PASS
|
||||
#ifdef IS_IN_BASE_PASS
|
||||
o.uv = float2(1, 1);
|
||||
TRANSFER_SHADOW(o)
|
||||
o.worldPos = mul(unity_ObjectToWorld, float4(basePos, 1.0));
|
||||
#endif
|
||||
triStream.Append(o);
|
||||
}
|
||||
@ -139,7 +158,11 @@ void geom(point v2g IN[1], inout TriangleStream<g2f> triStream) {
|
||||
const float3 normal = normalize(cross(surfTangent1, surfTangent2)); // TODO remove normalize
|
||||
float3 normalWS = UnityObjectToWorldNormal(normal);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
const float3 camVec = normalize(segmentCenter - _WorldSpaceCameraPosEditor.xyz);
|
||||
#else
|
||||
const float3 camVec = normalize(segmentCenter - _WorldSpaceCameraPos.xyz);
|
||||
#endif
|
||||
|
||||
// at which side of the blade are we looking?
|
||||
const bool lookingFromAbove = dot(camVec, normalWS) > 0;
|
||||
@ -151,6 +174,7 @@ void geom(point v2g IN[1], inout TriangleStream<g2f> triStream) {
|
||||
#ifdef IS_IN_BASE_PASS
|
||||
o.uv = float2(0, segmentHeightNormalized);
|
||||
TRANSFER_SHADOW(o)
|
||||
o.worldPos = mul(unity_ObjectToWorld, float4(basePos, 1.0));
|
||||
#endif
|
||||
triStream.Append(o);
|
||||
|
||||
@ -158,6 +182,7 @@ void geom(point v2g IN[1], inout TriangleStream<g2f> triStream) {
|
||||
#ifdef IS_IN_BASE_PASS
|
||||
o.uv = float2(1, segmentHeightNormalized);
|
||||
TRANSFER_SHADOW(o)
|
||||
o.worldPos = mul(unity_ObjectToWorld, float4(basePos, 1.0));
|
||||
#endif
|
||||
triStream.Append(o);
|
||||
|
||||
@ -168,17 +193,17 @@ void geom(point v2g IN[1], inout TriangleStream<g2f> triStream) {
|
||||
#ifdef IS_IN_BASE_PASS
|
||||
o.uv = float2(.5, 1);
|
||||
TRANSFER_SHADOW(o)
|
||||
o.worldPos = mul(unity_ObjectToWorld, float4(basePos, 1.0));
|
||||
#endif
|
||||
triStream.Append(o);
|
||||
}
|
||||
|
||||
fixed4 frag(g2f i) : SV_Target{
|
||||
float4 frag(g2f i) : SV_Target{
|
||||
#ifdef IS_IN_SHADOW_PASS
|
||||
return 0;
|
||||
#else
|
||||
float atten = 1.0;
|
||||
|
||||
const fixed shadow = SHADOW_ATTENUATION(i);
|
||||
|
||||
const float shadow = SHADOW_ATTENUATION(i);
|
||||
|
||||
float3 light = float3(i.uv.yyy);
|
||||
light *= max(.35, shadow);
|
||||
@ -186,16 +211,20 @@ fixed4 frag(g2f i) : SV_Target{
|
||||
light *= 0.75;
|
||||
#endif
|
||||
|
||||
const float camDist = getCameraDistance(i.worldPos);
|
||||
float interpolator = invLerp(_TransitionRange.x, _TransitionRange.y, camDist);
|
||||
|
||||
float3 albedo;
|
||||
#if _LOD_LOD_0
|
||||
float3 albedo = float3(0.3,1.0,0.3);
|
||||
albedo = lerp(_Color0.xyz, _Color1.xyz, interpolator);
|
||||
#elif _LOD_LOD_1
|
||||
float3 albedo = float3(1.0,0.7,0.3);
|
||||
albedo = float3(0.3,1.0,0.3);
|
||||
albedo = lerp(_Color1.xyz, _Color2.xyz, interpolator);
|
||||
#elif _LOD_LOD_2
|
||||
float3 albedo = float3(1.0,0.3,0.1);
|
||||
albedo = float3(0.3,1.0,0.3);
|
||||
albedo = _Color2.xyz;
|
||||
#endif
|
||||
// albedo = _Color0.xyz;
|
||||
|
||||
return float4(light * albedo, 1);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -301,7 +301,11 @@ PlayerSettings:
|
||||
- m_BuildTarget: WebGL
|
||||
m_StaticBatching: 0
|
||||
m_DynamicBatching: 0
|
||||
m_BuildTargetShaderSettings: []
|
||||
m_BuildTargetShaderSettings:
|
||||
- m_BuildTarget: Standalone
|
||||
m_ChunkSizeInMB: 16
|
||||
m_MaxChunks: 0
|
||||
m_OverrideDefaultSettings: 0
|
||||
m_BuildTargetGraphicsJobs:
|
||||
- m_BuildTarget: MacStandaloneSupport
|
||||
m_GraphicsJobs: 0
|
||||
|
||||
12
README.md
12
README.md
@ -1,3 +1,15 @@
|
||||
# Grass Rendering Prototype
|
||||
|
||||
Optimized rendering of huge grass fields.
|
||||
|
||||
## To-Do
|
||||
|
||||
- [x] LODs: reduced detail (number of vertices)
|
||||
- [x] LODs: reduced number of blades
|
||||
- [ ] Smooth LOD transition: number of blades
|
||||
- [ ] Smooth LOD transition: detail
|
||||
- [ ] Thicker blades with increased distance
|
||||
- [ ] Cut map
|
||||
- [ ] Cut map LOD versions
|
||||
- [ ] Lighting
|
||||
- [ ] Grass field generation: spawn in patches
|
||||
|
||||
Loading…
Reference in New Issue
Block a user