rj-action-library/Runtime/Procedural/Scatter/Transform/ProjectOnColliders.cs

121 lines
2.9 KiB
C#

using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
namespace Rokojori
{
[Tool]
[GlobalClass]
public partial class ProjectOnColliders:Scatterer
{
[ExportGroup("Ray")]
[Export]
public Vector3 rayDirection = Vector3.Down;
[Export]
public float rayLength = 10;
[Export]
public Vector3 rayOffset = Vector3.Zero;
[ExportGroup("Normal")]
[Export(PropertyHint.Range, "0,1")]
public float rotationAlignment = 1;
[Export]
public bool discardSteepNormals = true;
[Export]
public Vector3 steepNormalDirection = Vector3.Down;
[Export(PropertyHint.Range, "0,180")]
public float steepNormalRemovalAngle = 0;
[ExportGroup("Collisions")]
[Export( PropertyHint.Layers3DPhysics)]
public uint collisionLayer = 0;
[Export]
public bool collideWithAreas = true;
[Export]
public bool collideWithBodies = true;
[Export]
public bool hitFromInside = true;
[Export]
public bool hitBackFaces = true;
protected override List<ScatterPoint> _Scatter( List<ScatterPoint> points )
{
var world = GetWorld3D();
var ray = new PhysicsRayQueryParameters3D();
var direction = rayDirection.Normalized();
var normalizedSteepNormalDirection = steepNormalDirection.Normalized();
var steepNormalRemovalTreshold = Mathf.Cos( Mathf.DegToRad( steepNormalRemovalAngle ) );
points.ForEach(
p =>
{
if ( ! p.visible )
{
return;
}
ray.From = p.globalPosition;
ray.To = ray.From + direction * rayLength;
var collisionData = CollisionData.FindCollision( world, ray,
( cd ) =>
{
if ( ! CollisionData.HasCollisionLayer( cd.collider ) )
{
return false;
}
var colliderCollisionLayer = CollisionData.GetCollisionLayer( cd.collider );
var collides = ( colliderCollisionLayer & collisionLayer ) != 0;
// RJLog.Log( "Collision With:", "collides", collides, "colliderLayer:", colliderCollisionLayer, "own", collisionLayer, "name:", cd.collider.Name );
return collides;
}
);
p.visible = collisionData != null;
if ( ! p.visible )
{
return;
}
if ( discardSteepNormals )
{
var dot = normalizedSteepNormalDirection.Dot( collisionData.normal );
if ( dot >= steepNormalRemovalTreshold )
{
p.visible = false;
return;
}
}
p.position = collisionData.position;
var alginedRotation =Math3D.AlignUp( p.rotation, collisionData.normal );
p.rotation = p.rotation.Slerp( alginedRotation, rotationAlignment );
}
);
return points;
}
}
}