Improve chunk bounds calculation + better gizmos

This commit is contained in:
Timo Eberl 2024-09-28 01:06:57 +02:00
parent 268a22ad63
commit 253bdbf854
Signed by: Timo
SSH Key Fingerprint: SHA256:swVjhbVzKCLQZNtwPqMEmtOUG3FTydzVrpIKpUZYTQw
5 changed files with 19273 additions and 19145 deletions

File diff suppressed because one or more lines are too long

View File

@ -3,10 +3,10 @@ using UnityEngine;
[RequireComponent(typeof(MeshRenderer)), RequireComponent(typeof(MeshFilter))]
public class GrassChunk : MonoBehaviour {
void OnDrawGizmos() {
Gizmos.color = Color.yellow;
var renderer = GetComponent<MeshRenderer>();
Gizmos.DrawWireCube(renderer.bounds.center, renderer.bounds.size);
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);
}
}

View File

@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using UnityEngine;
using Random = UnityEngine.Random;
public class GrassField : MonoBehaviour {
public int size = 100;
@ -16,13 +19,26 @@ public class GrassField : MonoBehaviour {
public void GenerateGrassField() {
Debug.Log("Generating grass field... ");
var blades = GenerateBlades();
var blades = GenerateBladesRandom(100000);
CreateChunks(blades);
Debug.Log("Generating grass field done");
}
private BladeData[] GenerateBlades() {
private BladeData[] GenerateBladesRandom(int num) {
var blades = new BladeData[num];
for (int i = 0; i < num; i++) {
blades[i].rootPosition = new Vector3(
Random.Range(0f, size), Random.Range(-0.5f, 0.5f), Random.Range(0f, size)
);
blades[i].tipOffset = new Vector3(0.01f, 1.0f, 0.01f);
}
return blades;
}
private BladeData[] GenerateBladesEven() {
var blades = new BladeData[size * size * 100];
for (int x = 0; x < size * 10; x++)
@ -48,21 +64,22 @@ public class GrassField : MonoBehaviour {
chunks.transform.SetParent(this.transform, false);
var chunkSize = ((float)size) / numChunks;
// bounds of the chunk (relative to chunk) - do not consider y position
var chunkBounds = new Bounds(
new Vector3(0.5f * chunkSize, 0.0f, 0.5f * chunkSize),
new Vector3(chunkSize, 10000f, chunkSize)
);
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> tipOffsets = new();
List<int> indices = new();
foreach (var blade in blades) {
// position relative to chunk
var localRootPos = blade.rootPosition - chunkPos;
if (bounds.Contains(localRootPos)) {
if (chunkBounds.Contains(localRootPos)) {
rootPositions.Add(localRootPos);
tipOffsets.Add(blade.tipOffset);
indices.Add(rootPositions.Count - 1);
@ -74,10 +91,19 @@ public class GrassField : MonoBehaviour {
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, tipOffsets);
mesh.SetUVs(0, tipOffsets); // Vector3 UVs
// AABB gets calculated automatically (considers all root positions)
mesh.SetIndices(indices, MeshTopology.Points, 0);
// update the AABB to match the actual grass (not just the root positions)
// use mesh.bounds rather than meshRenderer.localBounds,
// because the latter gets overwritten automatically
var previousBounds = mesh.bounds;
float width = 1f;
float height = 1f;
mesh.bounds = new Bounds(
previousBounds.center + new Vector3(0f, height * 0.5f, 0f),
previousBounds.size + new Vector3(width, height, width)
);
var chunk = Instantiate(chunkPrefab, chunks.transform);
chunk.name = "Chunk [" + x + ", " + y +"]";
@ -86,9 +112,24 @@ public class GrassField : MonoBehaviour {
var meshFilter = chunk.GetComponent<MeshFilter>();
meshFilter.sharedMesh = mesh;
var meshRenderer = chunk.GetComponent<MeshRenderer>();
meshRenderer.localBounds = bounds;
meshRenderer.sharedMaterial = grassMaterial;
}
}
private void OnDrawGizmos() {
Gizmos.color = new Color(0f, 0.2f, 1f, 1f);
var chunkSize = ((float)size) / numChunks;
var bounds = new Bounds(
new Vector3(0.5f * chunkSize, 0.0f, 0.5f * chunkSize),
new Vector3(chunkSize, 0f, chunkSize)
);
for (int x = 0; x < numChunks; x++)
for (int y = 0; y < numChunks; y++) {
var chunkPos = new Vector3(x, 0.0f, y) * chunkSize;
Gizmos.DrawWireCube(bounds.center + chunkPos + transform.position, bounds.size);
}
}
}

View File

@ -160,7 +160,8 @@ PlayerSettings:
resetResolutionOnWindowResize: 0
androidSupportedAspectRatio: 1
androidMaxAspectRatio: 2.1
applicationIdentifier: {}
applicationIdentifier:
Standalone: com.DefaultCompany.GrassRenderingPrototype
buildNumber:
Standalone: 0
VisionOS: 0

View File

@ -6,7 +6,7 @@ QualitySettings:
serializedVersion: 5
m_CurrentQuality: 5
m_QualitySettings:
- serializedVersion: 2
- serializedVersion: 3
name: Very Low
pixelLightCount: 0
shadows: 0
@ -18,17 +18,21 @@ QualitySettings:
shadowCascade2Split: 0.33333334
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
shadowmaskMode: 0
blendWeights: 1
textureQuality: 1
skinWeights: 1
globalTextureMipmapLimit: 1
textureMipmapLimitSettings: []
anisotropicTextures: 0
antiAliasing: 0
softParticles: 0
softVegetation: 0
realtimeReflectionProbes: 0
billboardsFaceCameraPosition: 0
useLegacyDetailDistribution: 1
vSyncCount: 0
realtimeGICPUUsage: 25
lodBias: 0.3
maximumLODLevel: 0
enableLODCrossFade: 1
streamingMipmapsActive: 0
streamingMipmapsAddAllCameras: 1
streamingMipmapsMemoryBudget: 512
@ -40,8 +44,18 @@ QualitySettings:
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
customRenderPipeline: {fileID: 0}
terrainQualityOverrides: 0
terrainPixelError: 1
terrainDetailDensityScale: 1
terrainBasemapDistance: 1000
terrainDetailDistance: 80
terrainTreeDistance: 5000
terrainBillboardStart: 50
terrainFadeLength: 5
terrainMaxTrees: 50
excludedTargetPlatforms: []
- serializedVersion: 2
- serializedVersion: 3
name: Low
pixelLightCount: 0
shadows: 0
@ -53,17 +67,21 @@ QualitySettings:
shadowCascade2Split: 0.33333334
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
shadowmaskMode: 0
blendWeights: 2
textureQuality: 0
skinWeights: 2
globalTextureMipmapLimit: 0
textureMipmapLimitSettings: []
anisotropicTextures: 0
antiAliasing: 0
softParticles: 0
softVegetation: 0
realtimeReflectionProbes: 0
billboardsFaceCameraPosition: 0
useLegacyDetailDistribution: 1
vSyncCount: 0
realtimeGICPUUsage: 25
lodBias: 0.4
maximumLODLevel: 0
enableLODCrossFade: 1
streamingMipmapsActive: 0
streamingMipmapsAddAllCameras: 1
streamingMipmapsMemoryBudget: 512
@ -75,8 +93,18 @@ QualitySettings:
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
customRenderPipeline: {fileID: 0}
terrainQualityOverrides: 0
terrainPixelError: 1
terrainDetailDensityScale: 1
terrainBasemapDistance: 1000
terrainDetailDistance: 80
terrainTreeDistance: 5000
terrainBillboardStart: 50
terrainFadeLength: 5
terrainMaxTrees: 50
excludedTargetPlatforms: []
- serializedVersion: 2
- serializedVersion: 3
name: Medium
pixelLightCount: 1
shadows: 1
@ -88,17 +116,21 @@ QualitySettings:
shadowCascade2Split: 0.33333334
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
shadowmaskMode: 0
blendWeights: 2
textureQuality: 0
skinWeights: 2
globalTextureMipmapLimit: 0
textureMipmapLimitSettings: []
anisotropicTextures: 1
antiAliasing: 0
softParticles: 0
softVegetation: 0
realtimeReflectionProbes: 0
billboardsFaceCameraPosition: 0
useLegacyDetailDistribution: 1
vSyncCount: 1
realtimeGICPUUsage: 25
lodBias: 0.7
maximumLODLevel: 0
enableLODCrossFade: 1
streamingMipmapsActive: 0
streamingMipmapsAddAllCameras: 1
streamingMipmapsMemoryBudget: 512
@ -110,8 +142,18 @@ QualitySettings:
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
customRenderPipeline: {fileID: 0}
terrainQualityOverrides: 0
terrainPixelError: 1
terrainDetailDensityScale: 1
terrainBasemapDistance: 1000
terrainDetailDistance: 80
terrainTreeDistance: 5000
terrainBillboardStart: 50
terrainFadeLength: 5
terrainMaxTrees: 50
excludedTargetPlatforms: []
- serializedVersion: 2
- serializedVersion: 3
name: High
pixelLightCount: 2
shadows: 2
@ -123,17 +165,21 @@ QualitySettings:
shadowCascade2Split: 0.33333334
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
shadowmaskMode: 1
blendWeights: 2
textureQuality: 0
skinWeights: 2
globalTextureMipmapLimit: 0
textureMipmapLimitSettings: []
anisotropicTextures: 1
antiAliasing: 0
softParticles: 0
softVegetation: 1
realtimeReflectionProbes: 1
billboardsFaceCameraPosition: 1
useLegacyDetailDistribution: 1
vSyncCount: 1
realtimeGICPUUsage: 50
lodBias: 1
maximumLODLevel: 0
enableLODCrossFade: 1
streamingMipmapsActive: 0
streamingMipmapsAddAllCameras: 1
streamingMipmapsMemoryBudget: 512
@ -145,8 +191,18 @@ QualitySettings:
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
customRenderPipeline: {fileID: 0}
terrainQualityOverrides: 0
terrainPixelError: 1
terrainDetailDensityScale: 1
terrainBasemapDistance: 1000
terrainDetailDistance: 80
terrainTreeDistance: 5000
terrainBillboardStart: 50
terrainFadeLength: 5
terrainMaxTrees: 50
excludedTargetPlatforms: []
- serializedVersion: 2
- serializedVersion: 3
name: Very High
pixelLightCount: 3
shadows: 2
@ -158,17 +214,21 @@ QualitySettings:
shadowCascade2Split: 0.33333334
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
shadowmaskMode: 1
blendWeights: 4
textureQuality: 0
skinWeights: 4
globalTextureMipmapLimit: 0
textureMipmapLimitSettings: []
anisotropicTextures: 2
antiAliasing: 2
softParticles: 1
softVegetation: 1
realtimeReflectionProbes: 1
billboardsFaceCameraPosition: 1
useLegacyDetailDistribution: 1
vSyncCount: 1
realtimeGICPUUsage: 50
lodBias: 1.5
maximumLODLevel: 0
enableLODCrossFade: 1
streamingMipmapsActive: 0
streamingMipmapsAddAllCameras: 1
streamingMipmapsMemoryBudget: 512
@ -180,8 +240,18 @@ QualitySettings:
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
customRenderPipeline: {fileID: 0}
terrainQualityOverrides: 0
terrainPixelError: 1
terrainDetailDensityScale: 1
terrainBasemapDistance: 1000
terrainDetailDistance: 80
terrainTreeDistance: 5000
terrainBillboardStart: 50
terrainFadeLength: 5
terrainMaxTrees: 50
excludedTargetPlatforms: []
- serializedVersion: 2
- serializedVersion: 3
name: Ultra
pixelLightCount: 4
shadows: 2
@ -193,17 +263,21 @@ QualitySettings:
shadowCascade2Split: 0.33333334
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
shadowmaskMode: 1
blendWeights: 4
textureQuality: 0
skinWeights: 4
globalTextureMipmapLimit: 0
textureMipmapLimitSettings: []
anisotropicTextures: 2
antiAliasing: 2
softParticles: 1
softVegetation: 1
realtimeReflectionProbes: 1
billboardsFaceCameraPosition: 1
vSyncCount: 1
useLegacyDetailDistribution: 1
vSyncCount: 0
realtimeGICPUUsage: 100
lodBias: 2
maximumLODLevel: 0
enableLODCrossFade: 1
streamingMipmapsActive: 0
streamingMipmapsAddAllCameras: 1
streamingMipmapsMemoryBudget: 512
@ -215,16 +289,28 @@ QualitySettings:
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
customRenderPipeline: {fileID: 0}
terrainQualityOverrides: 0
terrainPixelError: 1
terrainDetailDensityScale: 1
terrainBasemapDistance: 1000
terrainDetailDistance: 80
terrainTreeDistance: 5000
terrainBillboardStart: 50
terrainFadeLength: 5
terrainMaxTrees: 50
excludedTargetPlatforms: []
m_TextureMipmapLimitGroupNames: []
m_PerPlatformDefaultQuality:
Android: 2
Lumin: 5
GameCoreScarlett: 5
GameCoreXboxOne: 5
Lumin: 5
Nintendo 3DS: 5
Nintendo Switch: 5
PS4: 5
PS5: 5
Server: 0
Stadia: 5
Standalone: 5
WebGL: 3