zoukankan      html  css  js  c++  java
  • [翻译]XNA 3.0 Game Programming Recipes之twentyfive

    PS:自己翻译的,转载请著明出处格
                                                 4-18 使用Pre-三角形检查,检测射线模式的碰撞
    问题
              你想检测3D射线是否与模型碰撞。这是必须的,如果你想执行一个碰撞检测在最好的详细程度。它可以被用来作为4-11节的一个扩展去检测在高级别的细节中,是否有一颗子弹已经击中了一个物体。如下一节所显示的那样,这是可能的,例如,同样可以用来检查指针是否是在当前的模型上。
              更多的,它可以被用来作为极细小的检查为模型到模型的碰撞,由于一个三角形的每个边对应一个射线,可以用来测试与另一个模型的碰撞。
              这一节将处理很复杂的情况,允许模型分开的部分转化成单独的,使这节适合模型的活动。这些变化将影响模型顶点的最后的位置。例如,如果一个人移动他的胳膊,胳膊最终的顶点位置别改变了。这节将这些变换考虑在内。
              或者,您想要一个速成课在三维矢量数学上。
    解决方案
              这节使用一个自定义混合管道内容创建在4-13和4-14节中,因为它保存一个三角形数组对象在每一个模型的ModelMesh的Tag属性里。每个三角形对象都有三个Vector3定义一个三角形的ModelMesh
              有利于使每个ModelMesh都有自己的三角形位置的数组,你可以转变他们用ModelMesh的Bone转化。无论如何改变,你目前设定在模型的那部分上,你可以找到三角形的位置在绝对的3D空间里靠使用绝对的ModelMesh转换矩阵来转化他们。这是必须的,由于在大多数情况下,3D射线会被定义在绝对的3D空间里,这样你需要知道绝对顶点的3D位置,如果你想做任何他们之间的比较形式。
              一旦你知道模型的每一个三角形绝对3D位置,这个问题迫使Ray-Triangle检查为每模型的一个三角形。
    它是如何工作的
              由于必须的4-15节内容管道使用一个自定义的类(三角形),很容易的方法是添加内容管道到你的解决方案。右击你的解决方案添加Add-Existing Project.浏览到内容目录包含到你内容管道工程中.csproj文件,选择这个文件。
              下一步仍然需要允许你的主要XNA工程访问内容管道工程。参看3-9节更多详细步骤1-5步。最后的两步允许你的XNA工程序列化三角形对象,4-15有详细说明。
              6。添加新创建的组件到你的主工程中。
              7。选择新创建的处理器去处理一个资源。
              8。设置项目的属性。
              9。在你的主XNA工程中,添加一个引用到你内容管道工程中。
              10。添加你内容管道命名空间到主XNA工程的using区块中
              请务必不要忘记第7步,选择ModelMeshTriangleProcessor去处理你的导入模型。这个处理器将会保存一个三角形对象数组在模型的每一个ModelMesh的Tag属性里。
    Transformations
              现在你有权使用所有模型顶点位置,你可以定义一个方法检查Rey-Model碰撞:
     1 private bool ModelRayCollision(Model model,Matrix modelWorld,Ray ray)
     2 {
     3       Matrix[] modelTransforms=new Matrix[model.Bones.Count];
     4       model.CopyAbsoluteBoneTransformsTo(modelTransforms);
     5       bool collision=false;
     6       foreach(ModelMesh mesh in model.Meshes)
     7       {
     8           Matrix absTransform=modelTransforms[mesh.ParentBone.Index]*modelWorld;
     9           Trianle[] meshTriangles=(Triangle[])mesh.Tag;
    10           foreach(Triangle tri in meshTriangles)
    11           {
    12               Vector3 transP0=Vector3.Transform(tri.P0,absTransform);
    13               Vector3 transP1=Vector3.Transform(tri.P1,absTransform);
    14               Vector3 transP2=Vector3.Transform(tri.P2,absTransform);
    15           }
    16       }
    17      return collision;
    18 }
             这个概念很简单:你开始设置collision=false.模型的每一部分,你会翻阅它的三角形所有的对象,包括三角形的位置。每一个三角形,检查三角形是否与射线碰撞。如果碰撞,返回true.
             这时候应该提醒你,保存在三角形对象内的位置是于ModelMesh的初始状态相关的。意思是他们必须首先改变用ModelMesh的绝对变换矩阵去获得他们相对与模型初始的位置。接下来,他们需要被转换靠模型的世界矩阵来获得他们相对于3D世界的位置(换句话说,就是绝对位置)。
             第一种转变看起来象一种负担,但事实是它提供了一个巨大的优势:如果你旋转模型的一个ModelMesh(例如,人的胳膊),这个旋转这里需要被考虑。在你改变了胳膊顶点的位置靠绝对矩阵变换之后,你得到她们的相对于模型的初始位置。
             在前面的代码,你首先计算绝对变换矩阵为模型的所有的Bones。接下来,你用世界矩阵结合绝对矩阵为了当前的Bone。使用结果矩阵去转变每一个三角形,你提供ModelMesh到绝对3D位置。
             最后,为每一个ModelMesh的三角形,你最终确定3D空间的位置,采取任何动作在模型上和模型的位置需要被考虑!That's how far the previous code goes.
    Ray-Triangle Collision
             一旦你有每个三角形的绝对位置,检查三角形和射线是否碰撞。
             如果(Ray-Triangle碰撞)被分为两个部分。首先你要找到射线和三角形平面碰撞的点。由于三角形和交叉点在同样的平面内,这个问题变成了2D问题,如图4-25显示的那样,接下来,检查碰撞点是否在三角形内。

             你将编写两个方法处理两个部分的问题。第一种方法,RayPlaneIntersection,接收一个平面和一条射线,返回在射线上碰撞的点的距离。从这个距离你很容易的计算射线和三角形之间的交叉点。
             第二种方法,PointInsideTriangle,接收三角形的三个坐标,和额外的坐标点(交叉点)。这个方法将返回点是否在三角形内。
             如果是这种情况,你必须检测射线和模型之间的碰撞。这个代码应该取代两行伪代码:
    1 Plane trianglePlane=new Plane(transP0,transP1,transP2);
    2 float distanceOnRay=RayPlaneIntersection(ray,trianglePlane);
    3 Vector3 intersectionPoint=ray.Position+distanceOnRay*ray.Direction;
    4 if(PointInsideTriangle(transP0,transP1,transP2,intersectionPoint))
    5    return true;
             首先你建立一个三角形平面,基于三角形的三个角点。你传递这个平面和射线到RayPlaneIntersection方法,接收在射线上的交叉点的位置,射线用来计算交叉点的位置。最后,检查交叉点是否在三角形的内部。
    注意:欲了解更多的射线对象的例子,参看4-11和4-19节
    在射线和平面之间找一个碰撞点
             你非常幸运,第一个方法相当精确的。不要担心的太多;我已经选择了一个基于这个向量的方法,如图4-26。

             假定一个射线和一个平面,这个方法找到从ray.Direcion点到collisionPoint点的距离,基于图4-26所显示的方法。注意所有变量的长度在这个方法中的在图象的左和右显示出来了!
    1 private float RayPlaneIntersectoin(Ray ray,Plane plane)
    2 {
    3     float rayPointDist=-plane.DotNormal(ray.Position);
    4     float rayPointToPlaneDist=rayPointDist-plane.D;
    5     float directoinProjectedLength=Vector3.Dot(pane.Normal,ray.Direction);
    6     float factor=rayPointToPlaneDist/directionProjectionLength;
    7     return factor;
    8 }




  • 相关阅读:
    Java学习二十九天
    Java学习二十八天
    47. Permutations II 全排列可重复版本
    46. Permutations 全排列,无重复
    subset ii 子集 有重复元素
    339. Nested List Weight Sum 339.嵌套列表权重总和
    251. Flatten 2D Vector 平铺二维矩阵
    217. Contains Duplicate数组重复元素
    209. Minimum Size Subarray Sum 结果大于等于目标的最小长度数组
    438. Find All Anagrams in a String 查找字符串中的所有Anagrams
  • 原文地址:https://www.cnblogs.com/315358525/p/1536909.html
Copyright © 2011-2022 走看看