⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sceneobject.cc

📁 五行MMORPG引擎系统V1.0
💻 CC
📖 第 1 页 / 共 5 页
字号:
//           - The optimal grid size isn't necessarily what we have set here. possibly
//             a resolution of 16 meters would give better results
//           - The line rasterizer is pretty lame.  Unfortunately we can't use a
//             simple bres. here, since we need to check every grid element that the line
//             passes through, which bres does _not_ do for us.  Possibly there's a
//             rasterizer for anti-aliased lines that will serve better than what
//             we have below.
//
bool Container::castRay(const Point3F &start, const Point3F &end, U32 mask, RayInfo* info)
{
   PROFILE_START(ContainerCastRay);
   F32 currentT = 2.0;
   smCurrSeqKey++;

   SceneObjectRef* chain = mOverflowBin.nextInBin;
   while (chain)
   {
      SceneObject* ptr = chain->object;
      if (ptr->getContainerSeqKey() != smCurrSeqKey)
      {
         ptr->setContainerSeqKey(smCurrSeqKey);

         // In the overflow bin, the world box is always going to intersect the line,
         //  so we can omit that test...
         if ((ptr->getType() & mask) != 0 &&
             ptr->isCollisionEnabled() == true)
         {
            Point3F xformedStart, xformedEnd;
            ptr->mWorldToObj.mulP(start, &xformedStart);
            ptr->mWorldToObj.mulP(end,   &xformedEnd);
            xformedStart.convolveInverse(ptr->mObjScale);
            xformedEnd.convolveInverse(ptr->mObjScale);

            RayInfo ri;
            if (ptr->castRay(xformedStart, xformedEnd, &ri))
            {
               if(ri.t < currentT)
               {
                  *info = ri;
                  info->point.interpolate(start, end, info->t);
                  currentT = ri.t;
               }
            }
         }
      }
      chain = chain->nextInBin;
   }

   // These are just for rasterizing the line against the grid.  We want the x coord
   //  of the start to be <= the x coord of the end
   Point3F normalStart, normalEnd;
   if (start.x <= end.x)
   {
      normalStart = start;
      normalEnd   = end;
   }
   else
   {
      normalStart = end;
      normalEnd   = start;
   }

   // Ok, let's scan the grids.  The simplest way to do this will be to scan across in
   //  x, finding the y range for each affected bin...
   U32 minX, maxX;
   U32 minY, maxY;
//if (normalStart.x == normalEnd.x)
//   Con::printf("X start = %g, end = %g", normalStart.x, normalEnd.x);

   getBinRange(normalStart.x, normalEnd.x, minX, maxX);
   getBinRange(getMin(normalStart.y, normalEnd.y),
               getMax(normalStart.y, normalEnd.y), minY, maxY);

//if (normalStart.x == normalEnd.x && minX != maxX)
//   Con::printf("X min = %d, max = %d", minX, maxX);
//if (normalStart.y == normalEnd.y && minY != maxY)
//   Con::printf("Y min = %d, max = %d", minY, maxY);

   // We'll optimize the case that the line is contained in one bin row or column, which
   //  will be quite a few lines.  No sense doing more work than we have to...
   //
   if ((mFabs(normalStart.x - normalEnd.x) < csmTotalBinSize && minX == maxX) ||
       (mFabs(normalStart.y - normalEnd.y) < csmTotalBinSize && minY == maxY))
   {
      U32 count;
      U32 incX, incY;
      if (minX == maxX)
      {
         count = maxY - minY + 1;
         incX  = 0;
         incY  = 1;
      }
      else
      {
         count = maxX - minX + 1;
         incX  = 1;
         incY  = 0;
      }

      U32 x = minX;
      U32 y = minY;
      for (U32 i = 0; i < count; i++)
      {
         U32 checkX = x % csmNumBins;
         U32 checkY = y % csmNumBins;

         SceneObjectRef* chain = mBinArray[(checkY * csmNumBins) + checkX].nextInBin;
         while (chain)
         {
            SceneObject* ptr = chain->object;
            if (ptr->getContainerSeqKey() != smCurrSeqKey)
            {
               ptr->setContainerSeqKey(smCurrSeqKey);

               if ((ptr->getType() & mask) != 0      &&
                   ptr->isCollisionEnabled() == true)
               {
                  if (ptr->getWorldBox().collideLine(start, end) || chain->object->isGlobalBounds())
                  {
                     Point3F xformedStart, xformedEnd;
                     ptr->mWorldToObj.mulP(start, &xformedStart);
                     ptr->mWorldToObj.mulP(end,   &xformedEnd);
                     xformedStart.convolveInverse(ptr->mObjScale);
                     xformedEnd.convolveInverse(ptr->mObjScale);

                     RayInfo ri;
                     if (ptr->castRay(xformedStart, xformedEnd, &ri))
                     {
                        if(ri.t < currentT)
                        {
                           *info = ri;
                           info->point.interpolate(start, end, info->t);
                           currentT = ri.t;
                        }
                     }
                  }
               }
            }
            chain = chain->nextInBin;
         }

         x += incX;
         y += incY;
      }
   }
   else
   {
      // Oh well, let's earn our keep.  We know that after the above conditional, we're
      //  going to cross at least one boundary, so that simplifies our job...

      F32 currStartX = normalStart.x;

      AssertFatal(currStartX != normalEnd.x, "This is going to cause problems in Container::castRay");
      while (currStartX != normalEnd.x)
      {
         F32 currEndX   = getMin(currStartX + csmTotalBinSize, normalEnd.x);

         F32 currStartT = (currStartX - normalStart.x) / (normalEnd.x - normalStart.x);
         F32 currEndT   = (currEndX   - normalStart.x) / (normalEnd.x - normalStart.x);

         F32 y1 = normalStart.y + (normalEnd.y - normalStart.y) * currStartT;
         F32 y2 = normalStart.y + (normalEnd.y - normalStart.y) * currEndT;

         U32 subMinX, subMaxX;
         getBinRange(currStartX, currEndX, subMinX, subMaxX);

         F32 subStartX = currStartX;
         F32 subEndX   = currStartX;

         if (currStartX < 0.0f)
            subEndX -= mFmod(subEndX, csmBinSize);
         else
            subEndX += (csmBinSize - mFmod(subEndX, csmBinSize));

         for (U32 currXBin = subMinX; currXBin <= subMaxX; currXBin++)
         {
            U32 checkX = currXBin % csmNumBins;

            F32 subStartT = (subStartX - currStartX) / (currEndX - currStartX);
            F32 subEndT   = getMin(F32((subEndX   - currStartX) / (currEndX - currStartX)), 1.f);

            F32 subY1 = y1 + (y2 - y1) * subStartT;
            F32 subY2 = y1 + (y2 - y1) * subEndT;

            U32 newMinY, newMaxY;
            getBinRange(getMin(subY1, subY2), getMax(subY1, subY2), newMinY, newMaxY);

            for (U32 i = newMinY; i <= newMaxY; i++)
            {
               U32 checkY = i % csmNumBins;

               SceneObjectRef* chain = mBinArray[(checkY * csmNumBins) + checkX].nextInBin;
               while (chain)
               {
                  SceneObject* ptr = chain->object;
                  if (ptr->getContainerSeqKey() != smCurrSeqKey)
                  {
                     ptr->setContainerSeqKey(smCurrSeqKey);

                     if ((ptr->getType() & mask) != 0      &&
                         ptr->isCollisionEnabled() == true)
                     {
                        if (ptr->getWorldBox().collideLine(start, end))
                        {
                           Point3F xformedStart, xformedEnd;
                           ptr->mWorldToObj.mulP(start, &xformedStart);
                           ptr->mWorldToObj.mulP(end,   &xformedEnd);
                           xformedStart.convolveInverse(ptr->mObjScale);
                           xformedEnd.convolveInverse(ptr->mObjScale);

                           RayInfo ri;
                           if (ptr->castRay(xformedStart, xformedEnd, &ri))
                           {
                              if(ri.t < currentT)
                              {
                                 *info = ri;
                                 info->point.interpolate(start, end, info->t);
                                 currentT = ri.t;
                              }
                           }
                        }
                     }
                  }
                  chain = chain->nextInBin;
               }
            }

            subStartX = subEndX;
            subEndX   = getMin(subEndX + csmBinSize, currEndX);
         }

         currStartX = currEndX;
      }
   }

   // Bump the normal into worldspace if appropriate.
   if(currentT != 2)
   {
      PlaneF fakePlane;
      fakePlane.x = info->normal.x;
      fakePlane.y = info->normal.y;
      fakePlane.z = info->normal.z;
      fakePlane.d = 0;

      PlaneF result;
      mTransformPlane(info->object->getTransform(), info->object->getScale(), fakePlane, &result);
      info->normal = result;

      PROFILE_END();
      return true;
   }
   else
   {
      // Do nothing and exit...
      PROFILE_END();
      return false;
   }

}

// collide with the objects projected object box
bool Container::collideBox(const Point3F &start, const Point3F &end, U32 mask, RayInfo * info)
{
   F32 currentT = 2;
   for (Link* itr = mStart.next; itr != &mEnd; itr = itr->next)
   {
      SceneObject* ptr = static_cast<SceneObject*>(itr);
      if (ptr->getType() & mask && !ptr->mCollisionCount)
      {
         Point3F xformedStart, xformedEnd;
         ptr->mWorldToObj.mulP(start, &xformedStart);
         ptr->mWorldToObj.mulP(end,   &xformedEnd);
         xformedStart.convolveInverse(ptr->mObjScale);
         xformedEnd.convolveInverse(ptr->mObjScale);

         RayInfo ri;
         if(ptr->collideBox(xformedStart, xformedEnd, &ri))
         {
            if(ri.t < currentT)
            {
               *info = ri;
               info->point.interpolate(start, end, info->t);
               currentT = ri.t;
            }
         }
      }
   }
   return currentT != 2;
}

//----------------------------------------------------------------------------

static void buildCallback(SceneObject* object,void *key)
{
   Container::CallbackInfo* info = reinterpret_cast<Container::CallbackInfo*>(key);
   object->buildPolyList(info->polyList,info->boundingBox,info->boundingSphere);
}


//----------------------------------------------------------------------------

bool Container::buildPolyList(const Box3F& box, U32 mask, AbstractPolyList* polyList,FindCallback callback,void *key)
{
   CallbackInfo info;
   info.boundingBox = box;
   info.polyList = polyList;
   info.key = key;

   // Build bounding sphere
   info.boundingSphere.center = (info.boundingBox.min + info.boundingBox.max) * 0.5;
   VectorF bv = box.max - info.boundingSphere.center;
   info.boundingSphere.radius = bv.len();

   sPolyList = polyList;
   findObjects(box,mask,callback? callback: buildCallback,&info);
   return !polyList->isEmpty();
}


//----------------------------------------------------------------------------

bool Container::buildCollisionList(const Box3F&   box,
                                   const Point3F& start,
                                   const Point3F& end,
                                   const VectorF& velocity,
                                   U32            mask,
                                   CollisionList* collisionList,
                                   FindCallback   callback,
                                   void *         key,
                                   const Box3F*   queryExpansion)
{
   VectorF vector = end - start;
   if (mFabs(vector.x) + mFabs(vector.y) + mFabs(vector.z) == 0)
      return false;
   CallbackInfo info;
   info.key = key;

   // Polylist bounding box & sphere
   info.boundingBox.min = info.boundingBox.max = start;
   info.boundingBox.min.setMin(end);
   info.boundingBox.max.setMax(end);
   info.boundingBox.min += box.min;
   info.boundingBox.max += box.max;
   info.boundingSphere.center = (info.boundingBox.min + info.boundingBox.max) * 0.5;
   VectorF bv = info.boundingBox.max - info.boundingSphere.center;
   info.boundingSphere.radius = bv.len();

   // Box polyhedron edges & planes normals are always the same,
   // just need to fill in the vertices and plane.d
   Point3F* point = &sBoxPolyhedron.pointList[0];
   point[0].x = point[1].x = point[4].x = point[5].x = box.min.x + start.x;
   point[0].y = point[3].y = point[4].y = point[7].y = box.min.y + start.y;
   point[2].x = point[3].x = point[6].x = point[7].x = box.max.x + start.x;
   point[1].y = point[2].y = point[5].y = point[6].y = box.max.y + start.y;
   point[0].z = point[1].z = point[2].z = point[3].z = box.min.z + start.z;
   point[4].z = point[5].z = point[6].z = point[7].z = box.max.z + start.z;

   PlaneF* plane = &sBoxPolyhedron.planeList[0];
   plane[0].d = point[0].x;
   plane[3].d = point[0].y;
   plane[4].d = point[0].z;
   plane[1].d = -point[6].y;
   plane[2].d = -point[6].x;
   plane[5].d = -point[6].z;

   // Extruded
   sExtrudedPolyList.extrude(sBoxPolyhedron,vector);
   sExtrudedPolyList.setVelocity(velocity);
   sExtrudedPolyList.setCollisionList(collisionList);
   if (velocity.isZero())
   {
      sExtrudedPolyList.clearInterestNormal();
   } else
   {
      Point3F normVec = velocity;
      normVec.normalize();
      sExtrudedPolyList.setInterestNormal(normVec);
   }
   info.polyList = &sExtrudedPolyList;

   // Optional expansion of the query box
   Box3F queryBox = info.boundingBox;
   if (queryExpansion)
   {
      queryBox.min += queryExpansion->min;
      queryBox.max += queryExpansion->max;
   }

   // Query main database
   findObjects(queryBox,mask,callback? callback: buildCallback,&info);
   sExtrudedPolyList.adjustCollisionTime();
   return collisionList->count != 0;
}


//----------------------------------------------------------------------------

bool Container::buildCollisionList(const Polyhedron& polyhedron,
                                   const Point3F& start, const Point3F& end,
                                   const VectorF& velocity,
                                   U32 mask, CollisionList* collisionList,
                                   FindCallback callback, void *key)
{
   VectorF vector = end - start;
   if (mFabs(vector.x) + mFabs(vector.y) + mFabs(vector.z) == 0)
      return false;

   CallbackInfo info;
   info.key = key;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -