""" 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_seconds') 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() py_val = out['py'].eval() pz_val = out['pz'].eval() - camera_y_offset 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