forked from LeenkxTeam/LNXSDK
@ -1,190 +0,0 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Mat4;
|
||||
import iron.object.Object;
|
||||
|
||||
class SetLookAtRotationNode extends LogicNode {
|
||||
|
||||
public var property0: String; // Axis to align
|
||||
public var property1: String; // Use vector for target (true/false)
|
||||
public var property2: String; // Use vector for source (true/false)
|
||||
public var property3: String; // Damping value (backward compatibility, now input socket)
|
||||
public var property4: String; // Disable rotation on aligning axis (true/false)
|
||||
|
||||
// Store the calculated rotation for output
|
||||
var calculatedRotation: Quat = null;
|
||||
// Store the previous rotation for smooth interpolation
|
||||
var previousRotation: Quat = null;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
previousRotation = new Quat();
|
||||
}
|
||||
|
||||
override function run(from: Int): Void {
|
||||
// Determine if we're using a vector or an object as source
|
||||
var useSourceVector: Bool = property2 == "true";
|
||||
var objectToUse: Object = null;
|
||||
var objectLoc: Vec4 = null;
|
||||
|
||||
if (useSourceVector) {
|
||||
// Use tree.object as the object to rotate
|
||||
objectToUse = tree.object;
|
||||
if (objectToUse == null) {
|
||||
runOutput(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the source location directly
|
||||
objectLoc = inputs[1].get();
|
||||
if (objectLoc == null) {
|
||||
runOutput(0);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Get the source object (or fallback to tree.object)
|
||||
objectToUse = (inputs.length > 1 && inputs[1] != null) ? inputs[1].get() : tree.object;
|
||||
if (objectToUse == null) {
|
||||
runOutput(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get source object's position
|
||||
objectLoc = objectToUse.transform.loc;
|
||||
}
|
||||
|
||||
// Determine if we're using a vector or an object as target
|
||||
var useTargetVector: Bool = property1 == "true";
|
||||
var targetLoc: Vec4 = null;
|
||||
|
||||
if (useTargetVector) {
|
||||
// Get the target location directly
|
||||
targetLoc = inputs[2].get();
|
||||
if (targetLoc == null) {
|
||||
runOutput(0);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Get the target object
|
||||
var targetObject: Object = inputs[2].get();
|
||||
if (targetObject == null) {
|
||||
runOutput(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get target object's position
|
||||
targetLoc = targetObject.transform.loc;
|
||||
}
|
||||
|
||||
// Calculate direction to target
|
||||
var direction = new Vec4(
|
||||
targetLoc.x - objectLoc.x,
|
||||
targetLoc.y - objectLoc.y,
|
||||
targetLoc.z - objectLoc.z
|
||||
);
|
||||
direction.normalize();
|
||||
|
||||
// Calculate target rotation based on selected axis
|
||||
calculatedRotation = new Quat();
|
||||
switch (property0) {
|
||||
case "X":
|
||||
calculatedRotation.fromTo(new Vec4(1, 0, 0), direction);
|
||||
case "-X":
|
||||
calculatedRotation.fromTo(new Vec4(-1, 0, 0), direction);
|
||||
case "Y":
|
||||
calculatedRotation.fromTo(new Vec4(0, 1, 0), direction);
|
||||
case "-Y":
|
||||
calculatedRotation.fromTo(new Vec4(0, -1, 0), direction);
|
||||
case "Z":
|
||||
calculatedRotation.fromTo(new Vec4(0, 0, 1), direction);
|
||||
case "-Z":
|
||||
calculatedRotation.fromTo(new Vec4(0, 0, -1), direction);
|
||||
}
|
||||
|
||||
// If disable rotation on aligning axis is enabled, constrain the target rotation
|
||||
if (property4 == "true") {
|
||||
// Apply constraint to the target rotation BEFORE damping to avoid jiggling
|
||||
var eulerAngles = calculatedRotation.toEulerOrdered("XYZ");
|
||||
|
||||
// Set the rotation around the selected axis to 0
|
||||
switch (property0) {
|
||||
case "X", "-X":
|
||||
eulerAngles.x = 0.0;
|
||||
case "Y", "-Y":
|
||||
eulerAngles.y = 0.0;
|
||||
case "Z", "-Z":
|
||||
eulerAngles.z = 0.0;
|
||||
}
|
||||
|
||||
// Convert back to quaternion
|
||||
calculatedRotation.fromEulerOrdered(eulerAngles, "XYZ");
|
||||
}
|
||||
|
||||
// Apply rotation with damping
|
||||
var dampingValue: Float = 0.0;
|
||||
|
||||
// Try to get damping from input socket first (index 3), fallback to property
|
||||
if (inputs.length > 3 && inputs[3] != null) {
|
||||
var dampingInput: Dynamic = inputs[3].get();
|
||||
if (dampingInput != null) {
|
||||
dampingValue = dampingInput;
|
||||
}
|
||||
} else {
|
||||
// Fallback to property for backward compatibility
|
||||
dampingValue = Std.parseFloat(property3);
|
||||
}
|
||||
|
||||
if (dampingValue > 0.0) {
|
||||
// Create a fixed interpolation rate that never reaches exactly 1.0
|
||||
// Higher damping = slower rotation (smaller step)
|
||||
var step = Math.max(0.001, (1.0 - dampingValue) * 0.2); // 0.001 to 0.2 range
|
||||
|
||||
// Get current rotation as quaternion
|
||||
var currentRot = new Quat().setFrom(objectToUse.transform.rot);
|
||||
|
||||
// Calculate the difference between current and target rotation
|
||||
var diffQuat = new Quat();
|
||||
// q1 * inverse(q2) gives the rotation from q2 to q1
|
||||
var invCurrent = new Quat().setFrom(currentRot);
|
||||
invCurrent.x = -invCurrent.x;
|
||||
invCurrent.y = -invCurrent.y;
|
||||
invCurrent.z = -invCurrent.z;
|
||||
diffQuat.multquats(calculatedRotation, invCurrent);
|
||||
|
||||
// Convert to axis-angle representation
|
||||
var axis = new Vec4();
|
||||
var angle = diffQuat.toAxisAngle(axis);
|
||||
|
||||
// Apply only a portion of this rotation (step)
|
||||
var partialAngle = angle * step;
|
||||
|
||||
// Create partial rotation quaternion
|
||||
var partialRot = new Quat().fromAxisAngle(axis, partialAngle);
|
||||
|
||||
// Apply this partial rotation to current
|
||||
var newRot = new Quat();
|
||||
newRot.multquats(partialRot, currentRot);
|
||||
|
||||
// Apply the new rotation
|
||||
objectToUse.transform.rot.setFrom(newRot);
|
||||
} else {
|
||||
// No damping, apply instant rotation
|
||||
objectToUse.transform.rot.setFrom(calculatedRotation);
|
||||
}
|
||||
|
||||
objectToUse.transform.buildMatrix();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
// Getter method for output sockets
|
||||
override function get(from: Int): Dynamic {
|
||||
// Output index 1 is the rotation socket (global rotation)
|
||||
if (from == 1) {
|
||||
return calculatedRotation;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user