2025-07-17 11:50:37 +00:00
|
|
|
using System.Collections;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using Godot;
|
|
|
|
using System;
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace Rokojori
|
|
|
|
{
|
|
|
|
/** <summary for="class FoliageRenderer">
|
|
|
|
|
|
|
|
<title>
|
|
|
|
A node to render foliage.
|
|
|
|
</title>
|
|
|
|
|
|
|
|
<description>
|
|
|
|
The GrassPatch has various settings to create a different styles of grass.
|
|
|
|
It allows to change the shapes of the blades, their number and distribution, their triangle count,
|
|
|
|
rotation and scale, LOD levels and much more.
|
|
|
|
|
|
|
|
|
|
|
|
</description>
|
|
|
|
|
|
|
|
</summary>
|
|
|
|
*/
|
|
|
|
|
|
|
|
[Tool]
|
|
|
|
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Scatterer.svg") ]
|
2025-07-18 12:06:09 +00:00
|
|
|
public partial class FoliageRenderer:Node3D
|
2025-07-17 11:50:37 +00:00
|
|
|
{
|
|
|
|
[Export]
|
2025-07-18 12:06:09 +00:00
|
|
|
public FoliageData[] foliage = [];
|
2025-07-17 11:50:37 +00:00
|
|
|
|
2025-07-19 06:22:56 +00:00
|
|
|
|
2025-07-18 14:45:23 +00:00
|
|
|
[Export( PropertyHint.Range, "0, 200" )]
|
|
|
|
public float quality = 100;
|
|
|
|
|
|
|
|
[Export]
|
|
|
|
public FoliageQualitySettings[] qualitySettingsAll;
|
|
|
|
|
2025-07-19 06:22:56 +00:00
|
|
|
[Export]
|
|
|
|
public Node3D[] obstacles = [];
|
|
|
|
|
|
|
|
[Export]
|
|
|
|
public float[] obstacleSizes = [];
|
|
|
|
|
|
|
|
Vector4[] obstaclesData = new Vector4[4];
|
|
|
|
|
|
|
|
public Vector4 GetObstacleData( int index )
|
|
|
|
{
|
|
|
|
return obstaclesData[ index ];
|
|
|
|
}
|
|
|
|
|
2025-07-17 11:50:37 +00:00
|
|
|
List<FoliageRenderLayer> renderLayers = [];
|
|
|
|
|
|
|
|
[Export]
|
|
|
|
public bool processLayers = true;
|
|
|
|
|
|
|
|
[Export]
|
|
|
|
public bool updateLayers = true;
|
|
|
|
|
|
|
|
[Export]
|
|
|
|
public Camera3D camera;
|
|
|
|
|
|
|
|
|
|
|
|
Camera3D _assignedCamera;
|
|
|
|
|
|
|
|
[Export]
|
|
|
|
public Texture2D noise;
|
|
|
|
|
|
|
|
public Camera3D GetAssignedCamera()
|
|
|
|
{
|
|
|
|
return _assignedCamera;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void _Process( double delta )
|
|
|
|
{
|
|
|
|
_assignedCamera = null;
|
|
|
|
|
2025-07-18 12:06:09 +00:00
|
|
|
if ( ! processLayers || foliage == null || foliage.Length == 0 )
|
2025-07-17 11:50:37 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-07-18 12:06:09 +00:00
|
|
|
|
|
|
|
|
2025-07-17 11:50:37 +00:00
|
|
|
if ( updateLayers || foliage.Length != renderLayers.Count )
|
|
|
|
{
|
|
|
|
updateLayers = false;
|
|
|
|
this.DestroyChildren();
|
|
|
|
renderLayers = foliage.Map<FoliageData,FoliageRenderLayer>( f => FoliageRenderLayer.Create( this, f ) ).ToList();
|
|
|
|
renderLayers.ForEach( r => r.data.Initialize( r ) );
|
|
|
|
}
|
|
|
|
|
2025-07-19 06:22:56 +00:00
|
|
|
if ( obstaclesData.Length != 4 )
|
|
|
|
{
|
|
|
|
obstaclesData = new Vector4[ 4];
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( int i = 0; i < obstaclesData.Length; i++ )
|
|
|
|
{
|
|
|
|
var position = obstacles == null || i >= obstacles.Length ? Vector3.Zero : obstacles[ i ].GlobalPosition;
|
|
|
|
var size = obstacleSizes == null || i >= obstacleSizes.Length ? 0 : obstacleSizes[ i ];
|
|
|
|
|
|
|
|
obstaclesData[ i ] = new Vector4( position.X, position.Y, position.Z, size );
|
|
|
|
}
|
|
|
|
|
2025-07-17 11:50:37 +00:00
|
|
|
|
|
|
|
if ( Engine.IsEditorHint() )
|
|
|
|
{
|
|
|
|
_assignedCamera = EditorInterface.Singleton.GetEditorViewport3D().GetCamera3D();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_assignedCamera = camera;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( _assignedCamera == null )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// this.LogInfo( "Processing", renderLayers.Count );
|
|
|
|
|
2025-07-18 12:06:09 +00:00
|
|
|
renderLayers.ForEach( r =>
|
|
|
|
{
|
|
|
|
if ( r == null )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
r.Update( delta );
|
|
|
|
}
|
|
|
|
);
|
2025-07-17 11:50:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|