Unity基础1——3D数学

news2025/2/8 14:16:27

一、Mathf

(一)Mathf 和 Math

​ Math 是 C# 中封装好的用于数学计算的工具类 —— 位于 System 命名空间中

​ Mathf 是 Unity 中封装好的用于数学计算的工具结构体 —— 位于 UnityEngine 命名空间中

​ 他们都是提供来用于进行数学相关计算的

​ Mathf 和 Math 中的相关方法几乎一样
​ 但 Mathf 是 Unity 专门封装的,不仅包含 Math 中的方法,还多了一些适用于游戏开发的方法
​ 所以我们在进行 Unity 游戏开发时,使用 Mathf 中的方法用于数学计算即可

(二)常用方法

  1. PI

print(Mathf.PI);

      2.Abs - 取绝对值

print(Mathf.Abs(-10));  // 10
print(Mathf.Abs(-20));  // 20
print(Mathf.Abs(1));    // 1

3.CeilToInt - 向上取整

float f = 1.3f;
int   i = (int)f;
print(i);                          // 1
print(Mathf.CeilToInt(f));         // 2
print(Mathf.CeilToInt(1.00001f));  // 2

4.FloorToInt - 向下取整

print(Mathf.FloorToInt(9.6f));     // 9

5.Clamp - 钳制函数

print(Mathf.Clamp(10, 11, 20));    // 11
print(Mathf.Clamp(21, 11, 20));    // 20
print(Mathf.Clamp(15, 11, 20));    // 15

6.Max / Min - 获取最大 / 小值

print(Mathf.Max(1, 2, 3, 4, 5, 6, 7, 8));          // 8 
print(Mathf.Max(1, 2));                            // 2

print(Mathf.Min(1, 2, 3, 4, 545, 6, 1123, 123));   // 1
print(Mathf.Min(1.1f, 0.4f));                      // 0.4

7.Pow - 一个数的 n 次幂

print(Mathf.Pow(4, 2));  // 16
print(Mathf.Pow(2, 3));  // 8

8.RoundToInt - 四舍五入

print(Mathf.RoundToInt(1.3f));  // 1
print(Mathf.RoundToInt(1.5f));  // 2

9.Sqrt - 返回一个数的平方根

print(Mathf.Sqrt(4));   // 2
print(Mathf.Sqrt(16));  // 4
print(Mathf.Sqrt(64));  // 8

10.IsPowerOfTwo - 判断一个数是否是 2 的 n 次方

print(Mathf.IsPowerOfTwo(4));  // true
print(Mathf.IsPowerOfTwo(8));  // true
print(Mathf.IsPowerOfTwo(3));  // false
print(Mathf.IsPowerOfTwo(1));  // true

11.Sign - 判断正负数

print(Mathf.Sign(0));    // 0
print(Mathf.Sign(10));   // 1
print(Mathf.Sign(-10));  // -1
print(Mathf.Sign(3));    // 1
print(Mathf.Sign(-2));   // -1

(三)Lerp 方法

​ Lerp 函数公式:result = start + (end - start) * t

​ 其中,t 为插值系数,取值范围为 0 ~ 1

​ 函数调用:result = Mathf.Lerp(start, end, t);

// 插值运算用法一
// 每帧改变start的值——变化速度先快后慢,位置无限接近,但是不会得到end位置
start = Mathf.Lerp(start, 10, Time.deltaTime);

// 插值运算用法二
// 每帧改变t的值——变化速度匀速,位置每帧接近,当t>=1时,得到结果
time   += Time.deltaTime;
result =  Mathf.Lerp(start, 10, time);

​ 应用:控制物体移动

public  Transform B;          // 目标物体位置
public  float     moveSpeed;  // 移动速度
private Vector3   bNowPos;    // B 当前的位置

private Vector3 pos;          // 该物体的位置
private Vector3 startPos;     // 每次运动的起始位置

private float time;

// 第一种  先快后慢的形式
pos = this.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);
this.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);
pos.y              =  Mathf.Lerp(startPos.y, bNowPos.y, time);
pos.z              =  Mathf.Lerp(startPos.z, bNowPos.z, time);
transform.position =  pos;

(四)三角函数

// 弧度转角度
float rad   = 1;
float anger = rad * Mathf.Rad2Deg;
print(anger);

// 角度转弧度
anger = 1;
rad   = anger * Mathf.Deg2Rad;
print(rad);

// 注意:Mathf中的三角函数相关函数,传入的参数需要时弧度值
print(Mathf.Sin(30 * Mathf.Deg2Rad));  // 0.5
print(Mathf.Cos(60 * Mathf.Deg2Rad));  // 0.5

// 注意:反三角函数得到的结果是 正弦或者余弦值对应的弧度
rad = Mathf.Asin(0.5f);
print(rad * Mathf.Rad2Deg);
rad = Mathf.Acos(0.5f);
print(rad * Mathf.Rad2Deg);

二、坐标系

(一)世界坐标系

​ 原点:世界的中心点

​ 轴向:世界坐标系的三个轴向是固定的

// 目前学习的和世界坐标系相关的
this.transform.position;     // 坐标
this.transform.rotation;     // 旋转角度
this.transform.eulerAngles;  // 欧拉角度
this.transform.lossyScale;   // 本地缩放大小
// 修改他们 会是相对世界坐标系的变化

(二)物体坐标系

​ 原点:物体的中心点(建模时决定)

​ 轴向:

​ 物体右方为 x 轴正方向

​ 物体上方为 y 轴正方向

​ 物体前方为 z 轴正方向

// 相对父对象的物体坐标系的位置 本地坐标 相对坐标
this.transform.localPosition;
this.transform.localEulerAngles;
this.transform.localRotation;
this.transform.localScale;
// 修改他们 会是相对父对象物体坐标系的变化

(三)屏幕坐标系

​ 原点:屏幕左下角

​ 轴向:

​ 向右为 x 轴正方向

​ 向上为 y 轴正方向

​ 最大宽高:

​ Screen.width

​ Screen.height

Input.mousePosition;  // 鼠标位置
Screen.width;         // 屏幕宽
Screen.height;        // 屏幕高

(四)视口坐标系

​ 原点:屏幕左下角

​ 轴向:

​ 向右为 x 轴正方向

​ 向上为 y 轴正方向

​ 特点:

​ 左下角为(0, 0)

​ 右上角为(1, 1)

​ 和屏幕坐标类似,将坐标单位化

(五)坐标转换

// 世界转本地
this.transform.InverseTransformDirection
this.transform.InverseTransformPoint
this.transform.InverseTransformVector
// 本地转世界
this.transform.TransformDirection
this.transform.TransformPoint  
this.transform.TransformVector

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

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

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

三、向量 Vector3

(一)向量模长和单位向量

// Vector3中提供了获取向量模长的成员属性
// magnitude
print(AB.magnitude);
Vector3 C = new Vector3(5, 6, 7);
print(C.magnitude);

print(Vector3.Distance(A, B));

// Vector3中提供了获取单位向量的成员属性
// normalized
print(AB.normalized);
print(AB / AB.magnitude);

(二)调试画线

// 画线段 
// 前两个参数 分别是 起点 终点
Debug.DrawLine(this.transform.position, this.transform.position + this.transform.forward, Color.red);

// 画射线
// 前两个参数 分别是 起点 方向
Debug.DrawRay(this.transform.position, this.transform.forward, Color.white);

(三)向量点乘

public Transform target;

// 得到两个向量的点乘结果
// 向量 a 点乘 AB 的结果
float dotResult = Vector3.Dot(transform.forward, target.position - transform.position);
if (dotResult >= 0) print("它在我前方");
else                print("它在我后方");

// 通过点乘推导公式算出夹角

// 1.用单位向量算出点乘结果
dotResult = Vector3.Dot(transform.forward, (target.position - transform.position).normalized);
// 2.用反三角函数得出角度
print(Mathf.Acos(dotResult) * Mathf.Rad2Deg);
// Vector3中提供了 得到两个向量之间夹角的方法 
print(Vector3.Angle(transform.forward, target.position - transform.position));

(四)向量叉乘

// 假设向量 A和B 都在 XZ平面上
// 向量A 叉乘 向量 B
// y大于0 证明 B在A右侧
// y小于0 证明 B在A左侧

Vector3 C = Vector3.Cross(B.position, A.position);
if (C.y > 0) print("A在B的右侧");
else         print("A在B的左侧");

(五)向量插值运算

  1. 线性插值

public Transform target;    // 目标物体位置
public Transform A;         // 先快后慢移动到 Target
public Transform B;         // 匀速运动到 Target

private Vector3 nowTarget;  // 当前 B 的位置

private Vector3 startPos;   // 每次运行时 B 的起始位置
private float   time;

// Start is called before the first frame update
private void Start() {
    startPos = B.position;
}

// Update is called once per frame
private void Update() {
    // result = start + (end - start) * t

    // 1.先快后慢 每帧改变start位置 位置无限接近 但不会得到end位置
    A.position = Vector3.Lerp(A.position, target.position, Time.deltaTime);

    // 2.匀速 每帧改变时间  当t>=1时 得到结果
    // 这种匀速移动 当time>=1时  我改变了 目标位置后  它会直接瞬移到我们的目标位置
    if (nowTarget != target.position) {
        nowTarget = target.position;
        time      = 0;
        startPos  = B.position;
    }
    time       += Time.deltaTime;
    B.position =  Vector3.Lerp(startPos, nowTarget, time);
}
  1. 球形插值

position = Vector3.Slerp(Vector3.right * 10, Vector3.left * 10 + Vector3.up * 0.1f, time * 0.01f);

四、四元数 Quaternion

(一)欧拉角

​ 由三个角度 (x, y, z) 组成 ,在特定坐标系下用于描述物体的旋转量

​ 空间中的任意旋转都可以分解成绕三个互相垂直轴的三个旋转角组成的序列

​ heading-pitch-bank 是一种最常用的旋转序列约定,即 Y - X - Z 约定

​ heading:物体绕自身的对象坐标系的 Y 轴,旋转的角度

​ pitch:物体绕自身的对象坐标系的 X 轴,旋转的角度

​ ban:物体绕自身的对象坐标系的 Z 轴,旋转的角度

​ Inspector 窗口中调节的 Rotation 就是欧拉角

​ this.transform.eulerAngles 得到的就是欧拉角角度


  • 优点:

    • 直观、易理解

    • 存储空间小(三个数表示)

    • 可以进行从一个方向到另一个方向旋转大于180度的角度

  • 缺点:

    • 同一旋转的表示不唯一

      例如,Rotation(x, y, z) = Rotation(x + 360, y + 360, z + 360)

    • 万向节死锁

(二)万向节死锁

​ 万向节死锁的意义就是在 X 轴转 90度的情况下,后面左乘 Z(绕基坐标下 Z)与右乘 Y(绕自身 Y,实际与基坐标 Z 一样了)实际效果是相同的,丧失了自由度。

​ 例如,在 Unity 中,将 Rotation 中的 X 设置为 90,之后调节 Y 和调节 Z 的大小,物体的转动都会是沿一个角度的。

(三)四元数简介

​ 四元数是简单的超复数,由实数加上三个虚数单位组成 主要用于在三维空间中表示旋转

​ 四元数原理包含大量数学相关知识,较为复杂,比如:复数、四维空间等等

​ 因此此处我们只对其基本构成和基本公式进行讲解,如想深入了解数学原理请从数学层面去查找资料了解它

  1. 四元数的构成

​ 一个四元数包含一个标量和一个 3D 向量

​ [w, v],w为标量,v为 3D 向量,即[w, (x, y, z)]

​ 对于给定的任意一个四元数: 表示 3D 空间中的一个旋转量

  1. 轴角对

    在 3D 空间中,任意旋转都可以表示绕着某个轴旋转一个旋转角得到

    对于给定旋转,假设为绕着 n 轴,旋转 β 度,n 轴为 (x, y, z)

    那么可以构成四元数为

    四元数 Q = [cos(β / 2), n · sin(β / 2)]

    四元数 Q = [cos(β / 2), x · sin(β / 2), y · sin(β / 2), z · sin(β / 2)]

    四元数 Q 则表示绕着轴 n,旋转 β 度的旋转量

  2. Unity 中的 Quaternion

    Quaternion 是 Unity 中表示四元数的结构体

// 轴角对公式初始化 
// 四元数 Q = [cos(β/2), sin(β/2)x, sin(β/2)y, sin(β/2)z] 
Quaternion q = new Quaternion(sin(β/2)x, sin(β/2)y, sin(β/2)z, cos(β/2));
    
// 轴角对方法初始化 
// 四元数Q = Quaternion.AngleAxis(角度, 轴); 
Quaternion q = Quaternion.AngleAxis(60, Vector3.right);

3.四元数和欧拉角转换

// 1.欧拉角转四元数
Quaternion q2 = Quaternion.Euler(60, 0, 0);

// 2.四元数转欧拉角
print(q2.eulerAngles);

(四)常用方法

  1. 单位四元数

    单位四元数表示没有旋转量(角位移)

    当角度为 0 或者 360 度时,对于给定轴都会得到单位四元数

    [1, (0, 0, 0)]和[-1, (0, 0, 0)] 都是单位四元数,表示没有旋转量

// 单位四元数
print(Quaternion.identity);

2.插值运算

四元数中同样提供如同 Vector3 的插值运算:Lerp 和 Slerp

在四元数中 Lerp 和 Slerp 只有一些细微差别,由于算法不同,Slerp 的效果会好一些

Lerp 的效果相比 Slerp 更快但是如果旋转范围较大效果较差,所以建议使用 Slerp 进行插值运算

public Transform target;
public Transform A;
public Transform B;
private Quaternion start;
private float time;

start = B.transform.rotation;

// 无限接近 先快后慢
A.transform.rotation = Quaternion.Slerp(A.transform.rotation, target.rotation, Time.deltaTime);

// 匀速变化 time>=1 到达目标
time                 += Time.deltaTime;
B.transform.rotation =  Quaternion.Slerp(start, target.rotation, time);

3.方向转四元数

Quaternino.LookRotation(面朝向量);

LookRoataion 方法可以将传入的面朝向量转换为对应的四元数角度信息

当人物面朝向想要改变时,只需要把目标面朝向传入该函数,便可以得到目标四元数角度信息,之后将人物四元数角度信息改为得到的信息即可达到转向

Quaternion q = Quaternion.LookRotation(lookB.position - lookA.position);
lookA.rotation = q;

(五)实现缓慢看向目标

public  Transform  target;
private float      roundTime;
public  float      roundSpeed;
private Quaternion startQ;
private Quaternion targetQ;

// 用目标的位置 减去 摄像机的位置 得到新的面朝向向量
targetQ = Quaternion.LookRotation(target.position - this.transform.position);

//先快后慢
this.transform.rotation = Quaternion.Slerp(this.transform.rotation, targetQ, Time.deltaTime* roundSpeed);

//匀速旋转
if (targetQ != Quaternion.LookRotation(target.position - transform.position)) {
    targetQ   = Quaternion.LookRotation(target.position - transform.position);
    roundTime = 0;
    startQ    = transform.rotation;
}
roundTime          += Time.deltaTime;
transform.rotation =  Quaternion.Slerp(startQ, targetQ, roundTime * roundSpeed);

(六)四元数计算

  1. 四元数乘四元数

    q3 = q1 * q2

    两个四元数相乘得到一个新的四元数,代表两个旋转量的叠加,相当于旋转

    注意:旋转相对的坐标系是物体自身坐标系

Quaternion q = Quaternion.AngleAxis(20, Vector3.up);
transform.rotation *= q;

2.四元数乘向量

v2 = q1 * v1(顺序不能反)

四元数乘向量返回一个新向量,可以将指定向量旋转对应四元数的旋转量,相当于旋转向量

Vector3 v = Vector3.forward;
print(v);
v = Quaternion.AngleAxis(45, Vector3.up) * v;
print(v);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/646175.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习 day18(用Tensorflow搭建一个神经网络)

之前搭建神经网络的方法 先初始化输入数据X,创建layer 1并计算激活值a1,创建layer 2并计算激活值a2,这是前向传播代码的显式形式。 另一种简单些的创建神经网络的方法 创建layer 1和layer 2与前一种方法相同,但我们不需要手动…

JUC并发编程学习笔记

1:回顾多线程 进程和线程是什么 进程是操作系统分配资源的最小单元,而线程是cpu调度的最小单元。 java默认有几个线程 2个,main线程和GC线程(GC垃圾回收机制) java可以开启线程么 不能 并发和并行 并发,多线程操作同一个资源,cp…

纯电驱动车辆动力总成的优化与比较研究

摘要: 不同动力总成拓扑结构的对比分析 前言 纯电驱动的电动汽车因为集成有大容量电池组,可以存储取自公共电网的电能,用来驱动车辆的行驶。相比于传统的混合动力汽车,具有更加优越的节能减排效果和潜力。因此,近年来…

cpp文件编译过程 makefile cmake

这里写目录标题 argc argv参数头文件编译过程静态链接&#xff0c;动态链接&#xff0c;静态库&#xff0c;动态库 -shared制作使用动态库libxxx。so冲突 静态库预处理编译汇编链接目录选项-Idir 大写Iinclude<> 与 " "-I -I- 与 -I- -I ld/objdump/objcopy 选…

内网渗透—隧道搭建Ngrok与Frp内网穿透

这里写目录标题 1. 前言1.1. 隧道技术介绍1.2. 代理技术介绍1.2.1. 正向代理1.2.2. 反向代理1.2.3. 透明代理1.2.4. 正向代理与透明代理区别 2. 内网穿透2.1. Ngrok2.1.1. 访问Ngrok2.1.2. 代理设置2.1.2.1. 开通代理2.1.2.2. 配置隧道2.1.2.3. 下载客户端 2.1.3. 配置客户端2.…

P20[6-8]编码器接口测速(软)

与外部中断编码器逻辑不同,此处编码器使用的是定时器方法 1.Encoder编码器部分: #include "stm32f10x.h" // Device header void Encoder_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCm…

吐血整理,自动化测试场景处理(多场景覆盖)+解决方案

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、添加时间等待 …

53.最大子数组和

贪心算法 时间复杂度&#xff1a;代码中只有一个循环&#xff0c;循环次数为数组的长度&#xff0c;因此时间复杂度为 O(n)&#xff0c;其中 n 是数组的长度。空间复杂度&#xff1a;代码中只使用了常数级别的额外空间&#xff0c;因此空间复杂度为 O(1)。 这段代码使用贪心算…

QT C++入门学习(2) QT Creator写一个简单的上位机控制LED

上位机和下位机的概念 上位机&#xff1a;指的是可以直接发送操作指令的计算机或者单片机&#xff0c;一般提供用户操作交互界面并向用户展示反馈数据。 典型设备&#xff1a;电脑、平板、手机、面板、触摸屏 下位机&#xff1a;指的是与机器相连接的计算机或者单片机&#…

Studio 3T 2023.5 (macOS, Linux, Windows) - MongoDB 的专业 GUI、IDE 和 客户端

Studio 3T 2023.5 (macOS, Linux, Windows) - MongoDB 的专业 GUI、IDE 和 客户端 请访问原文链接&#xff1a;https://sysin.org/blog/studio-3t-2023/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org Studio 3T&#xff0c;M…

黑客松必备|Bear Necessities Hackathon Office Hours汇总

由Moonbeam和AWS Startups联合主办的Bear Necessities Hackathon黑客松启动仪式已于5月30日举行。本次黑客松将历时约1个月的时间&#xff0c;包含6个挑战&#xff0c;分别由Moonbeam基金会、Chainlink、StellaSwap、SubQuery、Biconomy提供赞助&#xff0c;总奖池超过5万美金。…

面试软件测试时,面试官最想听到的答案是什么?

问题&#xff1a;面试软件测试时&#xff0c;面试官让你测一个软件&#xff0c;比如朋友圈&#xff0c;或者让你测试你的电脑为什么打不开网页&#xff0c;而QQ可以打开之类的&#xff0c;他最想听到的答案是什么&#xff1f; 如上所述&#xff0c;在实际面试中&#xff0c;面试…

懂点测试基础就敢要17k? 面试官:最多8K,多一分都没有...

公司前段缺人&#xff0c;也面了不少测试&#xff0c;结果竟然没有一个合适的。一开始瞄准的就是中级的水准&#xff0c;也没指望来大牛&#xff0c;提供的薪资在10-25k&#xff0c;面试的人很多&#xff0c;但平均水平很让人失望。看简历很多都是3年工作经验&#xff0c;但面试…

Java泛型的使用

1.什么是泛型&#xff1f; 所谓泛型&#xff0c;就是允许在定义类、接口时通过 一个标识 表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时&#xff08;例如&#xff0c;继承或实现这个接口&#xff0c;用这个类型声明变量、创建对象时&#…

5.Opencv-图像滤波(均值,方框,高斯,中值,双边滤波)

常见的图像滤波操作有&#xff1a; 均值滤波&#xff08;cv2.blur&#xff09; 方框滤波&#xff08;cv2.boxFilter&#xff09; 高斯滤波&#xff08;cv2.GaussianBlur&#xff09; 中值滤波&#xff08;cv2.medianBlur&#xff09; 双边滤波&#xff08;cv2.bilateralFilter…

电脑小白不要错过这五款小众但强大的软件

电脑上的各类软件有很多&#xff0c;除了那些常见的大众化软件&#xff0c;还有很多不为人知的小众软件&#xff0c;专注于实用功能&#xff0c;简洁干净、功能强悍。 多语言翻译——QTranslate QTranslate是一款实用的多语言翻译工具。它可以在任何应用程序中选中文本&#…

【C++】模版进阶

目录 一、非类型模版参数二、模板的特化1、概念2、函数模版特化3、类模板特化1.全特化2.偏特化3.类模板特化应用示例 三、模版分离编译1、什么是分离编译2、模板的分离编译3、模板的优缺点 一、非类型模版参数 模版参数分为类型模版参数与非类型模版参数 类型模版参数&#x…

一定要看!带你选择适合自己的测试工具

目录 前言&#xff1a; Jmeter实现接口请求JSON断言 Postman接口请求断言 前言&#xff1a; 选择适合的测试工具对于测试人员和测试项目的成功非常重要。不同的测试工具都有其独特的优缺点&#xff0c;而且每个项目的需求也不尽相同。因此&#xff0c;在选择测试工具时&#…

使用vitepress快速搭建个人网站或官方文档网站

使用vitepress快速搭建个人网站或官方文档网站 1. vitepress是什么&#xff1f; 官方首页的介绍&#xff0c; 翻译过来就是&#xff0c;vite和vue组成的强大的静态网站构造器。简单、强大和快速&#xff0c;是你一直想要的SSG(Static Site Generator)框架。 官网地址&#…

python mitmproxy抓包库

一.简介 mitmproxy是一款用Python编写的支持HTTP(S)的中间人代理工具。它可以拦截、查看、修改、重放和保存HTTP/HTTPS流量 &#xff0c;支持命令行界面和图形界面&#xff0c;可用于安全测试、网络调试、API开发和反向工程等场景。mitmproxy具有很高的灵活性和扩展性&#xf…