Unity3D 向量运算
写在前面的话,前两天有个朋友在QQ上问我 如何获取主角面朝方向一定区域中的敌人对象。这个命题看似简单,其实里面蕴含了很多数学方面的东西。今天刚好有时间我就彻底的把这个疑问写在博客中。希望可以帮助到他。
在上代码之前请大家跟我先做几个简单的练习题,角度向量的计算一定要学会,不然后面的东西会很难懂。
1.已知3D坐标,和一个旋转角度,以及一段距离,求目标点的3D坐标。
已知当前点为Target,目标点沿着Target的Y轴旋转30度,沿着Target的X轴延伸10米求目标点的3D坐标?
using System.Collections; public class Test : MonoBehaviour
{ public Transform Target; void LateUpdate ()
{
Quaternion rotation = Quaternion.Euler(0f,30f,0f) * Target.rotation;
Vector3 newPos = rotation * new Vector3(10f,0f,0f);
Debug.DrawLine(newPos,Vector3.zero,Color.red);
Debug.Log("newpos " + newPos +" nowpos " + Target.position + " distance " + Vector3.Distance(newPos,Target.position));
} }
输出结果 :新坐标 (8.7, 0.0, -5.0) 当前坐标 (0.0, 0.0, 0.0)两点之间的距离 10。
2.已知3D模型的角度求它的向量。
已知3D模型Target,Y轴旋转30度后向前平移。
using UnityEngine;
using System.Collections; public class Test : MonoBehaviour
{ public Transform Target; void LateUpdate ()
{ if(Input.GetMouseButton(0))
{
Quaternion rotation = Quaternion.Euler(0f,30f,0f) * Target.rotation;
Vector3 newPos = rotation * Vector3.forward;
Target.Translate(newPos.x,newPos.y,newPos.z);
}
} }
3.已知一个目标点,让模型朝着这个目标点移动。
Target.transform.LookAt(new Vector3 (100f,200f,300f));
Target.Translate(Vector3.forward);
这里我要说的就是Vector3.forward ,它等价与 new Vector3(0,0,1);它并不是一个坐标,它是一个标准向量,方向是沿着Z轴向前。这样平移一次的距离就是1米, 如果Vector3.forward * 100那么一次平移的距离就是100米。
在看看下面这段代码
这是一个比较简单的例子,大家应该都能看明白。
Vector3 vecn = (TargetCube.position - Target.position).normalized;
Target.Translate(vecn *0.1f);
用向量减去一个向量求出它们的差值,normalized 是格式化向量,意思是把它们之间向量格式化到1米内。这样就可以更加精确的计算一次平移的距离了 vecn *0.1f 就标示一次平移1分米,蛤蛤。
向量不仅可以进行X Y Z轴的移动,同样可以进行旋转 ,下面这段代码就是让向量沿着Y轴旋转30度。
Vector3 vecn = (TargetCube.position - Target.position).normalized;
vecn = Quaternion.Euler(0f,30f,0f) * vecn;
Target.Translate(vecn *0.1f);
如果上述三道简单的练习题 你都能了然于心的话,那么本文最大的难题我相信也不会是什么难事,继续阅读吧。
假设我们需要计算主角面前5米内所有的对象时。以主角为圆心计算面前5米外的一个点,为了让大家看清楚我现将这条线绘制出来。
private float distance = 5f;
void Update ()
{
Quaternion r= transform.rotation;
Vector3 f0 = (transform.position + (r *Vector3.forward) * distance);
Debug.DrawLine(transform.position,f0,Color.red);
}
如下图所,我们已经将这两个点计算出来了。此时你可以动态的编辑主角Y轴的坐标,这个点永远都是沿着主角当前角度面前5米以外的点。
接下来,我们需要计算主角面前的一个发散性的角度。假设主角看到的是向左30度,向右30度在这个区域。
void Update ()
{
Quaternion r= transform.rotation;
Vector3 f0 = (transform.position + (r *Vector3.forward) * distance);
Debug.DrawLine(transform.position,f0,Color.red); Quaternion r0= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y - 30f,transform.rotation.eulerAngles.z);
Quaternion r1= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y + 30f,transform.rotation.eulerAngles.z); Vector3 f1 = (transform.position + (r0 *Vector3.forward) * distance);
Vector3 f2 = (transform.position + (r1 *Vector3.forward) * distance); Debug.DrawLine(transform.position,f1,Color.red);
Debug.DrawLine(transform.position,f2,Color.red); Debug.DrawLine(f0,f1,Color.red);
Debug.DrawLine
}
如下图所示,这时主角面前的区域就计算出来了。看起来就是两个三角形之间的区域。
最后就是简单的套用公式,计算一个点是否在三角形内,在本文中就是计算敌人的点是否在面前的这两个三角形内。
using System.Collections; public class MyTest : MonoBehaviour { public Transform cube; private float distance = 5f;
void Update ()
{
Quaternion r= transform.rotation;
Vector3 f0 = (transform.position + (r *Vector3.forward) * distance);
Debug.DrawLine(transform.position,f0,Color.red); Quaternion r0= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y - 30f,transform.rotation.eulerAngles.z);
Quaternion r1= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y + 30f,transform.rotation.eulerAngles.z); Vector3 f1 = (transform.position + (r0 *Vector3.forward) * distance);
Vector3 f2 = (transform.position + (r1 *Vector3.forward) * distance); Debug.DrawLine(transform.position,f1,Color.red);
Debug.DrawLine(transform.position,f2,Color.red); Debug.DrawLine(f0,f1,Color.red);
Debug.DrawLine(f0,f2,Color.red); Vector3 point = cube.position; if(isINTriangle(point,transform.position,f1,f0) || isINTriangle(point,transform.position,f2,f0) )
{
Debug.Log("cube in this !!!");
}else
{
Debug.Log("cube not in this !!!");
} } private float triangleArea(float v0x,float v0y,float v1x,float v1y,float v2x,float v2y)
{
return Mathf.Abs((v0x * v1y + v1x * v2y + v2x * v0y
- v1x * v0y - v2x * v1y - v0x * v2y) / 2f);
} bool isINTriangle(Vector3 point,Vector3 v0,Vector3 v1,Vector3 v2)
{
float x = point.x;
float y = point.z; float v0x = v0.x;
float v0y = v0.z; float v1x = v1.x;
float v1y = v1.z; float v2x = v2.x;
float v2y = v2.z; float t = triangleArea(v0x,v0y,v1x,v1y,v2x,v2y);
float a = triangleArea(v0x,v0y,v1x,v1y,x,y) + triangleArea(v0x,v0y,x,y,v2x,v2y) + triangleArea(x,y,v1x,v1y,v2x,v2y); if (Mathf.Abs(t - a) <= 0.01f)
{
return true;
}else
{
return false;
}
}
}
如下图所示,如果箱子对象是主角的视野中就会检测到。
注意,上图中我的视野选择了两个三角形,如果你需要视野目标点是椭圆形的话,那么可以多设置一些三角形。但是这样就会非常消耗效率,我觉得这里完全可以使用1个三角形,,只是正对的目标点会出现一些偏差,影响其实并不会很大。如下图所示
代码简单的修改一下即可。
public class MyTest : MonoBehaviour { public Transform cube; private float distance = 5f;
void Update ()
{
Quaternion r= transform.rotation;
Vector3 f0 = (transform.position + (r *Vector3.forward) * distance);
Debug.DrawLine(transform.position,f0,Color.red); Quaternion r0= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y - 30f,transform.rotation.eulerAngles.z);
Quaternion r1= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y + 30f,transform.rotation.eulerAngles.z); Vector3 f1 = (transform.position + (r0 *Vector3.forward) * distance);
Vector3 f2 = (transform.position + (r1 *Vector3.forward) * distance); Debug.DrawLine(transform.position,f1,Color.red);
Debug.DrawLine(transform.position,f2,Color.red);
Debug.DrawLine(f1,f2,Color.red); Vector3 point = cube.position; if(isINTriangle(point,transform.position,f1,f2))
{
Debug.Log("cube in this !!!");
}else
{
Debug.Log("cube not in this !!!");
} } private float triangleArea(float v0x,float v0y,float v1x,float v1y,float v2x,float v2y)
{
return Mathf.Abs((v0x * v1y + v1x * v2y + v2x * v0y
- v1x * v0y - v2x * v1y - v0x * v2y) / 2f);
} bool isINTriangle(Vector3 point,Vector3 v0,Vector3 v1,Vector3 v2)
{
float x = point.x;
float y = point.z; float v0x = v0.x;
float v0y = v0.z; float v1x = v1.x;
float v1y = v1.z; float v2x = v2.x;
float v2y = v2.z; float t = triangleArea(v0x,v0y,v1x,v1y,v2x,v2y);
float a = triangleArea(v0x,v0y,v1x,v1y,x,y) + triangleArea(v0x,v0y,x,y,v2x,v2y) + triangleArea(x,y,v1x,v1y,v2x,v2y); if (Mathf.Abs(t - a) <= 0.01f)
{
return true;
}else
{
return false;
}
}
}
上面我们介绍了三角形判断,当然也可以通过矩形来判断是否相交。。
public class MyTest : MonoBehaviour { public Transform cube; private float distance = 5f;
void Update ()
{
Quaternion r= transform.rotation;
Vector3 left = (transform.position + (r *Vector3.left) * distance);
Debug.DrawLine(transform.position,left,Color.red); Vector3 right = (transform.position + (r *Vector3.right) * distance);
Debug.DrawLine(transform.position,right,Color.red); Vector3 leftEnd = (left + (r *Vector3.forward) * distance);
Debug.DrawLine(left,leftEnd,Color.red); Vector3 rightEnd = (right + (r *Vector3.forward) * distance);
Debug.DrawLine(right,rightEnd,Color.red); Debug.DrawLine(leftEnd,rightEnd,Color.red); Vector3 point = cube.position; if(isINRect(point,leftEnd,rightEnd,right,left))
{
Debug.Log("cube in this !!!");
}else
{
Debug.Log("cube not in this !!!");
} } private float Multiply(float p1x , float p1y, float p2x,float p2y, float p0x,float p0y)
{
return ((p1x - p0x) * (p2y - p0y) - (p2x - p0x) * (p1y - p0y));
} bool isINRect(Vector3 point,Vector3 v0,Vector3 v1,Vector3 v2,Vector3 v3)
{
float x = point.x;
float y = point.z; float v0x = v0.x;
float v0y = v0.z; float v1x = v1.x;
float v1y = v1.z; float v2x = v2.x;
float v2y = v2.z; float v3x = v3.x;
float v3y = v3.z; if (Multiply(x,y, v0x,v0y, v1x,v1y) * Multiply(x,y, v3x,v3y, v2x,v2y) <= 0 && Multiply(x,y, v3x,v3y, v0x,v0y) * Multiply(x,y, v2x,v2y, v1x,v1y) <= 0)
return true;
else
return false; } }
这里我以角色左右个30度。 这样就可以根据两个模型的距离以及角度来判断了。。
public class NewBehaviourScript : MonoBehaviour { public Transform target; void Update()
{ float distance = Vector3.Distance(target.position,transform.position); Quaternion right = transform.rotation * Quaternion.AngleAxis(30,Vector3.up);
Quaternion left = transform.rotation * Quaternion.AngleAxis(30,Vector3.down); Vector3 n = transform.position + (Vector3.forward * distance);
Vector3 leftPoint = left * n ;
Vector3 rightPoint = right *n ; Debug.DrawLine(transform.position,leftPoint,Color.red);
Debug.DrawLine(transform.position,rightPoint,Color.red);
Debug.DrawLine(rightPoint,leftPoint,Color.red); }
}
文章地址:http://www.xuanyusong.com/archives/1977
Unity3D 向量运算的更多相关文章
- UVa 11437:Triangle Fun(计算几何综合应用,求直线交点,向量运算,求三角形面积)
Problem ATriangle Fun Input: Standard Input Output: Standard Output In the picture below you can see ...
- Unity 三角函数 向量 运算
其实三维的和二维的基本差不多,一样的运算方式,unity已经把所有的方法都封装起来,主要是理解,能理解了就直接调用了 三角函数 知识点:三角函数基础正玄余玄.三角函数曲线.弧度制和角度制.弧度制和角度 ...
- 向量运算 与 JavaScript
二维向量都包含两个值:方向(direction)及大小(magnitude) 这两个值可以表达出各种各样的物理特性来,比如力和运动.如两个物体间的碰撞检测. 向量的大小 虽说二维向量是对大 ...
- 3D数学读书笔记——向量运算及在c++上的实现
本系列文章由birdlove1987编写.转载请注明出处. 文章链接: http://blog.csdn.net/zhurui_idea/article/details/24782661 ...
- 向量运算(lua,三维) 点乘、叉乘、模、夹角
向量运算在游戏制作中经常用到,稍微总结一下. 一.点乘 如图,假设 向量a与b的点乘表示a在b上的投影与b的模的乘积 公式: 代码: function MathHelper.GetVector3D ...
- Eigen中的矩阵及向量运算
Eigen中的矩阵及向量运算 ,[+,+=,-,-=] ,[\*,\*=] ,[.transpose()] ,[.dot(),.cross(),.adjoint()] ,针对矩阵元素进行的操作[.su ...
- 快速电路仿真器(FastSPICE)中的高性能矩阵向量运算实现
今年10-11月份参加了EDA2020(第二届)集成电路EDA设计精英挑战赛,通过了初赛,并参加了总决赛,最后拿了一个三等奖,虽然成绩不是很好,但是想把自己做的分享一下,我所做的题目是概伦电子出的F题 ...
- python3 定义向量运算
from math import hypot #定义向量的构造方法 class Vector: def __init__(self,x=0,y=0): self.x=x; self.y=y; ''' ...
- [Unity3d]向量的过度方法以及拖尾效果
Vector3.RotateTowards() 用法 public static function RotateTowards(current: Vector3, target: Vector3, m ...
随机推荐
- [吴恩达机器学习笔记]12支持向量机2 SVM的正则化参数和决策间距
12.支持向量机 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考资料 斯坦福大学 2014 机器学习教程中文笔记 by 黄海广 12.2 大间距的直观理解- Large Margin I ...
- turn服务部署
centos7.2 git clone https://github.com/coturn/coturnyum -y install openssl-develyum install openssl ...
- HTML不常用的表单属性-fieldset
这是代码 这是生成的样子 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http: ...
- NOIP模拟3
期望得分:30+90+100=220 实际得分:30+0+10=40 T1智障错误:n*m是n行m列,硬是做成了m行n列 T2智障错误:读入三个数写了两个%d T3智障错误:数值相同不代表是同一个数 ...
- 一小时了解数据挖掘⑤数据挖掘步骤&常用的聚类、决策树和CRISP-DM概念
一小时了解数据挖掘⑤数据挖掘步骤&常用的聚类.决策树和CRISP-DM概念 接前面系列4篇: 一小时了解数据挖掘①:解析常见的大数据应用案例 一小时了解数据挖掘②:分类算法的应用和成熟案例解析 ...
- ② 设计模式的艺术-02.简单工厂(Simple Factory)模式
工厂模式 实现了创建者和调用者的分离. 详细分类:简单工厂模式.工厂方法模式.抽象工厂模式 面向对象设计的基本原则 OCP(开闭原则,Open-Closed Principle):一个软件的实体应当对 ...
- 【BZOJ】4555: [Tjoi2016&Heoi2016]求和 排列组合+多项式求逆 或 斯特林数+NTT
[题意]给定n,求Σi=0~nΣj=1~i s(i,j)*2^j*j!,n<=10^5. [算法]生成函数+排列组合+多项式求逆 [题解]参考: [BZOJ4555][Tjoi2016& ...
- SDUT 3917
UMR 现在手里有 n 张康纳的表情,最上面一张是玛吉呀巴库乃.现在 UMR 如果每次把最上面的 m 张牌移到最下面而不改变他们的顺序及朝向,那么至少经过多少次移动玛吉呀巴库乃才会又出现在最上面呢? ...
- 【洛谷 P4219】 [BJOI2014]大融合(LCT)
题目链接 维护子树信息向来不是\(LCT\)所擅长的,所以我没搞懂qwq 权当背背模板吧.Flash巨佬的blog里面写了虽然我没看懂. #include <cstdio> #define ...
- 微信小程序迁移到头条小程序工具
最近公司需要将微信小程序迁移到头条小程序,比较得知微信和头条小程序的写法类似,只有文件名称不同,相关的指令不同,以及头条在ttml绑定的数据不可使用function,于是就写了node脚本来实现这些重 ...