【UE5】关于C++使用右手坐标系而蓝图使用左手坐标系
最近使用FRotator类型变量在C++、蓝图和配置文件中互相使用的过程中发现了一个问题:C++中FRotator的(x,y,z)和蓝图中Rotator的(x,y,z)顺序并不是彼此对应的,这就导致我们在C++中按蓝图的习惯来设置旋转角时Actor实际的旋转方向与我们在C++中设置的旋转值并不一致。
其实x,y,z是我们习惯性的叫法,实际Rotator使用的并不是x,y,z,而是Roll,Pitch,Yaw,而在C++中FRotator的结构是FRotator(Pitch,Yaw,Roll),即(x,y,z),这是一个右手坐标系,而蓝图的Rotator的结构是Rotator(Roll,Pitch,Yaw),如果我们以右手坐标系作为参考的话,蓝图中Rotator的xyz顺序就应该是(z,x,y),所以如果我们在C++中使用顺序赋值:
1 | |
实际Pitch=0,Yaw=0,Roll=90,C++也会顺序的将这个值传给蓝图,于是蓝图的Rotator也是Rotator(0,0,90),所以实际的旋转值就变成了Pitch=0,Yaw=90,Roll=0。这就是C++传FRotator值到蓝图后实际旋转值和我们预想的不一致的原因。
避免方法也比较简单,就是抛弃我们的习惯性赋值,使用Pitch,Yaw,Roll来赋值,因为无论结构顺序怎么变,但是值是不变的:
1 | |
当我们要将C++的FRotator存储到配置文件去给美术使用时,由于即使我们使用Pitch,Roll,Yaw来赋值,但存储到文件中依旧是(0,0,90),当我们把这个值在蓝图中读出来使用时也是(0,0,90),这还是会导致实际旋转效果出错。
这里说明一下我为什么要在C++中去写文件,在蓝图中读文件,我这里是使用了在C++中直接将结构体转Json来写配置,而配置文件的实际使用是在蓝图中。
比较好的解决这个问题的办法是不使用FRotator来写配置,而是使用FVector来存储旋转值写配置,因为FVector使用的是左手坐标系,这与蓝图的Rotator一致,可以比较直观的理解,需要注意的是在蓝图中使用时不可以直接使用Rotation From X Vectror节点直接将Vector转到Rotator,因为这可能会触发万向锁,导致旋转传值错误,应该直接拆分为X,Y,Z直接赋值。
到这里细心的人可能已经发现了,我们从蓝图传Rotator值到C++时并不会出现赋值顺序出错的问题,这是因为UE在蓝图传Rotator到C++时已经为我们自动做了转换,所以不会出现这个问题。
UE之所以出现一个值类型在不同的情况下使用不同坐标系,是因为Rotator描述的是旋转角,底层使用的是欧拉角和四元数来描述,在判定正旋转方向时需要遵循右手螺旋定则,但UE底层和人们日常使用习惯都是使用左手坐标系,所以就有了两套坐标系。