rj-action-library/Runtime/LOD/LODParent.cs

174 lines
3.6 KiB
C#
Raw Normal View History

2024-12-01 17:07:41 +00:00
using Godot;
using System.Collections;
using System.Collections.Generic;
using Godot.Collections;
namespace Rokojori
{
[Tool]
[GlobalClass]
public partial class LODParent:Node3D
{
2025-01-03 12:09:23 +00:00
public enum DistanceMode
{
Via_Array,
Via_Curve
}
[Export]
public DistanceMode mode;
[ExportGroup("Array Mode")]
[Export]
public bool arrayCulling = true;
[Export]
public float[] arrayTresholds;
[ExportGroup("Curve Mode")]
2024-12-01 17:07:41 +00:00
[Export]
2025-01-03 12:09:23 +00:00
public bool curveCulling = true;
2024-12-01 17:07:41 +00:00
[Export]
2025-01-03 12:09:23 +00:00
public float curveCullDistance = 4000;
2024-12-01 17:07:41 +00:00
2025-01-03 12:09:23 +00:00
[Export]
public Curve curveDistribution = MathX.Curve( 0, 1 );
[ExportGroup("LODs")]
2024-12-01 17:07:41 +00:00
[Export]
public Node3D[] lods;
[Export]
public float updateDistance = 10;
2025-01-03 12:09:23 +00:00
[ExportGroup("Testing")]
[Export]
public float X_processingCameraDistance = 0;
[Export]
public float X_realCameraDistance = 0;
[Export]
public float X_selectedIndex = 0;
[Export]
public bool testMode = false;
[Export]
public float testDistance = 0;
[Export]
public bool processOnlyWhenVisible = true;
2024-12-01 17:07:41 +00:00
float lastSquaredDistance = -1;
int lastSelectedIndex = -1;
public int changeBlock = 0;
public int blocker = 0;
public override void _Process( double delta )
{
2025-01-03 12:09:23 +00:00
if ( processOnlyWhenVisible && ! Visible )
{
return;
}
2024-12-01 17:07:41 +00:00
if ( blocker > 0 )
{
blocker --;
return;
}
if ( lods == null || lods.Length == 0 )
{
return;
}
var camera = GetViewport().GetCamera3D();
#if TOOLS
if ( Engine.IsEditorHint() )
{
camera = EditorInterface.Singleton.GetEditorViewport3D().GetCamera3D();
}
#endif
var squaredDistance = GlobalPosition.DistanceSquaredTo( camera.GlobalPosition );
2025-01-03 12:09:23 +00:00
X_realCameraDistance = Mathf.Sqrt( squaredDistance );
2024-12-01 17:07:41 +00:00
2025-01-03 12:09:23 +00:00
if ( testMode )
2024-12-01 17:07:41 +00:00
{
2025-01-03 12:09:23 +00:00
squaredDistance = testDistance * testDistance;
}
if ( Mathf.Abs( lastSquaredDistance - squaredDistance ) < updateDistance * updateDistance )
{
2024-12-01 17:07:41 +00:00
return;
}
2025-01-03 12:09:23 +00:00
2024-12-01 17:07:41 +00:00
lastSquaredDistance = squaredDistance;
var realDistance = Mathf.Sqrt( lastSquaredDistance );
2025-01-03 12:09:23 +00:00
X_processingCameraDistance = realDistance;
2024-12-01 17:07:41 +00:00
2025-01-03 12:09:23 +00:00
var selectedIndex = GetLODIndex( realDistance );
X_selectedIndex = selectedIndex;
2024-12-01 17:07:41 +00:00
if ( lastSelectedIndex == selectedIndex )
{
return;
}
lastSelectedIndex = selectedIndex;
blocker = changeBlock;
2025-01-03 12:09:23 +00:00
if ( selectedIndex >= lods.Length )
{
Arrays.ForEach( lods, l => NodeState.Set( l, false ) );
}
else
{
var selectedLOD = lods[ selectedIndex ];
Arrays.ForEach( lods, l => NodeState.Set( l, selectedLOD == l ) );
}
2024-12-01 17:07:41 +00:00
}
2025-01-03 12:09:23 +00:00
int GetLODIndex( float realDistance )
{
if ( DistanceMode.Via_Array == mode )
{
for ( int i = 0; i < arrayTresholds.Length; i++ )
{
if ( realDistance <= arrayTresholds[ i ] )
{
return i;
}
}
return arrayCulling ? lods.Length : ( lods.Length - 1 );
}
else if ( DistanceMode.Via_Curve == mode )
{
if ( curveCulling && realDistance >= curveCullDistance )
{
return lods.Length;
}
var normalizedDistance = MathX.NormalizeClamped( realDistance, 0, curveCullDistance );
var active = curveDistribution.Sample( normalizedDistance ) * lods.Length;
return Mathf.Min( lods.Length - 1, Mathf.RoundToInt( active ) );
}
return -1;
}
2024-12-01 17:07:41 +00:00
}
}