编程
Fundamentals
Setting Up Development Environment
UnigineScript
High-Level Systems
C++
C#
UUSL (Unified UNIGINE Shader Language)
File Formats
Rebuilding the Engine and Tools
GUI
Double Precision Coordinates
应用程序接口
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
Rendering-Related Classes

相交(Intersections)

Unigine使用不同方法检测相交。 相交是指定义区域(或线)和对象存在通用点。 本文介绍了不同类型的相交以及它们的用法。

如此一来,便存在3种主要类型的相交:

Shape类和Object类都拥有它们自己的getIntersection()函数。 该函数被用来检测与对象的特定形状或对象的特定表面的相交。

Object.getIntersection()函数之外的所有相交函数都使用的是世界坐标。

世界的相交(World Intersection)

通过使用不同的engine.world函数就能查找世界的相交。 您能查找与指定包围体的边界相交的对象和节点,或是查找对象与不可见轨迹线的首个相交。 存在3组世界相交函数:

与节点(Nodes)相交

要想查找节点与指定包围体的边界的相交,须使用这2个函数:

上图展示了engine.world.getIntersection()函数如何检测与BoundBox包围体的边界相交的节点。

这些函数会将找到的节点的数量作为整数值返回,并将数据保存进您能将函数作为参数传递的ret[]数组。

用法举例

下面的例子向您展示了如何通过engine.world.getIntersectionNodes()函数来获取相交节点。 这里假设您已经拥有了包含节点的虚拟世界,也已经使用了具有指定大小的BoundBox实例。 这段代码取自world(世界)脚本的update()方法。 在本例中,函数会检查指定BoundBox对象内部是否存在具有任意类型的节点。 其执行序列如下:

  1. 定义一个存放输出值的数组和一个BoundBox实例。
  2. 检查是否存在与节点的相交。 engine.world.getIntersectionNodes()函数返回一整数值,也就是:找到的节点的数量。
  3. 在本例中,当有某个节点与BoundBox相交时,控制台就会显示与这个节点相关的信息。 如果不存在交叉节点,那控制台就会显示另一条消息。
源代码 (UnigineScript)
/* ..。 */
// 这里假设您在自己的代码中使用了这些变量:
//  一个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.getIntersection()函数如何检测与BoundBox包围体的边界相交的对象。

所有这些函数会将找到的对象的数量作为整数值返回,并将数据保存进您能将函数作为参数传递的ret[]数组。 您可以传递相交线的起始点(vec3 p0)和结束点(vec3 p1)来获取对象与线的相交,或是传递variable vBoundBoxBoundFrustumBoundSphere)来获取对象与包围体的相交。

用法举例

下面的例子向您展示了如何通过engine.world.getIntersectionObjects()函数来获取交叉对象。 这里假设您已经拥有了包含对象的虚拟世界。 这段代码取自world(世界)脚本的update()方法。 在本例中,我们指定了这样一条线,它从摄像机的一点(vec3 p0)出发,到光标指针的一点(vec3 p1)结束。 其执行序列如下:

  1. 定义一个存放输出值的数组。 此外,通过路径下文件core/scripts/utils.h中的Unigine::getPlayerMouseDirection()函数定义并初始化两个点(p0和p1)。
  2. 检查是否存在与对象的相交。 engine.world.getIntersectionObjects()函数返回一整数值,也就是:找到的节点的数量。
  3. 在本例中,当有某个对象与轨迹线相交时,控制台就会显示与这个对象相关的信息。
源代码 (UnigineScript)
#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()函数被用来查找与轨迹线相交的那个最近的交叉对象。 您应指定线的起始点和结束点,这样函数才能在该条线上检测是否存在任意对象。

上图展示了engine.world.getIntersection()函数如何检测与线相交的对象。

该函数会检测与网格(mesh)对象的,与地形(terrain)对象的表面(多边形)的相交。 不过,检测与表面的相交是有一些条件的:

  1. per-surface Intersection(每个表面相交)标记选项须是启用的。
    注意
    您可通过Object.setIntersection()函数将该标记选项设置给对象的表面。
  2. Properties(属性)窗口中的属性的Intersection(相交)选项须是启用的。
    注意
    您可通过Property.setIntersection()函数启用该属性。
  3. 表面须是启用的。
  4. 表面须分配有材质。
  5. 表面须分配有属性。

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)结束。 其执行序列如下:

  1. 通过路径下文件core/scripts/utils.h中的Unigine::getPlayerMouseDirection()函数定义并初始化两个点(p0和p1)。
  2. 创建一个WorldIntersection类的实例来获取相交信息。
  3. 检查是否存在与对象的相交。 当对象与轨迹线相交时,engine.world.getIntersection()函数便会返回一个交叉对象。
  4. 在本例中,当有某个对象与轨迹线相交时,交叉对象的所有表面都会更改它们各自的材质参数。 WorldIntersection类的实例会获取相交点坐标,表面的索引,还有交叉三角形的索引。 您能通过函数getIndex()getPoint()getSurface()来获取所有这些字段(fields)。
源代码 (UnigineScript)
#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相交函数会是获取相交的最好方法。

上图展示了engine.physics.getIntersection()函数如何检测与线相交的形状。

有2个engine.physics函数可用来查找物理相交:

这2个函数会执行从起始点p0到结束点p1的追踪,继而来查找位于线上的碰撞对象(或形状)。 它们使用的是世界空间坐标。

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)结束。 其执行序列如下:

  1. 通过路径下文件core/scripts/utils.h中的Unigine::getPlayerMouseDirection()函数定义并初始化两个点(p0和p1)。
  2. 创建一个PhysicsIntersection类的实例来获取相交信息。
  3. 检查是否存在与带有形状或碰撞对象的对象的相交。 当对象与轨迹线相交时,engine.physics.getIntersection()函数便会返回一个交叉对象。
  4. 在本例中,当有某个对象与轨迹线相交时,交叉对象的所有表面都会更改它们各自的材质参数。 如果对象具有形状,那该形状的信息就会被显示在控制台中。 PhysicsIntersection类的实例会获取相交点坐标,表面的索引,还有Shape类的对象。 您能通过函数getShape()getPoint()getSurface()来获取所有这些字段(fields)
源代码 (UnigineScript)
#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),并检查障碍物是否出现在其中。

上图展示了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)结束。 其执行序列如下:

  1. 通过路径下文件core/scripts/utils.h中的Unigine::getPlayerMouseDirection()函数定义并初始化两个点(p0和p1) 。
  2. 创建一个GameIntersection类的实例来获取相交点坐标。
  3. 检查是否存在与障碍物的相交。 当有某个障碍物出现在缸体(cylinder)区域中时,engine.game.getIntersection()函数便会返回一个交叉障碍物。
  4. 在那之后,GameIntersection实例会获取距离最近的相交点,而您也就能通过getPoint()函数来获取该点了。
源代码 (UnigineScript)
#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()));
}
/* ... */
最新更新: 2017-07-03