-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
1,823 additions
and
0 deletions.
There are no files selected for viewing
139 changes: 139 additions & 0 deletions
139
asset-bundle-converter/Assets/AssetBundleConverter/EditorScripts/LODGenerationTool.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
3 changes: 3 additions & 0 deletions
3
asset-bundle-converter/Assets/AssetBundleConverter/EditorScripts/LODGenerationTool.cs.meta
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Empty file.
3 changes: 3 additions & 0 deletions
3
asset-bundle-converter/Assets/AssetBundleConverter/EditorScripts/MeshMerging.cs.meta
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
124 changes: 124 additions & 0 deletions
124
asset-bundle-converter/Assets/AssetBundleConverter/HLOD/HLOD.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |
3 changes: 3 additions & 0 deletions
3
asset-bundle-converter/Assets/AssetBundleConverter/HLOD/HLOD.cs.meta
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.