Pesquisar este blog

godot mato que amassa quando pisa e vento tbm usa o material em shader

 @tool

extends MultiMeshInstance3D


@export var clump_center: NodePath:

set(v):

clump_center = v

_request_scatter()


@export var clump_radius: int = 10:

set(v):

clump_radius = v

_request_scatter()


@export_range(1, 50) var clump_angulate: int = 1:

set(v):

clump_angulate = v

_request_scatter()


@export_range(0, 200) var thickness: int = 10:

set(v):

thickness = v

_request_scatter()


@export var meadowing: bool = false:

set(v):

meadowing = v

_request_scatter()


@export var meadow_radius: int = 0:

set(v):

meadow_radius = v

_request_scatter()


@export_range(0, 10) var blade_width: float = 1.0:

set(v):

blade_width = v

_request_scatter()


@export_range(0, 10) var blade_height: float = 1.0:

set(v):

blade_height = v

_request_scatter()


@export_range(0, 100) var amount_randomize: int = 3:

set(v):

amount_randomize = v

_request_scatter()


@export var y_offset: float = 0.0:

set(v):

y_offset = v

_request_scatter()


@export var randomize_hori: bool = true:

set(v):

randomize_hori = v

_request_scatter()


@export var randomize_vert: bool = true:

set(v):

randomize_vert = v

_request_scatter()


@export var skip_instances: Array[int] = []

@export var ground_collision_mask: int = 1

@export var max_instances: int = 20000

@export var player_node: Node3D


var _last_center_position: Vector3

var _needs_update := false

var _material_cache: ShaderMaterial


func _ready() -> void:

if not multimesh:

multimesh = MultiMesh.new()

multimesh.transform_format = MultiMesh.TRANSFORM_3D

_cache_material()

if clump_center != NodePath():

var c = get_node_or_null(clump_center)

if c:

_last_center_position = c.global_transform.origin

if Engine.is_editor_hint():

set_process(true)

_request_scatter()


func _process(_delta: float) -> void:

if Engine.is_editor_hint():

if not is_visible_in_tree():

return

if _needs_update:

scatter()

_needs_update = false

_update_shader_player()


# Checa mudança de posição do centro de forma otimizada

if clump_center != NodePath():

var c = get_node_or_null(clump_center)

if c and c.global_transform.origin != _last_center_position:

_last_center_position = c.global_transform.origin

_request_scatter()


func _request_scatter() -> void:

if Engine.is_editor_hint():

_needs_update = true


func scatter() -> void:

if not multimesh:

return

var center_node = get_node_or_null(clump_center)

if not center_node:

return

var center = center_node.global_transform.origin

var count = min(thickness * thickness, max_instances)

multimesh.instance_count = count

var space_state = get_world_3d().direct_space_state

var current_index := 0

for i in range(count):

if i in skip_instances:

continue

var angle = randf() * TAU

var dist = randf() * clump_radius

if meadowing:

dist += meadow_radius

var x = center.x + cos(angle) * dist

var z = center.z + sin(angle) * dist

# Raycast direto otimizado

var query = PhysicsRayQueryParameters3D.create(

Vector3(x, 500, z),

Vector3(x, -500, z),

ground_collision_mask

)

query.collide_with_areas = false

var hit = space_state.intersect_ray(query)

if hit.is_empty():

continue

var t = Transform3D()

if randomize_hori:

t = t.rotated(Vector3.UP, randf_range(-sqrt(amount_randomize), sqrt(amount_randomize)))

if randomize_vert:

t = t.rotated(Vector3.LEFT, randf_range(-0.2, 0.2))

t = t.rotated(Vector3.FORWARD, randf_range(-0.2, 0.2))

var scale_rand = randf_range(0.8, 1.2)

t = t.scaled(Vector3(blade_width * scale_rand, blade_height * scale_rand, blade_width * scale_rand))

t.origin = Vector3(x, hit.position.y + y_offset, z)

multimesh.set_instance_transform(current_index, t)

current_index += 1

multimesh.instance_count = current_index


func _cache_material() -> void:

if material_override is ShaderMaterial:

_material_cache = material_override

elif multimesh and multimesh.mesh:

var mat = multimesh.mesh.surface_get_material(0)

if mat is ShaderMaterial:

_material_cache = mat


func _update_shader_player() -> void:

if not player_node:

return

if not _material_cache:

_cache_material()

if _material_cache:

_material_cache.set_shader_parameter("player_pos", player_node.global_transform.origin)









codigo do material shder dos matos:


shader_type spatial;
render_mode cull_disabled; // Útil para grama 2D/planos para não sumir ao olhar por trás

uniform vec3 player_pos;
uniform float radius : hint_range(0.1, 10.0) = 2.0;
uniform float bend_amount : hint_range(0.0, 5.0) = 2.0;
uniform float height_influence : hint_range(0.0, 5.0) = 1.0;
uniform float wind_strength : hint_range(0.0, 1.0) = 0.10;
uniform float wind_speed : hint_range(0.0, 10.0) = 2.0;
uniform float wind_scale : hint_range(0.1, 10.0) = 2.0;
uniform vec4 grass_color : source_color = vec4(0.2, 0.8, 0.3, 1.0);
uniform float color_variation : hint_range(0.0, 0.5) = 0.15;

varying vec3 v_world_pos;

void vertex() {
    v_world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
    float height_mask = clamp(VERTEX.y * height_influence, 0.0, 1.0);

    // 🌬️ VENTO OTIMIZADO
    float wind_phase = TIME * wind_speed + (v_world_pos.x * 0.7 + v_world_pos.z * 0.5) * wind_scale;
    float wind_wave = sin(wind_phase);
    
    VERTEX.x += wind_wave * wind_strength * height_mask;
    VERTEX.z += cos(wind_phase * 0.8) * wind_strength * height_mask;

    // 👣 INTERAÇÃO COM O PLAYER
    vec2 to_player = v_world_pos.xz - player_pos.xz;
    float dist = length(to_player);
    
    if (dist < radius) {
        float t = dist / radius;
        float strength = smoothstep(1.0, 0.0, t);
        vec2 dir = to_player / max(dist, 0.0001); // Evita divisão por zero
        
        VERTEX.xz += dir * bend_amount * strength * height_mask;
        VERTEX.y -= bend_amount * 0.6 * strength * height_mask;
    }
}

void fragment() {
    // Ruído procedural leve para variação de cor sem texturas extras
    float noise = fract(sin(dot(v_world_pos.xz, vec2(12.9898, 78.233))) * 43758.5453);
    vec3 col = grass_color.rgb + (noise - 0.5) * color_variation;
    
    ALBEDO = col;
    ALPHA = grass_color.a;
    ALPHA_SCISSOR_THRESHOLD = 0.5; // Caso use texturas com transparência
}