相交(Intersections)
Unigine使用不同方法检测相交。 相交是指定义区域(或线)和对象存在通用点。 本文介绍了不同类型的相交以及它们的用法。
如此一来,便存在3种主要类型的相交:
- 世界的相交(World intersection) - 指与对象(objects)和节点(nodes)的相交。 通过engine.world函数执行此种相交的搜索。
- 物理的相交(Physics intersection) - 指与形状(shapes)和碰撞对象(collision objects)的相交。 通过engine.physics函数执行此种相交的搜索。
- 游戏的相交(Game intersection) - 指与障碍物(obstacles)的相交。 通过engine.game函数执行此种相交的搜索。
Shape类和Object类都拥有它们自己的getIntersection()函数。 该函数被用来检测与对象的特定形状或对象的特定表面的相交。
除Object.getIntersection()函数之外的所有相交函数都使用的是世界坐标。
世界的相交(World Intersection)
通过使用不同的engine.world函数就能查找世界的相交。 您能查找与指定包围体的边界相交的对象和节点,或是查找对象与不可见轨迹线的首个相交。 存在3组世界相交函数:
- 查找节点的函数,这里的节点指包围体内部的。
- 查找对象的函数, 这里的对象指包围体内部的,或是与轨迹线相交的。
- 查找首个相交对象的函数, 这里的相交对象指与轨迹线相交所得的。
与节点(Nodes)相交
要想查找节点与指定包围体的边界的相交,须使用这2个函数:
- engine.world.getIntersectionNodeVariables(),该函数用来查找与指定包围体的边界相交的所有节点(或指定类型的节点),这里的包围体指:BoundBox,BoundFrustum和BoundSphere。 此函数会查找已设置了用户变量的节点。
- engine.world.getIntersectionNodes(),该函数用来查找给定包围体内部的所有节点(或指定类型的节点),这里的包围体指:BoundBox,BoundFrustum和BoundSphere。
这些函数会将找到的节点的数量作为整数值返回,并将数据保存进您能将函数作为参数传递的ret[]数组。
用法举例
下面的例子向您展示了如何通过engine.world.getIntersectionNodes()函数来获取相交节点。 这里假设您已经拥有了包含节点的虚拟世界,也已经使用了具有指定大小的BoundBox实例。 这段代码取自world(世界)脚本的update()方法。 在本例中,函数会检查指定BoundBox对象内部是否存在具有任意类型的节点。 其执行序列如下:
- 定义一个存放输出值的数组和一个BoundBox实例。
- 检查是否存在与节点的相交。 engine.world.getIntersectionNodes()函数返回一整数值,也就是:找到的节点的数量。
- 在本例中,当有某个节点与BoundBox相交时,控制台就会显示与这个节点相关的信息。 如果不存在交叉节点,那控制台就会显示另一条消息。
/* ..。 */
// 这里假设您在自己的代码中使用了这些变量:
// 一个BoundBox实例
BoundBox boundBox;
// 一个存放结果的数组
int resultArray[0];
/* ..。 */
/* 这部分来自update()方法 */
// 检查BoundBox内部是否存在任何节点
int result = engine.world.getIntersectionNodes(boundBox, -1, resultArray);
// 如果存在相交,则执行下述循环:
if(result != 0)
{
// 获取数组的大小并执行一个for循环
forloop(int i=0; resultArray.size())
{
// 从数组获取一个Node,并在控制台中显示其名称和类型
Node node = resultArray[i];
log.message("node %i is : %s %i\n", i, node.getName(), node.getType() );
}
}
else
{
log.message("sorry, but your intersection is in another castle!\n");
}
/* ..。 */
与对象(Objects)的相交
engine.world类函数使用2个重载函数来获取带/不带用户数据的对象。 相交由表面(多边形)执行:
- engine.world.getIntersectionObjectVariables(variable v, int ret = [])
- engine.world.getIntersectionObjectVariables(vec3 p0, vec3 p1, int ret = [])
- engine.world.getIntersectionObjects(variable v, int ret = [])
- engine.world.getIntersectionObjects(vec3 p0, vec3 p1, int ret = [])
所有这些函数会将找到的对象的数量作为整数值返回,并将数据保存进您能将函数作为参数传递的ret[]数组。 您可以传递相交线的起始点(vec3 p0)和结束点(vec3 p1)来获取对象与线的相交,或是传递variable v(BoundBox,BoundFrustum和BoundSphere)来获取对象与包围体的相交。
用法举例
下面的例子向您展示了如何通过engine.world.getIntersectionObjects()函数来获取交叉对象。 这里假设您已经拥有了包含对象的虚拟世界。 这段代码取自world(世界)脚本的update()方法。 在本例中,我们指定了这样一条线,它从摄像机的一点(vec3 p0)出发,到光标指针的一点(vec3 p1)结束。 其执行序列如下:
- 定义一个存放输出值的数组。 此外,通过路径下文件core/scripts/utils.h中的Unigine::getPlayerMouseDirection()函数定义并初始化两个点(p0和p1)。
- 检查是否存在与对象的相交。 engine.world.getIntersectionObjects()函数返回一整数值,也就是:找到的节点的数量。
- 在本例中,当有某个对象与轨迹线相交时,控制台就会显示与这个对象相关的信息。
#include <core/scripts/utils.h>
/* ..。 */
// 这里假设您在自己的代码中使用了该变量:
// 一个存放结果的数组
int resultArray[0];
/* ..。 */
// 定义2个vec3类型坐标
vec3 p0,p1;
// 获取从摄像机(p0)到光标指针(p1)的鼠标方向
Unigine::getPlayerMouseDirection(p0,p1);
// 检查BoundBox内部是否存在任何节点
int result = engine.world.getIntersectionObjects(p0, p1, resultArray);
// 如果存在相交,则执行下述循环:
if(result != 0)
{
// 获取数组的大小
// 执行从0到数组的大小为止的一个for循环
// 来显示有关所有对象的信息
forloop(int i=0; resultArray.size())
{
// 从数组获取一个Ojbect,并在控制台中显示其材质名称和自身类型
Object object = resultArray[i];
log.message("object %i is : %s %i\n", i, object.getMaterialName(0), object.getType() );
}
}
/* ..。 */
首个相交对象
engine.world.getIntersection()函数被用来查找与轨迹线相交的那个最近的交叉对象。 您应指定线的起始点和结束点,这样函数才能在该条线上检测是否存在任意对象。
该函数会检测与网格(mesh)对象的,与地形(terrain)对象的表面(多边形)的相交。 不过,检测与表面的相交是有一些条件的:
-
per-surface Intersection(每个表面相交)标记选项须是启用的。
您可通过Object.setIntersection()函数将该标记选项设置给对象的表面。
-
Properties(属性)窗口中的属性的Intersection(相交)选项须是启用的。
您可通过Property.setIntersection()函数启用该属性。
- 表面须是启用的。
- 表面须分配有材质。
- 表面须分配有属性。
engine.world.getIntersection()函数会被重载并接收4个或5个参数:
- vec3 p0 - 指轨迹线的起始点坐标。
- vec3 p1 - 指轨迹线的结束点坐标。
- int mask - 指相交掩码。 使用相交掩码则只能查找带有指定相交掩码的对象。
- int exclude[] - 指要排除的对象的ID列表。
-
variable v - 指函数所返回的那个距起始点(p0)最近的交叉对象。 有关相交的信息将在您能将函数作为参数传递的变量中给出:
- WorldIntersection intersection - 指WorldIntersection类的实例。 通过使用该类,您就能获取相交点(坐标),对象的交叉三角形的索引,还有交叉表面的索引。
- WorldIntersectionNormal normal - 指WorldIntersectionNormal类的实例。 通过使用该类,您则只能获取相交点的法线。
- WorldIntersectionTexCoord texcoord - 指WorldIntersectionTexCoord类的实例。 通过使用该类,您则只能获取相交点的纹理坐标。
在不执行就近相交点搜索的情况下传递NULL而不是相交查询对象则可执行快速的相交算法。
因此,要想排除一些对象,您应使用如下方法:
- 使用相交掩码。 这种情况下,只有对象匹配相交掩码时才能找到相交。
- 指定要排除的对象的ID列表,并将函数作为参数传递。
用法举例
下面的例子向您展示了如何通过WorldIntersection类来获取相交信息。 这里假设您已经拥有了包含对象的虚拟世界。 这段代码取自world(世界)脚本的update()方法。 在本例中,我们指定了这样一条线,它从摄像机的一点(vec3 p0)出发,到光标指针的一点(vec3 p1)结束。 其执行序列如下:
- 通过路径下文件core/scripts/utils.h中的Unigine::getPlayerMouseDirection()函数定义并初始化两个点(p0和p1)。
- 创建一个WorldIntersection类的实例来获取相交信息。
- 检查是否存在与对象的相交。 当对象与轨迹线相交时,engine.world.getIntersection()函数便会返回一个交叉对象。
- 在本例中,当有某个对象与轨迹线相交时,交叉对象的所有表面都会更改它们各自的材质参数。 WorldIntersection类的实例会获取相交点坐标,表面的索引,还有交叉三角形的索引。 您能通过函数getIndex(),getPoint()和getSurface()来获取所有这些字段(fields)。
#include <core/scripts/utils.h>
/* ... */
// 定义2个vec3类型坐标
vec3 p0,p1;
// 获取从摄像机(p0)到光标指针(p1)的鼠标方向
Unigine::getPlayerMouseDirection(p0,p1);
// 创建一个WorldIntersection类的实例来获取结果
WorldIntersection intersection = new WorldIntersection();
// 为相交对象创建一个实例
Object object = engine.world.getIntersection(p0,p1,1,intersection);
// 如果存在相交,则更改参数和对象的材质纹理
if(object != NULL)
{
forloop(int i=0; object.getNumSurfaces())
{
object.setMaterialParameter("diffuse_color", vec4(1.0f, 0.0f, 0.0f, 1.0f),i);
object.setMaterialTexture("diffuse","", i);
// 在控制台中显示相交的详细信息
log.message("point: %s index: %i surface: %i \n", typeinfo(intersection.getPoint()), intersection.getIndex(), intersection.getSurface());
}
}
/* ..。 */
物理的相交(Physics Intersection)
物理相交函数用来检测与实体(bodies)的形状的相交。 如果对象没有body,那该函数就会检测与使用了相交标记选项的对象的表面(多边形)的相交。 当您需要查找与对象的形状(而不是多边形)的相交时,engine.physics相交函数会是获取相交的最好方法。
有2个engine.physics函数可用来查找物理相交:
- engine.physics.getIntersection (vec3 p0, vec3 p1, int mask, variable v)
- engine.physics.getIntersection (vec3 p0, vec3 p1, int mask, int exclude[] = [], variable v)
engine.physics.getIntersection()函数会被重载并接收4个或5个参数:
- vec3 p0 - 指轨迹线的起始点坐标。
- vec3 p1 - 指轨迹线的结束点坐标。
- int mask - 指相交掩码。 使用相交掩码则只能查找带有指定相交掩码的对象。
- int exclude[] - 指要排除的对象的ID列表,所有这些对象都将被忽略。
-
variable v - 指函数所返回的那个距起始点(p0)最近的交叉对象。 有关相交的信息将在您能将函数作为参数传递的变量中给出:
- PhysicsIntersection intersection - 指PhysicsIntersection类的实例。 通过使用该类,您就能获取相交点(坐标),交叉表面的索引,还有相交的形状(Shape)。
- WorldIntersectionNormal normal - 指PhysicsIntersectionNormal类的实例。 通过使用该类,您则只能获取相交点的法线。
在不执行就近相交点搜索的情况下传递NULL而不是相交查询对象则可执行快速的相交算法。
因此,要想排除一些障碍物,您应使用如下方法:
- 使用相交掩码。 这种情况下,只有对象匹配相交掩码时才能找到相交,否则对象会被忽略。
- 指定要排除的对象的列表,并将函数作为参数传递。
用法举例
下面的例子向您展示了如何通过PhysicsIntersection类来获取相交信息。 在本例中,我们指定了这样一条线,它从摄像机的一点(vec3 p0)出发,到光标指针的一点(vec3 p1)结束。 其执行序列如下:
- 通过路径下文件core/scripts/utils.h中的Unigine::getPlayerMouseDirection()函数定义并初始化两个点(p0和p1)。
- 创建一个PhysicsIntersection类的实例来获取相交信息。
- 检查是否存在与带有形状或碰撞对象的对象的相交。 当对象与轨迹线相交时,engine.physics.getIntersection()函数便会返回一个交叉对象。
- 在本例中,当有某个对象与轨迹线相交时,交叉对象的所有表面都会更改它们各自的材质参数。 如果对象具有形状,那该形状的信息就会被显示在控制台中。 PhysicsIntersection类的实例会获取相交点坐标,表面的索引,还有Shape类的对象。 您能通过函数getShape(),getPoint()和getSurface()来获取所有这些字段(fields)
#include <core/scripts/utils.h>
/* ... */
// 定义2个vec3类型坐标
vec3 p0,p1;
// 获取从摄像机(p0)到光标指针(p1)的鼠标方向
Unigine::getPlayerMouseDirection(p0,p1);
// 创建一个PhysicsIntersection对象的实例来获取结果
PhysicsIntersection intersection = new PhysicsIntersection();
// 为交叉对象创建一个实例并检测相交
Object object = engine.physics.getIntersection(p0,p1,1,intersection);
// 如果存在相交,则更改参数
// 以及更改对象的材质纹理
if(object != NULL)
{
forloop(int i=0; object.getNumSurfaces())
{
object.setMaterialParameter("diffuse_color", vec4(1.0f, 0.0f, 0.0f, 1.0f),i);
object.setMaterialTexture("diffuse","", i);
}
// 如果交叉对象具有形状,则显示有关其相交的信息
Shape shape = intersection.getShape();
if (shape != NULL)
{
log.message("physics intersection info: point: %s shape: %s surface: %i \n", typeinfo(intersection.getPoint()), typeinfo(shape.getType()), intersection.getSurface());
}
}
/* ..。 */
游戏的相交(Game Intersection)
您可通过engine.game.getIntersection()函数来检测与障碍物的相交。 该函数用来在两点间创建一个不可见的缸体(cylinder),并检查障碍物是否出现在其中。
函数会返回距起始点(p0)最近的那个交叉障碍物。 有关相交的信息将在您能将函数作为参数传递的GameIntersection类的实例中给出。 GameIntersection类的实例会保存距起始点(p0)最近的那个相交点。
engine.game.getIntersection()函数会被重载并接收5个或6个参数:
- vec3 p0 - 指起始点坐标。
- vec3 p1 - 指结束点坐标。
- float radius - 指结束点坐标。
- int mask - 指障碍物的相交掩码。 使用相交掩码则只能查找带有指定相交掩码的对象。
- int exclude[] - 指要排除的障碍物的列表。
-
GameIntersection intersection - 指函数所返回的那个距起始点(p0)最近的交叉障碍物。 有关相交的信息将在您能将函数作为参数传递的GameIntersection类的实例中给出。
在不执行就近相交点搜索的情况下传递NULL而不是相交查询对象则可执行快速的相交算法。
因此,要排除一些障碍物,您应使用如下方法:
- 使用 障碍物相交掩码。 这种情况下,只有对象匹配相交掩码时才能找到相交,否则对象会被忽略。
- 指定要排除的障碍物的列表,并将函数作为参数传递。
用法举例
下面的例子向您展示了如何获取缸体(cylinder)的两点之间与障碍物的相交点(vec3)。 在本例中,我们指定这样一个缸体(cylinder),它具有指定半径,从摄像机的一点(vec3 p0)出发,到鼠标指针的一点(vec3 p1)结束。 其执行序列如下:
- 通过路径下文件core/scripts/utils.h中的Unigine::getPlayerMouseDirection()函数定义并初始化两个点(p0和p1) 。
- 创建一个GameIntersection类的实例来获取相交点坐标。
- 检查是否存在与障碍物的相交。 当有某个障碍物出现在缸体(cylinder)区域中时,engine.game.getIntersection()函数便会返回一个交叉障碍物。
- 在那之后,GameIntersection实例会获取距离最近的相交点,而您也就能通过getPoint()函数来获取该点了。
#include <core/scripts/utils.h>
/* ..。 */
// 定义2个vec3类型坐标
vec3 p0,p1;
// 获取从摄像机(p0)到光标指针(p1)的鼠标方向
Unigine::getPlayerMouseDirection(p0,p1);
// 创建一个GameIntersection类的实例
GameIntersection intersection = new GameIntersection();
// 尝试获取与障碍物的相交
// 缸体(cylinder)的半径为0.1f,相交掩码等于1
Obstacle obstacle = engine.game.getIntersection(p0,p1,0.1f, 1, intersection);
// 检查是否存在鼠标方向与任意障碍物的相交
if(obstacle !=NULL)
{
// 在控制台中显示相交的坐标
log.message("The intersection with obstacle was here: %s\n", typeinfo(intersection.getPoint()));
}
/* ... */