174 lines
3.6 KiB
C#
174 lines
3.6 KiB
C#
using Godot;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using Godot.Collections;
|
|
|
|
namespace Rokojori
|
|
{
|
|
[Tool]
|
|
[GlobalClass]
|
|
public partial class LODParent:Node3D
|
|
{
|
|
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")]
|
|
[Export]
|
|
public bool curveCulling = true;
|
|
|
|
[Export]
|
|
public float curveCullDistance = 4000;
|
|
|
|
[Export]
|
|
public Curve curveDistribution = MathX.Curve( 0, 1 );
|
|
|
|
[ExportGroup("LODs")]
|
|
[Export]
|
|
public Node3D[] lods;
|
|
|
|
[Export]
|
|
public float updateDistance = 10;
|
|
|
|
[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;
|
|
|
|
float lastSquaredDistance = -1;
|
|
int lastSelectedIndex = -1;
|
|
|
|
public int changeBlock = 0;
|
|
|
|
public int blocker = 0;
|
|
|
|
public override void _Process( double delta )
|
|
{
|
|
if ( processOnlyWhenVisible && ! Visible )
|
|
{
|
|
return;
|
|
}
|
|
|
|
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 );
|
|
X_realCameraDistance = Mathf.Sqrt( squaredDistance );
|
|
|
|
|
|
if ( testMode )
|
|
{
|
|
squaredDistance = testDistance * testDistance;
|
|
}
|
|
|
|
if ( Mathf.Abs( lastSquaredDistance - squaredDistance ) < updateDistance * updateDistance )
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
lastSquaredDistance = squaredDistance;
|
|
|
|
var realDistance = Mathf.Sqrt( lastSquaredDistance );
|
|
|
|
X_processingCameraDistance = realDistance;
|
|
|
|
var selectedIndex = GetLODIndex( realDistance );
|
|
|
|
X_selectedIndex = selectedIndex;
|
|
|
|
if ( lastSelectedIndex == selectedIndex )
|
|
{
|
|
return;
|
|
}
|
|
|
|
lastSelectedIndex = selectedIndex;
|
|
blocker = changeBlock;
|
|
|
|
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 ) );
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
}
|
|
} |