unity3d欧拉角限制_unity3d 欧拉角 - CSDN
  • unity 旋转欧拉角 万向锁 解释

    万次阅读 多人点赞 2018-03-01 10:44:54
    原因出在这里,我以为欧拉角旋转是以模型坐标(齐次坐标系)为旋转轴。问题就来了,无论旋转那个轴,其它两个轴也会相应的变化,下面看图:根据上面的说明两个旋转面(圆圈)怎么会共面,让我迷糊。假设共面,那这两...

    万向锁 一直困惑我很久。。。。原因出在这里,我以为欧拉角旋转是以模型坐标(齐次坐标系)为旋转轴。问题就来了,无论旋转那个轴,其它两个轴也会相应的变化,下面看图:



    根据上面的说明两个旋转面(圆圈)怎么会共面,让我迷糊。假设共面,那这两个旋转面的法线应该是旋转轴,要想两个面共面,那旋转轴肯定平行的。但问题是以模型坐标(齐次坐标系)为旋转轴,无论旋转那个轴,其它两个轴也会相应的变化,而且相互垂直。就不会发生共面,不会出现万象锁???

    网上说欧拉角坐标轴旋转是按顺序旋转的,即父子关系,如下图


    还是不明白上图的旋转轴在哪???!

    下面我用unity演示一下


    从上面看,无论旋转那个轴,旋转后,他们的旋转轴都是垂直的。假设绕x轴旋转,y轴和z轴所确立的面就是这个变换的旋转面。问题来了,既然无论怎么旋转,旋转轴都是垂直的,当你旋转是其他轴所确立的旋转面也会旋转,保持垂直关系。那怎么会出现两个旋转面共面呢??


    下面开始说明万象锁(以unity 3D 说明)

    先说明unity 3D欧拉角的旋转顺序(父子关系)是y-x-z。即旋转y轴x和z轴都变,旋转x轴只有z轴变化,旋转z轴其它轴不变。

    再解释说明前,先说明一些坐标概念。

    模型坐标系---及模型导入时的坐标系,通过此坐标系记录模型顶点等的位置。

    世界坐标系---主要作用是表示模型与模型间的相对位置。

    惯性坐标系---和模型坐标系原点相同,但是坐标轴的方向和世界坐标系相同,作用应该是模型到世界变换的桥梁吧。


    具体请参照图书《3D数学基础:图形与游戏开发》

    引入惯性坐标是为了便于说明(实事上旋转是在一个坐标系上进行的)(在总结的时候会加以说明)

    unity模型坐标系和惯性坐标系间的查看方法


    local为模型坐标系

    global为惯性坐标系

    如果你不旋转模型,此时惯性坐标系和模型坐标系重合,你可以点选上面按钮切换看一下。

    ok,为了方便说明,我们用辅助线将惯性坐标系画到模型上,坐标轴颜色和模型坐标轴相对应

    代码如下:

    先创建一个脚本,名称为tuxingfuzhu.cs脚本,

    代码: 

    using UnityEngine;
    using System.Collections;
    //using UnityEditor;
    public class tuxingfuzhu : MonoBehaviour {
        public Mesh mesh;
    // Use this for initialization
    void Start () {

    }
        /// <summary>
        /// 如果你想绘制可被点选的gizmos,执行这个函数
        /// </summary>
        void OnDrawGizmos()
        {
            Gizmos.color = Color.red;
            Vector3 direction = Vector3.right* 2;  //世界坐标系的 轴向x
            Gizmos.DrawRay(transform.position, direction);
            Gizmos.color = Color.green;
             direction = Vector3.up* 2;   //世界坐标系的 轴向y
            Gizmos.DrawRay(transform.position, direction);
            Gizmos.color = Color.blue;
             direction = Vector3.forward* 2;     //世界坐标系的 轴向z
            Gizmos.DrawRay(transform.position, direction);


        
        }


        /// <summary>
        /// 如果你想在物体被选中时绘制gizmos,执行这个函数
        /// </summary>
        void OnDrawGizmosSelected()
        {


            //Gizmos.color = Color.white;
            //Gizmos.DrawSphere(transform.position, 1);


        
        }
    // Update is called once per frame
    void Update () {

    }
    }


    代码说明

    Gizmos.DrawRay   //绘制辅助射线,有关辅助工具请查阅unity官网的Gizmos类。

    然后将脚本挂载到要测试的物体上,这里我挂在到了cube物体上,效果如下:



    我们看到模型多了三条长线(惯性坐标)。

    ok,现在进行旋转说明。


    首先将坐标切换到模型坐标,



    下面将模型x和z轴分别旋转45度。

    点选你的测试模型,效果如下图


    ok,现在模型坐标和惯性坐标分离了。

    好,现在我们开始旋转最顶层的y轴。

    效果如下图:

    你发现了什么???

    你会发现旋转y轴是绕着惯性左边的y轴旋转的,而不是模型的坐标。

    ok,现在将z轴置0,然后旋转x轴,y轴可以有一定的度数,为了作对照。

    效果如下图:



    此时你会发现x轴的变换是绕着模型坐标的x轴进行变换的。

    ok,接着进行z轴的变换,如下图:


    你会发现z轴的变换也是绕着模型的z轴变换。


    到这里问题就差不多了。为什么会共面,因为y轴变换将影响x和z轴,因为有轴处在变换的最顶层(y-x-z),最主要的是y轴变换是模型在惯性坐标里变换,而其他轴的变换是在模型轴变换。所以就会出旋转面共面(万向锁)的情况

    下面开始说明万向锁的情况。

    将模型x轴旋转90度(或者-90度)(最简单的万向锁)

    紧接着旋转y轴或者z轴,效果如下:


    这就是万向锁

    你会发现z轴旋转和y轴旋转效果是一样的,同时你会发现z轴(模型坐标系)和y轴坐标(惯性坐标系)平行。

    此时y轴(惯性坐标系)旋转面和z轴(模型坐标系)旋转面共面如下图,



    从上图很容易看出旋转y轴(惯性坐标系)和旋转z轴(模型坐标系)是一样的效果,只不过方向相反或相同。


    让我困惑的问题解决了。

    总结:

    万向锁产生时两个旋转轴平行(旋转面共面)是模型的旋转失去的一个方向的旋转。

    最主要的是弄明白旋转是围绕着什么样的坐标系做旋转。

    上面的解释只是从表面上解释了万向锁

    实际上模型的旋转是以一个坐标系进行旋转。但上面解释是等效的。下面解释一下。

    计算机模型的旋转过程不是我们想的连续旋转。什么意思呢?

    假设U3D每一帧绕Y旋转5度,他的旋转过程是:第一次旋转从(0,0,0)绕Y轴旋转5度为(0,5,0),到现在还没有问题,那第二次旋转会是什么情况呢。

    有人说,简单,再从现在以变换的模型旋转(0,5,0)绕Y轴旋转5度---->(0,10,0)不就行了。但计算机不会这样做。它是在原模型坐标(0,0,0)重新开始变化,

    即(0,0,0)------>(0,10,0)。

    就是说模型的变换都是(0,0,0)开始变换,主意,知道这一点才是最主要的。

    当模型绕Y-X-Z顺序旋转时,当模型发生旋转变换时:

    步骤1.每次变换的顺序都是(0,0,0)-------------->(x,y,z),即都是从(0,0,0)开始,先变换Y轴,在变换X轴,然后在变换轴。

    每次只要有变换,都要重复步骤1的过程。

    每次旋转都先绕Y轴旋转,所以每次旋转变换的Y轴方向是不变的,和惯性坐标重合。所以我上面的旋转是以惯性坐标去解释。其实这个困惑是时间上的先后顺序产生的,准确的

    说是时间上的共轴或共面


    下面我演示变换过程如下图:


    上面演示了三次图形变换(0,0,0)----->(58,67,40);  (0,0,0)-------->(45,87,60);   (0,0,0)-------->(45,67,67)

    在变换时,内部程序都是从(0,0,0)开始变换(算法)的。即使你再U3D参数设置上可以在现有的变换进行变换,但程序内部还是从(0,0,0)开始变换。

    从上面三次(或者更多次)变换,你会发现三次变换的第一次Y轴变换的轴是一样的。绿色的圆为旋转面。

    接下来是X轴旋转,z轴旋转。即使Y轴变换了,但是三次变化在第一次绕y轴变换的时刻Y轴是不变的。所以y轴与Z轴会有共线,或者说Y轴的旋转轴和Z轴的旋转轴共面只

    是在时间变换上的共面。(万向锁的产生)




    在U3D中,旋转顺序是y-x-z(模型坐标---惯性坐标系旋转),官网为z-x-y(惯性坐标系----模型坐标)。

    y轴是惯性坐标系的y轴,其它轴是模型的坐标轴。这是因为不同坐标系的轴才有可能产生共面


    如果不明白坐标系的,具体请查阅《3D数学基础:图形与游戏开发》图书。

    打个广告吧。推荐一下吧,非常基础,非常形象易懂的图形学图书。

    万象锁有关视频

    http://v.youku.com/v_show/id_XNzkyOTIyMTI=.html




    展开全文
  • Unity 3D数学之欧拉角

    2019-10-17 20:04:29
    什么是欧拉角 ...Unity引擎限制沿x轴旋转范围如下: 用欧拉角做旋转代码如下; public Vector3 eluer; private void OnGUI() { eluer = this.transform.eulerAngles; if (GUILayout.Repe...

    什么是欧拉角

     

    欧拉角的优点:

    欧拉角的缺点:

    Unity引擎限制沿x轴旋转范围如下:

    欧拉角做旋转代码如下;

      public Vector3 eluer;
        private void OnGUI()
        {
            eluer = this.transform.eulerAngles;
            if (GUILayout.RepeatButton("沿x轴旋转"))
            {
                transform.eulerAngles += new Vector3(1, 0, 0);
               // transform.eulerAngles += new Vector3(-1, 0, 0);
               // this.transform.eulerAngles += Vector3.left;
            }
          
            if (GUILayout.RepeatButton("沿Y轴旋转"))
            {
    
                transform.eulerAngles += new Vector3(0,1,0);
                //this.transform.eulerAngles += Vector3.up;
            }
            if (GUILayout.RepeatButton("沿z轴旋转"))
            {
                transform.eulerAngles += new Vector3(0, 0, 1);
              //  this.transform.eulerAngles += Vector3.forward;
            }
        }

    即用上面代码表示获取的X值在-90—90之间,Y值与Z值在0—360之间 (编译器中Y与Z值显示在-180—180之间)

    万向节死锁

     

     

     

    总结:

    用欧拉角做物体的旋转就会死锁,所以很少用欧拉角做空间的旋转,但是欧拉角对物体角度进行单独的设置是比较好的,但对于物体空间的旋转,数学家们引出了另外一种方式叫四元数。

     

    展开全文
  • 本文主要测试transform.localRotation的使用,该属性一般使用四元数赋值,通过Quaternion可以将欧拉角转化为四元数。`xxx.transform.localRotation = Quaternion.Eular(float x, float y, float z); 在三个立方体的...

    本文主要测试transform.localRotation的使用,该属性一般使用四元数赋值,通过Quaternion可以将欧拉角转化为四元数。`xxx.transform.localRotation = Quaternion.Eular(float x, float y, float z);

    在三个立方体的场景中,有根节点立方体、父节点立方体和子节点立方体共三个。下面的测试中分别控制三个立方体,分别控制立方体的不同坐标维度的旋转角度。

    第一部分:通过localRotation控制父节点立方体的转动

    一.使用实例1

    该实例只是简单表现localRotation的使用方法,使得Cube1绕Z轴旋转45°。
    这里写图片描述
    这里写图片描述
    【结论补充与分析】上述两个部分使用Rotation控制Cube1(父节点)绕单一坐标轴做旋转。注意,上述语句与使用Rotate(new Vector3(x,y,z), Space.Self)Rotate(new Vector3(x,y,z), Space.World)的结果一致。

    二.使用实例2

    该部分的实例都是通过localRotation控制Cube1绕两个坐标轴做旋转。同时探究旋转轴的顺序和参考坐标系的问题。
    先看结论:旋转轴的顺序是X-Y-Z,该旋转轴是父节点的本地坐标系。

    (一)实例2-1

    实例2-1使得Cube1绕z轴和y轴旋转
    这里写图片描述
    这里写图片描述
    这里写图片描述
    【结论分析】从上图联合控制的结果中分析可得,Cube1可以从以下方式获得:①如图0614456,绕世界坐标系正z轴旋转45°,绕世界坐标系正y轴旋转45°(顺序反之则不可);②如图0614231,绕世界坐标系正y轴(本地坐标系y轴)旋转45°,再绕旋转所得本地坐标系z轴旋转45°;注意,根据其他资料显示第1种是正确的。后面将做具体讲解。

    (二)实例2-2

    实例2-2使得Cube1绕x轴和y轴旋转
    这里写图片描述

    这里写图片描述
    这里写图片描述
    【结论分析】从上图联合控制的结果中分析可得,Cube1可以从以下方式获得:①如图69523所示,绕世界坐标系正x轴旋转-45°,绕世界坐标系正y轴旋转45°(顺序反之则不正确);③如图0614528,绕本地坐标系Y轴旋转45°,再绕旋转之后所得的本地坐标系X轴旋转-45°。

    (三)实例2-3

    实例2-2使得Cube1绕x轴和z轴旋转
    这里写图片描述
    这里写图片描述
    【结论分析】从上图联合控制的结果来看,Cube1可以从以下方式得到:①如图0614756,绕世界坐标系Z轴旋转45°,然后再绕世界坐标系X轴旋转45°。由于时间关系,此处不再验证与本地坐标系的关系。直接甩结论。

    初步结论transform.localRotation控制旋转角度与本地坐标系无直接联系,其实与世界坐标系也无直接联系。上面三组实验,初步可以看出transform.localRotation可以分解成绕世界坐标系的旋转,其实此处的世界坐标系与Cube1的父节点Cube0的本地坐标系相同。所以上述的所有结果都显示了与世界坐标系挂钩,下面我们将使Cube0发生一点旋转,以使得世界坐标系和Cube0的本地坐标系不再重合。同时,可以大致推断出旋转轴的顺序是Z-X-Y

    三、使用实例3

    在前面两个部分的实例当中,我们已经可以大致推断出localRotation的使用规律,即
    - 旋转的参考坐标系是父节点的本地坐标系
    - 旋转轴的顺序是Z-X-Y

    后面的部分将着重进行验证

    实例3-1

    这里写图片描述
    【结果分析】该实例绕x,y,z分别做旋转,做分解之后与先绕z,再绕x,最后绕y的结果是一致的。这与之前的结论是对应的。

    第二部分:探究localRotation的使用注意事项

    四、使用注意事项

    localRotationtransform组件的一个属性。表现了该实例在父节点坐标系下的旋转情况。根据前面内容可以知道是按照Z-X-Y的顺规绕父节点的坐标系进行的旋转。除此之外,我们还有其他的一些注意事项,下面将做简单介绍。

    (一) 赋值边界

    我们知道旋转角度存在周期性,旋转x度和旋转x+360*k的效果是一样的。那么在利用Quaternion.Eular(x,y,z)将欧拉角转化为四元数给localRotation赋值的时候是否有限制呢?
    这里写图片描述
    【结果分析】很多资料提到Rotate()方法在使用的时候不要超过360°,我们发现在上面的测试中,角度值超过360度并不影响,只需要除以360取余数即可。

    全文总述,明确结论

    五、结论

    1. transform.localRotation = Quaternion.Eular(x,y,z)控制旋转的时候,按照Z-X-Y的旋转顺规,且绕轴旋转的坐标轴是父节点本地坐标系的坐标轴
    2. 利用上述语句进行控制的时候,对赋值的角度没有必须在(-360°,360°)的约束。
    展开全文
  • [Unity3D]Unity3D游戏开发之自由视角下的角色控制

    万次阅读 热门讨论 2014-09-10 12:54:34
    在上一篇文章[Unity3D]Unity3D游戏开发之角色控制漫谈>一文中,博主与大家分享自己在角色控制方面的一些感悟。今天呢,我们继续来探讨Unity3D角色控制的内容,今天博主将解决在上一篇文章中没有解决的问题,即自由...

           各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei。在上一篇文章<[Unity3D]Unity3D游戏开发之角色控制漫谈>一文中,博主与大家分享自己在角色控制方面的一些感悟。今天呢,我们继续来探讨Unity3D角色控制的内容,今天博主将解决在上一篇文章中没有解决的问题,即自由视角下的角色控制。如图是博主非常喜欢的《古剑奇谭》游戏截图,在这款游戏中就使用了博主今天要讲解的自由视角,所谓自由视角是指玩家可以按照自身坐标系向着四个不同的方向移动,当玩家按下鼠标右键时,可以绕Y轴按照一定的角度旋转摄像机,在旋转的过程中,角色将旋转相应的角度。在移动的过程中,摄像机会保持与玩家间的一定距离,然后跟随角色进行移动。好了,下面我们正式开始今天的内容吧!


         

         在开始今天的内容前,首先让我们来学习下Unity3D中较为重要的一部分知识,理解这些知识是我们开始学习今天内容的基础。

         1、Input.GetAxis():该方法用于在Unity3D中根据坐标轴名称返回虚拟坐标系中的值,通常情况下,使用控制器和键盘输入时此值范围在-1到1之间。这段话怎么理解呢?我们来看下面这段脚本:

    using UnityEngine;
    using System.Collections;
    
    public class example : MonoBehaviour {
    
    	//水平速度
    	public float HorizontalSpeed = 2.0F;
    	//垂直速度
    	public float VerticalSpeed = 2.0F;
    
    	void Update() 
    	{
    		//水平方向
    		float h = HorizontalSpeed * Input.GetAxis("Mouse X");
    		//垂直方向
    		float v = VerticalSpeed * Input.GetAxis("Mouse Y");
    		//旋转
    		transform.Rotate(v, h, 0);
    	}
    }
    这段脚本呢是根据鼠标的位置来旋转物体从而实现对物体的观察,从这段脚本中我们可以看出,通过获取输入轴的办法,我们可以获得鼠标移动的方向进而实现对于物体的旋转控制。在Unity3D中我们可以通过Edit->Project Setting->Input来查看项目中的坐标轴名称:


    在后面,我们还将使用这种方式,大家可以对这个方法有进一步的了解。


         2、欧拉角eulerAngles:该值是Vector3类型的值,x、y、z分别代表绕x轴旋转x度,绕y轴旋转y度,绕z轴旋转z度。因此,该值最为直观的形式是可以允许我们直接以一个三维向量的形式来修改一个物体的角度,例如下面的脚本:

    float mY = 5.0;
    
    void Update () 
    {
    	mY += Input.GetAxis("Horizontal");
    	transform.eulerAngles =new Vector3(0,mY, 0);
    }
         如果你已经理解了上面的话,那么不出意外的,这段脚本会如你所愿的,按照鼠标在水平方向上移动的方向绕Y轴旋转。通常情况下,我们不会单独设置欧拉角其中一个轴,例如eulerAngles.x = 10,因为这将导致偏移和不希望的旋转。当设置它们一个新的值时,要同时设置全部。好在我们可以通过Quaternion.Euler()方法将一个Vector3类型的值转化为一个四元数,进而通过修改Transform.Rotation来实现相同的目的。

        

         3、插值:所谓插值是指离散数据的基础上补插连续函数,使得这条连续曲线通过全部给定的离散数据点。插值是离散函数逼近的重要方法,利用它可通过函数在有限个点处的取值状况,估算出函数在其他点处的近似值。在某些情况下,如果我们希望过程中处理得较为平滑,此时我们就可以使用插值的方法来实现对中间过程的模拟。在Unity3D中我们可以使用两种插值方法,即线性插值Lerp,球形插值SLerp。我们来看下面的脚本:

    void Rotating (float horizontal, float vertical)
    	{
    		// Create a new vector of the horizontal and vertical inputs.
    		Vector3 targetDirection = new Vector3(horizontal, 0f, vertical);
    		
    		// Create a rotation based on this new vector assuming that up is the global y axis.
    		Quaternion targetRotation = Quaternion.LookRotation(targetDirection, Vector3.up);
    		
    		// Create a rotation that is an increment closer to the target rotation from the player's rotation.
    		Quaternion newRotation = Quaternion.Lerp(rigidbody.rotation, targetRotation, turnSmoothing * Time.deltaTime);
    		
    		// Change the players rotation to this new rotation.
    		rigidbody.MoveRotation(newRotation);
    	}
    
    插值的方法很简单,只要我们给出初始和结束的状态、时间就可以了,大家可以自己看API。


          好了,有了这三部分的基础,我们就可以开始今天的内容了,今天的脚本分为两个部分,第一部分是角色控制的部分,主要负责的角色在场景中的移动、转身和动画处理。第二部分是相机控制的部分,主要涉及相机旋转、相机缩放的相关内容。下面,我们分别来讲这两个部分,场景依然是博主自己在做的小游戏:


    本次的主角呢,是博主非常喜欢的角色谢沧行,好了,我们回到今天的内容里吧!在第一部分,主要的是完成角色向各个方向的转身,这里博主定义四个方向(其实八个方向是一样的!),脚本如下:

    using UnityEngine;
    using System.Collections;
    
    public class NoLockiVew_Player : MonoBehaviour {
    
    	/*自由视角下的角色控制*/
    	/*作者:秦元培*/
    
    	//玩家的行走速度
    	public float WalkSpeed=1.5F;
    	//重力
    	public float Gravity=20;
    
    	//角色控制器
    	private CharacterController mController;
    	//动画组件
    	private Animation mAnim;
    	//玩家方向,默认向前
    	private DirectionType mType=DirectionType.Direction_Forward;
    
    	[HideInInspector]
    	//玩家状态,默认为Idle
    	public PlayerState State=PlayerState.Idle;
    
    	//定义玩家的状态枚举
    	public enum PlayerState
    	{
    		Idle,
    		Walk
    	}
    
    	//定义四个方向的枚举值,按照逆时针方向计算
    	protected enum DirectionType
    	{
    		Direction_Forward=90,
    		Direction_Backward=270,
    		Direction_Left=180,
    		Direction_Right=0
    	}
    	
    	void Start () 
    	{
    	   //获取角色控制器
    	   mController=GetComponent<CharacterController>();
    	   //获取动画组件
    	   mAnim=GetComponentInChildren<Animation>();
    	}
    	
    	
    	void Update () 
    	{
    		MoveManager();
    		//MouseEvent();
    	}
    
    	//玩家移动控制
    	void MoveManager()
    	{
    		//移动方向
    		Vector3 mDir=Vector3.zero;
    		if(mController.isGrounded)
    		{
    			//将角色旋转到对应的方向
    			if(Input.GetAxis("Vertical")==1)
    			{
    				SetDirection(DirectionType.Direction_Forward);
    				mDir=Vector3.forward * Time.deltaTime * WalkSpeed;
    				mAnim.CrossFade("Walk",0.25F);
    				State=PlayerState.Walk;
    			}
    			if(Input.GetAxis("Vertical")==-1)
    			{
    				SetDirection(DirectionType.Direction_Backward);
    				mDir=Vector3.forward * Time.deltaTime * WalkSpeed;
    				mAnim.CrossFade("Walk",0.25F);
    				State=PlayerState.Walk;
    			}
    			if(Input.GetAxis("Horizontal")==-1)
    			{
    				SetDirection(DirectionType.Direction_Left);
    				mDir=Vector3.forward * Time.deltaTime * WalkSpeed;
    				mAnim.CrossFade("Walk",0.25F);
    				State=PlayerState.Walk;
    			}
    			if(Input.GetAxis("Horizontal")==1)
    			{
    				SetDirection(DirectionType.Direction_Right);
    				mDir=Vector3.forward * Time.deltaTime * WalkSpeed;
    				mAnim.CrossFade("Walk",0.25F);
    				State=PlayerState.Walk;
    			}
    			//角色的Idle动画
    			if(Input.GetAxis("Vertical")==0 && Input.GetAxis("Horizontal")==0)
    			{
    				mAnim.CrossFade("Idle",0.25F);
    				State=PlayerState.Idle;
    			}
    
    		}
    		//考虑重力因素
    		mDir=transform.TransformDirection(mDir);
    		float y=mDir.y-Gravity *Time.deltaTime;
    		mDir=new Vector3(mDir.x,y,mDir.z);
    		mController.Move(mDir);
    	}
    
    	//设置角色的方向,有问题
    	void SetDirection(DirectionType mDir)
    	{
    		if(mType!=mDir)
    		{
    			transform.Rotate(Vector3.up*(mType-mDir));
    			mType=mDir;
    		}
    	}
    }
    
    这里定义四个方向,是按照逆时针方向转的,相邻的两个方向间相差90度,所以我们只需要将当前的角度和目标角度相减就可以转到目标角度的方向(其实这是以前写的代码,现在回头再看,直接用欧拉角似乎更为简单啊,呵呵)。这里主要的内容就是这样了。下面我们来看相机控制部分的代码吧,这里的代码参考了MouseOrbit脚本,主要完成了鼠标右键旋转控制,博主在此基础上增加了相机缩放的代码。提到相机缩放,其实就是根据鼠标滚轮滚动的方向和大小重新计算角色与相机的距离,与之类似地还有小地图的放缩,其实同样是通过修改距离来实现的。博主今天的一个体会是官方的代码能自己写一遍的最好自己写一遍,这样好多东西就能在这个过程中给理解了。我们一起来看脚本
    using UnityEngine;
    using System.Collections;
    
    public class NoLockView_Camera : MonoBehaviour 
    {
    	//观察目标
    	public Transform Target;
    	//观察距离
    	public float Distance = 5F;
    	//旋转速度
    	private float SpeedX=240;
    	private float SpeedY=120;
    	//角度限制
    	private float  MinLimitY = 5;
    	private float  MaxLimitY = 180;
    
    	//旋转角度
    	private float mX = 0.0F;
    	private float mY = 0.0F;
    
        //鼠标缩放距离最值
    	private float MaxDistance=10;
    	private float MinDistance=1.5F;
    	//鼠标缩放速率
    	private float ZoomSpeed=2F;
    
    	//是否启用差值
    	public bool isNeedDamping=true;
    	//速度
    	public float Damping=2.5F;
    
    	void Start () 
    	{
    		//初始化旋转角度
    		mX=transform.eulerAngles.x;
    		mY=transform.eulerAngles.y;
    	}
    	
    	void LateUpdate () 
    	{
    		//鼠标右键旋转
    		if(Target!=null && Input.GetMouseButton(1))
    		{
    		    //获取鼠标输入
    			mX += Input.GetAxis("Mouse X") * SpeedX * 0.02F;
    			mY -= Input.GetAxis("Mouse Y") * SpeedY * 0.02F;
    			//范围限制
    			mY = ClampAngle(mY,MinLimitY,MaxLimitY);
    		}
    
    		//鼠标滚轮缩放
    
    		Distance-=Input.GetAxis("Mouse ScrollWheel") * ZoomSpeed;
    		Distance=Mathf.Clamp(Distance,MinDistance,MaxDistance);
    
    		//重新计算位置和角度
    		Quaternion mRotation = Quaternion.Euler(mY, mX, 0);
    		Vector3 mPosition = mRotation * new Vector3(0.0F, 0.0F, -Distance) + Target.position;
    
    		//设置相机的角度和位置
    		if(isNeedDamping){
    		   //球形插值
    		   transform.rotation = Quaternion.Lerp(transform.rotation,mRotation, Time.deltaTime*Damping); 
    		   //线性插值
    		   transform.position = Vector3.Lerp(transform.position,mPosition, Time.deltaTime*Damping); 
    		}else{
    		   transform.rotation = mRotation;
    		   transform.position = mPosition;
    		}
    		//将玩家转到和相机对应的位置上
    		if(Target.GetComponent<NoLockiVew_Player>().State==NoLockiVew_Player.PlayerState.Walk)
    		{
    			Target.eulerAngles=new Vector3(0,mX,0);
    		}
    	}
    	
    	private float  ClampAngle (float angle,float min,float max) 
    	{
    		if (angle < -360) angle += 360;
    		if (angle >  360) angle -= 360;
    		return Mathf.Clamp (angle, min, max);
    	}
        
    
    
    
    }
    
    
    

    这里很多朋友可能对我设置一个状态很不理解吧,这其实是为了让玩家有一个自由查看角色的机会,否则当玩家按下鼠标右键的话,角色就会转向相机正对着的位置,这样玩家就看不到角色的正面了。当然,这里用到了插值,这样能使角色在转身的时候平滑一点,效果会更好。

    唉,不知不觉已经这个时候了,开学已经一周了,这学期我们只上九周课,然后就是实习、毕设、找工作一大堆事情在等着我们。可是不知道为什么博主宿舍的同学居然还能每天什么事情都不做,从早上一直看电视剧到晚上十点,虽然这件事情和博主没有什么关系吧,可是整个宿舍的人都安安静静地做着自己的事情,就有这么一个人整天声音开得很大在那里外放,这样真的好吗?以前和这个人闹过一次,因为他聚了一帮人在宿舍打麻将,我觉得吵就说了他一顿,结果就和我僵上了。说真的,博主对目前的专业真的没有什么情感,大学四年里最让博主开心的事情就是博主学会了好多自己想要学的东西,认识了几个不错的老师和朋友,仅此而已。或许我们注定要越走越远吧,因为我们根本就不是同一种人。

    前几天网上有人通过博客联系到博主,希望博主能到他哪里工作,可惜博主目前仍然有一大堆的琐事缠身,不然离开这喧嚣吵闹的宿舍,去做博主喜欢的事情,去寻找博主自己的梦想,博主相信,博主一定可以做得更好吧。人生或许就是这样,你越是在乎的可能越让你得不到,你无心插柳可能会得到一片绿荫。对于未来,不管怎么样,坦然面对就好了,博主改变不了周围的这群人,只能努力地去改变自己。好了,晚安吧!

    效果演示(2M的限制让很多展示都无可奈何)



    每日箴言:所有的悲伤,总会留下一丝欢乐的线索。所有的遗憾,总会留下一处完美的角落。我在冰封的深海,找寻希望的缺口。却在午夜惊醒时,蓦然瞥见绝美的月光。——几米


           喜欢我的博客请记住我的名字:秦元培,我博客地址是blog.csdn.net/qinyuanpei。
           转载请注明出处,本文作者:秦元培,本文出处:http://blog.csdn.net/qinyuanpei/article/details/39125353


          文章更新:

          9月10日,博主在测试这个项目的时候意外地发现了一个Bug。Bug出现在如下位置:

    		//设置玩家跟随角度
    		if(Target.GetComponent<NoLockiVew_Player>().State==NoLockiVew_Player.PlayerState.Walk)
    		{
    			Target.rotation=Quaternion.Euler(new Vector3(0,mX,0));
    		}

    该方法主要的作用是当玩家同时按下方向控制键和鼠标右键,玩家可以随着鼠标旋转到对应的角度,这主要是为了满足玩家双手操作的需求,不过由于这行代码,导致玩家在向左、向右、向后三个方向上的转身失效,如果除去这行代码,则原来的方向控制没有任何问题,可是没有这行代码,玩家的操作感就会下降。后来博主想到我们对角色的旋转实际上应该是放在鼠标右键事件里的,所以博主将代码修改如下,这样就解决了这个Bug:

    using UnityEngine;
    using System.Collections;
    
    public class NoLockView_Camera : MonoBehaviour 
    {
    	//观察目标
    	public Transform Target;
    	//观察距离
    	public float Distance = 5F;
    	//旋转速度
    	private float SpeedX=240;
    	private float SpeedY=120;
    	//角度限制
    	private float  MinLimitY = 5;
    	private float  MaxLimitY = 180;
    
    	//旋转角度
    	private float mX = 0.0F;
    	private float mY = 0.0F;
    
        //鼠标缩放距离最值
    	private float MaxDistance=10;
    	private float MinDistance=1.5F;
    	//鼠标缩放速率
    	private float ZoomSpeed=2F;
    
    	//是否启用差值
    	public bool isNeedDamping=true;
    	//速度
    	public float Damping=10F;
    
    	private Quaternion mRotation;
    
    	void Start () 
    	{
    		//初始化旋转角度
    		mX=transform.eulerAngles.x;
    		mY=transform.eulerAngles.y;
    	}
    	
    	void LateUpdate () 
    	{
    		//鼠标右键旋转
    		if(Target!=null && Input.GetMouseButton(1))
    		{
    		    //获取鼠标输入
    			mX += Input.GetAxis("Mouse X") * SpeedX * 0.02F;
    			mY -= Input.GetAxis("Mouse Y") * SpeedY * 0.02F;
    			//范围限制
    			mY = ClampAngle(mY,MinLimitY,MaxLimitY);
    			//计算旋转
    			mRotation = Quaternion.Euler(mY, mX, 0);
    			//根据是否插值采取不同的角度计算方式
    			if(isNeedDamping){
    				transform.rotation = Quaternion.Lerp(transform.rotation,mRotation, Time.deltaTime*Damping); 
    			}else{
    				transform.rotation = mRotation;
    			}
    			//处理同时按下鼠标右键和方向控制键
    			if(Target.GetComponent<NoLockiVew_Player>().State==NoLockiVew_Player.PlayerState.Walk){
    				Target.rotation=Quaternion.Euler(new Vector3(0,mX,0));
    			}
    		}
    
    		//鼠标滚轮缩放
    		Distance-=Input.GetAxis("Mouse ScrollWheel") * ZoomSpeed;
    		Distance=Mathf.Clamp(Distance,MinDistance,MaxDistance);
    
    		//重新计算位置
    		Vector3 mPosition = mRotation * new Vector3(0.0F, 0.0F, -Distance) + Target.position;
    
    		//设置相机的角度和位置
    		if(isNeedDamping){
    		   transform.position = Vector3.Lerp(transform.position,mPosition, Time.deltaTime*Damping); 
    		}else{
    		   transform.position = mPosition;
    		}
    
    	}
    
    
    	//角度限制
    	private float  ClampAngle (float angle,float min,float max) 
    	{
    		if (angle < -360) angle += 360;
    		if (angle >  360) angle -= 360;
    		return Mathf.Clamp (angle, min, max);
    	}
    }
    
    
    
    不过经过博主测试,如果不采用插值的话,似乎效果更为真实啊(为什么会和第一次测试的感觉不一样啊,囧!)




    展开全文
  • 摄像机镜头跟随鼠标移动,并限制上下左右的移动角度 public class ViewFromCream : MonoBehaviour { public int speed=5; public Vector3 vect; private float xcream; private float ycream; public void ...
  • Unity3D常见面试题

    万次阅读 多人点赞 2017-08-11 20:20:00
    Unity3D常见面试题
  • 1 using UnityEngine; 2 using System.Collections; 3 /* 4 * 控制摄像机的视野范围 5 */ 6 public class CameFieldCS : MonoBehaviour { 7 8 private Transform player;... 9 private Vec...
  • using System.Collections; using System.Collections.Generic; using UnityEngine; public class LimitGyroscope : MonoBehaviour { public GameObject gyroscopeGo; //自动旋转的物体 private Vector3 ...
  • Unity3D面试题整合

    千次阅读 2019-09-17 20:11:37
    最近unity3d找工作有些受挫,自己也开始补课了。 下面把这段时间看到的些面试题供出来让大家也学习下,题目只是面试官选拔人才的一部分,在研究面试题目的过程中,多检测下自己的不足,及时温习或补习下,最终学到真...
  • Unity3D 控制摄像机(二)

    千次阅读 2018-07-02 13:54:04
    Unity3D编辑器中Transform下的Rotation 3个值 实际上对应的值是该组件的欧拉角值(这句话不完全正确看下面) eulerAngles的属性是Vector3 x -&amp;amp;gt; transform.eulerAngles.x y -&amp;amp;gt; ...
  • Unity3D 控制摄像机(一)

    千次阅读 2018-07-02 13:32:24
    Unity3D 控制摄像机(一) 第一人称摄像机 该脚本效果 图示为Local坐标系 旋转引发Local坐标系的变化 几点说明 Unity3D 控制摄像机(一) 第一人称摄像机 using System.Collections; using System....
  • Unity3D面试题

    千次阅读 2018-11-20 14:09:58
    目录 第一部分 1. 请简述值类型与引用类型的区别 2.C#中所有引用类型的基类是什么  3.请简述ArrayList和List的主要区别 4.请简述GC(垃圾回收)产生的原因,并描述如何避免?...5.请描述Interface与抽象类之间的...
  • Unity3d面试题

    2018-06-25 15:16:20
    这个是我刚刚整理出的Unity面试题,为了帮助大家面试,同时帮助大家更好地复习Unity知识点,如果大家发现有什么错误,(包括错别字和知识点),或者发现哪里描述的不清晰,请在下面留言,我会重新更新,希望大家共同...
  • Unity3D基础2-12】Unity3D常用API

    千次阅读 2020-05-15 10:17:12
    Unity3D从入门到进阶】文章目录及设置这个专栏的初衷 二、Unity3D常用API 1、Event Function:事件函数 - Reset() :被附加脚本时、在游戏物体的组件上按Reset时会触发该事件函数 - Start() :在游戏初始化时会执行一...
  • Unity3D】笔试题、面试题

    千次阅读 2020-05-12 16:32:14
    1、请简述值类型与引用类型的区别。 值类型传递的是值本身,引用类型传递的是地址。 2、C#中所有引用类型的基类是什么? object ...3、请简述ArrayList和List之间的主要区别。...LIST是接口类,ArrayList类实现了这个...
  • Unity3D第三人称Camera视角旋转实现

    千次阅读 2018-08-11 10:43:57
    Unity3D第三人称Camera视角旋转,实现对player观察的实现,效果图如下(player and Scene 有点lou): 内容知识总结: Input.GetAxis():该方法用于在Unity3D中根据坐标轴名称返回虚拟坐标系中的值,通常情况下...
  • 实现第三人称视角有三种:方案1: 最简单的就是 直接 把主相机作为Player角色的子物体,并自行固定好相机的位置 方案2: 设置一个空的GameObject,并且与Player的旋转和位置保持一致,然后将 主相机 设置成该...
  • unity3d学习(一)制作第一人称射击-玩家的视口和移动unity3d学习一制作第一人称射击-玩家的视口和移动 构建简单场景 添加脚本 总结写在前面: - 学习课本:Unity5实战 使用c#和unity开发多平台游戏-作者:Joseph ...
  • Unity3D-----欧拉角与四元数

    千次阅读 2020-05-13 11:53:16
    欧拉角与四元数一、欧拉角1、什么是欧拉角2、欧拉角的优点3、欧拉角的缺点3.1 万向节死锁二、四元数1、什么是四元数2、基本运算2.1 与向量相乘2.2 与四元数相乘3、优点4、常用API 一、欧拉角 1、什么是欧拉角 ...
1 2 3 4 5 ... 17
收藏数 337
精华内容 134
关键字:

unity3d欧拉角限制