Grass FoliageRenderer Update

This commit is contained in:
Josef 2025-07-19 08:22:56 +02:00
parent 843b407bf5
commit e5166dd7cf
5 changed files with 127 additions and 2 deletions

View File

@ -70,5 +70,17 @@ namespace Rokojori
Set( n, false );
}
public static void SetEnabledState( this Node n, bool isEnabled )
{
if ( isEnabled )
{
n.Enable();
}
else
{
n.Disable();
}
}
}
}

View File

@ -46,6 +46,50 @@ uniform float windEnd = 1;
uniform float windWeightCurve:hint_range(0,1) = 0.5f;
uniform float windHeightCompensation :hint_range(0,1) = 0.5f;
uniform bool obstaclesEnabeld = false;
uniform vec4 obstacle1 = vec4( 0, 0, 0, 0 );
uniform vec4 obstacle2 = vec4( 0, 0, 0, 0 );
uniform vec4 obstacle3 = vec4( 0, 0, 0, 0 );
uniform vec4 obstacle4 = vec4( 0, 0, 0, 0 );
uniform float obstacleDeformation = 1.0;
uniform float obstacleScale = 1.0;
uniform float maxDeformation = 0.3;
uniform float maxYOffset = 0.1;
vec3 deform( vec3 worldPosition, vec4 obstacle )
{
vec3 direction = worldPosition - obstacle.xyz;
float d = length( direction );
float size = obstacle.w * obstacleScale;
if ( d <size && d >= 0.0 )
{
float amount = max( 0, ( size - d ) );
amount = pow( amount, obstacleDeformation );
return worldPosition + normalize( direction ) * amount;
}
return worldPosition;
}
vec3 limitDeform( vec3 originalWorldPosition, vec3 deformedWorldPosition )
{
vec3 direction =originalWorldPosition - deformedWorldPosition;
float d = length( direction );
vec3 outputPosition = deformedWorldPosition;
if ( d > maxDeformation )
{
outputPosition = originalWorldPosition + -normalize( direction ) * maxDeformation;
}
outputPosition.y = clamp( outputPosition.y, originalWorldPosition.y - maxYOffset, originalWorldPosition.y + maxYOffset );
return outputPosition;
}
void vertex()
{
@ -75,7 +119,23 @@ void vertex()
float angle = texture( windNoise, windUV + windNoiseAngleOffset).r * PI * 2.0;
float strength = texture( windNoise, windUV + windNoiseStrengthOffset ).r * windStrength;
vec2 circle = onCircle( angle ) * strength;
VERTEX = worldToLocal( worldVertex + vec3( circle.x, 0, circle.y ) * windAmount, MODEL_MATRIX );
vec3 originalWorldVertex = worldVertex;
worldVertex += vec3( circle.x, 0, circle.y ) * windAmount;
// VERTEX = worldToLocal( worldVertex + vec3( circle.x, 0, circle.y ) * windAmount, MODEL_MATRIX );
if ( obstaclesEnabeld )
{
worldVertex = deform( worldVertex, obstacle1 );
worldVertex = deform( worldVertex, obstacle2 );
worldVertex = deform( worldVertex, obstacle3 );
worldVertex = deform( worldVertex, obstacle4 );
worldVertex = limitDeform( originalWorldVertex, worldVertex );
}
VERTEX = worldToLocal( worldVertex, MODEL_MATRIX );
float minY = min( VERTEX.y, 0 ); // VERTEX.y = mix( VERTEX.y, max( 0, VERTEX.y - strength * windAmount), windHeightCompensation * 2.0f );
VERTEX.y = mix( VERTEX.y, max( minY, VERTEX.y - strength * windAmount), windHeightCompensation * 4.0f );

View File

@ -26,6 +26,9 @@ namespace Rokojori
public partial class FoliageData:Resource
{
[Export]
public bool enabled = true;
[Export]
public float cellSize = 1.0f;

View File

@ -42,10 +42,23 @@ namespace Rokojori
return rl;
}
bool _isEnabled = false;
public void Update( double delta )
{
if ( gpuFoliageShaderMaterial != null )
{
if ( data.enabled != _isEnabled)
{
_isEnabled = data.enabled;
gpuParticles3D.SetEnabledState( _isEnabled );
return;
}
if ( ! _isEnabled )
{
return;
}
gpuFoliageShaderMaterial.cameraPosition.Set( renderer.GetAssignedCamera().GlobalPosition );
@ -54,7 +67,7 @@ namespace Rokojori
var visibilityRange = FoliageQualitySettings.GetVisibilityRange( renderer.quality, renderer.qualitySettingsAll, data.qualitySettings, data.visibilityRange );
var sizeInt = Mathf.CeilToInt( visibilityRange / cellSize ) * 2;
if ( _lastCellSize != cellSize || _lastMaxVisibility != visibilityRange )
{
_lastCellSize = cellSize;
@ -105,6 +118,16 @@ namespace Rokojori
gpuFoliageShaderMaterial.occupancyUvScale.Set( Vector2.One * data.occupancyVarianceScale );
gpuFoliageShaderMaterial.occupancyUvOffset.Set( Vector2.One * data.occupancyVarianceOffset );
if ( gpuParticles3D.DrawPass1.SurfaceGetMaterial( 0 ) is ShaderMaterial drawMaterial )
{
drawMaterial.SetShaderParameter( "obstacle1", renderer.GetObstacleData( 0 ) );
drawMaterial.SetShaderParameter( "obstacle2", renderer.GetObstacleData( 1 ) );
drawMaterial.SetShaderParameter( "obstacle3", renderer.GetObstacleData( 2 ) );
drawMaterial.SetShaderParameter( "obstacle4", renderer.GetObstacleData( 3 ) );
// RJLog.Log( drawMaterial, renderer.GetObstacleData( 0 ) );
}
}
}
}

View File

@ -33,12 +33,26 @@ namespace Rokojori
[Export]
public FoliageData[] foliage = [];
[Export( PropertyHint.Range, "0, 200" )]
public float quality = 100;
[Export]
public FoliageQualitySettings[] qualitySettingsAll;
[Export]
public Node3D[] obstacles = [];
[Export]
public float[] obstacleSizes = [];
Vector4[] obstaclesData = new Vector4[4];
public Vector4 GetObstacleData( int index )
{
return obstaclesData[ index ];
}
List<FoliageRenderLayer> renderLayers = [];
[Export]
@ -80,6 +94,19 @@ namespace Rokojori
renderLayers.ForEach( r => r.data.Initialize( r ) );
}
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 );
}
if ( Engine.IsEditorHint() )
{