Unity三维数学总结
三维向量和三角函数
三维向量
// 向量的长度:求模的大小
void Update1()
{
Vector3 po = this.transform.position; // 向量的模
var l1 = Mathf.Sqrt(Mathf.Pow(po.x, 2) + Mathf.Pow(po.y, 2) + Mathf.Pow(po.z, 2));
var l2 = Vector3.Distance(Vector3.zero, po);
//po.magnitude: po向量的模,po点相对于世界坐标原点的距离
var l3 = po.magnitude;
Debug.LogFormat("{0}-{1}-{2}", l1, l2, l3); // 标准向量,归一向量,单位向量:模长度为1的向量
//po.normalized: 标准向量,归一向量,指的是将向量的模变成1,方向不变。改变后的向量。
//debug划线,从世界坐标系原点,到当前的坐标点
Debug.DrawLine(Vector3.zero, po);
Debug.DrawLine(Vector3.zero, po.normalized,Color.red);
} // 向量的方向:求方向,求向量模的方向,求标准向量,归一化向量
private void Update2()
{
Vector3 po = this.transform.position; //向量/向量模长 = 标准化向量
Vector3 n1 = po / po.magnitude;
//使用向量API 求的 标准化向量
Vector3 n2 = po.normalized; Debug.DrawLine(Vector3.zero,po);
Debug.DrawLine(Vector3.zero,n2,Color.blue);
}
public Transform t1, t2, t3;
private void Update3()
{
//减 向量:结果是 结果向量从减数箭头点指向t1【被减数箭头点】+ 平移到t1和t2的起点交点处
Vector3 n1 = t1.position - t2.position; if (Input.GetKey(KeyCode.A))
{
// 每次移动单位向量,这样距离越长,花费的时间就越长,能体现出距离感
t3.Translate(n1.normalized);
} // 加 向量:结果是 两个向量分别生成各自的辅助虚线向量,组成一个平行四边形,加向量的结果就是这个平行四边形的中间连线
Vector3 n2 = t1.position + t2.position;
if (Input.GetKey(KeyCode.B))
{
// 每次移动单位向量,这样距离越长,花费的时间就越长,能体现出距离感
t3.Translate(n2.normalized);
} Debug.DrawLine(Vector3.zero, n1);
Debug.DrawLine(Vector3.zero, n2, Color.red);
}
public float dotDegValue;
private void Update()
{
Debug.DrawLine(Vector3.zero, t1.position);
Debug.DrawLine(Vector3.zero, t2.position); //根据向量的点乘,求夹角
//注意:点乘求出来的夹角是2个单位向量的最小夹角,如果两个向量的夹角大于180,比如270,则求出来的结果是哪个小部分,90度。
float dotValue = Vector3.Dot(t1.position.normalized, t2.position.normalized);
dotDegValue = Mathf.Acos(dotValue) * Mathf.Rad2Deg;
Debug.Log(dotDegValue); //根据2个向量的叉乘求夹角是否大于180,当小于180时,结果向量的y是大于0的,大于180时,结果向量的y是小于0的
//2个向量叉乘的意义为:得出2个向量组成平面的垂直向量
Vector3 crossValue = Vector3.Cross(t1.position, t2.position);
Debug.DrawLine(this.transform.position, crossValue, Color.red);
//y小于0,大于180
if (crossValue.y < 0)
{
dotDegValue = 360 - dotDegValue;
}
}
private void Update4()
{
//角度 -> 弧度: 弧度 = 角度数 * PI/180
float d1 = 60;
float r1 = d1 * Mathf.Deg2Rad;
float r2 = d1 * Mathf.PI / 180;
print("r1: "+r1 + " r2:"+r2); //弧度 -> 角度: 角度 = 弧度数 * 180/PI
float r02 = Mathf.PI / 3;
float g02 = r02 * 180 / Mathf.PI;
float g03 = r02 * Mathf.Rad2Deg;
print("g02: "+g02+" g03:"+g03); }
private void Update5()
{
//列如:已知角度x, 边长b, 求边长a
//根据公式:tanx = a/b
float x = 50, b = 20;
float a = Mathf.Tan(x * Mathf.Deg2Rad) * b;
//Debug.Log(a); //已知:边长a, 边长b, 求角度 angle
//公式:angle = arc tan(a/b)
float angle = Mathf.Atan(a / b);
float angle2gad = Mathf.Rad2Deg * angle; //Debug.Log(string.Format("{0}:{1}", angle, angle2gad)); //三角函数在项目中的运用
//TransformPoint将自身坐标系中的点转成世界坐标系中的点,
//TransformPoint(0, 0, 10)的意思是延物体自身坐标向前(z轴)走10米,然后将这个点转到世界坐标系中对应的点
Vector3 worldSpaceP = transform.TransformPoint(0, 0, 10);
Debug.DrawLine(this.transform.position, worldSpaceP); //练习:计算物体右前方30度,10m远的坐标
// 根据题目可知,是知道角度和斜边,求a,b边
// 由公式:sinx = a/c, cosx = b/c 得:
// x = a = c * sinx; z = b = c * cosx;
float movX = 10 * Mathf.Sin(30 * Mathf.Deg2Rad);
float movZ = 10 * Mathf.Cos(30 * Mathf.Deg2Rad); Vector3 worldSpaceP2 = transform.TransformPoint(movX, 0, movZ);
Debug.DrawLine(this.transform.position, worldSpaceP2, Color.red);
}
private void OnGUI()
{
//欧拉角
if (GUILayout.RepeatButton("欧拉角X轴"))
{
//欧拉角采用Vector3类型设置是因为Vector3中有对应x,y,z的值,这和欧拉角中设置x,y,z轴上的旋转角度虽然数值意义不同,但它们有相同的数据结构,这是
//欧拉角选择使用Vector3表示的原因
//两者的区别如下: //1.位置:有方向(从世界坐标系原点指向当前点),有大小(从世界坐标原点到当前点的位置)
//向量的x,y,z分别表示当前点在各个轴向上的有向位移
Vector3 pos = this.transform.position; //2.欧拉角,没有方向,大小的概念。它表示的是在x,y,z轴上转了多少度
Vector3 euler = this.transform.eulerAngles; //各分量相加
this.transform.eulerAngles += new Vector3(1, 0,0);
} if (GUILayout.RepeatButton("欧拉角Y轴"))
{
this.transform.eulerAngles += Vector3.up;
}
if (GUILayout.RepeatButton("欧拉角Z轴"))
{
this.transform.eulerAngles += Vector3.forward;
} //四元数就是用来旋转用的,它是轴角模式的旋转,与欧拉角不同的是四元数的旋转全部是绕自己的x,y,z轴旋转。而欧拉角是x,z绕自身的轴y是绕世界坐标系的y,用来解决欧拉角的万向节死锁问题
if (GUILayout.RepeatButton("四元数旋转"))
{
//四元数设置需要2个条件:1.绕哪个轴,2.转多少度 //绕y轴
Vector3 axis = Vector3.right;
//旋转弧度
float radValue = 60 * Mathf.Deg2Rad; //组建四元数
Quaternion qt = new Quaternion();
qt.x = axis.x * Mathf.Sin(radValue / 2);
qt.y = axis.y * Mathf.Sin(radValue / 2);
qt.z = axis.z * Mathf.Sin(radValue / 2);
qt.w = Mathf.Cos(radValue / 2);
//设置四元数
//this.transform.rotation = qt; //使用系统便捷方式设置四元数。欧拉角转成四元数
this.transform.rotation = Quaternion.Euler(60,0,0);
} if (GUILayout.RepeatButton("四元数X轴旋转"))
{
this.transform.rotation *= Quaternion.Euler(1,0,0);
}
if (GUILayout.RepeatButton("四元数Y轴旋转"))
{
this.transform.rotation *= Quaternion.Euler(0, 1, 0);
}
if (GUILayout.RepeatButton("四元数Z轴旋转"))
{
this.transform.rotation *= Quaternion.Euler(0, 0, 1);
}
} void Update()
{
//四元数应用:求当前坐标右前方30度,距离10的坐标
if (Input.GetMouseButtonDown(1))
{
Vector3 v0 = new Vector3(0,0,10); // v0向量绕y轴旋转60度
Vector3 v1 = Quaternion.Euler(0, 30, 0) * v0;
// v1随自身四元数的旋转而旋转
Vector3 v2 = this.transform.rotation * v1;
// 两个向量相加,意义:将这个v0向量的起点移动到当前物体的位置上。
target = this.transform.position + v2;
}
Debug.DrawLine(this.transform.position, target,Color.blue);
}
碰撞回调方法
// 碰撞开始时,接触的第一帧,触发回调
private void OnCollisionEnter(Collision collision)
//中间的每一帧
private void OnCollisionStay(Collision collision)
// 碰撞结束时,接触的最后一帧,触发回调
private void OnCollisionExit(Collision collision)
public class ColisionDemo : MonoBehaviour
{ public float speet = 300; // 碰撞开始时,接触的第一帧,触发回调
private void OnCollisionEnter(Collision collision)
{
//通过collision.collider拿到了另一碰撞对象的碰撞器,那么就可以通过这个碰撞器获取这个对象上所有的其他组件。
//collision.collider.GetComponent<MeshRenderer>();
//Debug.Log(collision.collider.name);
Debug.Log(string.Format("碰撞器碰撞了:{0}", collision.collider.name)); //撞击的碰撞点
ContactPoint cp = collision.contacts[0];
//cp.point碰撞点的世界坐标
//cp.normal碰撞点接触面的法线
}
//中间的每一帧
private void OnCollisionStay(Collision collision)
{ }
// 碰撞结束时,接触的最后一帧,触发回调
private void OnCollisionExit(Collision collision)
{ } //触发回调,接触的第一帧,触发回调
private void OnTriggerEnter(Collider other)
{
Debug.Log(string.Format("触发器触发了:{0}", other.name));
} private void OnTriggerStay(Collider other)
{ } private void OnTriggerExit(Collider other)
{ } //当物体的移动速度非常快时可能检测不到触发和碰撞,情况是在接触前那一刻检测,等第二次检测时已经穿过去了,判断结果还是没有接触
private void FixedUpdate()
{
Debug.Log(string.Format("frameCount: {0}", Time.frameCount));
this.transform.Translate(Time.deltaTime * speet * -1, 0, 0);
} private RaycastHit hit;
public LayerMask layer;
private Vector3 targetPos;
// 使用射线解决移动速度过快,接触检查失效问题
void Start()
{
//射线投射命中
//射线投射:Raycast(起点坐标,方向,受击物体信息,距离,图层)
var res = Physics.Raycast(this.transform.position, -this.transform.right, out hit, 500, layer);
if (res)
{
//击中的位置
targetPos = hit.point;
}
else
{
//没有命中目标
//targetPos = this.transform.TransformPoint(0,0,500);
targetPos = this.transform.position + (-this.transform.right * 100);
}
} // Update is called once per frame
void Update()
{
transform.position = Vector3.MoveTowards(transform.position, targetPos, speet*Time.deltaTime);
//子弹从发射位置走到击中的位置就停止了
if ((transform.position - targetPos).sqrMagnitude < 0.1)
{
//击中: 击中的物体销毁,子弹也销毁
Destroy(hit.collider.gameObject);
Destroy(this.gameObject);
}
}
}
public class VectorAPIDemo : MonoBehaviour
{
public Transform t1;
private Vector3 tangent;
private Vector3 binNormal;
public Vector3 currentSpeed; public AnimationCurve curve;
private float x;
public float time = 5; //test
private float speetScall = 1/30; // Start is called before the first frame update
void Start1()
{
//属性设置注意,因为this.transform.position返回的是position的副本,无法真正修改position的值,所以会报错。
//this.transform.position.z = 1; //解决方案:将position作为一个整体设置
Vector3 p = this.transform.position;
p.z = 2;
this.transform.position = p; //Distance: 为模长。
//sqrMagnitude: 为(位置1-位置2).模长平方。
Vector3.Distance(tangent, binNormal);
} // Update is called once per frame
void Update()
{
Vector3 vect = new Vector3();
Vector3 vect0 = vect.normalized;
vect.Normalize(); //计算垂直向量:在三维坐标系中,一个向量的垂直向量有2条
//OrthoNormalize(ref Vector3 normal, ref Vector3 tangent); //计算t1物体在地面上的投影
Vector3 norm = t1.position;
Vector3 project = Vector3.ProjectOnPlane(norm, Vector3.up);
Debug.DrawLine(Vector3.zero, norm);
Debug.DrawLine(Vector3.zero, project, Color.red); //计算反射向量:Vector3.Reflect; //向量的加,减,点乘,差乘等。
} private void OnGUI()
{
if (GUILayout.RepeatButton("Lerp"))
{
//Lerp有快到慢,每次前进总长度的10%,无限接近目标点;
//每次都是起点改变,终点和比例不变。
this.transform.position = Vector3.Lerp(transform.position, new Vector3(0, 0, 10), 0.1f*Time.deltaTime);
} if (GUILayout.RepeatButton("MoveTowards---------------"))
{
//匀速前进,无限接近目标点;
this.transform.position = Vector3.MoveTowards(transform.position, new Vector3(0, 0, 10), 0.1f);
} if (GUILayout.RepeatButton("SmoothDamp"))
{
//平滑阻尼,速度按固定的速率在减弱
this.transform.position = Vector3.SmoothDamp(transform.position, new Vector3(0,0,10),ref currentSpeed,2);
} if (GUILayout.RepeatButton("变速运动"))
{
x += Time.deltaTime / time;
Vector3 begin = Vector3.zero; //与Lerp变速对比变速运动为:起点,终点不变,比例改变
//curve.Evaluate(x):随着时间的变化,根据x值取y值。因为x值没有,这里自己造一个,通过x += Time.deltaTime累加法,每秒加一
transform.position = Vector3.LerpUnclamped(begin, new Vector3(0,0,10),curve.Evaluate(x));
} }
}
public class QuaternionAPIDemo : MonoBehaviour
{
public float moveSpeed = 1;
// Start is called before the first frame update
void Start()
{
//四元数
Quaternion qt = transform.rotation;
//1.四元数 -> 欧拉角
Vector3 euler = qt.eulerAngles;
//2.欧拉角 -> 四元数
Quaternion qt02 = Quaternion.Euler(0, 90, 0);
//3.轴、角转换
//transform.rotation = Quaternion.AngleAxis(30, Vector3.up);
//transform.localRotation = Quaternion.AngleAxis(30,Vector3.up); } // Update is called once per frame
public Transform target; private void OnGUI()
{
Quaternion dir = Quaternion.LookRotation(target.position - transform.position);
if (GUILayout.RepeatButton("LookRotation+++++++++++++++++++"))
{
//4.注视旋转
//方法1
//Quaternion dir2 = Quaternion.LookRotation(target.position - transform.position);
//transform.rotation = dir2;
//方法2
transform.LookAt(target.position);
}
if (GUILayout.RepeatButton("Lerp"))
{
//5.Lerp差值旋转,由快到慢
//它与注视旋转的区别是:注视旋转是一帧设置完成,Lerp是多帧设置完成
transform.rotation = Quaternion.Lerp(transform.rotation, dir, 0.1f);
}
if (GUILayout.RepeatButton("RotateTowards"))
{
//6.RotateTowards: 匀速旋转
transform.rotation = Quaternion.RotateTowards(transform.rotation, dir, 0.1f);
}
if (GUILayout.RepeatButton("Angle角度判断"))
{
Quaternion dir2 = Quaternion.Euler(0, 180, 0);
transform.rotation = Quaternion.Lerp(transform.rotation, dir2, 0.005f);
//7.2个四元数角度差计算
if (Quaternion.Angle(transform.rotation, dir2) < 30)
{
transform.rotation = dir2;
}
} } void Update()
{
//上面提供的方法默认的旋转轴是绕z轴,如果想绕x轴旋转,可通过下面的方式
//this.transform.right = target.position - this.transform.position;
//从x轴正方向 -> 注视目标位置的方向
//8.从?到?的旋转
//transform.rotation = Quaternion.FromToRotation(Vector3.right, target.position - transform.position); //课后作业:物体随ad/sw进行上下旋转
var hRes = Input.GetAxis("Horizontal");
var vRes = Input.GetAxis("Vertical"); if (hRes != 0 || vRes != 0)
{
Debug.Log(string.Format("hRes:{0}- vRes:{1}", hRes, vRes));
//transform.rotation = Quaternion.LookRotation(new Vector3(hRes, 0, vRes)); //带旋转过程
var targetRotation = Quaternion.LookRotation(new Vector3(hRes, 0, vRes));
transform.rotation = Quaternion.Lerp(this.transform.rotation, targetRotation, moveSpeed *Time.deltaTime); transform.Translate(0, 0, moveSpeed * Time.deltaTime);
}
} }
Unity三维数学总结的更多相关文章
- Unity 三维软件单位导入资源单位比例
三维软件 内部米制尺寸/m 默认设置导入unity中的尺寸/m 与unity单位比例 Maya 1 100 1:100 3DS MAX 1 0.01 100:1 Cinema 4D 1 100 1:1 ...
- unity向量-数学-三角函数
1.如何在unity写cos60 Mathf.Cos(Mathf.Deg2Rad * ) Deg2Rad将 60 角度转换为弧度,因为里面参数只能填弧度数 2.计算一个Vector3绕旋转中心旋转指定 ...
- [转] Unity Mathf 数学运算(C#)
Mathf.Abs 绝对值 计算并返回指定参数 f 绝对值. Mathf.Acos 反余弦 static function Acos (f : float) : float 以弧度为单位计算并返回参数 ...
- unity三维地球模型生成
准备一张贴图 创建材质球 球面坐标系转直角坐标系 x=rsinθcosφ. y=rsinθsinφ. z=rcosθ. 效果如下 脚本如下 using System.Collections; ...
- Unity Mathf/Math数学运算函数说明全集(Chinar总结)
Unity Mathf 数学函数库 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- ...
- Unity射线检测的用法总结
RayCast 射线检测 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享.心 ...
- Unity DOTS 走马观花
https://segmentfault.com/a/1190000019143037 本文还在不断完善,可能不会及时同步在 SegmentFault,源文章在我的博客中:萤火之森 - Unity D ...
- Atitit 游戏的原理与概论attilax总结
Atitit 游戏的原理与概论attilax总结 1. 游戏历史2 1.1.1. 盘点PC游戏史上最重要的50款游戏2 1.1.2. 回味人类文明进程 五款经典的历史游戏2 2. 游戏类型(主要分为6 ...
- 分享我收集的引擎、图形学、WebGL方面的电子资料
本文分享我这一年以来收集的我认为比较经典的电子资料,希望能对大家有所帮助! 本文会不断更新! 目录 WebGL Insights OpenGL Insights Game Programming Pa ...
- 一起学习《C#高级编程》3--运算符重载
运算符的重载.C++的开发人员应该很熟悉这个概念,但这对Java 和 VB 开发人员确实全新的. 对于一些数值间的运算,如果通过方法来指定运算规则的话,不免会繁琐,这时就可以利用运算符的重载. 例: ...
随机推荐
- 2022-05-22:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p
2022-05-22:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义为:"对于有根树 T 的两个节点 p.q,最近公共祖先表示为一个节点 x,满足 x ...
- 2021-08-02:按公因数计算最大组件大小。给定一个由不同正整数的组成的非空数组 A,考虑下面的图:有 A.length 个节点,按从 A[0] 到 A[A.length - 1] 标记;只有当
2021-08-02:按公因数计算最大组件大小.给定一个由不同正整数的组成的非空数组 A,考虑下面的图:有 A.length 个节点,按从 A[0] 到 A[A.length - 1] 标记:只有当 ...
- 7-8 估值一亿的AI核心代码
题目描述: 以上图片来自新浪微博. 本题要求你实现一个稍微更值钱一点的 AI 英文问答程序,规则是: 无论用户说什么,首先把对方说的话在一行中原样打印出来: 消除原文中多余空格:把相邻单词间的多个空格 ...
- 【python基础】基本数据类型-字符串类型
1.初识字符串 字符串就是一系列字符.在python中,用引号括起来文本内容的都是字符串. 其语法格式为:'文本内容'或者"文本内容" 我们发现其中的引号可以是单引号,也可以是双引 ...
- 在 Net Core 开发中如何解决 Cannot access a disposed object 这个问题
一.简介 Net Core跨平台项目开发多了,总会遇到各种各样的问题,我就遇到了一个这样的问题,不能访问 Cannot access a disposed object 错误,经过自己多方努力,查阅资 ...
- 在 Linux 和 Windows 下源码安装 Perl
Perl 是一种功能丰富的计算机程序语言,运行在超过 100 种计算机平台上,适用广泛,从大型机到便携设备,从快速原型创建到大规模可扩展开发.在生物信息分析领域,Perl 主要是做数据预处理.文本处理 ...
- Vue跨域配置异常采坑:Request failed with status code 401
本地用Express作为服务端,前端Vue项目配置跨域代理,调用服务端api接口始终报错"Request failed with status code 401".原来发现是端口3 ...
- JuiceFS 社区版 v1.1- Beta 发布,新增五个实用功能
我们很高兴地宣布 JuiceFS v1.1-Beta 版本正式发布啦!这是一个功能丰富的版本,带来了许多实用的新功能和改进.在这个版本中我们新增了以下功能: 目录配额:为目录设置配额限制,控制其大小和 ...
- Hive常见时间日期函数的使用与问题整理
这里整理一下Hive常见的时间函数和日期函数和用法,作为平时数据处理过程的一个检索和记录. 平时在数据处理过程中,如果不经常使用时间函数,一时间遇到一些时间上的处理,难免会想不起来. hive本身提供 ...
- 有哪些ASIC加速技术可以实现低功耗运行?
目录 文章主题: 10. 有哪些ASIC加速技术可以实现低功耗运行? 背景介绍:随着移动设备.物联网.云计算等应用场景的不断增长,功耗成为了一个日益重要的技术问题.为了在移动设备上实现更长时间的运行, ...