FQuat FAnimNode_RotationMultiplier::MultiplyQuatBasedOnSourceIndex(const FTransform& RefPoseTransform, const FTransform& LocalBoneTransform, const EBoneAxis Axis, float InMultiplier, const FQuat& ReferenceQuat) { // Find delta angle for source bone. FQuat DeltaQuat = ExtractAngle(RefPoseTransform, LocalBoneTransform, Axis); // Turn to Axis and Angle FVector RotationAxis; float RotationAngle; DeltaQuat.ToAxisAndAngle(RotationAxis, RotationAngle); const FVector DefaultAxis = GetAxisVector(Axis); // See if we need to invert angle - shortest path if( (RotationAxis | DefaultAxis) < 0.f ) { RotationAxis = -RotationAxis; RotationAngle = -RotationAngle; } // Make sure it is the shortest angle. RotationAngle = FMath::UnwindRadians(RotationAngle); // New bone rotation FQuat OutQuat = ReferenceQuat * FQuat(RotationAxis, RotationAngle* InMultiplier); // Normalize resulting quaternion. OutQuat.Normalize(); #if 0 //DEBUG_TWISTBONECONTROLLER UE_LOG(LogSkeletalControl, Log, TEXT("\t RefQuat: %s, Rot: %s"), *ReferenceQuat.ToString(), *ReferenceQuat.Rotator().ToString() ); UE_LOG(LogSkeletalControl, Log, TEXT("\t NewQuat: %s, Rot: %s"), *OutQuat.ToString(), *OutQuat.Rotator().ToString() ); UE_LOG(LogSkeletalControl, Log, TEXT("\t RollAxis: %s, RollAngle: %f"), *RotationAxis.ToString(), RotationAngle ); #endif return OutQuat; }
FQuat FAnimNode_RotationMultiplier::ExtractAngle(const TArray<FTransform> & RefPoseTransforms, FA2CSPose & MeshBases, const EBoneAxis Axis, int32 SourceBoneIndex) { // local bone transform const FTransform & LocalBoneTransform = MeshBases.GetLocalSpaceTransform(SourceBoneIndex); // local bone transform with reference rotation FTransform ReferenceBoneTransform = RefPoseTransforms[SourceBoneIndex]; ReferenceBoneTransform.SetTranslation(LocalBoneTransform.GetTranslation()); // find delta angle between the two quaternions X Axis. const FVector RotationAxis = GetAxisVector(Axis); const FVector LocalRotationVector = LocalBoneTransform.GetRotation().RotateVector(RotationAxis); const FVector ReferenceRotationVector = ReferenceBoneTransform.GetRotation().RotateVector(RotationAxis); const FQuat LocalToRefQuat = FQuat::FindBetween(LocalRotationVector, ReferenceRotationVector); checkSlow( LocalToRefQuat.IsNormalized() ); // Rotate parent bone atom from position in local space to reference skeleton // Since our rotation rotates both vectors with shortest arc // we're essentially left with a quaternion that has angle difference with reference skeleton version const FQuat BoneQuatAligned = LocalToRefQuat * LocalBoneTransform.GetRotation(); checkSlow( BoneQuatAligned.IsNormalized() ); // Find that delta angle const FQuat DeltaQuat = (ReferenceBoneTransform.GetRotation().Inverse()) * BoneQuatAligned; checkSlow( DeltaQuat.IsNormalized() ); #if 0 //DEBUG_TWISTBONECONTROLLER UE_LOG(LogSkeletalControl, Log, TEXT("\t ExtractAngle, Bone: %s (%d)"), *SourceBone.BoneName.ToString(), SourceBoneIndex); UE_LOG(LogSkeletalControl, Log, TEXT("\t\t Bone Quat: %s, Rot: %s, AxisX: %s"), *LocalBoneTransform.GetRotation().ToString(), *LocalBoneTransform.GetRotation().Rotator().ToString(), *LocalRotationVector.ToString() ); UE_LOG(LogSkeletalControl, Log, TEXT("\t\t BoneRef Quat: %s, Rot: %s, AxisX: %s"), *ReferenceBoneTransform.GetRotation().ToString(), *ReferenceBoneTransform.GetRotation().Rotator().ToString(), *ReferenceRotationVector.ToString() ); UE_LOG(LogSkeletalControl, Log, TEXT("\t\t LocalToRefQuat Quat: %s, Rot: %s"), *LocalToRefQuat.ToString(), *LocalToRefQuat.Rotator().ToString() ); const FVector BoneQuatAlignedX = LocalBoneTransform.GetRotation().RotateVector(RotationAxis); UE_LOG(LogSkeletalControl, Log, TEXT("\t\t BoneQuatAligned Quat: %s, Rot: %s, AxisX: %s"), *BoneQuatAligned.ToString(), *BoneQuatAligned.Rotator().ToString(), *BoneQuatAlignedX.ToString() ); UE_LOG(LogSkeletalControl, Log, TEXT("\t\t DeltaQuat Quat: %s, Rot: %s"), *DeltaQuat.ToString(), *DeltaQuat.Rotator().ToString() ); FTransform BoneAtomAligned(BoneQuatAligned, ReferenceBoneTransform.GetTranslation()); const FQuat DeltaQuatAligned = FQuat::FindBetween(BoneAtomAligned.GetScaledAxis( EAxis::X ), ReferenceBoneTransform.GetScaledAxis( EAxis::X )); UE_LOG(LogSkeletalControl, Log, TEXT("\t\t DeltaQuatAligned Quat: %s, Rot: %s"), *DeltaQuatAligned.ToString(), *DeltaQuatAligned.Rotator().ToString() ); FVector DeltaAxis; float DeltaAngle; DeltaQuat.ToAxisAndAngle(DeltaAxis, DeltaAngle); UE_LOG(LogSkeletalControl, Log, TEXT("\t\t DeltaAxis: %s, DeltaAngle: %f"), *DeltaAxis.ToString(), DeltaAngle ); #endif return DeltaQuat; }
//----------------------------------------------------------------------------- // Purpose: How far away is this point? This is different for point and bar magnets // Input : &vecPoint - the point // Output : float - the dist //----------------------------------------------------------------------------- float CRagdollMagnet::DistToPoint( const Vector &vecPoint ) { if( IsBarMagnet() ) { // I'm a bar magnet, so the point's distance is really the plane constant. // A bar magnet is a cylinder who's length is AbsOrigin() to m_axis, and whose // diameter is m_radius. // first we build two planes. The TOP and BOTTOM planes. // the idea is that vecPoint must be on the right side of both // planes to be affected by this particular magnet. // TOP and BOTTOM planes can be visualized as the 'caps' of the cylinder // that describes the bar magnet, and they point towards each other. // We're making sure vecPoint is between the caps. Vector vecAxis; vecAxis = GetAxisVector(); VectorNormalize( vecAxis ); CPlane top, bottom; bottom.InitializePlane( -vecAxis, m_axis ); top.InitializePlane( vecAxis, GetAbsOrigin() ); if( top.PointInFront( vecPoint ) && bottom.PointInFront( vecPoint ) ) { // This point is between the two caps, so calculate the distance // of vecPoint from the axis of the bar magnet CPlane axis; Vector vecUp; Vector vecRight; // Horizontal and Vertical distances. float hDist, vDist; // Need to get a vector that's right-hand to m_axis VectorVectors( vecAxis, vecRight, vecUp ); //CrossProduct( vecAxis, vecUp, vecRight ); //VectorNormalize( vecRight ); //VectorNormalize( vecUp ); // Set up the plane to measure horizontal dist. axis.InitializePlane( vecRight, GetAbsOrigin() ); hDist = fabs( axis.PointDist( vecPoint ) ); axis.InitializePlane( vecUp, GetAbsOrigin() ); vDist = fabs( axis.PointDist( vecPoint ) ); return MAX( hDist, vDist ); } else { return FLT_MAX; } } else { // I'm a point magnet. Just return dist return ( GetAbsOrigin() - vecPoint ).Length(); } }
void UStretchGizmoHandleGroup::UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, bool bAllHandlesVisible, class UActorComponent* DraggingHandle, const TArray< UActorComponent* >& HoveringOverHandles, float AnimationAlpha, float GizmoScale, const float GizmoHoverScale, const float GizmoHoverAnimationDuration, bool& bOutIsHoveringOrDraggingThisHandleGroup ) { // Call parent implementation (updates hover animation) Super::UpdateGizmoHandleGroup(LocalToWorld, LocalBounds, ViewLocation, bAllHandlesVisible, DraggingHandle, HoveringOverHandles, AnimationAlpha, GizmoScale, GizmoHoverScale, GizmoHoverAnimationDuration, bOutIsHoveringOrDraggingThisHandleGroup ); for (int32 HandleIndex = 0; HandleIndex < Handles.Num(); ++HandleIndex) { FGizmoHandle& Handle = Handles[ HandleIndex ]; UStaticMeshComponent* StretchingHandle = Handle.HandleMesh; if (StretchingHandle != nullptr) // Can be null if no handle for this specific placement { const FTransformGizmoHandlePlacement HandlePlacement = MakeHandlePlacementForIndex( HandleIndex ); float GizmoHandleScale = GizmoScale; const float OffsetFromSide = GizmoHandleScale * (0.0f + // @todo vreditor tweak: Hard coded handle offset from side of primitive (1.0f - AnimationAlpha) * 10.0f); // @todo vreditor tweak: Animation offset // Make the handle bigger while hovered (but don't affect the offset -- we want it to scale about it's origin) GizmoHandleScale *= FMath::Lerp( 1.0f, GizmoHoverScale, Handle.HoverAlpha ); FVector HandleRelativeLocation = FVector::ZeroVector; for (int32 AxisIndex = 0; AxisIndex < 3; ++AxisIndex) { if (HandlePlacement.Axes[AxisIndex] == ETransformGizmoHandleDirection::Negative) // Negative direction { HandleRelativeLocation[AxisIndex] = LocalBounds.Min[AxisIndex] - OffsetFromSide; } else if (HandlePlacement.Axes[AxisIndex] == ETransformGizmoHandleDirection::Positive) // Positive direction { HandleRelativeLocation[AxisIndex] = LocalBounds.Max[AxisIndex] + OffsetFromSide; } else // ETransformGizmoHandleDirection::Center { HandleRelativeLocation[AxisIndex] = LocalBounds.GetCenter()[AxisIndex]; } } StretchingHandle->SetRelativeLocation( HandleRelativeLocation ); int32 CenterHandleCount, FacingAxisIndex, CenterAxisIndex; HandlePlacement.GetCenterHandleCountAndFacingAxisIndex( /* Out */ CenterHandleCount, /* Out */ FacingAxisIndex, /* Out */ CenterAxisIndex ); FRotator Rotator = FRotator::ZeroRotator; { // Back bottom left if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Negative) { Rotator.Yaw = 0.0f; Rotator.Pitch = 0.0f; } // Back bottom right else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Negative) { Rotator.Yaw = -90.0f; Rotator.Pitch = 0.0f; } // Back top left else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Positive) { Rotator.Yaw = 0.0f; Rotator.Pitch = -90.0f; } // Back top right else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Positive) { Rotator.Yaw = -90.0f; Rotator.Pitch = -90.0f; } // Front bottom left else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Negative) { Rotator.Yaw = 0.0f; Rotator.Pitch = 90.0f; } // Front bottom right else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Negative) { Rotator.Yaw = 90.0f; Rotator.Pitch = 90.0f; } // Front top left else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Positive) { Rotator.Yaw = 0.0f; Rotator.Pitch = -180.0f; } // Front top right else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Positive) { Rotator.Yaw = 180.0f; Rotator.Pitch = -90.0f; } // Back left/right edge else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[1] != ETransformGizmoHandleDirection::Center) { Rotator.Yaw = 0.0f; Rotator.Pitch = 90.0f; } // Back bottom/top edge else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[2] != ETransformGizmoHandleDirection::Center) { Rotator.Yaw = 90.0f; Rotator.Pitch = 0.0f; } // Front left/right edge else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[1] != ETransformGizmoHandleDirection::Center) { Rotator.Yaw = 0.0f; Rotator.Pitch = 90.0f; } // Front bottom/top edge else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[2] != ETransformGizmoHandleDirection::Center) { Rotator.Yaw = 90.0f; Rotator.Pitch = 0.0f; } else { // Facing out from center of a face if (CenterHandleCount == 2) { const FQuat GizmoSpaceOrientation = GetAxisVector( FacingAxisIndex, HandlePlacement.Axes[FacingAxisIndex] ).ToOrientationQuat(); Rotator = GizmoSpaceOrientation.Rotator(); } else { // One of the left/right bottom or top edges } } } StretchingHandle->SetRelativeRotation( Rotator ); StretchingHandle->SetRelativeScale3D( FVector( GizmoHandleScale ) ); // Update material UpdateHandleColor( FacingAxisIndex, Handle, DraggingHandle, HoveringOverHandles ); } } }