131 lines
3.0 KiB
C#
131 lines
3.0 KiB
C#
|
using Godot;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using Godot.Collections;
|
||
|
|
||
|
namespace Rokojori
|
||
|
{
|
||
|
[Tool]
|
||
|
[GlobalClass]
|
||
|
public partial class LODMultiMesh:MultiMeshInstance3D
|
||
|
{
|
||
|
[Export]
|
||
|
public float minDistance = 0;
|
||
|
|
||
|
[Export]
|
||
|
public float cullDistance = 100;
|
||
|
|
||
|
[Export]
|
||
|
public Curve fillCurve = MathX.Curve( 0, 1 );
|
||
|
|
||
|
float _distance = -10;
|
||
|
|
||
|
[Export]
|
||
|
public float distanceTreshold = 0.01f;
|
||
|
|
||
|
[Export( PropertyHint.Range, "0,1" )]
|
||
|
public float scaleRange = 0.5f;
|
||
|
|
||
|
[Export]
|
||
|
public float downMax = 0.1f;
|
||
|
|
||
|
[Export]
|
||
|
Vector3[] cachedOrigins = null;
|
||
|
|
||
|
[Export]
|
||
|
Vector3[] cachedBasis = null;
|
||
|
|
||
|
public void CacheTransforms()
|
||
|
{
|
||
|
var mm = Multimesh;
|
||
|
cachedOrigins = new Vector3[ mm.InstanceCount ];
|
||
|
cachedBasis = new Vector3[ mm.InstanceCount * 3 ];
|
||
|
|
||
|
|
||
|
for ( int i = 0; i < mm.InstanceCount; i++ )
|
||
|
{
|
||
|
var trsf = mm.GetInstanceTransform( i );
|
||
|
|
||
|
cachedBasis[ i * 3 + 0 ] = trsf.Basis.Column0;
|
||
|
cachedBasis[ i * 3 + 1 ] = trsf.Basis.Column1;
|
||
|
cachedBasis[ i * 3 + 2 ] = trsf.Basis.Column2;
|
||
|
|
||
|
cachedOrigins[ i ] =( trsf.Origin );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void _Process(double delta)
|
||
|
{
|
||
|
var camera = GetViewport().GetCamera3D();
|
||
|
|
||
|
#if TOOLS
|
||
|
|
||
|
if ( Engine.IsEditorHint() )
|
||
|
{
|
||
|
camera = EditorInterface.Singleton.GetEditorViewport3D().GetCamera3D();
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
var distance = ( camera.GlobalPosition - GlobalPosition ).Length();
|
||
|
|
||
|
if ( Mathf.Abs( _distance - distance ) < distanceTreshold )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
_distance = distance;
|
||
|
|
||
|
var mapped = MathX.RemapClamped( distance, minDistance, cullDistance, 1, 0 );
|
||
|
|
||
|
var mm = Multimesh;
|
||
|
|
||
|
// this.LogInfo( "MM", (int) distance, ( (int) ( 100 * mapped ) ) + "%", (int)( fillCurve.Sample( mapped ) * mm.InstanceCount) + " instances" );
|
||
|
|
||
|
|
||
|
if ( mm == null )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( distance >= cullDistance )
|
||
|
{
|
||
|
mm.VisibleInstanceCount = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
var count = Mathf.RoundToInt( fillCurve.Sample( mapped ) * mm.InstanceCount );
|
||
|
|
||
|
count = Mathf.Clamp( count, 0, mm.InstanceCount );
|
||
|
|
||
|
var fadeStart = count * ( 1 - scaleRange );
|
||
|
|
||
|
for ( int i = 0; i < count; i++ )
|
||
|
{
|
||
|
var cbasis = new Basis( cachedBasis[ i * 3 + 0 ], cachedBasis[ i * 3 + 1 ], cachedBasis[ i * 3 + 2 ] );
|
||
|
|
||
|
var trsf = new Transform3D( cbasis, cachedOrigins[ i ] );
|
||
|
|
||
|
if ( i >= fadeStart )
|
||
|
{
|
||
|
var amount = MathX.RemapClamped( i, fadeStart, count, 0, 1 );
|
||
|
var basis = trsf.Basis.Scaled( new Vector3( 1, Mathf.Max( ( 1f - amount ), 0.0001f ), 1 ));
|
||
|
|
||
|
var offsetTrsf = new Transform3D( basis, trsf.Origin + downMax * Vector3.Down);
|
||
|
|
||
|
mm.SetInstanceTransform( i, offsetTrsf );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
mm.SetInstanceTransform( i, trsf );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
mm.VisibleInstanceCount = count;
|
||
|
}
|
||
|
}
|
||
|
}
|