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; } } }