1、前语
前段时间接到一个开发任务,在unity中做一个仿真模仿的功用,由于不是简略的直线规范工件,一般来说简略的直线工件运用三角函数就能解决相关的核算,然后完成仿真模仿。本次模仿涉及到圆、圆弧以及直线,需求求解直线与圆相交的直线与直线相交,以及求解线段在圆内的折射、反射,思来想去就运用了向量核算,分享下开发过程中运用到的关于向量的核算。
2、向量的根本运算与运用
向量的根本运算及运用不过多介绍,网上文章较多,可参考向量运算与运用,本次首要分享在unity中向量的加减、向量点乘及向量旋转。
3、unity中向量的运用
3.1向量的加减与坐标点核算
在unity三维坐标系中一个坐标用类Vector3表明,在二维坐标系中用类Vector2表明,若已知点A坐标为(x1,y1,z1),B点坐标为(x2,y2,z2),向量AB=B-A(箭头由A指向B),向量在unity中也是用Vector3来表明,向量不能简略理解为一个坐标点,这点要留意。
//点A
var A = new Vector3(x1, y1, z1);
//点B
var B= new Vector3(x2, y2, z2);
//向量AB
var AB = B - A;
已知向量AB,假如这个时分有一个点C间隔点A或点B的间隔是已知的(点C在向量AB的方向上),怎么求这个坐标点的坐标呢?很简略,先求向量AB的单位向量,C点坐标就等于点A或点B坐标加上方向向量乘以对应的间隔。需求判别的是C在AB向量的正方形还是反方向,这个结合实际情况判别,为正就A点加上单位向量乘以间隔,反之则减去。
//假设点A间隔点C间隔为10
var distance = 10;
//点C的坐标,若在向量AB的正方向上则
var C = A + AB.normalized * distance;
//若在向量AB的负方向上则
C = A - AB.normalized * distance;
3.2坐标点之间间隔的核算
unity中两个坐标点之间间隔的核算运用Vector3的函数Distance即可得到,十分简略,例如求A点、C点之前的间隔:
//点A到点C的间隔
var distanceAToC = Vector3.Distance(A, C);
3.3向量的点乘
向量的点乘在unity中用类Vector3的静态函数Dot(d1,d2)表明,即向量d1与d2进行点乘核算,数学含义便是向量d1与向量d2围成的平行四边形的面积。
接着上面的代码,存在点D,向量AB与向量CD的夹角为r,经过向量点乘公式能够求的夹角的弧度值。
//点D
var D = new Vector3(x3, y3, z3);
//向量CD
var CD = D - C;
//向量AB与向量CD的夹角的余弦值
var cos = Vector3.Dot(AB, CD) / (AB.magnitude * CD.magnitude);
//夹角的弧度值
var radians = Mathf.Acos(cos);
//夹角的视点值
float degrees = Mathf.Rad2Deg * radians;
由单位向量的定义,能够先求每个向量的单位向量,再求夹角,上述代码也可描述为:
var D = new Vector3(x3, y3, z3);
var CD = D - C;
var cos = Vector3.Dot(AB.normalized, CD.normalized) / (AB.normalized.magnitude * CD.normalized.magnitude);
//夹角的弧度值
var radians = Mathf.Acos(cos);
//夹角的视点值
float degrees = Mathf.Rad2Deg * radians;
var incidentPoint = new Vector3(x, refPoint.y, z);
运用向量的加减、间隔核算,加上向量的点乘这些知识点,再运用二分法,能够轻松求解直线与圆的交点,直线与直线的交点等数学问题。下面放一段运用二分法求直线与圆相交点的代码,仅供参考:
//直线的点
tempIncident = new Vector3(x, centerElem.y, z);
//求直线在圆外表的交点
xLeft = tempIncident.x;
xRight = 0;
x = (xLeft + xRight) / 2;
//由圆的方程知x得z
z = Mathf.Sqrt((radius * radius) - Mathf.Pow(x + (wedgeLength / 2), 2)) - radius;
//由直线方程式(x-x1)/(X2-x1)=(z-z1)/(z2-z1)可得
difference = (x - tempIncident.x) / (centerElem.x - tempIncident.x)
- (z - tempIncident.z) / (centerElem.z - tempIncident.z);
--------运用二分法求解交点----------
count = 0;
//当差错小于0.00001或迭代核算次数超过20次即退出循环
while (Mathf.Abs(difference) > 0.00001 && count < 20)
{
if (difference > 0)
{
xLeft = x;
}
else
{
xRight = x;
x = (xLeft + xRight) / 2;
// 核算新的中点坐标和函数值
z = Mathf.Sqrt((radius * radius) - Mathf.Pow(x + (wedgeLength / 2), 2)) - radius;
difference = (x - tempIncident.x) / (centerElem.x - tempIncident.x)
- (z - tempIncident.z) / (centerElem.z - tempIncident.z);
count++;
}
//交点坐标
incidentPoint = new Vector3(x, centerE
3.4向量的旋转
什么情况下能用到向量的转转呢?便是已知一条向量在物体上反射之后,求反射后的向量,会用到向量的旋转,已知条件便是向量、反射点的法向量与向量的夹角。还是以上面的简略比如为比如进行阐明,已知向量AB和旋转角R,求向量AB以A点为旋转点,顺时针旋转R后的向量A’B’。
//反射角(弧度值)
var refractAngle = R;
//我这里假设一切向量都在X-Z平面,旋转轴便是Y轴,旋转轴的单位向量为 Vector3.up
var rotationAxis = Vector3.up;
//运用unity中Quaternion的AngleAxis来完成旋转,办法里边视点需转换为视点值,得到一个四元数
var rotationQuaternion = Quaternion.AngleAxis(-2 * refractAngle2 * 180 / Mathf.PI, rotationAxis);
//求解旋转后的向量
var A'B' = rotationQuaternion * AB;
4、总结
1、运用二分法求解直线与直线相交点、直线与圆弧的相交点十分便利,但是过程中要留意二分法的取值规模及指针移动的条件判别正确,否则就无法得到正确的交点。
2、已知夹角,运用向量的点乘加上二分法能够便利求解直线与圆的交点,相同需求留意的是圆的方程对于一个任何的x,y,z值都有对应的两个交点,需求根据条件判别你所求的点。
3、向量的旋转对于求解圆的折射和反射时十分便利,需求留意向量的正负与旋转视点的正负值,顺时针为负,逆时针选择则取正值。
4、unity三维坐标系中,常用的坐标核算相关的类便是vector3以及四元数Quaternion,把握这两个及相关的类的运用比较重要。