VibeGeometry/examples/geometry_script/blender_index_of_nearest.py
2026-05-04 17:56:40 +01:00

150 lines
5.7 KiB
Python

"""Geometry Script footholds from Blender's index_of_nearest demo."""
try:
from tools.geometry_script_loader import load_repo_geometry_script
except ModuleNotFoundError:
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
from tools.geometry_script_loader import load_repo_geometry_script
load_repo_geometry_script()
from geometry_script import * # noqa: F403 - Geometry Script exposes node functions as DSL globals.
@tree("VG Boundary Step")
def vg_boundary_step(
geometry: Geometry,
vector: Vector = (0.0, 0.0, 0.0),
b: Float = 0.05000000074505806,
):
from_center = vector_math(operation=VectorMath.Operation.SUBTRACT, vector=(position(), vector))
distance = vector_math(operation=VectorMath.Operation.LENGTH, vector=from_center)
outside = compare(
operation=Compare.Operation.GREATER_THAN,
data_type=Compare.DataType.FLOAT,
mode=Compare.Mode.ELEMENT,
a=distance,
b=b,
)
clamped_xy = vector_math(
operation=VectorMath.Operation.MULTIPLY,
vector=(vector_math(operation=VectorMath.Operation.SCALE, vector=vector_math(operation=VectorMath.Operation.NORMALIZE, vector=from_center), scale=b), (1.0, 1.0, 0.0)),
)
return {"Geometry": set_position(geometry=geometry, selection=outside, position=clamped_xy, offset=(0.0, 0.0, 0.0))}
@tree("VG Update Velocity")
def vg_update_velocity(
current_velocity: Vector = (0.0, 0.0, 0.0),
last_position: Vector = (0.0, 0.0, 0.0),
):
movement = vector_math(operation=VectorMath.Operation.SUBTRACT, vector=(position(), last_position))
damped_movement = vector_math(operation=VectorMath.Operation.SCALE, vector=movement, scale=0.9599999785423279)
planar_movement = vector_math(operation=VectorMath.Operation.MULTIPLY, vector=(damped_movement, (1.0, 1.0, 0.0)))
fast_enough = compare(
operation=Compare.Operation.GREATER_THAN,
data_type=Compare.DataType.FLOAT,
mode=Compare.Mode.ELEMENT,
a=vector_math(operation=VectorMath.Operation.LENGTH, vector=planar_movement),
b=0.009999999776482582,
)
blended = vector_math(
operation=VectorMath.Operation.ADD,
vector=(
vector_math(operation=VectorMath.Operation.SCALE, vector=current_velocity, scale=0.75),
vector_math(operation=VectorMath.Operation.SCALE, vector=planar_movement, scale=0.25),
),
)
capped = vector_math(
operation=VectorMath.Operation.SCALE,
vector=vector_math(operation=VectorMath.Operation.NORMALIZE, vector=damped_movement),
scale=0.009999999776482582,
)
return {"velocity": switch(input_type=Switch.InputType.VECTOR, switch=fast_enough, false=blended, true=capped)}
@tree("VG Collision Step")
def vg_collision_step(geometry: Geometry):
current_position = position()
neighbor = index_of_nearest(position=position())
neighbor_position = evaluate_at_index(
domain="POINT",
data_type="FLOAT_VECTOR",
value=position(),
index=neighbor.index,
)
from_neighbor = vector_math(operation=VectorMath.Operation.SUBTRACT, vector=(current_position, neighbor_position))
too_close = compare(
operation=Compare.Operation.LESS_THAN,
data_type=Compare.DataType.FLOAT,
mode=Compare.Mode.ELEMENT,
a=vector_math(operation=VectorMath.Operation.LENGTH, vector=from_neighbor),
b=radius(),
)
push_strength = math(operation=Math.Operation.MULTIPLY, value=(too_close, 0.02500000037252903))
push = vector_math(
operation=VectorMath.Operation.MULTIPLY,
vector=(vector_math(operation=VectorMath.Operation.SCALE, vector=from_neighbor, scale=push_strength), (1.0, 1.0, 0.0)),
)
return {"Geometry": set_position(geometry=geometry, offset=push)}
@tree("VG Collider Step")
def vg_collider_step(geometry: Geometry, collider: Object = None):
collider_info = object_info(transform_space="ORIGINAL", object=collider, as_instance=False)
from_collider = vector_math(operation=VectorMath.Operation.SUBTRACT, vector=(position(), collider_info.location))
collider_radius = vector_math(operation=VectorMath.Operation.ABSOLUTE, vector=collider_info.scale)
inside = compare(
operation=Compare.Operation.LESS_THAN,
data_type=Compare.DataType.FLOAT,
mode=Compare.Mode.ELEMENT,
a=vector_math(operation=VectorMath.Operation.LENGTH, vector=from_collider),
b=collider_radius,
)
clamped = vector_math(
operation=VectorMath.Operation.ADD,
vector=(
vector_math(
operation=VectorMath.Operation.SCALE,
vector=vector_math(operation=VectorMath.Operation.NORMALIZE, vector=from_collider),
scale=collider_radius,
),
collider_info.location,
),
)
planar_clamped = vector_math(operation=VectorMath.Operation.MULTIPLY, vector=(clamped, (1.0, 1.0, 0.0)))
return {"Geometry": set_position(geometry=geometry, selection=inside, position=planar_clamped, offset=(0.0, 0.0, 0.0))}
def _finalize_groups():
import bpy
groups = []
for name in (
"VG Boundary Step",
"VG Update Velocity",
"VG Collision Step",
"VG Collider Step",
):
group = bpy.data.node_groups.get(name)
if group:
group.use_fake_user = True
groups.append(group)
return groups
_finalize_groups()
if __name__ == "__main__":
for group in _finalize_groups():
print(
"VG_INDEX_OF_NEAREST_GROUP",
group.name,
len(group.nodes),
len(group.links),
sorted(set(node.bl_idname for node in group.nodes)),
)