万向锁
- 目录
- 万向锁的来源
- Unity中最简单的万向锁
- UE4最简单万向锁
- 解决方案
- 四元数与欧拉角之间的转换
- 参考链接
目录
万向锁的来源
简单而言,万向锁就是由于物体在进行旋转时(前提是通过欧拉角进行旋转),当旋转到某个特定角度会导致两个旋转轴处于同一个平面,导致旋转不能到达自己的预期效果,产生这种现象的原因是因为轴与轴之间存在父子关系。
视频展示链接:https://www.bilibili.com/video/av76536794/
Unity中最简单的万向锁
将x轴设为90度,旋转y轴和旋转z轴有相同效果
UE4最简单万向锁
将y轴设为90度,旋转x轴和旋转z轴有相同效果
旋转角度为0时:
绕y轴旋转90度时:
x轴和z轴的值都奇怪的变成了180度,或者当y轴设为90度时,旋转x轴和z轴效果相同,
解决方案
1 使用x轴旋转代替y轴旋转,首先将z值设置为90度,然后旋转x轴即可产生绕y轴旋转的效果
不过此方案只适用于比较规则的物体,如长方体,正方体
2 使用四元数旋转来代替欧拉角
四元数与欧拉角之间的转换
四元数的定义
四元数与欧拉角的转换
下面展示使用UE4,通过四元数处理物体旋转的代码:
// An highlighted block
// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "RotationByQuaternion.generated.h"/*** */
UCLASS()
class TWODTEST_API URotationByQuaternion : public UBlueprintFunctionLibrary
{GENERATED_BODY()UFUNCTION(BlueprintCallable, meta = (DisplayName = "Euler To Quaternion", keywords = "rotation,quaterion"), Category = "Quaternion Rotation")static FQuat Euler_To_Quaternion(FRotator Current_Rotation);UFUNCTION(BlueprintCallable, meta = (DisplayName = "Set World Rotation", keywords = "rotation,quaterion"), Category = "Quaternion Rotation")static void SetWorldRotationQuat(USceneComponent *SceneComponent, const FQuat &Target_Rotation);UFUNCTION(BlueprintCallable, meta = (DisplayName = "Set Relative Rotation", keywords = "rotation,quaterion"), Category = "Quaternion Rotation")static void SetRelativeRotationQuat(USceneComponent *SceneComponent, const FQuat &Target_Rotation);UFUNCTION(BlueprintCallable, meta = (DisplayName = "AddLocalRotationQuat", keywords = "rotation,quaterion"), Category = "Quaternion Rotation")static void AddLocalRotationQuat(USceneComponent *SceneComponent,const FQuat &DeltaRotation);};
// An highlighted block
// Fill out your copyright notice in the Description page of Project Settings.#include "RotationByQuaternion.h"
#include "Math/Quat.h"FQuat URotationByQuaternion::Euler_To_Quaternion(FRotator Current_Rotation)
{FQuat q;float yaw = Current_Rotation.Yaw*PI / 180;float roll = Current_Rotation.Roll*PI / 180;float pitch = Current_Rotation.Pitch*PI / 180;double cy = cos(yaw*0.5);double sy = sin(yaw*0.5);double cr = cos(roll*0.5);double sr = sin(roll*0.5);double cp = cos(pitch*0.5);double sp = sin(pitch*0.5);q.W = cy * cr*cp + sy * sr*sp;q.X = cy * sr*cp - sy * cr*sp;q.Y = cy * cr*sp + sy * sr*cp;q.Z = sy * cr*cp - cy * sr*sp;return q;
}void URotationByQuaternion::SetWorldRotationQuat(USceneComponent * SceneComponent, const FQuat & Target_Rotation)
{if (SceneComponent){SceneComponent->SetWorldRotation(Target_Rotation);}
}void URotationByQuaternion::SetRelativeRotationQuat(USceneComponent * SceneComponent, const FQuat & Target_Rotation)
{if (SceneComponent){SceneComponent->SetRelativeRotation(Target_Rotation);}
}void URotationByQuaternion::AddLocalRotationQuat(USceneComponent * SceneComponent, const FQuat & DeltaRotation)
{if (SceneComponent){SceneComponent->AddLocalRotation(DeltaRotation);}
}
参考链接
https://blog.csdn.net/AndrewFan/article/details/60981437
https://blog.csdn.net/u012700322/article/details/52252305