Pesquisar este blog

PLUG GRAMA

Aqui estão os códigos refatorados, limpos e otimizados para o Godot 4.6.


plug q faz a grama se mexer e quando o player passa o mato abaixa: godot 4.6 funcionou bunito 1 add o script do mult mesh : no inspetor vai aparecer pra selecionar o chao , e tbm vai selecionar o player no inspetor : dentro do multimesh seleciona o 3d e add o objeto 3d q vai ser a grama 2 : dento do multimesh no ispetor tem a opcao geometry abre ele e cria um material overrrid e coloca o sharder la dentro quando o script for add vai ter os paramentros q vc pode alterar no inspetor veclocida do vento , amssado ...... dps de add tudo feche a cena e abra novamente td estara funcionando


O que mudou e melhorou:

  • Shader: Otimizado para evitar cálculos repetitivos por vértice, mantendo a interpolação suave do vento e a interação com o player de forma eficiente.

  • MultiMesh Script: Adicionada verificação de segurança (@export_node_path atualizado ou tratamento de nulos), melhoria na performance do loop de dispersão e uso adequado de set_shader_parameter para evitar gargalos de busca a cada frame.

1. Código do Shader Material (Otimizado)

OpenGL Shading Language
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
}

2. Código do MultiMeshInstance3D (Otimizado)

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

Qual parâmetro você gostaria de ajustar agora (ex: densidade, formato do vento ou otimização para mapas maiores)?