Skip to content

Commit

Permalink
HLOD test bed
Browse files Browse the repository at this point in the history
  • Loading branch information
GBirch33 committed Nov 15, 2024
1 parent 1e395c7 commit 0ddde24
Show file tree
Hide file tree
Showing 16 changed files with 1,823 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityMeshSimplifier;

public class LODGenerationTool : EditorWindow
{
private float[] lodLevels = new float[] { 0.8f, 0.6f, 0.4f, 0.2f, 0.1f, 0.05f };
private int minTriangleCount = 512;

[MenuItem("Tools/Generate LODs")]
public static void ShowWindow()
{
GetWindow<LODGenerationTool>("LOD Generation");
}

void OnGUI()
{
GUILayout.Label("LOD Generation Settings", EditorStyles.boldLabel);

EditorGUILayout.BeginVertical();
for (int i = 0; i < lodLevels.Length; i++)
{
lodLevels[i] = EditorGUILayout.Slider($"LOD {i + 1} Quality", lodLevels[i], 0.01f, 1f);
}
EditorGUILayout.EndVertical();

minTriangleCount = EditorGUILayout.IntField("Minimum Triangle Count", minTriangleCount);

if (GUILayout.Button("Generate LODs"))
{
GenerateLODs();
}
}

void GenerateLODs()
{
GameObject[] selectedObjects = Selection.gameObjects;

foreach (GameObject obj in selectedObjects)
{
MeshFilter meshFilter = obj.GetComponent<MeshFilter>();
MeshRenderer meshRenderer = obj.GetComponent<MeshRenderer>();

if (meshFilter != null && meshRenderer != null)
{
Mesh originalMesh = meshFilter.sharedMesh;
Material[] materials = meshRenderer.sharedMaterials;

LODGroup lodGroup = obj.GetComponent<LODGroup>();
if (lodGroup == null)
{
lodGroup = obj.AddComponent<LODGroup>();
}

List<LOD> lods = new List<LOD>();

// Original mesh as LOD0
LOD originalLOD = new LOD(1f, new Renderer[] { meshRenderer });
lods.Add(originalLOD);

for (int i = 0; i < lodLevels.Length; i++)
{
float quality = lodLevels[i];
Mesh simplifiedMesh = SimplifyMesh(originalMesh, quality);

if (simplifiedMesh.triangles.Length / 3 <= minTriangleCount)
{
Debug.Log($"Stopped LOD generation for {obj.name} at LOD {i + 1} due to minimum triangle count.");
break;
}

GameObject lodObject = new GameObject($"LOD_{i + 1}");
lodObject.transform.SetParent(obj.transform);
lodObject.transform.localPosition = Vector3.zero;
lodObject.transform.localRotation = Quaternion.identity;
lodObject.transform.localScale = Vector3.one;

MeshFilter lodMeshFilter = lodObject.AddComponent<MeshFilter>();
lodMeshFilter.sharedMesh = simplifiedMesh;

MeshRenderer lodMeshRenderer = lodObject.AddComponent<MeshRenderer>();
lodMeshRenderer.sharedMaterials = materials;

float lodThreshold = i < lodLevels.Length - 1 ? (lodLevels[i] + lodLevels[i + 1]) / 2 : 0.01f;
LOD lod = new LOD(lodThreshold, new Renderer[] { lodMeshRenderer });
lods.Add(lod);
}

lodGroup.SetLODs(lods.ToArray());
lodGroup.RecalculateBounds();

EditorUtility.SetDirty(obj);
}
}

AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}

Mesh SimplifyMesh(Mesh originalMesh, float quality)
{
MeshSimplifier meshSimplifier = new MeshSimplifier();
meshSimplifier.Initialize(originalMesh);
meshSimplifier.SimplifyMesh(quality);

Mesh simplifiedMesh = meshSimplifier.ToMesh();
LODGeneratorHelper LGH = new LODGeneratorHelper();
SimplificationOptions SO = new SimplificationOptions();
SO.PreserveBorderEdges = false;
SO.PreserveUVSeamEdges = false;
SO.PreserveUVFoldoverEdges = false;
SO.PreserveSurfaceCurvature = false;
SO.EnableSmartLink = true;
SO.VertexLinkDistance = double.Epsilon;
SO.MaxIterationCount = 100;
SO.Agressiveness = 7.0;
SO.ManualUVComponentCount = false;
SO.UVComponentCount = 2;
LGH.SimplificationOptions = SO;
float screenRelativeTransitionHeight = 1.0f;
float fadeTransitionWidth = 2.0f;
float fQuality = 1.0f;
bool combineMeshes = true;
bool combineSubMeshes = true;
Renderer[] renderers = new Renderer[1];
LGH.Levels[0] = new LODLevel(screenRelativeTransitionHeight, fadeTransitionWidth, fQuality, combineMeshes, combineSubMeshes, renderers);

// LODGroup lodGroup = simplifiedMesh.GetComponent<LODGroup>();
// LOD[] lods = lodGroup.GetLODs();
// for (int i = 0; i < lodGroup.lodCount; ++i)
// {
// lods[0].screenRelativeTransitionHeight;
// }

return simplifiedMesh;
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Empty file.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

124 changes: 124 additions & 0 deletions asset-bundle-converter/Assets/AssetBundleConverter/HLOD/HLOD.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
using UnityEngine;
using System;
using System.Collections.Generic;
using UnityEngine.Rendering;

public class CustomMeshRenderer : MonoBehaviour
{
[System.Serializable]
private struct MeshInfo
{
public int vertexStart;
public int vertexCount;
public int indexStart;
public int indexCount;
}

private struct ObjRenderFlags
{
public bool isVisible;
public int nLODLevel;
}

List<ObjRenderFlags> ObjectRenderFlags = new List<ObjRenderFlags>();
public Mesh combinedMesh;
public Mesh[,] m_mesh = new Mesh[2, 5];
public Material[] m_material = new Material[2];
private List<MeshInfo> meshInfos;
public Transform objectTransform;

private GraphicsBuffer[,] meshIndices = new GraphicsBuffer[2, 5];
private GraphicsBuffer[,] meshPositions = new GraphicsBuffer[2,5];
private GraphicsBuffer[,] meshNormals = new GraphicsBuffer[2,5];
private GraphicsBuffer[,] meshTangents = new GraphicsBuffer[2,5];
private GraphicsBuffer[,] meshTexcoords = new GraphicsBuffer[2,5];

private CommandBuffer cmd;

// Knowledge of OctTree and built status
// Knowledge of Objects and Mesh data (1to1 array)
// Communication to system to say that a GameObject is no longer considered static
// Communication to server to inform of GameObject state change
// Knowledge of streaming system
// Knowledge of LOD state

void Start()
{
cmd = new CommandBuffer();
cmd.name = "Custom Mesh Renderer";

// Add this command buffer to the main light's shadow pass
Light mainLight = RenderSettings.sun;
if (mainLight != null)
{
mainLight.AddCommandBuffer(LightEvent.BeforeScreenspaceMask, cmd);
}
}

void DrawMeshStream(int nOpacity, int nLODLevel, Material _material, int _indexStart, int _indexCount, int _instanceCount)
{
MaterialPropertyBlock properties = new MaterialPropertyBlock();
properties.SetBuffer("_Positions", meshPositions[nOpacity, nLODLevel]);
properties.SetBuffer("_Normals", meshNormals[nOpacity, nLODLevel]);
properties.SetBuffer("_Tangents", meshTangents[nOpacity, nLODLevel]);
properties.SetBuffer("_Texcoords", meshTexcoords[nOpacity, nLODLevel]);
properties.SetInt("_StartIndex", _indexStart);
cmd.DrawProcedural(meshIndices[nOpacity, nLODLevel], objectTransform.localToWorldMatrix, _material, shaderPass:0, MeshTopology.Triangles, _indexCount, _instanceCount, properties);
}

void Update()
{
cmd.Clear();

int nVertexStart = Int32.MaxValue;
int nIndexStart = Int32.MaxValue;
int nVertexCount = 0;
int nIndexCount = 0;
int nMaxLODLevel = 5;
for (int nOpacity = 0; nOpacity < 2; ++nOpacity)
{
for (int nLODLevel = 0; nLODLevel < nMaxLODLevel; ++nLODLevel)
{
for (int i = 0; i < ObjectRenderFlags.Count; ++i)
{
if (ObjectRenderFlags[i].isVisible == true)
{
if (ObjectRenderFlags[i].nLODLevel == nLODLevel)
{
if (nVertexStart == Int32.MaxValue)
{
nVertexStart = meshInfos[i].vertexStart;
nIndexStart = meshInfos[i].indexStart;
}

nVertexCount += meshInfos[i].vertexCount;
nIndexCount += meshInfos[i].indexCount;

continue;
}
}

if (nVertexCount > 0 && nIndexCount > 0) // Draw all previously collated meshes
{
DrawMeshStream(nOpacity, nLODLevel, m_material[nOpacity], nIndexStart, nIndexCount, 0);
nVertexStart = Int32.MaxValue;
nIndexStart = Int32.MaxValue;
nVertexCount = 0;
nIndexCount = 0;
}
}
DrawMeshStream(nOpacity, nLODLevel, m_material[nOpacity], nIndexStart, nIndexCount, 0);
}
}
}

void OnDestroy()
{
Light mainLight = RenderSettings.sun;
if (mainLight != null)
{
mainLight.RemoveCommandBuffer(LightEvent.BeforeScreenspaceMask, cmd);
}
cmd.Release();
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 0ddde24

Please sign in to comment.