コード例 #1
0
bool intersectLineSegmentAABB(const float bmin[3],const float bmax[3],const float p1[3],const float dir[3],float &dist,float intersect[3])
{
    bool ret = false;

    if ( dist > RAYAABB_EPSILON )
    {
        ret = intersectRayAABB(bmin,bmax,p1,dir,intersect);
        if ( ret )
        {
            float dx = p1[0]-intersect[0];
            float dy = p1[1]-intersect[1];
            float dz = p1[2]-intersect[2];
            float d = dx*dx+dy*dy+dz*dz;
            if ( d < dist*dist )
            {
                dist = sqrtf(d);
            }
            else
            {
                ret = false;
            }
        }
    }
    return ret;
}
コード例 #2
0
ファイル: Broadphase.cpp プロジェクト: janoldsen/Onager
	bool HGrid::queryRay(const vec3& origin, const vec3& dir, RayQueryResult* hit, float tmax)
	{

		m_tick++;


		struct Cell
		{
			int i, j, k;
			vec3 t;
			vec3 d;
		};


		Cell cells[MAX_LEVELS];

		int iEnd;
		int jEnd;
		int kEnd;

		int di = ((dir.x > 0) ? 1 : (dir.x < 0) ? -1 : 0);
		int dj = ((dir.y > 0) ? 1 : (dir.y < 0) ? -1 : 0);
		int dk = ((dir.z > 0) ? 1 : (dir.z < 0) ? -1 : 0);


		float maxSize = MIN_CELL_SIZE;
		int occupiedLevelsMask = m_occupiedLevelsMask;
		int maxLevel = 0;
		for (maxLevel = 0; maxLevel < MAX_LEVELS; ++maxLevel, occupiedLevelsMask >>= 1)
		{
			if (occupiedLevelsMask == 0)
				break;
			maxSize *= CELL_TO_CELL_RATIO;
		}


		vec3 end = origin + maxSize * dir;
		
		float size = MIN_CELL_SIZE;
		for (int level = 0; level < maxLevel; ++level)
		{

			cells[level].i = (int)floorf(origin.x / size);
			cells[level].j = (int)floorf(origin.y / size);
			cells[level].k = (int)floorf(origin.z / size);

			float minx = size * floorf(origin.x / size);
			float miny = size * floorf(origin.y / size);
			float minz = size * floorf(origin.z / size);

			float maxx = minx + size;
			float maxy = miny + size;
			float maxz = minz + size;
						 
			cells[level].t.x = ((dir.x < 0) ? (origin.x - minx) : (maxx - origin.x)) / abs(dir.x);
			cells[level].t.y = ((dir.y < 0) ? (origin.y - miny) : (maxy - origin.y)) / abs(dir.y);
			cells[level].t.z = ((dir.z < 0) ? (origin.z - miny) : (maxy - origin.z)) / abs(dir.z);

			cells[level].d.x = size / abs(dir.x);
			cells[level].d.y = size / abs(dir.y);
			cells[level].d.z = size / abs(dir.z);

			size *= CELL_TO_CELL_RATIO;
		}

		cells[maxLevel].i = (int)floorf(origin.x / maxSize);
		cells[maxLevel].j = (int)floorf(origin.y / maxSize);
		cells[maxLevel].k = (int)floorf(origin.z / maxSize);

		iEnd = (int)floorf((di >= 0 ? m_maxExtend.x : m_minExtend.x) / maxSize);
		jEnd = (int)floorf((dj >= 0 ? m_maxExtend.y : m_minExtend.y) / maxSize);
		kEnd = (int)floorf((dk >= 0 ? m_maxExtend.z : m_minExtend.z) / maxSize);


		RayQueryResult minResult;
		minResult.collider = 0;
		minResult.t = FLT_MAX;


		//check origin for neighbouring cells
		size = MIN_CELL_SIZE;
		for (int level = 0; level < maxLevel; ++level)
		{
			if (m_objectsAtLevel[level] == 0)
				continue;


			int x0 = cells[level].i, x1 = cells[level].i;
			int y0 = cells[level].j, y1 = cells[level].j;
			int z0 = cells[level].k, z1 = cells[level].k;


			if ((int)floorf(origin.x / size - SPHERE_TO_CELL_RATIO * size) != cells[level].i)
				--x0;
			if ((int)floorf(origin.y / size + SPHERE_TO_CELL_RATIO * size) != cells[level].i)
				++x1;

			if ((int)floorf(origin.y / size - SPHERE_TO_CELL_RATIO * size) != cells[level].j)
				--y0;
			if ((int)floorf(origin.y / size + SPHERE_TO_CELL_RATIO * size) != cells[level].j)
				++y1;

			if ((int)floorf(origin.z / size - SPHERE_TO_CELL_RATIO * size) != cells[level].k)
				--z0;
			if ((int)floorf(origin.y / size + SPHERE_TO_CELL_RATIO * size) != cells[level].k)
				++z1;

			for (int x = x0; x <= x1; ++x)
			{
				for (int y = y0; y <= y1; ++y)
				{
					for (int z = z0; z <= z1; ++z)
					{
						int bucket = calculateBucketID(x, y, z, level);
						if (m_timeStamp[bucket] == m_tick)
							continue;
						m_timeStamp[bucket] = m_tick;

						for (Object& obj : m_objectBucket[bucket])
						{
							float tmin;
							vec3 p;
							if (intersectRayAABB(origin, dir, obj.id->pBody->getAABB(), tmin, p) && tmin < tmax)
							{
								RayQueryResult result = { 0 };
								if (obj.id->pBody->queryRay(origin, dir, &result, tmax))
								{
									if (result.t < minResult.t)
										minResult = result;
								}
							}
						}


					}
				}
			}
								


			size *= CELL_TO_CELL_RATIO;
		}

		int bucket;
		//todo FIX !!!
		static int MAX_ITERS = 100;
		for (int iter = 0 ; iter < MAX_ITERS;++ iter)
		{
			float ooSize = 1.0f / maxSize;

			for (int l = maxLevel - 1; l >= 0; --l)
			{
				ooSize *= CELL_TO_CELL_RATIO;

				if (m_objectsAtLevel[l] == 0)
					continue;


				for (;;)
				{
					int x0 = cells[l].i, x1 = cells[l].i;
					int y0 = cells[l].k, y1 = cells[l].j;
					int z0 = cells[l].j, z1 = cells[l].k;

					bool quit = false;

					if (cells[l].t.x <= cells[l].t.y && cells[l].t.x <= cells[l].t.z)
					{

						vec3 p = origin + cells[l].t.x * dir;

						if ((int)floorf(p.y - SPHERE_TO_CELL_RATIO * 1.0f / ooSize) != cells[l].j)
							--y0;
						else if ((int)floorf(p.y + SPHERE_TO_CELL_RATIO * 1.0f / ooSize) != cells[l].j)
							++y1;

						if ((int)floorf(p.z - SPHERE_TO_CELL_RATIO * 1.0f / ooSize) != cells[l].k)
							--z0;
						else if ((int)floorf(p.z + SPHERE_TO_CELL_RATIO * 1.0f / ooSize) != cells[l].k)
							++z1;
						
						cells[l].t.x += cells[l].d.x;
						cells[l].i += di;

						if ((int)floorf(cells[l].i/(maxSize*ooSize)) != cells[maxLevel].i)
							quit = true;
					}
					else if (cells[l].t.y <= cells[l].t.z)
					{

						vec3 p = origin + cells[l].t.y * dir;

						if ((int)floorf(p.x - SPHERE_TO_CELL_RATIO * 1.0f / ooSize) != cells[l].i)
							--x0;
						else if ((int)floorf(p.x + SPHERE_TO_CELL_RATIO * 1.0f / ooSize) != cells[l].i)
							++x1;

						if ((int)floorf(p.z - SPHERE_TO_CELL_RATIO * 1.0f / ooSize) != cells[l].k)
							--z0;
						else if ((int)floorf(p.z + SPHERE_TO_CELL_RATIO * 1.0f / ooSize) != cells[l].k)
							++z1;


						cells[l].t.y += cells[l].d.y;
						cells[l].j += dj;

						if ((int)floorf(cells[l].j / (maxSize*ooSize)) != cells[maxLevel].j)
							quit = true;
					}
					else
					{

						vec3 p = origin + cells[l].t.z * dir;

						if ((int)floorf(p.x - SPHERE_TO_CELL_RATIO * 1.0f / ooSize) != cells[l].i)
							--x0;
						else if ((int)floorf(p.x + SPHERE_TO_CELL_RATIO * 1.0f / ooSize) != cells[l].i)
							++x1;

						if ((int)floorf(p.y - SPHERE_TO_CELL_RATIO * 1.0f / ooSize) != cells[l].j)
							--y0;
						else if ((int)floorf(p.y + SPHERE_TO_CELL_RATIO * 1.0f / ooSize) != cells[l].j)
							++y1;


						cells[l].t.z += cells[l].d.z;
						cells[l].k += dk;

						if ((int)floorf(cells[l].k / (maxSize*ooSize)) != cells[maxLevel].k)
							quit = true;
					}


					for (int x = x0; x <= x1; ++x)
					{
						for (int y = y0; y <= y1; ++y)
						{
							for (int z = z0; z <= z1; ++z)
							{
								bucket = calculateBucketID(x, y, z, l);
								if (m_timeStamp[bucket] == m_tick)
									continue;
								m_timeStamp[bucket] = m_tick;

								for (Object& obj : m_objectBucket[bucket])
								{
									float tmin;
									vec3 p;
									if (intersectRayAABB(origin, dir, obj.id->pBody->getAABB(), tmin, p) && tmin < tmax)
									{
										RayQueryResult result = { 0 };
										if (obj.id->pBody->queryRay(origin, dir, &result, tmax))
										{
											if (result.t < minResult.t)
												minResult = result;
										}
									}
								}


							}
						}
					}
						
					if (quit)
						break;
				}
			}

			if (minResult.collider != 0)
			{
				*hit = minResult;
				return true;
			}

			if (cells[maxLevel].t.x <= cells[maxLevel].t.y && cells[maxLevel].t.x <= cells[maxLevel].t.z)
			{
				if (cells[maxLevel].i == iEnd)
					return false;
				cells[maxLevel].t.x += cells[maxLevel].d.x;
				cells[maxLevel].i += di;

			}
			else if (cells[maxLevel].t.y <= cells[maxLevel].t.z)
			{
				if (cells[maxLevel].j == jEnd)
					return false;
				cells[maxLevel].t.y += cells[maxLevel].d.y;
				cells[maxLevel].j += dj;

			}
			else
			{
				if (cells[maxLevel].k == kEnd) 
					return false;
				cells[maxLevel].t.z += cells[maxLevel].d.z;
				cells[maxLevel].k += dk;

			}

		}
	}