forked from LeenkxTeam/LNXSDK
Merge pull request 'main' (#88) from wuaieyo/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#88
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 property2: String; // Use vector for source (true/false)
|
||||||
public var property3: String; // Damping value (backward compatibility, now input socket)
|
public var property3: String; // Damping value (backward compatibility, now input socket)
|
||||||
public var property4: String; // Disable rotation on aligning axis (true/false)
|
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
|
// Store the calculated rotation for output
|
||||||
var calculatedRotation: Quat = null;
|
var calculatedRotation: Quat = null;
|
||||||
@ -51,8 +52,8 @@ class SetLookAtRotationNode extends LogicNode {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get source object's position
|
// Get source object's WORLD position (important for child objects)
|
||||||
objectLoc = objectToUse.transform.loc;
|
objectLoc = new Vec4(objectToUse.transform.worldx(), objectToUse.transform.worldy(), objectToUse.transform.worldz());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine if we're using a vector or an object as target
|
// Determine if we're using a vector or an object as target
|
||||||
@ -74,8 +75,8 @@ class SetLookAtRotationNode extends LogicNode {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get target object's position
|
// Get target object's WORLD position (important for child objects)
|
||||||
targetLoc = targetObject.transform.loc;
|
targetLoc = new Vec4(targetObject.transform.worldx(), targetObject.transform.worldy(), targetObject.transform.worldz());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate direction to target
|
// Calculate direction to target
|
||||||
@ -122,6 +123,28 @@ class SetLookAtRotationNode extends LogicNode {
|
|||||||
calculatedRotation.fromEulerOrdered(eulerAngles, "XYZ");
|
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
|
// Apply rotation with damping
|
||||||
var dampingValue: Float = 0.0;
|
var dampingValue: Float = 0.0;
|
||||||
|
|
||||||
@ -141,17 +164,17 @@ class SetLookAtRotationNode extends LogicNode {
|
|||||||
// Higher damping = slower rotation (smaller step)
|
// Higher damping = slower rotation (smaller step)
|
||||||
var step = Math.max(0.001, (1.0 - dampingValue) * 0.2); // 0.001 to 0.2 range
|
var step = Math.max(0.001, (1.0 - dampingValue) * 0.2); // 0.001 to 0.2 range
|
||||||
|
|
||||||
// Get current rotation as quaternion
|
// Get current local rotation as quaternion
|
||||||
var currentRot = new Quat().setFrom(objectToUse.transform.rot);
|
var currentLocalRot = new Quat().setFrom(objectToUse.transform.rot);
|
||||||
|
|
||||||
// Calculate the difference between current and target rotation
|
// Calculate the difference between current and target rotation
|
||||||
var diffQuat = new Quat();
|
var diffQuat = new Quat();
|
||||||
// q1 * inverse(q2) gives the rotation from q2 to q1
|
// 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.x = -invCurrent.x;
|
||||||
invCurrent.y = -invCurrent.y;
|
invCurrent.y = -invCurrent.y;
|
||||||
invCurrent.z = -invCurrent.z;
|
invCurrent.z = -invCurrent.z;
|
||||||
diffQuat.multquats(calculatedRotation, invCurrent);
|
diffQuat.multquats(targetRotation, invCurrent);
|
||||||
|
|
||||||
// Convert to axis-angle representation
|
// Convert to axis-angle representation
|
||||||
var axis = new Vec4();
|
var axis = new Vec4();
|
||||||
@ -163,15 +186,15 @@ class SetLookAtRotationNode extends LogicNode {
|
|||||||
// Create partial rotation quaternion
|
// Create partial rotation quaternion
|
||||||
var partialRot = new Quat().fromAxisAngle(axis, partialAngle);
|
var partialRot = new Quat().fromAxisAngle(axis, partialAngle);
|
||||||
|
|
||||||
// Apply this partial rotation to current
|
// Apply this partial rotation to current local rotation
|
||||||
var newRot = new Quat();
|
var newLocalRot = new Quat();
|
||||||
newRot.multquats(partialRot, currentRot);
|
newLocalRot.multquats(partialRot, currentLocalRot);
|
||||||
|
|
||||||
// Apply the new rotation
|
// Apply the new local rotation
|
||||||
objectToUse.transform.rot.setFrom(newRot);
|
objectToUse.transform.rot.setFrom(newLocalRot);
|
||||||
} else {
|
} else {
|
||||||
// No damping, apply instant rotation
|
// No damping, apply instant rotation
|
||||||
objectToUse.transform.rot.setFrom(calculatedRotation);
|
objectToUse.transform.rot.setFrom(targetRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
objectToUse.transform.buildMatrix();
|
objectToUse.transform.buildMatrix();
|
||||||
@ -179,12 +202,5 @@ class SetLookAtRotationNode extends LogicNode {
|
|||||||
runOutput(0);
|
runOutput(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getter method for output sockets
|
// No output sockets needed - this node only performs actions
|
||||||
override function get(from: Int): Dynamic {
|
|
||||||
// Output index 1 is the rotation socket (global rotation)
|
|
||||||
if (from == 1) {
|
|
||||||
return calculatedRotation;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,8 @@ class SetLookAtRotationNode(LnxLogicTreeNode):
|
|||||||
update=lambda self, context: self.update_sockets(context)
|
update=lambda self, context: self.update_sockets(context)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
damping: bpy.props.FloatProperty(
|
damping: bpy.props.FloatProperty(
|
||||||
name='Damping',
|
name='Damping',
|
||||||
description='Amount of damping for rotation (0.0 = instant, 1.0 = no movement)',
|
description='Amount of damping for rotation (0.0 = instant, 1.0 = no movement)',
|
||||||
@ -74,6 +76,12 @@ class SetLookAtRotationNode(LnxLogicTreeNode):
|
|||||||
('false', 'False', 'False')],
|
('false', 'False', 'False')],
|
||||||
name='Disable Rotation on Aligning Axis', default='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):
|
def lnx_init(self, context):
|
||||||
# Add inputs in standard order
|
# Add inputs in standard order
|
||||||
self.inputs.new('LnxNodeSocketAction', 'In')
|
self.inputs.new('LnxNodeSocketAction', 'In')
|
||||||
@ -90,8 +98,6 @@ class SetLookAtRotationNode(LnxLogicTreeNode):
|
|||||||
|
|
||||||
# Add outputs
|
# Add outputs
|
||||||
self.add_output('LnxNodeSocketAction', 'Out')
|
self.add_output('LnxNodeSocketAction', 'Out')
|
||||||
# Add rotation output socket
|
|
||||||
self.add_output('LnxRotationSocket', 'Rotation')
|
|
||||||
|
|
||||||
def draw_buttons(self, context, layout):
|
def draw_buttons(self, context, layout):
|
||||||
# 1. Axis Selector
|
# 1. Axis Selector
|
||||||
@ -114,6 +120,7 @@ class SetLookAtRotationNode(LnxLogicTreeNode):
|
|||||||
self.property2 = 'true' if self.use_source_vector else 'false'
|
self.property2 = 'true' if self.use_source_vector else 'false'
|
||||||
self.property3 = str(self.damping) # Keep for backward compatibility
|
self.property3 = str(self.damping) # Keep for backward compatibility
|
||||||
self.property4 = 'true' if self.disable_rotation_on_align_axis else 'false'
|
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
|
# Store current object references before changing sockets
|
||||||
self.save_object_references()
|
self.save_object_references()
|
||||||
|
Reference in New Issue
Block a user