// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "std3d.h" #include "nel/3d/ray_mesh.h" #include "nel/misc/vector_2f.h" #include "nel/misc/fast_mem.h" #include "nel/3d/matrix_3x4.h" using namespace NLMISC; using namespace std; namespace NL3D { // *************************************************************************** // The number of byte to process per block const uint NL_BlockByteL1= 4096; // Number of vertices per block to process For vertices mul uint CRayMesh::NumCacheVertex= NL_BlockByteL1 / sizeof(CVector); // *************************************************************************** template static bool getRayIntersectionT(std::vector &vertices, const std::vector &tris, float &dist2D, float &distZ, bool computeDist2D) { uint numTris= tris.size()/3; if(!numTris) return false; // test all tris const TIndex *pTri= &tris[0]; float minSkinDistZ= FLT_MAX; for(uint i=0;i=0; // Line p1-p2. a= -p12.y; b= p12.x; c= (p1.x*a + p1.y*b); allInf= allInf && c<=0; allSup= allSup && c>=0; // Line p2-p0. a= -p20.y; b= p20.x; c= (p2.x*a + p2.y*b); allInf= allInf && c<=0; allSup= allSup && c>=0; // all on same side (don't bother front or backfaces)? if(allInf || allSup) { // => ray intersect. compute the intersection now. // This code is called for a very small subset of faces, hence don't bother optim. CPlane plane; plane.make(p0,p1,p2); // intersect with the ray. Since vertices are in ray basis, the Ray is (Null, K). CVector hit= plane.intersect(CVector::Null, CVector::K); // then dist of Null to the tri is just Z. float distToTri= hit.z; // avoid problems if the plane is // to the ray. take maximum proj dist with the 3 points float minVertDist= min(p0.z, p1.z); minVertDist= min(minVertDist, p2.z); // distToTri cannot be less than minVertDist distToTri= max(minVertDist, distToTri); // NB: it is possible than distToTri<0 (face behind or clipped by camera). clamp then to 0 distToTri= max(distToTri, 0.f); minSkinDistZ= min(minSkinDistZ, distToTri); } } // don't intersect? if(minSkinDistZ==FLT_MAX) { // get the nearest distance to the ray (do the compute only if no IT found at all => optim) const TIndex *pTri= &tris[0]; float minSkinSqrDist2D= FLT_MAX; // only if user want this feature if(computeDist2D) { for(uint i=0;i value between 0 and p01sqdist (if in segment) fSeg= -p0.x*p01.x -p0.y*p01.y; if(fSeg>0 && fSeg0 && fSeg0 && fSeg &vertices, const std::vector &tris, float &dist2D, float &distZ, bool computeDist2D) { return getRayIntersectionT(vertices, tris, dist2D, distZ, computeDist2D); } // *************************************************************************** bool CRayMesh::getRayIntersection(std::vector &vertices, const std::vector &tris, float &dist2D, float &distZ, bool computeDist2D) { return getRayIntersectionT(vertices, tris, dist2D, distZ, computeDist2D); } // *************************************************************************** bool CRayMesh::fastIntersect(const NLMISC::CMatrix &worldMatrix, const NLMISC::CVector &p0, const NLMISC::CVector &dir, float &dist2D, float &distZ, bool computeDist2D) const { if(empty()) return false; // *** Compute toRaySpace matrix // The skinning must be done in final RaySpace. CMatrix toRaySpace; // compute the ray matrix CVector dirn= dir; if(dirn.isNull()) dirn= CVector::K; dirn.normalize(); toRaySpace.setArbitraryRotK(dirn); toRaySpace.setPos(p0); // The skinning must be done in ray space: (RayMat-1)*worldMatrix; toRaySpace.invert(); toRaySpace*= worldMatrix; CMatrix3x4 fastMat; fastMat.set(toRaySpace); // *** Make all points in ray space uint numVerts= Vertices.size(); const CVector *src= &Vertices[0]; // enlarge temp buffer static std::vector meshInRaySpace; if(Vertices.size()>meshInRaySpace.size()) meshInRaySpace.resize(Vertices.size()); CVector *dst= &meshInRaySpace[0]; // Then do the skin for(;numVerts>0;) { // number of vertices to process for this block. uint nBlockInf= min(NumCacheVertex, numVerts); // next block. numVerts-= nBlockInf; // cache the data in L1 cache. CFastMem::precache(src, nBlockInf * sizeof(CVector)); // for all InfluencedVertices only. for(;nBlockInf>0;nBlockInf--, src++, dst++) { fastMat.mulSetPoint( *src, *dst ); } } // *** and get ray intersection return getRayIntersection(meshInRaySpace, Triangles, dist2D, distZ, computeDist2D); } } // NL3D