146 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C#
		
	
	
	
		
		
			
		
	
	
			146 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C#
		
	
	
	
| 
								 | 
							
								using System.Collections;
							 | 
						||
| 
								 | 
							
								using System.Collections.Generic;
							 | 
						||
| 
								 | 
							
								using Godot;
							 | 
						||
| 
								 | 
							
								using System;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace Rokojori
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  [Tool]
							 | 
						||
| 
								 | 
							
								  [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Scatterer.svg") ]
							 | 
						||
| 
								 | 
							
								  public partial class BillboardTree:Node3D
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    float _startHeight = 2;
							 | 
						||
| 
								 | 
							
								    [Export]
							 | 
						||
| 
								 | 
							
								    public float startHeight 
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      get => _startHeight;
							 | 
						||
| 
								 | 
							
								      set { _startHeight = value; }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    float _endHeight = 7;
							 | 
						||
| 
								 | 
							
								    [Export]
							 | 
						||
| 
								 | 
							
								    public float endHeight 
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      get => _endHeight;
							 | 
						||
| 
								 | 
							
								      set { _endHeight = value; }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    [Export]
							 | 
						||
| 
								 | 
							
								    public Curve radiusShape;
							 | 
						||
| 
								 | 
							
								  	
							 | 
						||
| 
								 | 
							
								    [Export]
							 | 
						||
| 
								 | 
							
								    public MeshInstance3D leavesMesh;
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    [Export]
							 | 
						||
| 
								 | 
							
								    public Material leavesMaterial;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    [Export]
							 | 
						||
| 
								 | 
							
								    public int numRows = 5;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    [Export]
							 | 
						||
| 
								 | 
							
								    public Curve rowDensity = MathX.Curve( 0.2f, 0.8f ); 
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    [Export]
							 | 
						||
| 
								 | 
							
								    public Curve leavesSize = MathX.Curve( 0.2f, 0.8f );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    [Export]
							 | 
						||
| 
								 | 
							
								    public Curve leavesRotation = MathX.Curve( 0f, 360f );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    [Export]
							 | 
						||
| 
								 | 
							
								    public int seed = 2000;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    MeshGeometry mg;
							 | 
						||
| 
								 | 
							
								    RandomEngine random;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    [Export]
							 | 
						||
| 
								 | 
							
								    public bool update = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    [Export]
							 | 
						||
| 
								 | 
							
								    public bool updateAlways = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    public override void _Process( double d )
							 | 
						||
| 
								 | 
							
								    { 
							 | 
						||
| 
								 | 
							
								      if ( ! ( updateAlways || update ) )
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      update = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      Generate();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    void Generate()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      if ( leavesMesh == null )
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								        leavesMesh = this.CreateChild<MeshInstance3D>( "Leaves" );
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      mg = new MeshGeometry();      
							 | 
						||
| 
								 | 
							
								      random = LCG.WithSeed( seed );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      for ( int i = 0; i < numRows; i++ )
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								        CreateRow( i );
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      leavesMesh.Mesh = mg.GenerateMesh();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      Materials.Set( leavesMesh, leavesMaterial );
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    void CreateRow( int rowIndex )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      
							 | 
						||
| 
								 | 
							
								      var rowNormalized = rowIndex / (float) ( numRows - 1 );
							 | 
						||
| 
								 | 
							
								      var rowRadius = radiusShape.Sample( rowNormalized );
							 | 
						||
| 
								 | 
							
								      var rowDensityValue = random.Sample( rowDensity );
							 | 
						||
| 
								 | 
							
								      var numLeaves = Mathf.Ceil( rowRadius / rowDensityValue );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      var rowAngleOffset = random.Range( 0, 360f );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      //this.LogInfo( "index:", rowIndex, "leaves:", numLeaves );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      for ( int i = 0; i < numLeaves; i++ )
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								        var size =  random.Sample( leavesSize );
							 | 
						||
| 
								 | 
							
								        var leave = MeshGeometry.BillboardQuad( size );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        var angle = 360f * i / ( (float) numLeaves ) + rowAngleOffset;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        var position = Math3D.OnCircleXZ( MathX.DegreesToRadians * angle ) * rowRadius;
							 | 
						||
| 
								 | 
							
								        position.Y = Mathf.Lerp( startHeight, endHeight, rowNormalized );      
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        var rotation = random.Sample( leavesRotation );
							 | 
						||
| 
								 | 
							
								        //this.LogInfo( "index:", rowIndex, "leaves:", numLeaves, i, "size/angle", size, "/", angle, "pos:", position.X, position.Z );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        leave.ApplyTransform( position, Math3D.RotateZ( MathX.DegreesToRadians * rotation ), Vector3.One );         
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        var normal = position - new Vector3( 0, ( startHeight + endHeight ) / 2f, 0);
							 | 
						||
| 
								 | 
							
								        normal = normal.Normalized();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        this.LogInfo( "index:", rowIndex, "leaves:", numLeaves, i, normal );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        mg.Add( leave );
							 | 
						||
| 
								 | 
							
								        mg.NormalsLookAt( normal, 1 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        var clone = leave.Clone();
							 | 
						||
| 
								 | 
							
								        clone.FlipNormalDirection();
							 | 
						||
| 
								 | 
							
								        clone.NormalsLookAt( normal, 1 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        mg.Add( clone );
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 |