forked from LeenkxTeam/LNXSDK
1. added local rotation so that if the source object is child then it would still align to the target object. 2. removed rotation output socket since is not really needed.
This commit is contained in:
@ -12,6 +12,7 @@ class SetLookAtRotationNode extends LogicNode {
|
||||
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)
|
||||
public var property5: String; // Use local space (true/false)
|
||||
|
||||
// Store the calculated rotation for output
|
||||
var calculatedRotation: Quat = null;
|
||||
@ -51,8 +52,8 @@ class SetLookAtRotationNode extends LogicNode {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get source object's position
|
||||
objectLoc = objectToUse.transform.loc;
|
||||
// Get source object's WORLD position (important for child objects)
|
||||
objectLoc = new Vec4(objectToUse.transform.worldx(), objectToUse.transform.worldy(), objectToUse.transform.worldz());
|
||||
}
|
||||
|
||||
// Determine if we're using a vector or an object as target
|
||||
@ -74,8 +75,8 @@ class SetLookAtRotationNode extends LogicNode {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get target object's position
|
||||
targetLoc = targetObject.transform.loc;
|
||||
// Get target object's WORLD position (important for child objects)
|
||||
targetLoc = new Vec4(targetObject.transform.worldx(), targetObject.transform.worldy(), targetObject.transform.worldz());
|
||||
}
|
||||
|
||||
// Calculate direction to target
|
||||
@ -122,6 +123,28 @@ class SetLookAtRotationNode extends LogicNode {
|
||||
calculatedRotation.fromEulerOrdered(eulerAngles, "XYZ");
|
||||
}
|
||||
|
||||
// Convert world rotation to local rotation if local space is enabled and object has a parent
|
||||
var targetRotation = new Quat();
|
||||
if (property5 == "true" && objectToUse.parent != null) {
|
||||
// Get parent's world rotation
|
||||
var parentWorldLoc = new Vec4();
|
||||
var parentWorldRot = new Quat();
|
||||
var parentWorldScale = new Vec4();
|
||||
objectToUse.parent.transform.world.decompose(parentWorldLoc, parentWorldRot, parentWorldScale);
|
||||
|
||||
// Convert world rotation to local space by removing parent's rotation influence
|
||||
// local_rotation = inverse(parent_world_rotation) * world_rotation
|
||||
var invParentRot = new Quat().setFrom(parentWorldRot);
|
||||
invParentRot.x = -invParentRot.x;
|
||||
invParentRot.y = -invParentRot.y;
|
||||
invParentRot.z = -invParentRot.z;
|
||||
|
||||
targetRotation.multquats(invParentRot, calculatedRotation);
|
||||
} else {
|
||||
// No local space conversion needed, use world rotation directly
|
||||
targetRotation.setFrom(calculatedRotation);
|
||||
}
|
||||
|
||||
// Apply rotation with damping
|
||||
var dampingValue: Float = 0.0;
|
||||
|
||||
@ -141,17 +164,17 @@ class SetLookAtRotationNode extends LogicNode {
|
||||
// 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);
|
||||
// Get current local rotation as quaternion
|
||||
var currentLocalRot = 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);
|
||||
var invCurrent = new Quat().setFrom(currentLocalRot);
|
||||
invCurrent.x = -invCurrent.x;
|
||||
invCurrent.y = -invCurrent.y;
|
||||
invCurrent.z = -invCurrent.z;
|
||||
diffQuat.multquats(calculatedRotation, invCurrent);
|
||||
diffQuat.multquats(targetRotation, invCurrent);
|
||||
|
||||
// Convert to axis-angle representation
|
||||
var axis = new Vec4();
|
||||
@ -163,15 +186,15 @@ class SetLookAtRotationNode extends LogicNode {
|
||||
// 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 this partial rotation to current local rotation
|
||||
var newLocalRot = new Quat();
|
||||
newLocalRot.multquats(partialRot, currentLocalRot);
|
||||
|
||||
// Apply the new rotation
|
||||
objectToUse.transform.rot.setFrom(newRot);
|
||||
// Apply the new local rotation
|
||||
objectToUse.transform.rot.setFrom(newLocalRot);
|
||||
} else {
|
||||
// No damping, apply instant rotation
|
||||
objectToUse.transform.rot.setFrom(calculatedRotation);
|
||||
objectToUse.transform.rot.setFrom(targetRotation);
|
||||
}
|
||||
|
||||
objectToUse.transform.buildMatrix();
|
||||
@ -179,12 +202,5 @@ class SetLookAtRotationNode extends LogicNode {
|
||||
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;
|
||||
}
|
||||
// No output sockets needed - this node only performs actions
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ class SetLookAtRotationNode(LnxLogicTreeNode):
|
||||
update=lambda self, context: self.update_sockets(context)
|
||||
)
|
||||
|
||||
|
||||
|
||||
damping: bpy.props.FloatProperty(
|
||||
name='Damping',
|
||||
description='Amount of damping for rotation (0.0 = instant, 1.0 = no movement)',
|
||||
@ -74,6 +76,12 @@ class SetLookAtRotationNode(LnxLogicTreeNode):
|
||||
('false', 'False', 'False')],
|
||||
name='Disable Rotation on Aligning Axis', default='false')
|
||||
|
||||
property5: HaxeEnumProperty(
|
||||
'property5',
|
||||
items = [('true', 'True', 'True'),
|
||||
('false', 'False', 'False')],
|
||||
name='Use Local Space', default='false')
|
||||
|
||||
def lnx_init(self, context):
|
||||
# Add inputs in standard order
|
||||
self.inputs.new('LnxNodeSocketAction', 'In')
|
||||
@ -90,8 +98,6 @@ class SetLookAtRotationNode(LnxLogicTreeNode):
|
||||
|
||||
# Add outputs
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
# Add rotation output socket
|
||||
self.add_output('LnxRotationSocket', 'Rotation')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
# 1. Axis Selector
|
||||
@ -114,6 +120,7 @@ class SetLookAtRotationNode(LnxLogicTreeNode):
|
||||
self.property2 = 'true' if self.use_source_vector else 'false'
|
||||
self.property3 = str(self.damping) # Keep for backward compatibility
|
||||
self.property4 = 'true' if self.disable_rotation_on_align_axis else 'false'
|
||||
self.property5 = 'true' # Always use local space functionality
|
||||
|
||||
# Store current object references before changing sockets
|
||||
self.save_object_references()
|
||||
|
Reference in New Issue
Block a user