Pesquisar este blog
plug q faz a grama se mexer e quando o player passa o mato abaixa
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
================================================================
======== codigo do shader material :
shader_type spatial;
uniform vec3 player_pos;
uniform float radius = 2.0;
uniform float bend_amount = 2.0;
uniform float height_influence = 1.0;
uniform float wind_strength = 0.10;
uniform float wind_speed = 2.0;
uniform float wind_scale = 2.0;
uniform vec4 grass_color : source_color = vec4(0.2, 0.8, 0.3, 1.0);
uniform float color_variation = 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 ----------------------------
float wind_phase =
TIME * wind_speed +
v_world_pos.x * 0.7 +
v_world_pos.z * 0.5;
float wind_wave = sin(wind_phase * wind_scale);
VERTEX.x += wind_wave * wind_strength * height_mask;
VERTEX.z += cos(wind_phase * 0.8) * wind_strength * height_mask;
// -------------------------------------
// š£ INTERAĆĆ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 = normalize(to_player);
VERTEX.xz += dir * bend_amount * strength * height_mask;
VERTEX.y -= bend_amount * 0.6 * strength * height_mask;
}
}
void fragment() {
float noise = fract(
sin(dot(v_world_pos.xz ,vec2(12.9898,78.233))) * 43758.5453
);
vec3 col = grass_color.rgb;
col += (noise - 0.5) * color_variation;
ALBEDO = col;
ALPHA = grass_color.a;
}
===================================
===== abaixo tem o codigo do multimesh
@tool
extends MultiMeshInstance3D
@export var clump_center: NodePath
@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:
set(v): blade_width = v; _request_scatter()
@export_range(0, 10) var blade_height: float = 1:
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()
# ignorar instâncias finais reais
@export var skip_instances: Array[int] = []
# layer do terreno (ajuste conforme seu projeto)
@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
# -------------------------------------------------
func _ready():
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):
if Engine.is_editor_hint():
if not is_visible_in_tree():
return
if _needs_update:
scatter()
_needs_update = false
else:
_update_shader_player()
# detectar movimento do centro
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():
if Engine.is_editor_hint():
_needs_update = true
# -------------------------------------------------
# SCATTER
func scatter():
if not multimesh:
return
var center_node = get_node_or_null(clump_center)
if not center_node:
print("clump_center não encontrado")
return
randomize()
var center = center_node.global_transform.origin
var count = thickness * thickness
count = min(count, max_instances)
multimesh.instance_count = count
var current_index := 0
for i in range(count):
# distribuição orgânica
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
var hit = get_pos_under_vert(Vector3(x, 500, z))
if hit == null:
continue
if current_index in skip_instances:
current_index += 1
continue
var t := Transform3D()
# rotação
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))
# escala variada
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.y + y_offset, z)
multimesh.set_instance_transform(current_index, t)
current_index += 1
multimesh.instance_count = current_index
# -------------------------------------------------
# RAYCAST
func raycast_from_vert(start_pos: Vector3) -> Dictionary:
var space = get_world_3d().direct_space_state
var pars := PhysicsRayQueryParameters3D.new()
pars.from = start_pos
pars.to = start_pos + Vector3.DOWN * 1000
pars.collision_mask = ground_collision_mask
pars.collide_with_areas = false
return space.intersect_ray(pars)
func get_pos_under_vert(v: Vector3):
var r = raycast_from_vert(v)
if r:
return r.position
return null
# -------------------------------------------------
# SHADER PLAYER UPDATE
func _update_shader_player():
if not player_node or not multimesh:
return
var pos = player_node.global_transform.origin
if material_override is ShaderMaterial:
material_override.set_shader_parameter("player_pos", pos)
return
if multimesh.mesh:
var mat = multimesh.mesh.surface_get_material(0)
if mat is ShaderMaterial:
mat.set_shader_parameter("player_pos", pos)