1、Unity【基础】3D数学

3D数学

文章目录

3D数学

1、数学计算公共类Mathf

1、Mathf和Math

c 复制代码
Math是c#中封装好的用于【数学计算的工具类】位于system命名空间中
    public static class Math{}
Mathf是Unity中封装好的用于【数学计算的工具结构体】位于UnityEngine命名空间中
    public struct Mathf{}
他们都是提供来用于进行【数学相关计算】的

2、区别

c 复制代码
一个是静态类,一个是结构体
Mathf比Math有更多的数学计算方法

3、Mathf中的常用方法(一般计算一次)

csharp 复制代码
void Start()
{
    1、π PI
        Mathf.PI
    2、绝对值 Abs
    3、向上取整 CeilToInt
        print(Mathf.CeilToInt(1.3f)); //2
    4、向下取整 FloorToInt
    5、钳制函数 Clamp (在参数二,和参数三的范围里取值)
        print(Mathf.Clamp(10, 11, 22)); //11
        print(Mathf.Clamp(23, 11, 22)); //22
        print(Mathf.Clamp(16, 11, 22)); //16
    6、获取最大值 Max
    7、获取最小值 Min
    8、一个数的n次方 Pow
        print(Mathf.Pow(2, 3)); //2的3次方
    9、四舍五入 RoundToInt
    10、返回一个数的平方根 Sqrt
    11、判断一个数是否是2的n次方 IsPowerOfTwo
        print(Mathf.IsPowerOfTwo(1)); //true
    12、判断正负数 Sign
        print(Mathf.Sign(8)); //1
        print(Mathf.Sign(-8)); //-1
}

4、Mathf中的常用方法(一般不停计算)

csharp 复制代码
float start = 0;
float result = 0;
float time = 0;
void Update()
{
插值运算 Lerp
    Lerp函数公式
        result = Mathf.Lerp(start,end,t);
    t为插值系数,取值范围为0~1,计算方法:
        result = start + (end - start) * t

    插值运算用法1
    每帧改变start的值:变化速度先快后慢,位置无限接近,但是不会得到end位置
		//此处相当于log函数
        start = Mathf.Lerp(start, 10, Time.deltaTime);
    
    插值运算用法2
    每帧改变t的值:变化速度匀速,每帧接近,当t>=1时,得到结果
        //此处相当于正比例函数
        time += Time.deltaTime;
        result = Mathf.Lerp(result, 10, time);
}

练习 A物体跟随B物体移动

csharp 复制代码
using UnityEngine;

public class FollowCube : MonoBehaviour
{
    public Transform B;
    public float moveSpeed = 1;

    private Vector3 pos;
    private Vector3 bNowPos;
    private Vector3 startPos;
    private float time;
    void Update()
    {
        //先快后慢
        //pos = transform.position;
        //pos.x = Mathf.Lerp(pos.x, B.position.x, Time.deltaTime * moveSpeed);
        //pos.y = Mathf.Lerp(pos.y, B.position.y, Time.deltaTime * moveSpeed);
        //pos.z = Mathf.Lerp(pos.z, B.position.z, Time.deltaTime * moveSpeed);
        //transform.position = pos;

        //匀速运动
        if (bNowPos!= B.transform.position)
        {
            time = 0;
            bNowPos = B.transform.position;
            startPos= transform.position;
        }
        time += Time.deltaTime;
        pos.x = Mathf.Lerp(startPos.x, bNowPos.x, time * moveSpeed);
        pos.y = Mathf.Lerp(startPos.y, bNowPos.y, time * moveSpeed);
        pos.z = Mathf.Lerp(startPos.z, bNowPos.z, time * moveSpeed);
        transform.position = pos;
    }
}

2、三角函数

1、角度和弧度

csharp 复制代码
1.角度和弧度
    角度:1°
    弧度:1 (radian)
    圆一周的弧度:2π (radian)

2.角度和弧度的关系
    π rad = 180°
    则:
    1 rad ≈ 57.3°
    1° ≈ 0.01745 rad
    
    角度 = 弧度 * 57.3
        float rad = 1;
        float angle = rad * Mathf.Rad2Deg;
    弧度 = 角度 * 0.01745
        angle = 1;
    	rad = angle * Mathf.Deg2Rad;

2、三角函数

csharp 复制代码
Mathf中,只使用弧度,所以要角度转弧度(Deg2Rad)
sin30°
	Mathf.Sin(30 * Mathf.Deg2Rad);

3、反三角函数

c 复制代码
通过反三角函数计算正弦值或余弦值对应的弧度值
    弧度 = Mathf.Asin(正弦值)
    弧度 = Mathf.Acos(余弦值)
        float radian = Mathf.Asin(0.5f);   //先将值转化为弧度
        float degree = radian * Mathf.Rad2Deg;   //再将弧度转角度
        print(degree);

练习 物体曲线移动

csharp 复制代码
using UnityEngine;

public class SinMove : MonoBehaviour
{
    public float moveSpeed = 1; //前后移动
    public float changeSpeed = 2; //左右移动
    public float changeSize = 5; //左右幅度
    private float time = 0;
    void Update()
    {    
        time += Time.deltaTime * changeSpeed;
        //前后移动
        transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
        //左右移动
        transform.Translate(Vector3.right * changeSize * Time.deltaTime * Mathf.Sin(time));
    }
}

3、Unity中的坐标系

1、世界坐标系

c 复制代码
原点:世界的中心点
轴向:世界坐标系的三个轴向是固定的
        transform.position;
        transform.rotation;
        transform.eulerAngles; //欧拉角
        transform.lossyScale; //缩放

2、物体坐标系

c 复制代码
原点:物体的中心点(建模时决定)
轴向:
    物体的方右为x轴正方向
    物体的上方为y轴正方向
    物体的前方为z轴正方向
    //相对父对象的坐标
        transform.localPosition;
        transform.localRotation;
        transform.localEulerAngles;
        transform.localScale;

3、屏幕坐标系

c 复制代码
原点:屏幕左下角
轴向:
    向右为x轴正方向
    向上为y轴正方向
最大宽高:
    Input.mousePosition;
    Screen.width;
    Screen.height;

4、视口坐标系

c 复制代码
原点:屏幕左下角
轴向:
	向右为x轴正方向
    向上为y轴正方向
特点:
    左下角(0,0)
    右上角(1,1)
和屏幕坐标类似,将坐标单位化
摄像机上的【视口范围】属于视口 Viewport Rect

5、坐标转换

c 复制代码
世界转本地
    transform.InverseTransformDirection;
    transform.InverseTransformPoint;
    transform.InverseTransformVector;

本地转世界
    transform.TransformDirection;
    transform.TransformPoint;
    transform.TransformVector;

世界转屏幕
    Camera.main.WorldToScreenPoint;
屏幕转世界
	Camera.main.ScreenToWorldPoint;

世界转视口
	Camera.main.WorldToViewportPoint;
视口转世界
    Camera.main.ViewportToWorldPoint;

视口转屏幕
    Camera.main.ViewportToScreenPoint;
屏幕转视口
	Camera.main.ScreenToViewportPoint;

4、Vector3向量

1、向量模长和单位向量

1、向量基础
c 复制代码
三维向量 Vector3
Vector3有两种意义:
    1、可以表示位置 代表一个点
    	transform.position;
    2、也可以表示方向 代表一个方向
    	transform.forward;
2、两点决定 向量
csharp 复制代码
Vector3 A = new Vector3(1, 2, 3);
Vector3 B = new Vector3(2, 3, 4);
求向量 终点 - 起点
Vector3 AB = B - A;
Vector3 BA = A - B;
3、零向量和负向量
c 复制代码
零向量
	(0,0,0)
    Vector3.zero;
负向量
	(x,y,z)的负向量为(-x,-y,-z)
    Vector3.forward;
	-Vector3.forward;
4、向量模长
c 复制代码
模长:向量的长度
    AB.magnitude; //AB的模长

    Vector3 C = new Vector3(3, 4, 5);
    print(C.magnitude); //点C到原点的模长

	Vector3.Distance(A, B); //两点之间的距离
5、单位向量
c 复制代码
模长为1的向量
	只管方向
	AB.normalized;
	AB / AB.magnitude;

2、向量加减乘除

c 复制代码
1、向量加法:
    位置+位置:Unity无意义
    向量+向量:首位相连
    位置+向量:平移位置
    transform.Translate(Vector3.forward * 5);
    //transform.position += new Vector3(1, 2, 3);
	
2、向量减法:
	位置-位置:向量
    向量-向量:新向量 (A-B=B向量头指向A向量头)
    位置-向量:平移位置
    transform.Translate(-Vector3.forward * 5);
    //transform.position -= new Vector3(1, 2, 3);
	
3、向量的乘除
    向量 */ 标量 = 缩放向量的模长
    transform.localScale *= 2;
	transform.localScale /= 2;
	//LossyScale只能得,不能改
练习:向量实现摄像机跟随
csharp 复制代码
public float z = 4;
public float y = 7;
public Transform target;

void LateUpdate()
{
    //摄像机移动在LateUpdate中
    transform.position = target.position + -target.forward * z + target.up * y;
    transform.LookAt(target);
}

3、向量点乘

1、点乘的计算
c 复制代码
向量A(Xa,Ya,Za)
向量B(Xb,Yb,Zb)
    A*B = Xa*Xb + Ya*Yb + Za*Zb
向量 * 向量 = 标量
2、点乘的几何意义
c 复制代码
点乘可以得到向量的投影长度
点乘结果>0,两个向量的夹角为锐角 (目标在前)
点乘结果=0,两个向量的夹角为直角 (目标在左or右两侧不确定)
点乘结果<0,两个向量的夹角为钝角 (目标在后)
作用:判断目标的大致方位

unity点乘

csharp 复制代码
调试画线
    //线段 参数(起点,终点)
    Debug.DrawLine(transform.position, transform.position + transform.forward * 3, Color.red);
    //射线 参数(起点,方向)
    Debug.DrawRay(transform.position,transform.right, Color.green);
通过点乘判断对象方位
    //得到两个向量的点乘结果
    Debug.DrawRay(transform.position, transform.forward * 10);
	Debug.DrawRay(transform.position, target.position - transform.position);

    float a = Vector3.Dot(transform.forward, target.position - transform.position);
    if (a >= 0)
    {
        print("目标在前方");
    }
    else
    {
        print("目标在后方");
    }
    
3、公式推导
c 复制代码
已知单位模长A 单位模长B,以及点乘的几何意义;
则:
    cosβ = 单位向量A * 单位向量B
再根据数学的反三角函数推出:
    β = Mathf.Acos(A*B) * Mathf.Rad2Deg
4、通过点乘推导公式算出夹角
csharp 复制代码
//单位向量算出点乘结果(方向向量)
float dotResult = Vector3.Dot(transform.forward, (target.position - transform.position).normalized);
//用Unity反三角函数算出角度
print(Mathf.Acos(dotResult) * Mathf.Rad2Deg);

最简单直接的方法:
//Unity只需两个向量算出夹角的方法
float ang = Vector3.Angle(transform.forward, target.position - transform.position);
print("角度" + ang);
练习 检测半径为5,角度为90°的扇形区域
csharp 复制代码
方法一:
public Transform B;
void Update()
{
    float c = Vector3.Distance(transform.position, B.position);
    if (c <= 5)
    {
        float dotResult = Vector3.Dot(transform.forward, (B.position - transform.position).normalized);
        //Debug.DrawRay(transform.position, (transform.forward + Vector3.right)*5);
        if ((Mathf.Acos(dotResult) * Mathf.Rad2Deg) <= 45f)
        {
            print("发现目标");
            print("与目标距离" + c + "米");
        }
    }
}
csharp 复制代码
方法二: 用Angle
public Transform B;
void Update()
{
    float c = Vector3.Distance(transform.position, B.position);
    if (c <= 5 && Vector3.Angle(transform.position, B.position - transform.position) <= 45)
    {
        print("发现目标");
        print("与目标距离" + c + "米");
    }
}

4、向量叉乘

1、叉乘计算公式
c 复制代码
向量 * 向量 = 向量
    向量A(Xa,Ya,Za)
    向量B(Xb,Yb,Zb)
    A*B=(X,Y,Z)
    X = Ya*Zb - Za*Yb
    Y = Za*Xb - Xa*Zb
    Z = Xa*Yb - Ya*Xb
    
    Vector3.Cross();
2、几何意义
c 复制代码
A*B得到的向量同时垂直A和B的法向量
A*B = - B*A
    
若A、B向量在同一平面上,A*B(y为法向量):
y>=0;则B在A的右侧
y<0;则B在A的左侧
    
    总结:根据向量叉乘的顺序决定左右位置
        Vector3 cross = Vector3.Cross(A.position, B.position);
        if (cross.y > 0)
        {
            print("B在A的右侧");
        }
        else
        {
            print("B在A的左侧");
        }
练习 物体方位
csharp 复制代码
1、//判断物体B相对于物体A的位置,左上,左下,右上,右下方位
public Transform A;
public Transform B;

//点乘判断前后
private float dotResult;
//叉乘判断左右
private float crossResult;

private float distance; //距离
private float angle; //角度

void Update()
{
    dotResult = Vector3.Dot(A.forward, B.position - A.position);
    crossResult = Vector3.Cross(A.forward, B.position - A.position).y;
    
    //点乘判断前后
    if (dotResult >= 0)
    {//前
        print(crossResult >= 0 ? "B在右上方" : "B在左上方");
    }
    else
    {//后
        print(crossResult >= 0 ? "B在右后方" : "B在左后方");
    }

    2、//判断一个物体在左前方20度角or右前方30度范围内,且在距离5米内
    distance = Vector3.Distance(A.position, B.position);
    angle = Vector3.Angle(A.forward, B.position - A.position);
    if (distance <= 5)
    {
        if (crossResult >= 0 && angle <= 30)
        {
            print("发现目标!!!");
            print("目标位于右前方" + decimalPoint2(angle) + "°," + decimalPoint2(distance) + "米处");
        }
        else if (crossResult < 0 && angle <= 20)
        {
            print("发现目标!!!");
            print("目标位于左前方" + decimalPoint2(angle) + "°," + decimalPoint2(distance) + "米处");
        }
    }
}

//小数点保留后两位
private float decimalPoint2(float f)
{
    int i = (int)(f * 100);
    return i * 0.01f;
}

5、差值运算

1、线性插值
c 复制代码
Vector3.Lerp(start, end, t);
对两个点进行插值计算
t的取值范围为0~1
    计算公式:result = start + (end - start) * t
    
应用
    1、每帧改变start的值(先快后慢)
    2、每帧改变t的值(匀速)
两种线性插值代码实现
csharp 复制代码
public Transform A;
public Transform B;
public Transform target;

private Vector3 startPos;
private float time;
private Vector3 nowTarget;

void Start()
{
    startPos = B.position;
}

void Update()
{
    //每帧改变start的值(先快后慢)
    A.position = Vector3.Lerp(A.position, target.position, Time.deltaTime);

    //每帧改变t的值(匀速)
    if (nowTarget != target.position)
    {
        nowTarget = target.position;
        startPos = B.position;
        time = 0;
    }
    time += Time.deltaTime;
    B.position = Vector3.Lerp(startPos, nowTarget, time);
}
2、球性插值
csharp 复制代码
Vector3.slerp(start, end, t);
对两个向量进行插值运算 t:(0~1)
//运动轨迹为弧形
C.position = Vector3.Slerp(transform.forward * 10, -transform.forward * 3, time);
思考1 Lerp摄像机跟随
csharp 复制代码
1.先快后慢
public float z = 4;
public float y = 7;
public Transform target;

public Vector3 targetPos;
public int speedMove = 1;

void LateUpdate()
{
    //目标位置
    if (targetPos != target.position + -target.forward * z + target.up * y)
    {
        targetPos = target.position + -target.forward * z + target.up * y;
    }
    transform.position = Vector3.Lerp(transform.position, targetPos, Time.deltaTime * speedMove);
    transform.LookAt(target);
}
csharp 复制代码
2、匀速跟随
public float z = 4;
public float y = 7;
public Transform target;

public Vector3 targetPos;
public int speedMove = 1;
private Vector3 startPos;
private float time;
void LateUpdate()
{
    //目标位置
    if (targetPos != target.position + -target.forward * z + target.up * y)
    {
        targetPos = target.position + -target.forward * z + target.up * y;
        startPos = transform.position;
        time = 0;
    }
    time += Time.deltaTime;
    transform.position = Vector3.Lerp(startPos, targetPos, time*speedMove);
    transform.LookAt(target);
}
思考2 球形插值模拟太阳升降
csharp 复制代码
public Transform C;
private float time;
void Update()
{
    time += Time.deltaTime;
    C.position = Vector3.Slerp(Vector3.right*10 + Vector3.up * 0.1f, Vector3.left*10, time*0.1f);
}

5、Quaternion四元数

1、为何使用四元数

csharp 复制代码
Rotation表示欧拉角 transform.eulerAngles
因为欧拉角存在一些缺点:
1、同一旋转的表示不唯一
2、万向节死锁
而四元数旋转不存在万向节死锁问题
所以使用四元数来表示三维空间中的旋转信息

2、四元数是什么

1、四元数的构成
csharp 复制代码
四元数包含一个标量和一个3D向量
[w,v] w为标量,v为3D向量
[w,(x,y,z)]
四元数表示3D空间中的一个旋转量

轴-角对(含义):
	绕一个轴(Q)旋转β度
2、Unity中的四元数
c 复制代码
Unity中的四元数:Quaternion
轴角对初始化
1、基本写法(很少用):
    公式:
    四元数Q = [cos(β/2),sin(β/2)*x,sin(β/2)*y,sin(β/2)*z]
    简化记忆:Q = c,s(x,y,z)  β/2
    //(1,0,0)旋转60度
	Quaternion q = new Quaternion(Mathf.Cos(60 / 2 * Mathf.Deg2Rad), 0, 0, Mathf.Sin(60 / 2 * Mathf.Deg2Rad) * 1);

2、Unity简单写法
    依据公式:
		四元数Q = Quaternion.AngleAxis(角度,轴);
	Unity代码:
		Quaternion q = Quaternion.AngleAxis(60,Vector3.right);

	//将四元数赋值给一个物体
	GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
	obj.transform.rotation = q;
3、四元数和欧拉角转换
csharp 复制代码
1、欧拉角转四元数
Quaternion q = Quaternion.Euler(60,0,0);
2、四元数转欧拉角
q.eulerAngles;
4、四元数弥补欧拉角的缺点
csharp 复制代码
四元数相乘:旋转四元数
1、四元数的结果始终是 -180~180
2、四元数旋转可以避免万向节死锁

3、四元数常用方法

1、单位四元数
c 复制代码
没有旋转量(角位移)
Unity:
	Quaternion.identity
例:
    [1,(0,0,0)]
    [-1,(0,0,0)]
作用:
    对象角度初始化
2、插值运算
csharp 复制代码
// Slerp比Lerp效果好
public Transform A;
public Transform B;
public Transform C;

private Quaternion start;
private float time;
void Start()
{
    start = B.rotation;
}

void Update()
{
    //先快后慢,无线接近
    A.rotation = Quaternion.Slerp(A.rotation, C.rotation, Time.deltaTime);

    //匀速变化 time>=1则到达目标
    time += Time.deltaTime;
    B.rotation = Quaternion.Slerp(start, C.rotation, time);
}
3、向量方向 转换为对应 四元数角度
csharp 复制代码
API:Quaternion.LookRotation(目标向量)

public Transform LA;
public Transform LB;
void Update()
{
    LA.rotation = Quaternion.LookRotation(LB.position - LA.position);
}
思考1 写一个类似LookAt()的拓展方法
csharp 复制代码
public static class Tool
{
    public static void MyLookAt(this Transform obj,Transform target)
    {
        obj.rotation = Quaternion.LookRotation(target.position - obj.position);
    }
}
思考2 用LookRotation实现摄像机跟随
csharp 复制代码
public float z = 4;
public float y = 7;
public Transform target;
public Vector3 targetPos;

public int speedMove = 1;
private Vector3 startPos;
private float time;

private Quaternion targetQua;

private Quaternion startQua;
private float roundTime;
void LateUpdate()
{
    //目标位置
    if (targetPos != target.position + -target.forward * z + target.up * y)
    {
        targetPos = target.position + -target.forward * z + target.up * y;
        startPos = transform.position;
        time = 0;
    }
    time += Time.deltaTime;
    transform.position = Vector3.Lerp(startPos, targetPos, time * speedMove);
    //transform.LookAt(target);
    //1、先快后慢
    //targetQua = Quaternion.LookRotation(target.position - transform.position);
    //transform.rotation = Quaternion.Slerp(transform.rotation, targetQua, Time.deltaTime);
    //2、匀速跟随
    if (targetQua != Quaternion.LookRotation(target.position - transform.position))
    {
        targetQua = Quaternion.LookRotation(target.position - transform.position);
        startQua = transform.rotation;
        roundTime = 0;
    }
    roundTime += Time.deltaTime;
    transform.rotation = Quaternion.Slerp(startQua, targetQua, roundTime);
}

4、四元数计算

1、四元数相乘
csharp 复制代码
q1 = q2 * q3
两个旋转量的叠加
旋转方向一直是本地坐标系

Quaternion qua = Quaternion.AngleAxis(30, Vector3.up);
transform.rotation *= qua; //沿y轴顺时针旋转30度
transform.rotation *= qua; //再旋转30度
2、四元数乘向量
csharp 复制代码
V1 = v2 * q
旋转【四元数角度】向量
    
Vector3 v = Vector3.forward;
v = Quaternion.AngleAxis(45, Vector3.up) * v; //此处必须:先四元数,再乘向量
思考1 模拟飞机发射子弹,单发、双发、扇形、环形

AirPlane 飞机类

csharp 复制代码
using UnityEngine;

public enum E_FireType
{
    SingleShoot,
    DoubleShoot,
    SectorShoot,
    AnnularShoot
}
public class AirPlane : MonoBehaviour
{
    public GameObject bullet;
    public int bulletNum = 4;
    private E_FireType nowType = E_FireType.SingleShoot;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            print("切换为单发");
            nowType = E_FireType.SingleShoot;
        }
        if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            print("切换为双发");
            nowType = E_FireType.DoubleShoot;
        }
        if (Input.GetKeyDown(KeyCode.Alpha3))
        {
            print("切换为扇形子弹");
            nowType = E_FireType.SectorShoot;
        }
        if (Input.GetKeyDown(KeyCode.Alpha4))
        {
            print("切换为环形子弹");
            nowType = E_FireType.AnnularShoot;
        }
        if (Input.GetKeyDown(KeyCode.Space))
        {
            print("开火");
            Fire();
        }

    }

    private void Fire()
    {
        switch (nowType)
        {
            case E_FireType.SingleShoot:
                Instantiate(bullet,transform.position,transform.rotation);
                break;
            case E_FireType.DoubleShoot:
                Instantiate(bullet, transform.position - transform.right * 0.5f, transform.rotation);
                Instantiate(bullet, transform.position + transform.right * 0.5f, transform.rotation);
                break;
            case E_FireType.SectorShoot:
                Instantiate(bullet, transform.position, transform.rotation);
                Instantiate(bullet, transform.position, transform.rotation * Quaternion.AngleAxis(-15, Vector3.up));
                Instantiate(bullet, transform.position, transform.rotation * Quaternion.AngleAxis(15, Vector3.up));

                break;
            case E_FireType.AnnularShoot:
                float angle = 360 / bulletNum;
                for (int i = 0; i < bulletNum; i++)
                    Instantiate(bullet,transform.position,transform.rotation*Quaternion.AngleAxis(i* angle, Vector3.up));
                break;
        }
    }
}

Bullet 子弹类

csharp 复制代码
using UnityEngine;

public class Bullet : MonoBehaviour
{
    public float moveSpeed = 10;
    private void Start()
    {
        Destroy(gameObject, 5);
    }
    void Update()
    {
        transform.Translate(Vector3.forward * Time.deltaTime * moveSpeed);
    }
}
思考2 摄像机跟随效果

1、摄像机看向人物头顶上方一个位置(可调节)

2、摄像机在任务斜后方,通过角度控制斜率

3、通过鼠标滚轮可以控制摄像机与人物的距离(有最大最小限制)

4、Quaternion.Slerp实现摄像机看向人物

5、Vector3.Lerp实现相机跟随人物

csharp 复制代码
using UnityEngine;

public class CameraMovePlus : MonoBehaviour
{
    //摄像目标
    public Transform target;
    //头顶偏移位置
    public float overHeadOffset = 1;
    //倾斜角度
    public float tiltAngle = 45;
    //摄像机到头顶偏移位置的距离
    public float distance = 5;
    public float minDis = 3;
    public float maxDis = 8;
    public int scrollSpeed = 2;
    public int lookSpeed = 1;
    Vector3 nowPos;
    Vector3 nowDir;
    void Start()
    {
        //transform.rotation *= Quaternion.AngleAxis(45, Vector3.right);
    }

    void Update()
    {
        //3、通过鼠标滚轮可以控制摄像机与人物的距离(有最大最小限制)
        //滚轮
        distance += Input.GetAxis("Mouse ScrollWheel") * scrollSpeed;
        distance = Mathf.Clamp(distance, minDis, maxDis);
        //1、摄像机看向人物头顶上方一个位置(可调节)
        //偏移
        nowPos = target.position + target.up * overHeadOffset;
        //2、摄像机在任务斜后方,通过角度控制斜率
        nowDir = Quaternion.AngleAxis(tiltAngle, target.right) * -target.forward;
        nowPos = nowPos + nowDir * distance;
        //transform.position = nowPos;
        //Debug.DrawLine(transform.position, target.position + target.up * overHeadOffset);
        //摄像机方向
        //4、Quaternion.Slerp实现摄像机看向人物
        transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(-nowDir), Time.deltaTime * lookSpeed * 2);
        //5、Vector3.Lerp实现相机跟随人物
        transform.position = Vector3.Lerp(transform.position, nowPos, Time.deltaTime);
    }
}
相关推荐
躺下睡觉~3 小时前
Unity-Transform类-父子关系
java·unity·游戏引擎
躺下睡觉~4 小时前
Unity-Transform类-缩放和看向
unity·游戏引擎
君莫愁。6 小时前
【Unity】检测鼠标点击位置是否有2D对象
unity·c#·游戏引擎
咩咩觉主7 小时前
Unity实战案例全解析:PVZ 植物卡片状态分析
unity·c#·游戏引擎
蓝裕安10 小时前
伪工厂模式制造敌人
开发语言·unity·游戏引擎
谢泽浩14 小时前
Unity 给模型贴上照片
unity·游戏引擎
z2014z14 小时前
Unity Resource System 优化笔记
unity·游戏引擎
王维志14 小时前
Unity 高亮插件HighlightPlus介绍
unity·游戏引擎
zaizai100715 小时前
我的demo保卫萝卜中的技术要点
unity
菌菌巧乐兹16 小时前
Unity 百度AI实现无绿幕拍照抠像功能(详解版)
人工智能·百度·unity