diff --git a/Runtime/Godot/NodeState.cs b/Runtime/Godot/NodeState.cs index 63119f8..d42999f 100644 --- a/Runtime/Godot/NodeState.cs +++ b/Runtime/Godot/NodeState.cs @@ -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(); + } + } + } } \ No newline at end of file diff --git a/Runtime/Procedural/Assets/Grass/Windy Grass Shader.gdshader b/Runtime/Procedural/Assets/Grass/Windy Grass Shader.gdshader index 34c95f1..da18f86 100644 --- a/Runtime/Procedural/Assets/Grass/Windy Grass Shader.gdshader +++ b/Runtime/Procedural/Assets/Grass/Windy Grass Shader.gdshader @@ -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 = 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 ); diff --git a/Runtime/Rendering/Assets/Foliage/FoliageData.cs b/Runtime/Rendering/Assets/Foliage/FoliageData.cs index 77c28bb..6392c71 100644 --- a/Runtime/Rendering/Assets/Foliage/FoliageData.cs +++ b/Runtime/Rendering/Assets/Foliage/FoliageData.cs @@ -26,6 +26,9 @@ namespace Rokojori public partial class FoliageData:Resource { + [Export] + public bool enabled = true; + [Export] public float cellSize = 1.0f; diff --git a/Runtime/Rendering/Assets/Foliage/FoliageRenderLayer.cs b/Runtime/Rendering/Assets/Foliage/FoliageRenderLayer.cs index 7186efc..8a677da 100644 --- a/Runtime/Rendering/Assets/Foliage/FoliageRenderLayer.cs +++ b/Runtime/Rendering/Assets/Foliage/FoliageRenderLayer.cs @@ -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 ) ); + } + } } } diff --git a/Runtime/Rendering/Assets/Foliage/FoliageRenderer.cs b/Runtime/Rendering/Assets/Foliage/FoliageRenderer.cs index 0e5004a..b0c07cf 100644 --- a/Runtime/Rendering/Assets/Foliage/FoliageRenderer.cs +++ b/Runtime/Rendering/Assets/Foliage/FoliageRenderer.cs @@ -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 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() ) {