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_pathatualizado ou tratamento de nulos), melhoria na performance do loop de dispersão e uso adequado deset_shader_parameterpara 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)?