diff --git a/Runtime/Godot/Nodes.cs b/Runtime/Godot/Nodes.cs index e24b465..7cb044f 100644 --- a/Runtime/Godot/Nodes.cs +++ b/Runtime/Godot/Nodes.cs @@ -21,6 +21,16 @@ namespace Rokojori return GetAnyChild( node ); } + public static T GetSelfOrChildOf( this Node node ) where T:Node + { + if ( node is T t ) + { + return t; + } + + return GetAnyChild( node ); + } + public static T GetChild( this Node node ) where T:Node { return GetDirectChild( node ); diff --git a/Runtime/Math/Geometry/Box3.cs b/Runtime/Math/Geometry/Box3.cs index 9a67ca1..a7806e5 100644 --- a/Runtime/Math/Geometry/Box3.cs +++ b/Runtime/Math/Geometry/Box3.cs @@ -44,6 +44,20 @@ namespace Rokojori return b; } + public static Box3 WithSize( Vector3 size ) + { + size = size.Abs(); + var max = size * 0.5f; + var min = -max; + + return Box3.Create( min, max ); + } + + public static Box3 WithSize( float size ) + { + return WithSize( Vector3.One * size ); + } + public static Box3 Create( List data, System.Func getPosition ) { var min = new Vector3( float.MaxValue, float.MaxValue, float.MaxValue ); diff --git a/Runtime/Rendering/Assets/Foliage/Foliage Renderer Default Noise.png b/Runtime/Rendering/Assets/Foliage/Foliage Renderer Default Noise.png new file mode 100644 index 0000000..8e0d9bf Binary files /dev/null and b/Runtime/Rendering/Assets/Foliage/Foliage Renderer Default Noise.png differ diff --git a/Runtime/Rendering/Assets/Foliage/Foliage Renderer Default Noise.png.import b/Runtime/Rendering/Assets/Foliage/Foliage Renderer Default Noise.png.import new file mode 100644 index 0000000..e896ec0 --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/Foliage Renderer Default Noise.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c30nul6romace" +path.s3tc="res://.godot/imported/Foliage Renderer Default Noise.png-18f32fa6cf85749d36ab7c25bf9094e5.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://addons/rokojori_action_library/Runtime/Rendering/Assets/Foliage/Foliage Renderer Default Noise.png" +dest_files=["res://.godot/imported/Foliage Renderer Default Noise.png-18f32fa6cf85749d36ab7c25bf9094e5.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/Runtime/Rendering/Assets/Foliage/Foliage Renderer Default Noise.tres b/Runtime/Rendering/Assets/Foliage/Foliage Renderer Default Noise.tres new file mode 100644 index 0000000..3ba4dfe --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/Foliage Renderer Default Noise.tres @@ -0,0 +1,14 @@ +[gd_resource type="Resource" script_class="TextureCombiner" load_steps=2 format=3 uid="uid://bmesbkwqek8ck"] + +[ext_resource type="Script" uid="uid://2srq0trsfhq1" path="res://addons/rokojori_action_library/Runtime/Procedural/Textures/TextureCombiner/TextureCombiner.cs" id="1_10cp2"] + +[resource] +script = ExtResource("1_10cp2") +createMipmaps = true +create = false +autoCreate = false +width = 1024 +height = 1024 +_creatingTexture = false +_blockSize = 512 +metadata/_custom_type_script = "uid://2srq0trsfhq1" diff --git a/Runtime/Rendering/Assets/Foliage/FoliageData.cs b/Runtime/Rendering/Assets/Foliage/FoliageData.cs new file mode 100644 index 0000000..d853d4b --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/FoliageData.cs @@ -0,0 +1,105 @@ +using System.Collections; +using System.Collections.Generic; +using Godot; +using System; +using System.Threading.Tasks; + + + +namespace Rokojori +{ + /** + + + Resource to define foliage data + + + + + + + + */ + + [Tool] + [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Scatterer.svg") ] + public partial class FoliageData:Resource + { + + [Export] + public float cellSize; + + [Export] + public float visibilityRange; + + [Export] + public float visibilityFadeRelative = 0.1f; + + [Export] + public float visibilityFadeAbsolute = 0f; + + [Export] + public float visibilityFadeHidingOffset = -0.7f; + + /** Render priority, only for transparent objects*/ + [Export] + public int renderPriority; + + + + [Export] + public string layerName; + + [Export] + public Vector3 positionVarianceMaxOffset = Vector3.Zero; + [Export] + public float positionVarianceScale = 1f; + [Export] + public Vector2 positionVarianceOffset = Vector2.Zero; + + [Export] + public Vector3 rotationMin = Vector3.Zero; + [Export] + public Vector3 rotationMax = new Vector3( 0, 1, 0 ); + + [Export] + public float rotationVarianceScale = 1f; + [Export] + public Vector2 rotationVarianceOffset = Vector2.Zero; + + + [Export] + public Vector3 scaleVarianceMinScale = Vector3.One; + [Export] + public Vector3 scaleVarianceMaxScale = Vector3.One; + [Export] + public float scaleVarianceScale = 1f; + [Export] + public Vector2 scaleVarianceOffset = Vector2.Zero; + + + [Export(PropertyHint.Range,"0,1")] + public float occupancyVarianceAmount = 1f; + [Export(PropertyHint.Range,"0,50")] + public float occupancyVariancePower = 0f; + + [Export(PropertyHint.Range,"0,1")] + public float occupancyTreshold = 0f; + + [Export] + public float occupancyHideOffset = -3f; + [Export] + public float occupancyHideScale = 0.1f; + + [Export] + public float occupancyVarianceScale = 1f; + [Export] + public Vector2 occupancyVarianceOffset = Vector2.Zero; + + public virtual void Initialize( FoliageRenderLayer renderLayer ) + { + + } + + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Assets/Foliage/FoliageData.cs.uid b/Runtime/Rendering/Assets/Foliage/FoliageData.cs.uid new file mode 100644 index 0000000..ace599a --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/FoliageData.cs.uid @@ -0,0 +1 @@ +uid://bcl28l8d5lxye diff --git a/Runtime/Rendering/Assets/Foliage/FoliageRenderLayer.cs b/Runtime/Rendering/Assets/Foliage/FoliageRenderLayer.cs new file mode 100644 index 0000000..eb34cc2 --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/FoliageRenderLayer.cs @@ -0,0 +1,106 @@ +using System.Collections; +using System.Collections.Generic; +using Godot; +using System; +using System.Threading.Tasks; + + + +namespace Rokojori +{ + /** + + + Is used by the FoliageRenderer to book keep and render a layer defined by the FoliageData. + + + + + + + + + + */ + + public class FoliageRenderLayer + { + public FoliageRenderer renderer; + public FoliageData data; + public GpuParticles3D gpuParticles3D; + public GPUFoliageShaderMaterial gpuFoliageShaderMaterial; + float _lastCellSize = -1; + float _lastMaxVisibility = -1; + + public static FoliageRenderLayer Create( FoliageRenderer renderer, FoliageData data ) + { + var rl = new FoliageRenderLayer(); + rl.renderer = renderer; + rl.data = data; + + + return rl; + } + + public void Update( double delta ) + { + if ( gpuFoliageShaderMaterial != null ) + { + gpuFoliageShaderMaterial.cameraPosition.Set( renderer.GetAssignedCamera().GlobalPosition ); + + var sizeInt = Mathf.CeilToInt( data.visibilityRange / data.cellSize ) * 2; + + if ( _lastCellSize != data.cellSize || _lastMaxVisibility != data.visibilityRange ) + { + _lastCellSize = data.cellSize; + _lastMaxVisibility = data.visibilityRange; + + gpuFoliageShaderMaterial.cellSize.Set( data.cellSize ); + + + + + gpuParticles3D.Amount = sizeInt * sizeInt; + gpuFoliageShaderMaterial.width.Set( sizeInt ); + gpuFoliageShaderMaterial.height.Set( sizeInt ); + + } + + var hideStart = data.visibilityRange - ( data.visibilityRange * data.visibilityFadeRelative + data.visibilityFadeAbsolute ); + gpuFoliageShaderMaterial.hideMax.Set( data.visibilityRange ); + gpuFoliageShaderMaterial.hideStart.Set( hideStart ); + gpuFoliageShaderMaterial.hideOffset.Set( data.visibilityFadeHidingOffset ); + + gpuFoliageShaderMaterial.positionVariance.Set( renderer.noise ); + gpuFoliageShaderMaterial.rotationVariance.Set( renderer.noise ); + gpuFoliageShaderMaterial.scaleVariance.Set( renderer.noise ); + gpuFoliageShaderMaterial.occupancyVariance.Set( renderer.noise ); + + gpuFoliageShaderMaterial.maxPositionOffset.Set( data.positionVarianceMaxOffset ); + gpuFoliageShaderMaterial.positionUvScale.Set( Vector2.One * data.positionVarianceScale ); + gpuFoliageShaderMaterial.positionUvOffset.Set( Vector2.One * data.positionVarianceOffset ); + + gpuFoliageShaderMaterial.minRotation.Set( data.rotationMin ); + gpuFoliageShaderMaterial.maxRotation.Set( data.rotationMax ); + gpuFoliageShaderMaterial.rotationUvScale.Set( Vector2.One * data.rotationVarianceScale ); + gpuFoliageShaderMaterial.rotationUvOffset.Set( Vector2.One * data.rotationVarianceOffset ); + + gpuFoliageShaderMaterial.minScale.Set( data.scaleVarianceMinScale ); + gpuFoliageShaderMaterial.maxScale.Set( data.scaleVarianceMaxScale ); + gpuFoliageShaderMaterial.scaleUvScale.Set( Vector2.One * data.scaleVarianceScale ); + gpuFoliageShaderMaterial.scaleUvOffset.Set( Vector2.One * data.scaleVarianceOffset ); + + gpuFoliageShaderMaterial.occupancyAmount.Set( data.occupancyVarianceAmount ); + gpuFoliageShaderMaterial.occupancyPower.Set( data.occupancyVariancePower ); + gpuFoliageShaderMaterial.occupancyTreshold.Set( data.occupancyTreshold ); + + gpuFoliageShaderMaterial.occupancyHideOffset.Set( data.occupancyHideOffset ); + gpuFoliageShaderMaterial.occupancyHideScale.Set( data.occupancyHideScale ); + + gpuFoliageShaderMaterial.occupancyUvScale.Set( Vector2.One * data.occupancyVarianceScale ); + gpuFoliageShaderMaterial.occupancyUvOffset.Set( Vector2.One * data.occupancyVarianceOffset ); + + } + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Assets/Foliage/FoliageRenderLayer.cs.uid b/Runtime/Rendering/Assets/Foliage/FoliageRenderLayer.cs.uid new file mode 100644 index 0000000..574577a --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/FoliageRenderLayer.cs.uid @@ -0,0 +1 @@ +uid://6ie7ggcqvjtj diff --git a/Runtime/Rendering/Assets/Foliage/FoliageRenderer.cs b/Runtime/Rendering/Assets/Foliage/FoliageRenderer.cs new file mode 100644 index 0000000..9da24c7 --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/FoliageRenderer.cs @@ -0,0 +1,97 @@ +using System.Collections; +using System.Collections.Generic; +using Godot; +using System; +using System.Threading.Tasks; +using System.Linq; + + + +namespace Rokojori +{ + /** + + + A node to render foliage. + + + + 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. + + + + + + */ + + [Tool] + [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Scatterer.svg") ] + public partial class FoliageRenderer:Node + { + [Export] + public FoliageData[] foliage; + + List 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; + + if ( ! processLayers ) + { + return; + } + + if ( updateLayers || foliage.Length != renderLayers.Count ) + { + updateLayers = false; + this.DestroyChildren(); + renderLayers = foliage.Map( f => FoliageRenderLayer.Create( this, f ) ).ToList(); + renderLayers.ForEach( r => r.data.Initialize( r ) ); + } + + + if ( Engine.IsEditorHint() ) + { + _assignedCamera = EditorInterface.Singleton.GetEditorViewport3D().GetCamera3D(); + } + else + { + _assignedCamera = camera; + } + + if ( _assignedCamera == null ) + { + return; + } + + + // this.LogInfo( "Processing", renderLayers.Count ); + + renderLayers.ForEach( r => r.Update( delta ) ); + } + + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Assets/Foliage/FoliageRenderer.cs.uid b/Runtime/Rendering/Assets/Foliage/FoliageRenderer.cs.uid new file mode 100644 index 0000000..8d26b70 --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/FoliageRenderer.cs.uid @@ -0,0 +1 @@ +uid://b1sjdhnriaeg6 diff --git a/Runtime/Rendering/Assets/Foliage/GPUFoliageGroundCoverage.gdshader b/Runtime/Rendering/Assets/Foliage/GPUFoliageGroundCoverage.gdshader new file mode 100644 index 0000000..20eb809 --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/GPUFoliageGroundCoverage.gdshader @@ -0,0 +1,75 @@ +shader_type spatial; +render_mode blend_mix, depth_draw_never, cull_back, diffuse_burley, specular_schlick_ggx; + +#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Transform.gdshaderinc" +#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Math.gdshaderinc" + +uniform vec4 albedo : source_color; +uniform sampler2D albedoTexture: source_color, filter_linear_mipmap, repeat_enable; +uniform float albedoUV; +uniform float albedoFadeDistance; + +uniform sampler2D opacity : filter_linear_mipmap, repeat_enable; +uniform float opacityVarianceScale = 1.0; +uniform float opacityScale = 1.0; +uniform float opacityTreshold = 0.5; + +uniform float opacityVarianceScale2 = 1.0; +uniform float opacityScale2 = 1.0; +uniform float opacityTreshold2 = 0.5; +uniform float opacity2Amount: hint_range( 0.0, 1.0 ) = 0.5; + +uniform float roughness : hint_range( 0.0, 1.0 ); +uniform float specular : hint_range( 0.0, 1.0 ); +uniform float metallic : hint_range( 0.0, 1.0 ); + +uniform sampler2D texture_normal : hint_roughness_normal, filter_linear_mipmap, repeat_enable; +uniform float normal_scale : hint_range(0, 2); +uniform float normal_uv = 1.0; + +uniform vec2 mapSize; +uniform vec2 mapCenter; + +uniform float fadeOutMax; +uniform float fadeOutStart; + +varying vec2 positionUV; + +void vertex() +{ + VERTEX += CAMERA_POSITION_WORLD * vec3( 1.0, 0.0, 1.0); + + positionUV = UV; + + UV = worldUVfromLocalXZ( VERTEX, mapCenter, mapSize, MODEL_MATRIX ); +} + +void fragment() +{ + vec2 uv = UV; + + float d = length( positionUV - vec2( 0.5, 0.5 ) ); + float fading = 1.0 - clamp01( d / 0.5 ); + float albedoFading = 1.0 - clamp01( d / albedoFadeDistance ); + vec4 sampledAlbedo = texture( albedoTexture, uv * albedoUV ); + ALBEDO = albedo.rgb * mix( vec3( 1, 1, 1 ), sampledAlbedo.rgb, albedoFading ); + + METALLIC = metallic; + SPECULAR = specular; + ROUGHNESS = roughness; + + float sampledOpacity = texture( opacity, uv * opacityVarianceScale ).r; + sampledOpacity = ( sampledOpacity - opacityTreshold ) * opacityScale + opacityTreshold; + sampledOpacity = clamp01( sampledOpacity ); + + float sampledOpacity2 = texture( opacity, uv * opacityVarianceScale2 ).r; + sampledOpacity2 = ( sampledOpacity2 - opacityTreshold2 ) * opacityScale2 + opacityTreshold2; + sampledOpacity2 = mix( 1, clamp01( sampledOpacity2 ), opacity2Amount ); + + + + NORMAL_MAP = texture( texture_normal, uv * normal_uv ).rgb; + NORMAL_MAP_DEPTH = normal_scale; + + ALPHA *= albedo.a * sampledOpacity * sampledOpacity2 * mix( 1, sampledAlbedo.a, albedoFading ) * fading; +} diff --git a/Runtime/Rendering/Assets/Foliage/GPUFoliageGroundCoverage.gdshader.uid b/Runtime/Rendering/Assets/Foliage/GPUFoliageGroundCoverage.gdshader.uid new file mode 100644 index 0000000..2db60a1 --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/GPUFoliageGroundCoverage.gdshader.uid @@ -0,0 +1 @@ +uid://dffj0xp766wka diff --git a/Runtime/Rendering/Assets/Foliage/GPUFoliageShader.gdshader b/Runtime/Rendering/Assets/Foliage/GPUFoliageShader.gdshader new file mode 100644 index 0000000..711434e --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/GPUFoliageShader.gdshader @@ -0,0 +1,97 @@ +shader_type particles; +#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Transform.gdshaderinc" +#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Math.gdshaderinc" +#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Textures.gdshaderinc" + +uniform vec3 cameraPosition; +uniform float yaw; +uniform float cellSize = 1.0; +uniform int width = 10; +uniform int height = 10; + +uniform sampler2D positionVariance; +uniform vec3 maxPositionOffset = vec3(0,0,0); +uniform vec2 positionUVScale = vec2( 1.0, 1.0 ); +uniform vec2 positionUVOffset = vec2( 1.0, 1.0 ); +uniform float heightOffset = 0; + +uniform sampler2D rotationVariance; +uniform vec3 minRotation = vec3( 0, 0, 0 ); +uniform vec3 maxRotation = vec3( 0, 1, 0 ); +uniform vec2 rotationUVScale = vec2( 1.0, 1.0 ); +uniform vec2 rotationUVOffset = vec2( 1.0, 1.0 ); + +uniform sampler2D scaleVariance; +uniform vec3 minScale = vec3( 1, 1, 1 ); +uniform vec3 maxScale = vec3( 1, 1, 1 ); +uniform vec2 scaleUVScale = vec2( 1.0, 1.0 ); +uniform vec2 scaleUVOffset = vec2( 1.0, 1.0 ); + +uniform float occupancyAmount = 0; +uniform float occupancyPower = 0; +uniform float occupancyTreshold = 0.5; +uniform float occupancyHideOffset = -3; +uniform float occupancyHideScale = 0.1; + +uniform sampler2D occupancyVariance; +uniform vec2 occupancyUVScale = vec2( 1.0, 1.0 ); +uniform vec2 occupancyUVOffset = vec2( 1.0, 1.0 ); + +uniform float hideStart = 40; +uniform float hideMax = 60; +uniform float hideOffset = -0.6; + +uniform vec2 mapSize = vec2(1024,1024); +uniform vec2 mapCenter = vec2(0,0); + +vec2 indexToPosition( int index ) +{ + int x = index % width; + int y = index / height; + + return vec2( float(x), float(y) ); +} + +void process() +{ + vec2 position = indexToPosition( int(INDEX) ); + float rotation = round( 4.0 * yaw / 360.0 ) * PI / 2.0; + + vec3 snappedCameraPosition = vec3( + floor( cameraPosition.x / cellSize ) * cellSize, + 0, + floor( cameraPosition.z / cellSize ) * cellSize + ); + + vec2 origin = vec2( float(width)/2.0, float(height)/2.0 ); + position -= origin; + + position = rotate_v2( position, rotation ) * cellSize; + + + vec3 position3D = vec3( position.x, heightOffset, position.y ) + snappedCameraPosition; + + float d = length( position3D - cameraPosition ); + float yOffset = mapClamped( d, hideStart, hideMax, 0, hideOffset ); + position3D.y += yOffset; + + + vec2 mapOffset = mapCenter - mapSize/2.0; + vec2 uv = ( vec2( position3D.x, position3D.z ) - mapOffset ) / mapSize; + + vec3 offset = (textureLod( positionVariance, tilingOffset( uv, positionUVScale, positionUVOffset ), 0 ).rgb - vec3(0.5,0.5,0.5) ) * maxPositionOffset; + position3D += offset; + vec3 rotSampled = textureLod( rotationVariance, tilingOffset( uv, rotationUVScale, rotationUVOffset ), 0 ).rgb; + vec3 rot = ( rotSampled * ( maxRotation - minRotation ) + minRotation ) * PI * 2.0; + // rot.y = round( 4.0 * rot.y / PI * 2.0 ) / 4.0 * PI * 2.0; + vec3 sca = textureLod( scaleVariance, tilingOffset( uv, scaleUVScale, scaleUVOffset ), 0 ).rgb; + sca = sca * ( maxScale - minScale ) + minScale; + + vec2 uv2 = ( vec2( position3D.x, position3D.z ) - mapOffset ) / mapSize; + + float occ = textureLod( occupancyVariance, tilingOffset( uv2, occupancyUVScale, occupancyUVOffset ), 0 ).r; + occ = clamp( ( occ - occupancyTreshold ) * occupancyPower + occupancyTreshold, 0.0, 1.0 ); + sca *= mix( 1.0, occupancyHideScale , ( 1.0 - occ ) * occupancyAmount ); + position3D.y += ( 1.0 - occ ) * occupancyAmount * occupancyHideOffset; + TRANSFORM = TRS( position3D, rot, vec3( sca.x , sca.y, sca.z ) ); +} diff --git a/Runtime/Rendering/Assets/Foliage/GPUFoliageShader.gdshader.uid b/Runtime/Rendering/Assets/Foliage/GPUFoliageShader.gdshader.uid new file mode 100644 index 0000000..05e45ad --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/GPUFoliageShader.gdshader.uid @@ -0,0 +1 @@ +uid://brk5g221ccd2x diff --git a/Runtime/Rendering/Assets/Foliage/GPUFoliageShaderMaterial.cs b/Runtime/Rendering/Assets/Foliage/GPUFoliageShaderMaterial.cs new file mode 100644 index 0000000..f6d3df8 --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/GPUFoliageShaderMaterial.cs @@ -0,0 +1,129 @@ +using Godot; + +namespace Rokojori +{ + // Generated by ShaderClassGenerator + + public class GPUFoliageShaderShader + { + public static readonly CachedResource shader = new CachedResource( + "res://addons/rokojori_action_library/Runtime/Rendering/Assets/Foliage/GPUFoliageShader.gdshader" + ); + + public static readonly Vector3PropertyName cameraPosition = Vector3PropertyName.Create( "cameraPosition" ); + public static readonly FloatPropertyName yaw = FloatPropertyName.Create( "yaw" ); + public static readonly FloatPropertyName cellSize = FloatPropertyName.Create( "cellSize" ); + public static readonly IntPropertyName width = IntPropertyName.Create( "width" ); + public static readonly IntPropertyName height = IntPropertyName.Create( "height" ); + public static readonly Texture2DPropertyName positionVariance = Texture2DPropertyName.Create( "positionVariance" ); + public static readonly Vector3PropertyName maxPositionOffset = Vector3PropertyName.Create( "maxPositionOffset" ); + public static readonly Vector2PropertyName positionUvScale = Vector2PropertyName.Create( "positionUVScale" ); + public static readonly Vector2PropertyName positionUvOffset = Vector2PropertyName.Create( "positionUVOffset" ); + public static readonly FloatPropertyName heightOffset = FloatPropertyName.Create( "heightOffset" ); + public static readonly Texture2DPropertyName rotationVariance = Texture2DPropertyName.Create( "rotationVariance" ); + public static readonly Vector3PropertyName minRotation = Vector3PropertyName.Create( "minRotation" ); + public static readonly Vector3PropertyName maxRotation = Vector3PropertyName.Create( "maxRotation" ); + public static readonly Vector2PropertyName rotationUvScale = Vector2PropertyName.Create( "rotationUVScale" ); + public static readonly Vector2PropertyName rotationUvOffset = Vector2PropertyName.Create( "rotationUVOffset" ); + public static readonly Texture2DPropertyName scaleVariance = Texture2DPropertyName.Create( "scaleVariance" ); + public static readonly Vector3PropertyName minScale = Vector3PropertyName.Create( "minScale" ); + public static readonly Vector3PropertyName maxScale = Vector3PropertyName.Create( "maxScale" ); + public static readonly Vector2PropertyName scaleUvScale = Vector2PropertyName.Create( "scaleUVScale" ); + public static readonly Vector2PropertyName scaleUvOffset = Vector2PropertyName.Create( "scaleUVOffset" ); + public static readonly FloatPropertyName occupancyAmount = FloatPropertyName.Create( "occupancyAmount" ); + public static readonly FloatPropertyName occupancyPower = FloatPropertyName.Create( "occupancyPower" ); + public static readonly FloatPropertyName occupancyTreshold = FloatPropertyName.Create( "occupancyTreshold" ); + public static readonly FloatPropertyName occupancyHideOffset = FloatPropertyName.Create( "occupancyHideOffset" ); + public static readonly FloatPropertyName occupancyHideScale = FloatPropertyName.Create( "occupancyHideScale" ); + public static readonly Texture2DPropertyName occupancyVariance = Texture2DPropertyName.Create( "occupancyVariance" ); + public static readonly Vector2PropertyName occupancyUvScale = Vector2PropertyName.Create( "occupancyUVScale" ); + public static readonly Vector2PropertyName occupancyUvOffset = Vector2PropertyName.Create( "occupancyUVOffset" ); + public static readonly FloatPropertyName hideStart = FloatPropertyName.Create( "hideStart" ); + public static readonly FloatPropertyName hideMax = FloatPropertyName.Create( "hideMax" ); + public static readonly FloatPropertyName hideOffset = FloatPropertyName.Create( "hideOffset" ); + public static readonly Vector2PropertyName mapSize = Vector2PropertyName.Create( "mapSize" ); + public static readonly Vector2PropertyName mapCenter = Vector2PropertyName.Create( "mapCenter" ); + + } + + [Tool] + public partial class GPUFoliageShaderMaterial:CustomMaterial + { + + + public readonly CustomMaterialProperty cameraPosition; + public readonly CustomMaterialProperty yaw; + public readonly CustomMaterialProperty cellSize; + public readonly CustomMaterialProperty width; + public readonly CustomMaterialProperty height; + public readonly CustomMaterialProperty positionVariance; + public readonly CustomMaterialProperty maxPositionOffset; + public readonly CustomMaterialProperty positionUvScale; + public readonly CustomMaterialProperty positionUvOffset; + public readonly CustomMaterialProperty heightOffset; + public readonly CustomMaterialProperty rotationVariance; + public readonly CustomMaterialProperty minRotation; + public readonly CustomMaterialProperty maxRotation; + public readonly CustomMaterialProperty rotationUvScale; + public readonly CustomMaterialProperty rotationUvOffset; + public readonly CustomMaterialProperty scaleVariance; + public readonly CustomMaterialProperty minScale; + public readonly CustomMaterialProperty maxScale; + public readonly CustomMaterialProperty scaleUvScale; + public readonly CustomMaterialProperty scaleUvOffset; + public readonly CustomMaterialProperty occupancyAmount; + public readonly CustomMaterialProperty occupancyPower; + public readonly CustomMaterialProperty occupancyTreshold; + public readonly CustomMaterialProperty occupancyHideOffset; + public readonly CustomMaterialProperty occupancyHideScale; + public readonly CustomMaterialProperty occupancyVariance; + public readonly CustomMaterialProperty occupancyUvScale; + public readonly CustomMaterialProperty occupancyUvOffset; + public readonly CustomMaterialProperty hideStart; + public readonly CustomMaterialProperty hideMax; + public readonly CustomMaterialProperty hideOffset; + public readonly CustomMaterialProperty mapSize; + public readonly CustomMaterialProperty mapCenter; + + public GPUFoliageShaderMaterial() + { + Shader = GPUFoliageShaderShader.shader.Get(); + + cameraPosition = new CustomMaterialProperty( this, GPUFoliageShaderShader.cameraPosition ); + yaw = new CustomMaterialProperty( this, GPUFoliageShaderShader.yaw ); + cellSize = new CustomMaterialProperty( this, GPUFoliageShaderShader.cellSize ); + width = new CustomMaterialProperty( this, GPUFoliageShaderShader.width ); + height = new CustomMaterialProperty( this, GPUFoliageShaderShader.height ); + positionVariance = new CustomMaterialProperty( this, GPUFoliageShaderShader.positionVariance ); + maxPositionOffset = new CustomMaterialProperty( this, GPUFoliageShaderShader.maxPositionOffset ); + positionUvScale = new CustomMaterialProperty( this, GPUFoliageShaderShader.positionUvScale ); + positionUvOffset = new CustomMaterialProperty( this, GPUFoliageShaderShader.positionUvOffset ); + heightOffset = new CustomMaterialProperty( this, GPUFoliageShaderShader.heightOffset ); + rotationVariance = new CustomMaterialProperty( this, GPUFoliageShaderShader.rotationVariance ); + minRotation = new CustomMaterialProperty( this, GPUFoliageShaderShader.minRotation ); + maxRotation = new CustomMaterialProperty( this, GPUFoliageShaderShader.maxRotation ); + rotationUvScale = new CustomMaterialProperty( this, GPUFoliageShaderShader.rotationUvScale ); + rotationUvOffset = new CustomMaterialProperty( this, GPUFoliageShaderShader.rotationUvOffset ); + scaleVariance = new CustomMaterialProperty( this, GPUFoliageShaderShader.scaleVariance ); + minScale = new CustomMaterialProperty( this, GPUFoliageShaderShader.minScale ); + maxScale = new CustomMaterialProperty( this, GPUFoliageShaderShader.maxScale ); + scaleUvScale = new CustomMaterialProperty( this, GPUFoliageShaderShader.scaleUvScale ); + scaleUvOffset = new CustomMaterialProperty( this, GPUFoliageShaderShader.scaleUvOffset ); + occupancyAmount = new CustomMaterialProperty( this, GPUFoliageShaderShader.occupancyAmount ); + occupancyPower = new CustomMaterialProperty( this, GPUFoliageShaderShader.occupancyPower ); + occupancyTreshold = new CustomMaterialProperty( this, GPUFoliageShaderShader.occupancyTreshold ); + occupancyHideOffset = new CustomMaterialProperty( this, GPUFoliageShaderShader.occupancyHideOffset ); + occupancyHideScale = new CustomMaterialProperty( this, GPUFoliageShaderShader.occupancyHideScale ); + occupancyVariance = new CustomMaterialProperty( this, GPUFoliageShaderShader.occupancyVariance ); + occupancyUvScale = new CustomMaterialProperty( this, GPUFoliageShaderShader.occupancyUvScale ); + occupancyUvOffset = new CustomMaterialProperty( this, GPUFoliageShaderShader.occupancyUvOffset ); + hideStart = new CustomMaterialProperty( this, GPUFoliageShaderShader.hideStart ); + hideMax = new CustomMaterialProperty( this, GPUFoliageShaderShader.hideMax ); + hideOffset = new CustomMaterialProperty( this, GPUFoliageShaderShader.hideOffset ); + mapSize = new CustomMaterialProperty( this, GPUFoliageShaderShader.mapSize ); + mapCenter = new CustomMaterialProperty( this, GPUFoliageShaderShader.mapCenter ); + } + + } + +} \ No newline at end of file diff --git a/Runtime/Rendering/Assets/Foliage/GPUFoliageShaderMaterial.cs.uid b/Runtime/Rendering/Assets/Foliage/GPUFoliageShaderMaterial.cs.uid new file mode 100644 index 0000000..3cbc5f5 --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/GPUFoliageShaderMaterial.cs.uid @@ -0,0 +1 @@ +uid://c4hg6rvrmjm6j diff --git a/Runtime/Rendering/Assets/Foliage/SceneFoliageData.cs b/Runtime/Rendering/Assets/Foliage/SceneFoliageData.cs new file mode 100644 index 0000000..4ceb0f6 --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/SceneFoliageData.cs @@ -0,0 +1,69 @@ +using System.Collections; +using System.Collections.Generic; +using Godot; +using System; +using System.Threading.Tasks; + + + +namespace Rokojori +{ + /** + + + A node to render foliage. + + + + 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. + + + + + + */ + + [Tool] + [GlobalClass] + public partial class SceneFoliageData:FoliageData + { + [Export] + public SceneReference sceneReference; + + public override void Initialize( FoliageRenderLayer renderLayer ) + { + var particles = renderLayer.renderer.CreateChild(); + + renderLayer.gpuParticles3D = particles; + + var processMaterial = new GPUFoliageShaderMaterial(); + particles.ProcessMaterial = processMaterial; + particles.Lifetime = 0.01f; + particles.Explosiveness = 1f; + particles.FixedFps = 0; + particles.Interpolate = false; + particles.FractDelta = false; + + particles.CustomAabb = Box3.WithSize( 10000 ); + + processMaterial.positionVariance.Set( renderLayer.renderer.noise ); + processMaterial.rotationVariance.Set( renderLayer.renderer.noise ); + processMaterial.scaleVariance.Set( renderLayer.renderer.noise ); + processMaterial.occupancyVariance.Set( renderLayer.renderer.noise ); + + renderLayer.gpuFoliageShaderMaterial = processMaterial; + + var packedScene = sceneReference.LoadScene(); + var sceneRoot = packedScene.Instantiate(); + + this.LogInfo( packedScene, sceneRoot ); + + var meshInstance = sceneRoot.GetSelfOrChildOf(); + particles.DrawPasses = 1; + particles.DrawPass1 = meshInstance.Mesh; + + } + } +} \ No newline at end of file diff --git a/Runtime/Rendering/Assets/Foliage/SceneFoliageData.cs.uid b/Runtime/Rendering/Assets/Foliage/SceneFoliageData.cs.uid new file mode 100644 index 0000000..f84ee14 --- /dev/null +++ b/Runtime/Rendering/Assets/Foliage/SceneFoliageData.cs.uid @@ -0,0 +1 @@ +uid://cm7ayfu511ijr diff --git a/Runtime/Scenes/SceneReference.cs b/Runtime/Scenes/SceneReference.cs new file mode 100644 index 0000000..ed9ed33 --- /dev/null +++ b/Runtime/Scenes/SceneReference.cs @@ -0,0 +1,34 @@ +using System.Collections; +using System.Collections.Generic; +using Godot; +using System; +using System.Threading.Tasks; +using System.Linq; + + + +namespace Rokojori +{ + /** + + + A resource to reference scenes safely by path. + + + + When the path is assigned, it will be updated, when the path moves. + + + + */ + + [Tool] + [GlobalClass ] + public partial class SceneReference:Resource + { + [Export(PropertyHint.File, "*.tscn,*.gltf,*.glb,*.fbx,*.obj,*.dae")] + public string scenePath; + + public PackedScene LoadScene() => scenePath == null || scenePath == "" ? null : GD.Load( scenePath ); + } +} \ No newline at end of file diff --git a/Runtime/Scenes/SceneReference.cs.uid b/Runtime/Scenes/SceneReference.cs.uid new file mode 100644 index 0000000..e838374 --- /dev/null +++ b/Runtime/Scenes/SceneReference.cs.uid @@ -0,0 +1 @@ +uid://d18oon3mkd5s4 diff --git a/Runtime/Shading/Library/Textures.gdshaderinc b/Runtime/Shading/Library/Textures.gdshaderinc index d86aca9..9118bda 100644 --- a/Runtime/Shading/Library/Textures.gdshaderinc +++ b/Runtime/Shading/Library/Textures.gdshaderinc @@ -140,3 +140,7 @@ vec3 heightMapNormalSmoothed( sampler2D terrain, vec2 terrainUV, vec2 kernelSize return normalize( n0 + n1 + n2 ); } +vec2 tilingOffset( vec2 uv, vec2 scale, vec2 offset ) +{ + return uv * scale + offset; +} \ No newline at end of file diff --git a/Runtime/Shading/Library/Transform.gdshaderinc b/Runtime/Shading/Library/Transform.gdshaderinc index 755ebc3..95555fa 100644 --- a/Runtime/Shading/Library/Transform.gdshaderinc +++ b/Runtime/Shading/Library/Transform.gdshaderinc @@ -577,6 +577,22 @@ mat4 mixTRS( mat4 a, mat4 b, float t ) vec3 o = mix( oA, oB, t ); vec3 s = mix( sA, sB, t ); vec4 r = quaternionSlerp( rA, rB, t ); - + return TRS( o, r, s ); +} + +vec2 worldUVfromWorldXZ( vec3 worldVertex, vec2 centerXZ, vec2 sizeXZ ) +{ + vec2 worldUV = vec2( worldVertex.x, worldVertex.z ); + + vec2 mapOffset = centerXZ - sizeXZ / 2.0; + + return ( worldUV - mapOffset ) / sizeXZ; +} + +vec2 worldUVfromLocalXZ( vec3 localVertex, vec2 centerXZ, vec2 sizeXZ, mat4 _MODEL_MATRIX ) +{ + vec3 worldVertex = localToWorld( localVertex, _MODEL_MATRIX ); + + return worldUVfromWorldXZ( worldVertex, centerXZ, sizeXZ ); } \ No newline at end of file diff --git a/Runtime/Tools/Arrays.cs b/Runtime/Tools/Arrays.cs index 98d07a2..ea325dd 100644 --- a/Runtime/Tools/Arrays.cs +++ b/Runtime/Tools/Arrays.cs @@ -22,7 +22,7 @@ namespace Rokojori return Array.IndexOf( values, other ); } - public static U[] Map( T[] values, Func mapper ) + public static U[] Map( this T[] values, Func mapper ) { var u = new U[ values.Length ]; diff --git a/Tools/gltf-export/GLTFExport.cs b/Tools/gltf-export/GLTFExport.cs index 6f5024b..9d794f2 100644 --- a/Tools/gltf-export/GLTFExport.cs +++ b/Tools/gltf-export/GLTFExport.cs @@ -16,6 +16,18 @@ namespace Rokojori.Tools public static void Save( Node3D node, string path, string texturesPath = null, string binPath = null ) { + if ( ! path.EndsWith( ".gltf" ) ) + { + if ( path.EndsWith( ".glb" ) ) + { + path.ReplaceEnd( ".glb", ".gltf" ); + } + else + { + path += ".gltf"; + } + } + FilesSync.EnsureParentDirectoryExists( path ); if ( binPath != null ) @@ -43,7 +55,7 @@ namespace Rokojori.Tools var gltfFilePath = FilePath.Absolute( path ); // Defines file name and gltfPath; var gltfParentFilePath = gltfFilePath.CreateAbsoluteParent(); var texturesDirPath = FilePath.Absolute( texturesPath ); // Only directory for textures - var binDirPath = FilePath.Absolute( binPath ); // Only directory for bins, name comes from gltf. + var binDirPath = binPath == null ? gltfParentFilePath : FilePath.Absolute( binPath ); // Only directory for bins, name comes from gltf. var temporaryFilePath = FilePath.Create( ProjectSettings.GlobalizePath( temporaryPath ) + "/" + gltfFilePath.fullFileName ); var temporaryDirPath = temporaryFilePath.CreateAbsoluteParent();