Featured image of post RayCast和Vector3D使用时所注意到的

RayCast和Vector3D使用时所注意到的

Vector3D的基本理解和解决连线问题的活用例

简介

之前一直以为Vector3d就只能代表一个点,最近在写ML-Agents环境用到RayCast时注意到Vector3D正如其名,需要将其看作是向量来用会更容易理解。以下用两个例子来实际操作。

第一需求:连接自机中心点S与敌机最左和最右两侧的点Le与Re

我的解决方案

射出一条垂直向上的向量Vertical,并连接自机与敌机所形成向量EnemytoMe

1
2
Vector3 Vertical = new Vector3(0, 100, 0);//垂直向上的向量
Vector3 EnemytoMe = MyselfPosition - thisEnemyPosition;//Enemy和自机连线,指向自机的向量
使用Vector3.Cross()射出垂直于VerticalEnemytoMe两向量所形成平面的向量LHorizontalRhorizontal (具体使用方法参考Vector3.Cross(),写的比我清楚_(:з」∠)_)
1
2
Vector3 LHorizontal = Vector3.Cross(Vertical, EnemytoMe);
Vector3 RHorizontal = Vector3.Cross(EnemytoMe, Vertical);
由于刚才垂直向上的向量太长了,需要下面操作缩短为1/2Enemy宽度
1
float standaedization = (float)thisEnemyWidth / Vector3.Distance(thisEnemyPosition, RHorizontal);//计算需要缩小的比例
适用该比例于RHorizontalLHorizontal
1
2
RHorizontal *= standaedization;//应用缩小比例,标准化完成
LHorizontal *= standaedization;//应用缩小比例,标准化完成
最后使用向量基本运算即可求出 自机与敌机左右连线的向量LMetoEnemy 和RMetoEnemy
1
2
Vector3 LMetoEnemy = LHorizontal - EnemytoMe;//自机与左侧边界连线Me<- Enemy
Vector3 RMetoEnemy = RHorizontal - EnemytoMe;//自机与右侧边界连线Enemy ->Me

实际执行示意图

第二需求:使用agentCam.WorldToViewportPoint()判断敌机左右两侧的点是否在视角内

我的解决方案

使用向量基本运算即可求出 0点与敌机左右连线的向量L0toEnemyR0toEnemy ,此时该向量可视为该点在世界中的绝对坐标 此时可直接讲两向量带入agentCam.WorldToViewportPoint()获得两点于视角内坐标LEnemyInViewREnemyInView

1
2
3
4
Vector3 L0toEnemy = LHorizontal + thisEnemyPosition;// Enemy左侧绝对坐标
Vector3 R0toEnemy = RHorizontal + thisEnemyPosition;// Enemy右侧绝对坐标
Vector3 LEnemyInView = agentCam.WorldToViewportPoint(L0toEnemy);//Enemy左侧于视角中位置
Vector3 REnemyInView = agentCam.WorldToViewportPoint(R0toEnemy);//Enemy右侧于视角中位置

LEnemyInViewREnemyInView 满足以下条件时既其在视角可见范围内,其中.x .y分别为在视角内横向与纵向坐标,.z为距离视角的深度,正为为该点在正面,负为该点在背面。

1
2
3
4
5
LEnemyInView.x >= 0
LEnemyInView.x <= 1
LEnemyInView.y >= 0
LEnemyInView.y <= 1
LEnemyInView.z >0

以下为所有代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Vector3 Vertical = new Vector3(0, 100, 0);//垂直向上的向量
Vector3 EnemytoMe = MyselfPosition - thisEnemyPosition;//Enemy和自机连线,指向自机的向量
Vector3 LHorizontal = Vector3.Cross(Vertical, EnemytoMe);// 垂直于Vc与Vertical向量所组成的面的,且指向<-左侧的小向量<- Enemy
Vector3 RHorizontal = Vector3.Cross(EnemytoMe, Vertical);// 垂直于Vc与Vertical向量所组成的面的,且指向->右侧的小向量Enemy ->

//此时RHorizontal,LHorizontal的长度巨几把长,需要下面操作标准化为1/2Enemy宽度
float standaedization = (float)thisEnemyWidth / Vector3.Distance(thisEnemyPosition, RHorizontal);//计算需要缩小的比例
RHorizontal *= standaedization;//应用缩小比例,标准化完成
LHorizontal *= standaedization;//应用缩小比例,标准化完成
Vector3 LMetoEnemy = LHorizontal - EnemytoMe;//自机与左侧边界连线Me<- Enemy
Vector3 RMetoEnemy = RHorizontal - EnemytoMe;//自机与右侧边界连线Enemy ->Me
Vector3 L0toEnemy = LHorizontal + thisEnemyPosition;// Enemy左侧绝对坐标
Vector3 R0toEnemy = RHorizontal + thisEnemyPosition;// Enemy右侧绝对坐标
float LMetoEnemyDist = Vector3.Distance(MyselfPosition, L0toEnemy);
float RMetoEnemyDist = Vector3.Distance(MyselfPosition, R0toEnemy);
Vector3 LEnemyInView = agentCam.WorldToViewportPoint(L0toEnemy);//Enemy左侧于视角中位置
Vector3 REnemyInView = agentCam.WorldToViewportPoint(R0toEnemy);//Enemy右侧于视角中位置

//Debug连线,颜色遵循飞机航行灯基本使用规则,左红右绿尾翼白。
//Debug.DrawRay(thisEnemyPosition, EnemytoMe, Color.white);//Enemy和自机连线,指向自机的向量
//Debug.DrawRay(thisEnemyPosition, Vertical, Color.white);//垂直向上的向量
//Debug.DrawRay(thisEnemyPosition, LHorizontal, Color.red);// 垂直于Vc与Vertical向量所组成的面的,且指向<-左侧的小向量<- Enemy
//Debug.DrawRay(thisEnemyPosition, RHorizontal, Color.green);// 垂直于Vc与Vertical向量所组成的面的,且指向->右侧的小向量Enemy ->
//Debug.DrawRay(MyselfPosition, LMetoEnemy, Color.red);//自机与左侧边界连线<- Enemy
//Debug.DrawRay(MyselfPosition, RMetoEnemy, Color.green);//自机与右侧边界连线Enemy ->
//Debug.Log("EnemyObj" + EnemyIndex + "Position:" + thisEnemyPosition);

//左侧于可见范围内--<--<--<--<--<--<--<--<--<--<--<--<--<--<
if (LEnemyInView.x >= (thisEnemyWidth - attentionRange / 2) && LEnemyInView.x <= (thisEnemyWidth + attentionRange / 2) && LEnemyInView.z >0)
{
//...
}
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus