Foliage Update

This commit is contained in:
Josef 2025-07-17 13:50:37 +02:00
parent fe2460239f
commit 94c90e03e7
25 changed files with 828 additions and 3 deletions

View File

@ -21,6 +21,16 @@ namespace Rokojori
return GetAnyChild<T>( node );
}
public static T GetSelfOrChildOf<T>( this Node node ) where T:Node
{
if ( node is T t )
{
return t;
}
return GetAnyChild<T>( node );
}
public static T GetChild<T>( this Node node ) where T:Node
{
return GetDirectChild<T>( node );

View File

@ -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<T>( List<T> data, System.Func<T,Vector3> getPosition )
{
var min = new Vector3( float.MaxValue, float.MaxValue, float.MaxValue );

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 MiB

View File

@ -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

View File

@ -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"

View File

@ -0,0 +1,105 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
using System.Threading.Tasks;
namespace Rokojori
{
/** <summary for="class FoliageData">
<title>
Resource to define foliage data
</title>
<description>
</description>
</summary>
*/
[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;
/** <summary for="field renderPriority">Render priority, only for transparent objects</summary>*/
[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 )
{
}
}
}

View File

@ -0,0 +1 @@
uid://bcl28l8d5lxye

View File

@ -0,0 +1,106 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
using System.Threading.Tasks;
namespace Rokojori
{
/** <summary for="class FoliageRenderLayer">
<title>
Is used by the FoliageRenderer to book keep and render a layer defined by the FoliageData.
</title>
<description>
</description>
</summary>
*/
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 );
}
}
}
}

View File

@ -0,0 +1 @@
uid://6ie7ggcqvjtj

View File

@ -0,0 +1,97 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
using System.Threading.Tasks;
using System.Linq;
namespace Rokojori
{
/** <summary for="class FoliageRenderer">
<title>
A node to render foliage.
</title>
<description>
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.
</description>
</summary>
*/
[Tool]
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Scatterer.svg") ]
public partial class FoliageRenderer:Node
{
[Export]
public FoliageData[] foliage;
List<FoliageRenderLayer> 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<FoliageData,FoliageRenderLayer>( 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 ) );
}
}
}

View File

@ -0,0 +1 @@
uid://b1sjdhnriaeg6

View File

@ -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;
}

View File

@ -0,0 +1 @@
uid://dffj0xp766wka

View File

@ -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 ) );
}

View File

@ -0,0 +1 @@
uid://brk5g221ccd2x

View File

@ -0,0 +1,129 @@
using Godot;
namespace Rokojori
{
// Generated by ShaderClassGenerator
public class GPUFoliageShaderShader
{
public static readonly CachedResource<Shader> shader = new CachedResource<Shader>(
"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<Vector3> cameraPosition;
public readonly CustomMaterialProperty<float> yaw;
public readonly CustomMaterialProperty<float> cellSize;
public readonly CustomMaterialProperty<int> width;
public readonly CustomMaterialProperty<int> height;
public readonly CustomMaterialProperty<Texture2D> positionVariance;
public readonly CustomMaterialProperty<Vector3> maxPositionOffset;
public readonly CustomMaterialProperty<Vector2> positionUvScale;
public readonly CustomMaterialProperty<Vector2> positionUvOffset;
public readonly CustomMaterialProperty<float> heightOffset;
public readonly CustomMaterialProperty<Texture2D> rotationVariance;
public readonly CustomMaterialProperty<Vector3> minRotation;
public readonly CustomMaterialProperty<Vector3> maxRotation;
public readonly CustomMaterialProperty<Vector2> rotationUvScale;
public readonly CustomMaterialProperty<Vector2> rotationUvOffset;
public readonly CustomMaterialProperty<Texture2D> scaleVariance;
public readonly CustomMaterialProperty<Vector3> minScale;
public readonly CustomMaterialProperty<Vector3> maxScale;
public readonly CustomMaterialProperty<Vector2> scaleUvScale;
public readonly CustomMaterialProperty<Vector2> scaleUvOffset;
public readonly CustomMaterialProperty<float> occupancyAmount;
public readonly CustomMaterialProperty<float> occupancyPower;
public readonly CustomMaterialProperty<float> occupancyTreshold;
public readonly CustomMaterialProperty<float> occupancyHideOffset;
public readonly CustomMaterialProperty<float> occupancyHideScale;
public readonly CustomMaterialProperty<Texture2D> occupancyVariance;
public readonly CustomMaterialProperty<Vector2> occupancyUvScale;
public readonly CustomMaterialProperty<Vector2> occupancyUvOffset;
public readonly CustomMaterialProperty<float> hideStart;
public readonly CustomMaterialProperty<float> hideMax;
public readonly CustomMaterialProperty<float> hideOffset;
public readonly CustomMaterialProperty<Vector2> mapSize;
public readonly CustomMaterialProperty<Vector2> mapCenter;
public GPUFoliageShaderMaterial()
{
Shader = GPUFoliageShaderShader.shader.Get();
cameraPosition = new CustomMaterialProperty<Vector3>( this, GPUFoliageShaderShader.cameraPosition );
yaw = new CustomMaterialProperty<float>( this, GPUFoliageShaderShader.yaw );
cellSize = new CustomMaterialProperty<float>( this, GPUFoliageShaderShader.cellSize );
width = new CustomMaterialProperty<int>( this, GPUFoliageShaderShader.width );
height = new CustomMaterialProperty<int>( this, GPUFoliageShaderShader.height );
positionVariance = new CustomMaterialProperty<Texture2D>( this, GPUFoliageShaderShader.positionVariance );
maxPositionOffset = new CustomMaterialProperty<Vector3>( this, GPUFoliageShaderShader.maxPositionOffset );
positionUvScale = new CustomMaterialProperty<Vector2>( this, GPUFoliageShaderShader.positionUvScale );
positionUvOffset = new CustomMaterialProperty<Vector2>( this, GPUFoliageShaderShader.positionUvOffset );
heightOffset = new CustomMaterialProperty<float>( this, GPUFoliageShaderShader.heightOffset );
rotationVariance = new CustomMaterialProperty<Texture2D>( this, GPUFoliageShaderShader.rotationVariance );
minRotation = new CustomMaterialProperty<Vector3>( this, GPUFoliageShaderShader.minRotation );
maxRotation = new CustomMaterialProperty<Vector3>( this, GPUFoliageShaderShader.maxRotation );
rotationUvScale = new CustomMaterialProperty<Vector2>( this, GPUFoliageShaderShader.rotationUvScale );
rotationUvOffset = new CustomMaterialProperty<Vector2>( this, GPUFoliageShaderShader.rotationUvOffset );
scaleVariance = new CustomMaterialProperty<Texture2D>( this, GPUFoliageShaderShader.scaleVariance );
minScale = new CustomMaterialProperty<Vector3>( this, GPUFoliageShaderShader.minScale );
maxScale = new CustomMaterialProperty<Vector3>( this, GPUFoliageShaderShader.maxScale );
scaleUvScale = new CustomMaterialProperty<Vector2>( this, GPUFoliageShaderShader.scaleUvScale );
scaleUvOffset = new CustomMaterialProperty<Vector2>( this, GPUFoliageShaderShader.scaleUvOffset );
occupancyAmount = new CustomMaterialProperty<float>( this, GPUFoliageShaderShader.occupancyAmount );
occupancyPower = new CustomMaterialProperty<float>( this, GPUFoliageShaderShader.occupancyPower );
occupancyTreshold = new CustomMaterialProperty<float>( this, GPUFoliageShaderShader.occupancyTreshold );
occupancyHideOffset = new CustomMaterialProperty<float>( this, GPUFoliageShaderShader.occupancyHideOffset );
occupancyHideScale = new CustomMaterialProperty<float>( this, GPUFoliageShaderShader.occupancyHideScale );
occupancyVariance = new CustomMaterialProperty<Texture2D>( this, GPUFoliageShaderShader.occupancyVariance );
occupancyUvScale = new CustomMaterialProperty<Vector2>( this, GPUFoliageShaderShader.occupancyUvScale );
occupancyUvOffset = new CustomMaterialProperty<Vector2>( this, GPUFoliageShaderShader.occupancyUvOffset );
hideStart = new CustomMaterialProperty<float>( this, GPUFoliageShaderShader.hideStart );
hideMax = new CustomMaterialProperty<float>( this, GPUFoliageShaderShader.hideMax );
hideOffset = new CustomMaterialProperty<float>( this, GPUFoliageShaderShader.hideOffset );
mapSize = new CustomMaterialProperty<Vector2>( this, GPUFoliageShaderShader.mapSize );
mapCenter = new CustomMaterialProperty<Vector2>( this, GPUFoliageShaderShader.mapCenter );
}
}
}

View File

@ -0,0 +1 @@
uid://c4hg6rvrmjm6j

View File

@ -0,0 +1,69 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
using System.Threading.Tasks;
namespace Rokojori
{
/** <summary for="class PackedSceneFoliageData">
<title>
A node to render foliage.
</title>
<description>
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.
</description>
</summary>
*/
[Tool]
[GlobalClass]
public partial class SceneFoliageData:FoliageData
{
[Export]
public SceneReference sceneReference;
public override void Initialize( FoliageRenderLayer renderLayer )
{
var particles = renderLayer.renderer.CreateChild<GpuParticles3D>();
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<MeshInstance3D>();
particles.DrawPasses = 1;
particles.DrawPass1 = meshInstance.Mesh;
}
}
}

View File

@ -0,0 +1 @@
uid://cm7ayfu511ijr

View File

@ -0,0 +1,34 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
using System.Threading.Tasks;
using System.Linq;
namespace Rokojori
{
/** <summary for="class SceneReference">
<title>
A resource to reference scenes safely by path.
</title>
<description>
When the path is assigned, it will be updated, when the path moves.
</description>
</summary>
*/
[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<PackedScene>( scenePath );
}
}

View File

@ -0,0 +1 @@
uid://d18oon3mkd5s4

View File

@ -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;
}

View File

@ -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 );
}

View File

@ -22,7 +22,7 @@ namespace Rokojori
return Array.IndexOf( values, other );
}
public static U[] Map<T,U>( T[] values, Func<T,U> mapper )
public static U[] Map<T,U>( this T[] values, Func<T,U> mapper )
{
var u = new U[ values.Length ];

View File

@ -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();