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

96 lines
2.0 KiB
C#

using Godot;
using System.Collections;
using System.Collections.Generic;
using Godot.Collections;
namespace Rokojori
{
[Tool]
[GlobalClass]
public partial class LODParent:Node3D
{
[Export]
public float cullDistance = 4000;
[Export]
public Curve distribution = MathX.Curve( 0, 1 );
[Export]
public Node3D[] lods;
[Export]
public float updateDistance = 10;
float lastSquaredDistance = -1;
int lastSelectedIndex = -1;
[Export]
public int changeBlock = 0;
[Export]
public int blocker = 0;
public override void _Process( double delta )
{
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 );
if ( Mathf.Abs( lastSquaredDistance - squaredDistance ) < updateDistance * updateDistance )
{
return;
}
lastSquaredDistance = squaredDistance;
var realDistance = Mathf.Sqrt( lastSquaredDistance );
var normalizedDistance = MathX.NormalizeClamped( realDistance, 0, cullDistance );
var active = distribution.Sample( normalizedDistance ) * lods.Length;
var selectedIndex = Mathf.Min( lods.Length - 1, Mathf.RoundToInt( active ) );
if ( lastSelectedIndex == selectedIndex )
{
return;
}
// RJLog.Log(
// "realDistance:", realDistance,
// "normalizedDistance:", normalizedDistance,
// "active:", active,
// "selectedIndex:", selectedIndex
// );
var selectedLOD = lods[ selectedIndex ];
lastSelectedIndex = selectedIndex;
Arrays.ForEach( lods, l => NodeState.Set( l, selectedLOD == l ) );
blocker = changeBlock;
}
}
}