LOPs - PY - transform point instances

from pxr import UsdGeom, Gf, Vt
import random
import hou
import re
import math

def euler_to_quat(rx, ry, rz):
# Create Gf.Rotation from Euler degrees
rotation = Gf.Rotation(Gf.Vec3d(1, 0, 0), rx) * \
Gf.Rotation(Gf.Vec3d(0, 1, 0), ry) * \
Gf.Rotation(Gf.Vec3d(0, 0, 1), rz)
quatf = rotation.GetQuat() # Returns Gf.Quatf (float)
# Convert Gf.Quatf to Gf.Quath (double precision)
quatd = Gf.Quath(quatf.GetReal(), *quatf.GetImaginary())
return quatd

node = hou.pwd()
stage = node.editableStage()
instancer_path = "/instancer1" # Change as needed

input_str = node.evalParm("instanceIndexes")
transx_value = node.evalParm("transParamx")
transy_value = node.evalParm("transParamy")
transz_value = node.evalParm("transParamz")
rotx_value = node.evalParm("rotParamx")
roty_value = node.evalParm("rotParamy")
rotz_value = node.evalParm("rotParamz")
scalex_value = node.evalParm("scaleParamx")
scaley_value = node.evalParm("scaleParamy")
scalez_value = node.evalParm("scaleParamz")

indices = [int(i) for i in re.findall(r'\[(\d+)\]', input_str)]
selected_indices = {i: 1 for i in indices}

instancer_prim = stage.GetPrimAtPath(instancer_path)
if not instancer_prim or not instancer_prim.IsValid():
raise RuntimeError(f"PointInstancer not found at path: {instancer_path}")

instancer = UsdGeom.PointInstancer(instancer_prim)

positions_attr = instancer.GetPositionsAttr()
positions = positions_attr.Get()

scales_attr = instancer.GetScalesAttr()
scales = scales_attr.Get()
if not scales:
scales = [Gf.Vec3f(1.0, 1.0, 1.0)] * len(positions)

orientations_attr = instancer.GetOrientationsAttr()
orientations = orientations_attr.Get()
if not orientations:
# Use identity Gf.Quath here, not Quatf
orientations = [Gf.Quath(1.0, 0.0, 0.0, 0.0)] * len(positions)

new_positions = []
new_scales = []
new_orientations = []

for i, (pos, scale, orient) in enumerate(zip(positions, scales, orientations)):
if i in selected_indices:
new_pos = Gf.Vec3d(
pos[0] + transx_value,
pos[1] + transy_value,
pos[2] + transz_value
)
new_scale = Gf.Vec3f(
scale[0] * scalex_value,
scale[1] * scaley_value,
scale[2] * scalez_value
)
quat = euler_to_quat(rotx_value, roty_value, rotz_value)
else:
new_pos = Gf.Vec3d(pos)
new_scale = Gf.Vec3f(scale)
quat = Gf.Quath(1.0, 0.0, 0.0, 0.0) # Identity rotation double precision

new_positions.append(new_pos)
new_scales.append(new_scale)
new_orientations.append(quat)

positions_attr.Set(Vt.Vec3dArray(new_positions))
scales_attr.Set(Vt.Vec3fArray(new_scales))
orientations_attr.Set(Vt.QuathArray(new_orientations))