You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
4.4 KiB

"""
Script DAT Callbacks
me - this DAT
scriptOp - the OP which is cooking
"""
import math
def onCook(scriptOp):
"""
Called when the Script DAT needs to cook.
"""
scriptOp.clear()
scriptOp.appendRow(['id', 'P(X)', 'P(Y)', 'P(Z)', 'Rot(x)', 'Rot(y)', 'Rot(z)'])
# 1. Fetch Constants
const_op = op('constant_camera')
camera_y_offset = 0
camera_y_far = 0
# Default rotation and timing values
rx, ry, rz = 0.0, 0.0, 0.0
duration_per_step = 3.0
if const_op:
# Distance Offsets
target_chan = const_op.chan('camera_distance_y')
if target_chan is not None:
camera_y_offset = target_chan.eval()
far_chan = const_op.chan('camera_distance_y_far')
if far_chan is not None:
camera_y_far = far_chan.eval()
# Rotation Values
rx_chan = const_op.chan('rot_x')
ry_chan = const_op.chan('rot_y')
rz_chan = const_op.chan('rot_z')
if rx_chan is not None: rx = rx_chan.eval()
if ry_chan is not None: ry = ry_chan.eval()
if rz_chan is not None: rz = rz_chan.eval()
# Duration / Speed
dur_chan = const_op.chan('duration_per_step')
if dur_chan is not None:
duration_per_step = max(0.1, dur_chan.eval()) # Prevent division by zero
# 2. Check for specific ID selection
const_select = op('SelectId')
select_id = -1
if const_select:
select_chan = const_select.chan('id')
if select_chan is not None:
select_id = int(select_chan.eval())
# 3. Input Validation
if len(scriptOp.inputs) == 0:
return
inputDat = scriptOp.inputs[0]
# CASE A: Tracking a specific single ID
if select_id >= 0:
# Ensure the target CHOP exists
target_path = 'grid_text' + str(select_id + 1) + '/OUT'
out = op(target_path)
rx=0
ry=0
rz=0
if out:
try:
px_val = out['px'].eval() + float(inputDat[select_id+1, 1] or 0)
py_val = out['py'].eval() + float(inputDat[select_id+1, 2] or 0)
pz_val = out['pz'].eval() - camera_y_offset + float(inputDat[select_id+1, 3] or 0)
scriptOp.appendRow([select_id, px_val, py_val, pz_val, rx, ry, rz])
except:
# Handle cases where channels might be missing
pass
return
# CASE B: Panning sequence (Average -> P1 -> P2 -> P3 -> P4)
else:
raw_points = []
sum_x, sum_y, sum_z = 0.0, 0.0, 0.0
# Gather up to 4 points from the input table
for i in range(1, min(5, inputDat.numRows)):
try:
px = float(inputDat[i, 1] or 0)
py = float(inputDat[i, 2] or 0)
pz = float(inputDat[i, 3] or 0)
raw_points.append((px, py, pz))
sum_x += px
sum_y += py
sum_z += pz
except (ValueError, TypeError):
continue
if not raw_points:
return
# Calculate Average Position
num_raw = len(raw_points)
avg_pos = (sum_x / num_raw, sum_y / num_raw, sum_z / num_raw)
# Build the sequence: [Average, P1, P2, P3, P4]
sequence = [avg_pos] + raw_points
num_steps = len(sequence)
if num_steps == 1:
p = sequence[0]
scriptOp.appendRow(['average_only', p[0], p[1], p[2] - camera_y_far, rx, ry, rz])
else:
total_time = absTime.seconds
# Calculate current segment and interpolation factor
progress = (total_time / duration_per_step) % num_steps
idx1 = int(progress)
idx2 = (idx1 + 1) % num_steps
alpha = progress - idx1
# Smooth transition (Cosine ease)
alpha = (1 - math.cos(alpha * math.pi)) / 2
# Perform Linear Interpolation
p1 = sequence[idx1]
p2 = sequence[idx2]
ax = p1[0] + (p2[0] - p1[0]) * alpha
ay = p1[1] + (p2[1] - p1[1]) * alpha
az = p1[2] + (p2[2] - p1[2]) * alpha
label = "avg" if (idx2 == 0) else str(idx2)
scriptOp.appendRow([label, ax, ay, az - camera_y_far, rx, ry, rz])
return
def onGetCookLevel(scriptOp):
return CookLevel.AUTOMATIC