Exemple #1
0
TEST_F(CubeMeshTests, IntersectionTest) {
  IObject3D *object = Cube;

  Ray ray(glm::dvec3(3.0, 2.0, -1.0), Z_NORM_VEC);
  IntersectionResult res = object->Intersect(ray);
  ASSERT_TRUE(res);
  ASSERT_DOUBLE_EQ(1.0, res.GetDistance());
  ASSERT_VEC_NEAR(-Z_NORM_VEC, (res.GetNormalRay().GetDirection()), EPS_WEAK);

  // Test ray falling on edge of triangle.
  ray.SetOrigin(glm::dvec3(3.0, 3.0, -1.0));
  res = object->Intersect(ray);
  ASSERT_TRUE(res);
  ASSERT_DOUBLE_EQ(1.0, res.GetDistance());
  ASSERT_VEC_NEAR(-Z_NORM_VEC, (res.GetNormalRay().GetDirection()), EPS_WEAK);

  // Test ray falling on vertex.
  ray.SetOrigin(glm::dvec3(10.0, 5.0, 0.0));
  ray.SetDirection(-X_NORM_VEC);
  res = object->Intersect(ray);
  ASSERT_TRUE(res);
  ASSERT_DOUBLE_EQ(5.0, res.GetDistance());
  ASSERT_VEC_NEAR(X_NORM_VEC, (res.GetNormalRay().GetDirection()), EPS_WEAK);
}
Exemple #2
0
 bool StaticMapTree::getObjectHitPos(const Vector3& pPos1, const Vector3& pPos2, Vector3& pResultHitPos, float pModifyDist) const
 {
     float maxDist = (pPos2 - pPos1).magnitude();
     // valid map coords should *never ever* produce float overflow, but this would produce NaNs too:
     MANGOS_ASSERT(maxDist < std::numeric_limits<float>::max());
     // prevent NaN values which can cause BIH intersection to enter infinite loop
     if (maxDist < 1e-10f)
     {
         pResultHitPos = pPos2;
         return false;
     }
     Vector3 dir = (pPos2 - pPos1) / maxDist;            // direction with length of 1
     G3D::Ray ray(pPos1, dir);
     float dist = maxDist;
     if (getIntersectionTime(ray, dist, false))
     {
         pResultHitPos = pPos1 + dir * dist;
         if (pModifyDist < 0)
         {
             if ((pResultHitPos - pPos1).magnitude() > -pModifyDist)
             {
                 pResultHitPos = pResultHitPos + dir * pModifyDist;
             }
             else
             {
                 pResultHitPos = pPos1;
             }
         }
         else
         {
             pResultHitPos = pResultHitPos + dir * pModifyDist;
         }
     }
     pResultHitPos = pPos2;
     return false;
 }
bool CGraphicView::GetXYPointForDXFTextExport( const CPoint& screenPt, CPoint3D& worldPt )
{
	//get a ray that goes through screenPt from the front of the view frustum to the back of it
	CPoint3D nearPt, farPt;
	if( !Get3DPointFromScreen( screenPt, nearPt, 0.f ) )
		return false;
	if( !Get3DPointFromScreen( screenPt, farPt, 1.f ) )
		return false;
	CLine3D ray( nearPt, farPt );

	//now find out where in 3D space the ray passes through the z=0 plane
	CVector3D xyNormal( 0., 0., 1. );
	CPoint3D ptOnXYPlane( 0., 0., 0. );
	CPlane3D xyPlane( xyNormal, ptOnXYPlane );
	double denom = xyNormal.dot( CVector3D( farPt, nearPt ) );
	if( zero( denom ) ) return false;
	double num = xyNormal.dot( CVector3D( ptOnXYPlane, nearPt  ) );
	double s = num/denom;
	worldPt = ray.offset( s );
	
	if( true/*is world point valid*/ )
		return true;
	else return false;
}
Exemple #4
0
void gkCameraNode::calculateNewPosition(const gkVector3& currentPosition, gkScalar rayLength, gkScalar tick)
{
	gkVector3 oDir = gkVector3::NEGATIVE_UNIT_Z * rayLength;

	gkVector3 tmpPosition = m_center - m_target->getOrientation() * oDir;

	bool newPosSet = false;

	if (GET_SOCKET_VALUE(AVOID_BLOCKING))
	{
		gkVector3 direction = tmpPosition - m_center;

		Ogre::Ray ray(m_center, direction);

		gkSweptTest::AVOID_LIST avoidList;
		avoidList.push_back(m_centerObj->getPhysicsController()->getCollisionObject());

		gkSweptTest sweptTest(avoidList);

		gkScalar blokingRadius = GET_SOCKET_VALUE(BLOCKING_RADIUS);

		if (sweptTest.collides(ray, blokingRadius))
		{
			gkVector3 displacement = (sweptTest.getHitPoint() - currentPosition) * 0.9f;

			m_target->setPosition(currentPosition + (displacement + sweptTest.getSliding()) * tick);

			newPosSet = true;
		}
	}

	if (!newPosSet)
	{
		m_target->setPosition(tmpPosition);
	}
}
Exemple #5
0
/** genRay **/
vector_t genRay(scene_t *scene, int column, int row) {
   vector_t direction;                       // Directior vector
   entity_t    *ent;
   window_t *window;

   assert(scene->magic == SCENE_T);
   ent = scene->window;
   window = ent->entDerived;
   assert(window->magic == WINDOW_T);

   /* Computer the pixel's real scene coordinates */
   direction.x = ((double)(column)/
      (double)(scene->picture->columns-1))*window->windowWidth;
   direction.x -= window->windowWidth/2.0;
   direction.y = ((double)(row)/
      (double)(scene->picture->rows-1))*window->windowHeight;
   direction.y -= window->windowHeight/2.0;
   direction.z = 0;

   /* And now construct a unit vector from the view point to the pixel */
   direction = ray(window->viewPoint, direction);
   direction = unitize(direction);
   return(direction);
} /* End genRay */
Exemple #6
0
  TEST_F(Ray3fTest, MethodIntersectPlane)
  {
    // Intersect.
    Ray3 ray(Vec3f(0, 0, 0), Vec3f(0, 0, 1));
    Plane plane(Vec3f(0, 0, 10), Vec3f(0, 0, -1));
    Vec3f intersection;
    bool intersect = ray.intersect(plane, intersection);
    float result[3];
    result[0] = 0;
    result[1] = 0;
    result[2] = 10;
    ASSERT_TRUE(intersect);
    cmpVec3f(result, intersection);

    // Ray pointing away.
    ray = Ray3(Vec3f(0, 0, 0), Vec3f(0, 0, -1));
    plane = Plane(Vec3f(0, 0, 10), Vec3f(0, 0, -1));
    intersect = ray.intersect(plane, intersection);
    ASSERT_TRUE(!intersect);

    // Normal same direction as ray.
    ray = Ray3(Vec3f(0, 0, 0), Vec3f(0, 0, 1));
    plane = Plane(Vec3f(0, 0, 10), Vec3f(0, 0, 1));
    intersect = ray.intersect(plane, intersection);
    result[0] = 0;
    result[1] = 0;
    result[2] = 10;
    ASSERT_TRUE(intersect);
    cmpVec3f(result, intersection);

    // Parallel.
    ray = Ray3(Vec3f(0, 0, 0), Vec3f(0, 0, 1));
    plane = Plane(Vec3f(0, 0, 10), Vec3f(0, 1, 0));
    intersect = ray.intersect(plane, intersection);
    ASSERT_TRUE(!intersect);
  }
Exemple #7
0
bool BaseTank::isCollision(const Ogre::Vector3& position, const Ogre::Vector3& direction, Ogre::Real RaySize)
{
	//根据初始位置和方向创建一条射线;
	Ogre::Ray ray(position, direction);
	m_pRaySceneQuery->setRay(ray);
	//获取射线查询结果;
	Ogre::RaySceneQueryResult	&result = m_pRaySceneQuery->execute();
	Ogre::RaySceneQueryResult::iterator ite;
	//遍历查询结果,对每个结果做相应的操作;
	for( ite = result.begin(); ite!=result.end(); ite++)
	{
		//如果在指定距离的射线范围内查找到实体,则返回true;
		Ogre::String p=m_pBodyEntity->getName();
		if (ite->movable->getName().compare(m_pBodyEntity->getName()) != 0
			&& ite->distance < RaySize)
		{
			if (ite->movable->getName() != "PlayingCamera")
			{
					return true;
			}
		}
	}
	return false;
}
Exemple #8
0
void Engine::Calculate()
{
    const int max = Width * Height;
    const double cellWidth = 0.005;
    const double cellHeight = 0.005;
    const Vector3 origin(0.0,0.0,-5.0);

    for (int i = 0; i < Width; i++)
    {
        for (int j = 0; j < Height; j++)
        {
            Vector3 a;
            a.x = 1.0 * cellWidth * (i - Width/2);
            a.y = -1.0 * cellHeight * (j - Height/2);
            a.z = 0.0;

            a = a - origin;
            a.Normalize();

            Ray ray(origin, a);
            m_image[i][j] = trace(m_scene, ray, 0);
            m_progress++;

            int part = (m_progress*100/max);
            if (part*max == (m_progress*100))
            {
                if ((part/5)*5 == part)
                {
                    std::ostringstream caption;
                    caption << part << "%";
                    m_screen.SetCaption(caption.str());
                }
            }
        }
    }
}
Exemple #9
0
Point Polygon::FarthestPointAtAngle(real angle) const
{
    // TODO(mraggi): Replace with Binary search implementation
    int n = NumPoints();

    for (int i = 0; i < n; ++i)
    {
        Point p1 = m_vPoints[i];
        Point p2 = m_vPoints[(i + 1)%n];
        real a1 = p1.Angle();
        real a2 = p2.Angle();

        if (isAngleBetweenAngles(angle, a1, a2))
        {
            Point hola;
            Ray ray(Ray(Point(0, 0), angle));
            ray.Intersects(Segment(p1, p2), hola);
            return hola + Position();
        }
    }
    if (NumPoints() > 2)
        std::cerr << "ERROR IN Polygon::FarthestPointAtAngle" << std::endl;
    return {0, 0};
}
 void PathTracingRenderer::Job::kernel(uint32_t threadID) {
     ArenaAllocator &mem = mems[threadID];
     IndependentLightPathSampler &pathSampler = *pathSamplers[threadID];
     for (int ly = 0; ly < numPixelY; ++ly) {
         for (int lx = 0; lx < numPixelX; ++lx) {
             float time = pathSampler.getTimeSample(timeStart, timeEnd);
             PixelPosition p = pathSampler.getPixelPositionSample(basePixelX + lx, basePixelY + ly);
             
             float selectWLPDF;
             WavelengthSamples wls = WavelengthSamples::createWithEqualOffsets(pathSampler.getWavelengthSample(), pathSampler.getWLSelectionSample(), &selectWLPDF);
             
             LensPosQuery lensQuery(time, wls);
             LensPosQueryResult lensResult;
             SampledSpectrum We0 = camera->sample(lensQuery, pathSampler.getLensPosSample(), &lensResult);
             
             IDFSample WeSample(p.x / imageWidth, p.y / imageHeight);
             IDFQueryResult WeResult;
             IDF* idf = camera->createIDF(lensResult.surfPt, wls, mem);
             SampledSpectrum We1 = idf->sample(WeSample, &WeResult);
             
             Ray ray(lensResult.surfPt.p, lensResult.surfPt.shadingFrame.fromLocal(WeResult.dirLocal), time);
             SampledSpectrum C = contribution(*scene, wls, ray, pathSampler, mem);
             SLRAssert(C.hasNaN() == false && C.hasInf() == false && C.hasMinus() == false,
                       "Unexpected value detected: %s\n"
                       "pix: (%f, %f)", C.toString().c_str(), px, py);
             
             SampledSpectrum weight = (We0 * We1) * (absDot(ray.dir, lensResult.surfPt.gNormal) / (lensResult.areaPDF * WeResult.dirPDF * selectWLPDF));
             SLRAssert(weight.hasNaN() == false && weight.hasInf() == false && weight.hasMinus() == false,
                       "Unexpected value detected: %s\n"
                       "pix: (%f, %f)", weight.toString().c_str(), px, py);
             sensor->add(p.x, p.y, wls, weight * C);
             
             mem.reset();
         }
     }
 }
Exemple #11
0
const std::shared_ptr<std::vector<ray>> mesh_light::shed(unsigned long samples) const {
	random_sampler s;
	std::vector<float> face_selector = *s.get_1d_samples(0.0f, 1.0f, samples);
	std::vector<vec2> c = *s.get_2d_samples(0, 1, 0, 1, samples);
	std::shared_ptr<std::vector<ray>> out(new std::vector<ray>());
	for (unsigned long i = 0; i < c.size(); i++) {
		for (unsigned long f = 0; f < cr_areas.size(); f++) {
			if (face_selector.at(i) < cr_areas[f]) {
				std::shared_ptr<triangle> face = faces->at(f);
				std::shared_ptr<vec2> lcoord(new vec2(c[i][0] + c[i][1] > 1 ? 1 - c[i][1] : c[i][0],
													  c[i][0] + c[i][1] > 1 ? 1 - c[i][0] : c[i][1]));
				std::shared_ptr<position> lpos = std::make_shared<position>(object_to_world(
						*face->get_barycentric_position(1 - (*lcoord)[0] - (*lcoord)[1], (*lcoord)[0], (*lcoord)[1]) +
						offset));
				std::array<position, 3> & v = *face->get_vertices();
				normal n = normalise(cross(object_to_world(v[1]-v[0]), object_to_world(v[2]-v[0])));
				if (dot(n, object_to_world(*face->get_avg_normal())) < 0)
					n = -n;
				out->push_back(ray(*lpos, s.get_solid_angle_samples(n, static_cast<float>(M_PI / 2), 1)->at(0)));
			}
		}
	}
	return out;
}
void kdtreebenthin::draw<1>(scene& scene, ray4* r, hit4* hit4)
{

        unsigned int signx = movemask(r->D().x());
        unsigned int signy = movemask(r->D().y());
        unsigned int signz = movemask(r->D().z());

        //If the traversal direction is not same for all rays we 
        //  do a single ray traversal
        if (((signx - 1) < 14)       // sign of x is 0xF or 0
            || ((signy - 1) < 14)    // sign of y is 0xF or 0
            || ((signz - 1) < 14)) { // sign of z is 0xF or 0
                hit hit[4];
                for (int i = 0; i < 4; ++i) {
                        vec3f d(r->D().x()[i], r->D().y()[i], r->D().z()[i]);
                        ray ray(r->O(), d);
                        hit[i].prim = -1;
                        draw(scene, ray, hit[i]);
                }
                hit4->prim = ssei(hit[0].prim, hit[1].prim, hit[2].prim, hit[3].prim);
                hit4->u    = ssef(hit[0].u, hit[1].u, hit[2].u, hit[3].u);
                hit4->v    = ssef(hit[0].v, hit[1].v, hit[2].v, hit[3].v);
                return;
        }

        ssef tnear, tfar;
        _boundingBox.clip(*r, tnear, tfar);
        if (movemask(tnear >= tfar) == 0xF)
                return;

        const unsigned int dir[3][2] = {
                { signx & 1 , 1 - (signx & 1) },
                { signy & 1 , 1 - (signy & 1) },
                { signz & 1 , 1 - (signz & 1) } };

        ssef far[MAX_STACK_SIZE];
        ssef near[MAX_STACK_SIZE];
        int  nodes[MAX_STACK_SIZE];

        //push dummyNode onto stack which will cause us to exit
        nodes[0] = 0;
        far[0]  = BPRAY_INF;

        uint32_t stackptr = 1;
        kdnode* currNode = _nodes + 1;

        int activemask = 0xF;
#if MAILBOX
        static uint64_t rayid = 0;
        __sync_add_and_fetch(&rayid, 1);
#endif
        while (true) {
                if (!currNode->isLeaf()) {
                        const int axis  = currNode->getAxis();
                        const int front = currNode->getLeft() + dir[axis][0];
                        const int back  = currNode->getLeft() + dir[axis][1];
                        const ssef dist = currNode->getSplit() - r->O()[axis];
                        const ssef t    = dist * r->rcpD()[axis];

                        currNode   = _nodes + back;
                        if (!(movemask(tnear <= t) & activemask)) continue;

                        currNode   = _nodes + front;
                        if (!(movemask(tfar >= t) & activemask))  continue;

                        nodes[stackptr] = back;
                        near[stackptr]  = max(tnear, t);
                        far[stackptr]   = tfar;
                        tfar            = min(tfar, t);
                        activemask     &= movemask(tnear <= tfar);
                        ++stackptr;
                } else {
                        int primidx   = currNode->getPrimitiveOffset();
                        int primcount = currNode->getNumPrims();

                        for (int i = 0; i != primcount; ++i) {
                                int t = _prims[primidx + i];

                                //prefetch
                                int t2 = _prims[primidx + i + 1];
                                _mm_prefetch((char*)&scene._accels[t2], _MM_HINT_T0);
#if MAILBOX
                                //mailboxing
                                if (mbox.find(scene, rayid, t)) continue;
#endif
                                scene.intersect(t, *r, *hit4);
#if MAILBOX
                                mbox.add(scene, rayid, t);
#endif
                        }

                        if (movemask(tfar < r->tfar) == 0) return;
                        
                        --stackptr;
                        currNode   = nodes[stackptr] + _nodes;
                        tfar       = far[stackptr];
                        tnear      = near[stackptr];
                        activemask = movemask(tnear <= tfar);
                }
        }
}
dgInt32 dgCollisionConvexPolygon::CalculateContactToConvexHullContinue (dgCollisionParamProxy& proxy, const dgVector& polyInstanceScale, const dgVector& polyInstanceInvScale)
{
    dgAssert (proxy.m_referenceCollision->IsType (dgCollision::dgCollisionConvexShape_RTTI));
    dgAssert (proxy.m_floatingCollision->IsType (dgCollision::dgCollisionConvexPolygon_RTTI));

    const dgCollisionInstance* const hull = proxy.m_referenceCollision;

    dgAssert (this == proxy.m_floatingCollision->GetChildShape());
    dgAssert (m_count);
    dgAssert (m_count < dgInt32 (sizeof (m_localPoly) / sizeof (m_localPoly[0])));

    const dgBody* const floatingBody = proxy.m_floatingBody;
    const dgBody* const referenceBody = proxy.m_referenceBody;

    dgContact* const contactJoint = proxy.m_contactJoint;
    contactJoint->m_closestDistance = dgFloat32 (1.0e10f);

    m_normal = m_normal.CompProduct4(polyInstanceInvScale);
    dgAssert (m_normal.m_w == dgFloat32 (0.0f));
    m_normal = m_normal.CompProduct4(m_normal.DotProduct4(m_normal).InvSqrt());
    const dgVector savedFaceNormal (m_normal);

    for (dgInt32 i = 0; i < m_count; i ++) {
        m_localPoly[i] = polyInstanceScale.CompProduct4(dgVector (&m_vertex[m_vertexIndex[i] * m_stride]));
        dgAssert (m_localPoly[i].m_w == dgFloat32 (0.0f));
    }

    dgVector hullOrigin (proxy.m_matrix.UntransformVector(dgVector (dgFloat32 (0.0f))));
    hullOrigin = (hullOrigin - m_normal.CompProduct4(m_normal.DotProduct4(hullOrigin - m_localPoly[0]))) | dgVector::m_wOne;

    dgMatrix polygonMatrix;
    polygonMatrix[0] = m_localPoly[1] - m_localPoly[0];
    polygonMatrix[0] = polygonMatrix[0].CompProduct4 (polygonMatrix[0].InvMagSqrt());
    polygonMatrix[1] = m_normal;
    polygonMatrix[2] = polygonMatrix[0] * m_normal;
    polygonMatrix[3] = hullOrigin;
    dgAssert (polygonMatrix.TestOrthogonal());

    dgMatrix savedProxyMatrix (proxy.m_matrix);
    proxy.m_matrix = polygonMatrix * proxy.m_matrix;

    dgVector floatingVeloc (floatingBody->m_veloc);
    dgVector referenceVeloc (referenceBody->m_veloc);
    const dgMatrix& hullMatrix = hull->GetGlobalMatrix();
    dgVector hullRelativeVeloc (hullMatrix.UnrotateVector(referenceVeloc - floatingVeloc));
    dgVector polyRelativeVeloc (proxy.m_matrix.UnrotateVector (hullRelativeVeloc));

    dgVector polyBoxP0 (dgFloat32 ( 1.0e15f));
    dgVector polyBoxP1 (dgFloat32 (-1.0e15f));
    m_normal = polygonMatrix.UnrotateVector(m_normal);

    if (m_normal.DotProduct4(polyRelativeVeloc).m_x >= 0.0f) {
        proxy.m_matrix = savedProxyMatrix;
        return 0;
    }
    for (dgInt32 i = 0; i < m_count; i ++) {
        m_localPoly[i] = polygonMatrix.UntransformVector(m_localPoly[i]);
        dgAssert (m_localPoly[i].m_w == dgFloat32 (0.0f));
        polyBoxP0 = polyBoxP0.GetMin (m_localPoly[i]);
        polyBoxP1 = polyBoxP1.GetMax (m_localPoly[i]);
    }
    dgInt32 count = 0;


    dgVector hullBoxP0;
    dgVector hullBoxP1;
    hull->CalcAABB (proxy.m_matrix.Inverse(), hullBoxP0, hullBoxP1);
    dgVector minBox (polyBoxP0 - hullBoxP1);
    dgVector maxBox (polyBoxP1 - hullBoxP0);
    dgFastRayTest ray (dgVector (dgFloat32 (0.0f)), polyRelativeVeloc);
    dgFloat32 distance = ray.BoxIntersect(minBox, maxBox);

    if (distance < dgFloat32 (1.0f)) {

        dgVector boxSize ((hullBoxP1 - hullBoxP0).Scale4 (dgFloat32 (0.5f)));
//		dgVector boxOrigin ((hullBoxP1 + hullBoxP0).Scale4 (dgFloat32 (0.5f)));
//		boxOrigin += polyRelativeVeloc.Scale4 (distance);

        dgVector normalInHull (proxy.m_matrix.RotateVector (m_normal.Scale4 (dgFloat32 (-1.0f))));
        dgVector pointInHull (hull->SupportVertex (normalInHull, NULL));
        dgVector pointInPlane (proxy.m_matrix.UntransformVector (pointInHull));
        dgFloat32 distToPlane = (m_localPoly[0] - pointInPlane) % m_normal;
        dgFloat32 timeToPlane = distToPlane / (polyRelativeVeloc % m_normal);
        dgVector boxOrigin (pointInPlane + polyRelativeVeloc.Scale4(timeToPlane));

        bool inside = true;
        dgInt32 i0 = m_count - 1;
        for (dgInt32 i = 0; i < m_count; i ++) {
            dgVector e (m_localPoly[i] - m_localPoly[i0]);
            dgVector n (m_normal * e);
            dgPlane plane (n, - (m_localPoly[i0] % n));

            dgVector supportDist (plane.Abs().DotProduct4 (boxSize));
            dgFloat32 centerDist = plane.Evalue(boxOrigin);

            if ((centerDist + supportDist.m_x) < dgFloat32 (0.0f)) {
                proxy.m_matrix = savedProxyMatrix;
                return 0;
            }

            if ((centerDist - supportDist.m_x) < dgFloat32 (0.0f)) {
                inside = false;
            }
            i0 = i;
        }

// for the time being for the minkousky contact calculation
        inside = false;
        const dgInt32 hullId = hull->GetUserDataID();
        if (inside) {
            dgVector normalInHull (proxy.m_matrix.RotateVector (m_normal.Scale4 (dgFloat32 (-1.0f))));
            dgVector pointInHull (hull->SupportVertex (normalInHull, NULL));
            dgVector p0 (proxy.m_matrix.UntransformVector (pointInHull));

            dgFloat32 timetoImpact = dgFloat32 (0.0f);
            //dgFloat32 closestDistance = dgFloat32 (0.0f);
            dgAssert (0);
//			dgFloat32 penetration = (m_localPoly[0] - p0) % m_normal + proxy.m_skinThickness + DG_IMPULSIVE_CONTACT_PENETRATION;
            dgFloat32 penetration = (m_localPoly[0] - p0) % m_normal + proxy.m_skinThickness;
            if (penetration < dgFloat32 (0.0f)) {
                timetoImpact = penetration / (polyRelativeVeloc % m_normal);
                dgAssert (timetoImpact >= dgFloat32 (0.0f));
//				closestDistance = -penetration;
            }

            if (timetoImpact <= proxy.m_timestep) {
                dgVector pointsContacts[64];

                contactJoint->m_closestDistance = penetration;
                dgAssert (0);
//				dgVector point (pointInHull - normalInHull.Scale4(DG_IMPULSIVE_CONTACT_PENETRATION));
                dgVector point (pointInHull);

                count = hull->CalculatePlaneIntersection (normalInHull, point, pointsContacts, 1.0f);
                dgAssert (0);
//				dgVector step (hullRelativeVeloc.Scale3 (timetoImpact) + normalInHull.Scale4(DG_IMPULSIVE_CONTACT_PENETRATION));
                dgVector step (hullRelativeVeloc.Scale3 (timetoImpact));

                penetration = dgMax (penetration, dgFloat32 (0.0f));
                const dgMatrix& worldMatrix = hull->m_globalMatrix;
                dgContactPoint* const contactsOut = proxy.m_contacts;
                dgVector globalNormal (worldMatrix.RotateVector(normalInHull));
                for (dgInt32 i = 0; i < count; i ++) {
                    contactsOut[i].m_point = worldMatrix.TransformVector (pointsContacts[i] + step);
                    contactsOut[i].m_normal = globalNormal;
                    contactsOut[i].m_shapeId0 = hullId;
                    contactsOut[i].m_shapeId1 = m_faceId;
                    contactsOut[i].m_penetration = penetration;
                }
            }
        } else {
            dgFloat32 convexSphapeUmbra = hull->GetUmbraClipSize ();
            if (m_faceClipSize > convexSphapeUmbra) {
                BeamClipping (boxOrigin, convexSphapeUmbra);
                m_faceClipSize = hull->m_childShape->GetBoxMaxRadius();
            }

            dgCollisionConvex* const convexShape = (dgCollisionConvex*) hull->m_childShape;
            count = convexShape->CalculateConvexCastContacts (proxy);

//			dgAssert (proxy.m_intersectionTestOnly || (count >= 0));
            if (count >= 1) {
                dgContactPoint* const contactsOut = proxy.m_contacts;
#if 0
                if (m_closestFeatureType == 3) {
                    for (dgInt32 i = 0; i < count; i ++) {
                        contactsOut[i].m_shapeId0 = hullId;
                        contactsOut[i].m_shapeId1 = m_faceId;
                    }
                } else {
                    dgVector normal (polygonInstance->m_globalMatrix.UnrotateVector(contactsOut[0].m_normal));
                    if ((normal % savedFaceNormal) < dgFloat32 (0.995f)) {
                        dgInt32 index = m_adjacentFaceEdgeNormalIndex[m_closestFeatureStartIndex];
                        dgVector n (&m_vertex[index * m_stride]);
                        dgVector dir0 (n * savedFaceNormal);
                        dgVector dir1 (n * normal);
                        dgFloat32 projection = dir0 % dir1;
                        if (projection <= dgFloat32 (0.0f)) {
                            normal = n;
                        }
                        normal = polygonInstance->m_globalMatrix.RotateVector(normal);
                        for (dgInt32 i = 0; i < count; i ++) {
                            contactsOut[i].m_normal = normal;
                            //contactsOut[i].m_userId = m_faceId;
                            contactsOut[i].m_shapeId0 = hullId;
                            contactsOut[i].m_shapeId1 = m_faceId;
                        }
                    } else {
                        for (dgInt32 i = 0; i < count; i ++) {
                            //contactsOut[i].m_userId = m_faceId;
                            contactsOut[i].m_shapeId0 = hullId;
                            contactsOut[i].m_shapeId1 = m_faceId;
                        }
                    }
                }
#endif

                for (dgInt32 i = 0; i < count; i ++) {
                    contactsOut[i].m_shapeId0 = hullId;
                    contactsOut[i].m_shapeId1 = m_faceId;
                }
            }
        }
    }

    proxy.m_matrix = savedProxyMatrix;
    return count;
}
dgInt32 dgCollisionConvexPolygon::CalculateContactToConvexHullContinue(const dgWorld* const world, const dgCollisionInstance* const parentMesh, dgCollisionParamProxy& proxy)
{
	dgAssert(proxy.m_instance0->IsType(dgCollision::dgCollisionConvexShape_RTTI));
	dgAssert(proxy.m_instance1->IsType(dgCollision::dgCollisionConvexPolygon_RTTI));

	dgAssert(this == proxy.m_instance1->GetChildShape());
	dgAssert(m_count);
	dgAssert(m_count < dgInt32(sizeof (m_localPoly) / sizeof (m_localPoly[0])));

	const dgBody* const body0 = proxy.m_body0;
	const dgBody* const body1 = proxy.m_body1;

	dgAssert (proxy.m_instance1->GetGlobalMatrix().TestIdentity());

	dgVector relativeVelocity (body0->m_veloc - body1->m_veloc);
	if (m_normal.DotProduct4(relativeVelocity).GetScalar() >= 0.0f) {
		return 0;
	}
	dgFloat32 den = dgFloat32 (1.0f) / (relativeVelocity % m_normal);
	if (den > dgFloat32 (1.0e-5f)) {
		// this can actually happens
		dgAssert(0);
		return 0;
	}

	dgContact* const contactJoint = proxy.m_contactJoint;
	contactJoint->m_closestDistance = dgFloat32(1.0e10f);

	dgMatrix polygonMatrix;
	dgVector right (m_localPoly[1] - m_localPoly[0]);
	polygonMatrix[0] = right.CompProduct4(right.InvMagSqrt());
	polygonMatrix[1] = m_normal;
	polygonMatrix[2] = polygonMatrix[0] * m_normal;
	polygonMatrix[3] = dgVector::m_wOne;
	dgAssert (polygonMatrix.TestOrthogonal());

	dgVector polyBoxP0(dgFloat32(1.0e15f));
	dgVector polyBoxP1(dgFloat32(-1.0e15f));
	for (dgInt32 i = 0; i < m_count; i++) {
		dgVector point (polygonMatrix.UnrotateVector(m_localPoly[i]));
		polyBoxP0 = polyBoxP0.GetMin(point);
		polyBoxP1 = polyBoxP1.GetMax(point);
	}

	dgVector hullBoxP0;
	dgVector hullBoxP1;
	dgMatrix hullMatrix (polygonMatrix * proxy.m_instance0->m_globalMatrix);
	proxy.m_instance0->CalcAABB(hullMatrix, hullBoxP0, hullBoxP1);
	dgVector minBox(polyBoxP0 - hullBoxP1);
	dgVector maxBox(polyBoxP1 - hullBoxP0);
	dgVector veloc (polygonMatrix.UnrotateVector (relativeVelocity));
	dgFastRayTest ray(dgVector(dgFloat32(0.0f)), veloc);
 	dgFloat32 distance = ray.BoxIntersect(minBox, maxBox);

	dgInt32 count = 0;
	if (distance < dgFloat32(1.0f)) {
		bool inside = false;

		dgVector boxSize((hullBoxP1 - hullBoxP0).CompProduct4(dgVector::m_half));
		dgVector sphereMag2 (boxSize.DotProduct4(boxSize));
		boxSize = sphereMag2.Sqrt();

		dgVector pointInPlane (polygonMatrix.RotateVector(hullBoxP1 + hullBoxP0).CompProduct4(dgVector::m_half));
		dgFloat32 distToPlane = (m_localPoly[0] - pointInPlane) % m_normal;

		dgFloat32 timeToPlane0 = (distToPlane + boxSize.GetScalar()) * den;
		dgFloat32 timeToPlane1 = (distToPlane - boxSize.GetScalar()) * den;

		dgVector boxOrigin0 (pointInPlane + relativeVelocity.Scale4(timeToPlane0));
		dgVector boxOrigin1 (pointInPlane + relativeVelocity.Scale4(timeToPlane1));
		dgVector boxOrigin ((boxOrigin0 + boxOrigin1).CompProduct4(dgVector::m_half)); 
		dgVector boxProjectSize (((boxOrigin0 - boxOrigin1).CompProduct4(dgVector::m_half))); 
		sphereMag2 = boxProjectSize.DotProduct4(boxProjectSize);
		boxSize = sphereMag2.Sqrt();

		dgAssert (boxOrigin.m_w == 0.0f);
		boxOrigin = boxOrigin | dgVector::m_wOne;
		
		if (!proxy.m_intersectionTestOnly) {
			inside = true;
			dgInt32 i0 = m_count - 1;

			for (dgInt32 i = 0; i < m_count; i++) {
				dgVector e(m_localPoly[i] - m_localPoly[i0]);
				dgVector n(m_normal * e & dgVector::m_triplexMask);
				dgFloat32 param = dgSqrt (sphereMag2.GetScalar() / (n.DotProduct4(n)).GetScalar());
				dgPlane plane(n, -(m_localPoly[i0] % n));

				dgVector p0 (boxOrigin + n.Scale4 (param));
				dgVector p1 (boxOrigin - n.Scale4 (param));

				dgFloat32 size0 = (plane.DotProduct4 (p0)).GetScalar();
				dgFloat32 size1 = (plane.DotProduct4 (p1)).GetScalar();

				if ((size0 < 0.0f) && (size1 < 0.0f)) {
					return 0;
				}

				if ((size0 * size1) < 0.0f) {
					inside = false;
					break;
				}
				i0 = i;
			}
		}

		dgFloat32 convexSphapeUmbra = dgMax (proxy.m_instance0->GetUmbraClipSize(), boxSize.GetScalar());
		if (m_faceClipSize > convexSphapeUmbra) {
			BeamClipping(boxOrigin, convexSphapeUmbra);
			m_faceClipSize = proxy.m_instance0->m_childShape->GetBoxMaxRadius();
		}

		const dgInt32 hullId = proxy.m_instance0->GetUserDataID();
		if (inside & !proxy.m_intersectionTestOnly) {
			const dgMatrix& matrixInstance0 = proxy.m_instance0->m_globalMatrix;
			dgVector normalInHull(matrixInstance0.UnrotateVector(m_normal.Scale4(dgFloat32(-1.0f))));
			dgVector pointInHull(proxy.m_instance0->SupportVertex(normalInHull, NULL));
			dgVector p0 (matrixInstance0.TransformVector(pointInHull));

			dgFloat32 timetoImpact = dgFloat32(0.0f);
			dgFloat32 penetration = (m_localPoly[0] - p0) % m_normal + proxy.m_skinThickness;
			if (penetration < dgFloat32(0.0f)) {
				timetoImpact = penetration / (relativeVelocity % m_normal);
				dgAssert(timetoImpact >= dgFloat32(0.0f));
			}

			if (timetoImpact <= proxy.m_timestep) {
				dgVector contactPoints[64];
				contactJoint->m_closestDistance = penetration;
				proxy.m_timestep = timetoImpact;
				proxy.m_normal = m_normal;
				proxy.m_closestPointBody0 = p0;
				proxy.m_closestPointBody1 = p0 + m_normal.Scale4(penetration);

				if (!proxy.m_intersectionTestOnly) {
					pointInHull -= normalInHull.Scale4 (DG_ROBUST_PLANE_CLIP);
					count = proxy.m_instance0->CalculatePlaneIntersection(normalInHull, pointInHull, contactPoints);

					dgVector step(relativeVelocity.Scale4(timetoImpact));
					penetration = dgMax(penetration, dgFloat32(0.0f));
					dgContactPoint* const contactsOut = proxy.m_contacts;
					for (dgInt32 i = 0; i < count; i++) {
						contactsOut[i].m_point = matrixInstance0.TransformVector(contactPoints[i]) + step;
						contactsOut[i].m_normal = m_normal;
						contactsOut[i].m_shapeId0 = hullId;
						contactsOut[i].m_shapeId1 = m_faceId;
						contactsOut[i].m_penetration = penetration;
					}
				}
			}
		} else {
			m_vertexCount = dgUnsigned16 (m_count);
			count = world->CalculateConvexToConvexContacts(proxy);
			if (count >= 1) {
				dgContactPoint* const contactsOut = proxy.m_contacts;
				for (dgInt32 i = 0; i < count; i++) {
					contactsOut[i].m_shapeId0 = hullId;
					contactsOut[i].m_shapeId1 = m_faceId;
				}
			}
		}
	}

	return count;
}
Exemple #15
0
vec3f RayTracer::traceRay( Scene *scene, const ray& r, 
	const vec3f& thresh, int depth, isect& i, vector<const SceneObject*>& stack )
{
	if( depth>=0
		&& thresh[0] > threshold - RAY_EPSILON && thresh[1] > threshold - RAY_EPSILON && thresh[2] > threshold - RAY_EPSILON
		&& scene->intersect( r, i ) ) {
		// YOUR CODE HERE

		// An intersection occured!  We've got work to do.  For now,
		// this code gets the material for the surface that was intersected,
		// and asks that material to provide a color for the ray.  

		// This is a great place to insert code for recursive ray tracing.
		// Instead of just returning the result of shade(), add some
		// more steps: add in the contributions from reflected and refracted
		// rays.
		
		const Material& m = i.getMaterial();
		vec3f color = m.shade(scene, r, i);
		//calculate the reflected ray
		vec3f d = r.getDirection();
		vec3f position = r.at(i.t);
		vec3f direction = d - 2 * i.N * d.dot(i.N);
		ray newray(position, direction);
		if(!m.kr.iszero()) {
			vec3f reflect = m.kr.multiply(traceRay(scene, newray, thresh.multiply(m.kr), depth-1, stack).clamp());
			color += reflect;
		}

		//calculate the refracted ray
		double ref_ratio;
		double sin_ang = d.cross(i.N).length();
		vec3f N = i.N;
		//Decide going in or out
		const SceneObject *mi = NULL, *mt = NULL;
		int stack_idx = -1;
		vector<const SceneObject*>::reverse_iterator itr;
		//1 use the normal to decide whether to go in or out
		//0: travel through, 1: in, 2: out
		char travel = 0;
		if(i.N.dot(d) <= -RAY_EPSILON) {
			//from outer surface in
			//test whether the object has two face
			ray test_ray(r.at(i.t) + d * 2 * RAY_EPSILON, -d);
			isect test_i;
			if(i.obj->intersect(r, test_i) && test_i.N.dot(N) > -RAY_EPSILON) {
				//has interior
				travel = 1;
			}
		}
		else {
			travel = 2;
		}

		if(travel == 1) {
			if(!stack.empty()) {
				mi = stack.back();
			}
			mt = i.obj;
			stack.push_back(mt);
		}
		else if(travel == 2) {
			//if it is in our stack, then we must pop it
			for(itr = stack.rbegin(); itr != stack.rend(); ++itr) {
				if(*itr == i.obj) {
					mi = *itr;
					vector<const SceneObject*>::iterator ii = itr.base() - 1;
					stack_idx = ii - stack.begin();
					stack.erase(ii);
					break;
				}
			}
			if(!stack.empty()) {
				mt = stack.back();
			}
		}

		if(N.dot(d) >= RAY_EPSILON) {
			N = -N;
		}
		
		ref_ratio = (mi?(mi->getMaterial().index):1.0) / (mt?(mt->getMaterial().index):1.0);

		if(!m.kt.iszero() && (ref_ratio < 1.0 + RAY_EPSILON || sin_ang < 1.0 / ref_ratio + RAY_EPSILON)) {
			//No total internal reflection
			//We do refraction now
			double c = N.dot(-d);
			direction = (ref_ratio * c - sqrt(1 - ref_ratio * ref_ratio * (1 - c * c))) * N + ref_ratio * d;
			newray = ray(position, direction);
			vec3f refraction = m.kt.multiply(traceRay(scene, newray, thresh.multiply(m.kt), depth-1, stack).clamp());
			color += refraction;
		}

		if(travel == 1) {
			stack.pop_back();
		}
		else if(travel == 2) {
			if(mi) {
				stack.insert(stack.begin() + stack_idx, mi);
			}
		}

		return color;

	} else {
		// No intersection.  This ray travels to infinity, so we color
		// it according to the background color, which in this (simple) case
		// is just black.
		if(m_bBackground && bg) {
			double u, v;
			angleToSphere(r.getDirection(), u, v);
			//Scale to [0, 1];
			u /= 2 * M_PI;
			v /= M_PI;
			int tx = int(u * bg_width), ty = bg_height - int(v * bg_height);
			return vec3f(bg[3 * (ty * bg_width + tx)] / 255.0, bg[3 * (ty * bg_width + tx) + 1] / 255.0, bg[3 * (ty * bg_width + tx) + 2] / 255.0);
		}
		else {
			return vec3f( 0.0, 0.0, 0.0 );
		}
	}
}
Exemple #16
0
bool UniformGrid::intersectsCell(const Model& model, const CellCoord& coord) {
  // Left side
  // Bottom left point
  Point3D p0 = pointAt(coord);
  Point3D p1(p0[0], p0[1] + cellSize, p0[2]);
  Point3D p2(p0[0], p0[1] + cellSize, p0[2] + cellSize);
  Point3D p3(p0[0], p0[1], p0[2] + cellSize);

  // Right side
  Point3D p4(p0[0] + cellSize, p0[1], p0[2]);
  Point3D p5(p0[0] + cellSize, p0[1] + cellSize, p0[2]);
  Point3D p6(p0[0] + cellSize, p0[1] + cellSize, p0[2] + cellSize);
  Point3D p7(p0[0] + cellSize, p0[1], p0[2] + cellSize);

  const std::vector<Point3D> pts = {p0, p1, p2, p3, p4, p5, p6, p7};

  auto cellMat = translationMatrix(p0[0], p0[1], p0[2]) * cellSizeScaleMatrix;
  // But we need the inverse of course
  cellMat = cellMat.invert();

  // Check if a pt is in the cell
  auto inCell = [&] (const Point3D& pt) -> bool {
    return p0[0] <= pt[0] && pt[0] <= (p0[0] + cellSize) &&
           p0[1] <= pt[1] && pt[1] <= (p0[1] + cellSize) &&
           p0[2] <= pt[2] && pt[2] <= (p0[2] + cellSize);
  };

  // First, we need to get the 8 points of the bounding box
  auto bbox = model.getBoundingBox();

  auto inBoundingBox = [&bbox] (const Point3D& pt) -> bool {
    // We are in the box if we are in between all the opposite parallel planes
    const auto c1 = bbox[0]; // Bottom back left corner
    const auto v1a = bbox[1] - c1; // Bottom back left to bottom back right
    const auto v1b = bbox[3] - c1; // Bottom back left to top back left
    const auto v1c = bbox[4] - c1; // Bottom back left to bottom front left
    const auto n1 = v1a.cross(v1b); // Back face
    const auto n2 = v1b.cross(v1c); // Left face
    const auto n3 = v1c.cross(v1a); // Bottom face

    const auto c2 = bbox[6]; // Top front right corner
    const auto v2a = bbox[5] - c2; // Top front right to bottom front right
    const auto v2b = bbox[7] - c2; // Top front right to top front left
    const auto v2c = bbox[2] - c2; // Top front right to top back right
    // We want this to be opposite sign (i.e. not pointing inwards)
    // so we do the opposite cross as above
    const auto n4 = v2b.cross(v2a); // Front face
    const auto n5 = v2c.cross(v2b); // Top face
    const auto n6 = v2a.cross(v2c); // Right face

    return betweenPlanes(n1, c1, n4, c2, pt) &&
           betweenPlanes(n2, c1, n6, c2, pt) &&
           betweenPlanes(n3, c1, n5, c2, pt);
  };

  // A corner of the bbox being inside the cell implies an intersection
  // between the bbox and the cell.
  for (const auto& pt : bbox) {
    if (inCell(pt)) {
      return true;
    }
  }

  // Similarly, a corner of cell inside bbox implies intersection
  for (const auto& pt : pts) {
    if (inBoundingBox(pt)) {
      return true;
    }
  }

  // Check if any of the 12 lines from bbox intersect this cell
  HitRecord hr;
  for (size_t i = 0; i < 8; ++i) {
    // This is the vector of one edge
    Vector3D v = bbox[(i % 4 == 0) ? i + 3 : i - 1] - bbox[i];
    Ray ray(bbox[i] - v, bbox[i]);
    if (utilityCube.intersects(ray, &hr, cellMat) && 1 <= hr.t && hr.t <= 2) {
      // This edge of the bounding box intersects our cell cube.
      return true;
    }
  }
  for (size_t i = 0; i < 4; ++i) {
    Vector3D v = bbox[i + 4] - bbox[i];
    Ray ray(bbox[i] - v, bbox[i]);
    if (utilityCube.intersects(ray, &hr, cellMat) && 1 <= hr.t && hr.t <= 2) {
      // This edge of the bounding box intersects our cell cube.
      return true;
    }
  }

  // Now check if any of the 12 lines from this cell intersect the model
  for (size_t i = 0; i < pts.size(); ++i) {
    Vector3D v = pts[(i % 4 == 0) ? i + 3 : i - 1] - pts[i];
    // Note: We are doing pts[i] - v and checking for t between 1 and 2.
    // This is equivalent to checking between 0 and 1 without doing the
    // subtraction, *but* we have an epsilon check in the intersects code.
    // For this case, we do *not* want to bother with epsilon check, so we
    // will check from 1 to 2 to avoid it.
    if (model.intersects(Ray(pts[i] - v, pts[i]), &hr)) {
      if (1 <= hr.t && hr.t <= 2) {
        return true;
      }
    }
  }

  // Now we have to check the struts between the two sides
  for (size_t i = 0; i < 4; ++i) {
    Vector3D v = pts[i + 4] - pts[i];
    if (model.intersects(Ray(pts[i] - v, pts[i]), &hr)) {
      if (1 <= hr.t && hr.t <= 2) {
        return true;
      }
    }
  }

  return false;
}
Exemple #17
0
/**
 *  Causes the object to be positioned in front of the tank every
 *  frame.
 *
 *  Adds all non-sensor geoms from object to the tank's
 *  body. Collision callbacks for tank are not installed on the picked
 *  up object!
 */
bool Tank::pickupObject(RigidBody * object)
{
    assert(!carried_object_);
    
    carried_object_ = object;
    Vector docking_offset = params_.get<Vector>("tank.docking_pos");

    if (getLocation() == CL_SERVER_SIDE)
    {
        // First we have to check whether the LOS to the object is given.

        // Use turret pos because tank position will likely be below terrain...
        Vector tank_pos    = target_object_->getPosition() + target_object_->vecToWorld(turret_pos_);
        Vector docking_pos = target_object_->getPosition() + target_object_->vecToWorld(docking_offset);
        Vector ab = docking_pos - tank_pos;

        pickup_los_given_ = true;
    
        physics::OdeRayGeom ray(ab.length());
        ray.set(tank_pos, ab);
        target_object_->getSimulator()->getStaticSpace()->collide(
            &ray, physics::CollisionCallback(this, &Tank::pickupRayCollisionCallback));
        if (pickup_los_given_)
        {
            target_object_->getSimulator()->getActorSpace()->collide(
                &ray, physics::CollisionCallback(this, &Tank::pickupRayCollisionCallback));
        }

        if (!pickup_los_given_)
        {
            carried_object_ = NULL;
            return false;
        }
    }
    
    s_log << Log::debug('l')
          << *this
          << " now carries "
          << *object
          << "\n";

    physics::OdeRigidBody * obj_body  = object->getProxy() ? object->getProxy() : object->getTarget();
    physics::OdeRigidBody * this_body = getProxy()         ? getProxy()         : getTarget();

    Matrix offset(true);
    offset.getTranslation() = docking_offset;
    
    for (unsigned g=0; g<obj_body->getGeoms().size(); ++g)
    {
        if (obj_body->getGeoms()[g]->isSensor()) continue;
        
        physics::OdeGeom * clone = obj_body->getGeoms()[g]->instantiate();

        clone->setName(clone->getName() + "-clone");
        clone->setMass(0.0f);
        clone->setOffset(offset);
        clone->setSpace(this_body->getSimulator()->getActorSpace());
        
        this_body->addGeom(clone);

        clone->setCategory(obj_body->getGeoms()[g]->getCategory());

        ++num_carried_object_geoms_;
    }

    return true;
}
Exemple #18
0
// VolPathIntegrator Method Definitions
Spectrum VolPathIntegrator::Li(const RayDifferential &r, const Scene &scene,
                               Sampler &sampler, MemoryArena &arena,
                               int depth) const {
    ProfilePhase p(Prof::SamplerIntegratorLi);
    Spectrum L(0.f), alpha(1.f);
    RayDifferential ray(r);
    bool specularBounce = false;
    for (int bounces = 0;; ++bounces) {
        // Store intersection into _isect_
        SurfaceInteraction isect;
        bool foundIntersection = scene.Intersect(ray, &isect);

        // Sample the participating medium, if present
        MediumInteraction mi;
        if (ray.medium) alpha *= ray.medium->Sample(ray, sampler, arena, &mi);
        if (alpha.IsBlack()) break;

        // Handle an interaction with a medium or a surface
        if (mi.IsValid()) {
            // Handle medium scattering case
            Vector3f wo = -ray.d, wi;
            L += alpha * UniformSampleOneLight(mi, scene, sampler, arena, true);
            Point2f phaseSample = sampler.Get2D();
            mi.phase->Sample_p(wo, &wi, phaseSample);
            ray = mi.SpawnRay(wi);
        } else {
            // Handle surface scattering case

            // Possibly add emitted light and terminate
            if (bounces == 0 || specularBounce) {
                // Add emitted light at path vertex or from the environment
                if (foundIntersection)
                    L += alpha * isect.Le(-ray.d);
                else
                    for (const auto &light : scene.lights)
                        L += alpha * light->Le(ray);
            }
            if (!foundIntersection || bounces >= maxDepth) break;

            // Compute scattering functions and skip over medium boundaries
            isect.ComputeScatteringFunctions(ray, arena, true);
            if (!isect.bsdf) {
                ray = isect.SpawnRay(ray.d);
                bounces--;
                continue;
            }

            // Sample illumination from lights to find attenuated path
            // contribution
            L += alpha *
                 UniformSampleOneLight(isect, scene, sampler, arena, true);

            // Sample BSDF to get new path direction
            Vector3f wo = -ray.d, wi;
            Float pdf;
            BxDFType flags;
            Spectrum f = isect.bsdf->Sample_f(wo, &wi, sampler.Get2D(), &pdf,
                                              BSDF_ALL, &flags);
            if (f.IsBlack() || pdf == 0.f) break;
            alpha *= f * AbsDot(wi, isect.shading.n) / pdf;
            Assert(std::isinf(alpha.y()) == false);
            specularBounce = (flags & BSDF_SPECULAR) != 0;
            ray = isect.SpawnRay(wi);

            // Account for attenuated subsurface scattering, if applicable
            if (isect.bssrdf && (flags & BSDF_TRANSMISSION)) {
                // Importance sample the BSSRDF
                SurfaceInteraction pi;
                Spectrum S = isect.bssrdf->Sample_S(
                    scene, sampler.Get1D(), sampler.Get2D(), arena, &pi, &pdf);
#ifndef NDEBUG
                Assert(std::isinf(alpha.y()) == false);
#endif
                if (S.IsBlack() || pdf == 0) break;
                alpha *= S / pdf;

                // Account for the attenuated direct subsurface scattering
                // component
                L += alpha *
                     UniformSampleOneLight(pi, scene, sampler, arena, true);

                // Account for the indirect subsurface scattering component
                Spectrum f = pi.bsdf->Sample_f(pi.wo, &wi, sampler.Get2D(),
                                               &pdf, BSDF_ALL, &flags);
                if (f.IsBlack() || pdf == 0.f) break;
                alpha *= f * AbsDot(wi, pi.shading.n) / pdf;
#ifndef NDEBUG
                Assert(std::isinf(alpha.y()) == false);
#endif
                specularBounce = (flags & BSDF_SPECULAR) != 0;
                ray = pi.SpawnRay(wi);
            }
        }

        // Possibly terminate the path
        if (bounces > 3) {
            Float continueProbability = std::min((Float).5, alpha.y());
            if (sampler.Get1D() > continueProbability) break;
            alpha /= continueProbability;
            Assert(std::isinf(alpha.y()) == false);
        }
    }
    return L;
}
Exemple #19
0
void Raycaster::shPrecomputation_Stage2_Interreflection( AllVertex& vertex )
{
  // at each vertex, shoot rays and see what other polygons you hit.
  // work in their direct response into your response.
  // This is PRT.

  int si = 0;//randInt( 0, window->shSamps->n ) ;
  for( int j = 0 ; j < window->shSamps->nU ; j++ )
  {
    SHSample& samp = window->shSamps->samps[(si+j)%window->shSamps->n];
    Vector sampdir = samp.dir() ;

    // it has to be on the + hemisphere to be usable
    real dot = sampdir • vertex.norm ;
    if( dot < 0 )  continue ; // angle is obtuse, don't use it
    
    Ray ray( vertex.pos + EPS_MIN*vertex.norm, sampdir, 1000 ) ;
    
    // shoot the ray in this direction using the raytracer
    Shape* closestShape=0 ;
    MeshIntersection intn ;
        
    // Force use the mesh, never use exactShape intersection.
    // This is important because we need a mesh intersection only,
    // data is parked at the vertices.
    if( window->scene->getClosestIntnMesh( ray, &intn ) )
    {
      // Now that it hits some poly..
      // we know 2 things:
      //   1. VERTEX DOESN'T GET AMBIENT FROM THIS SAMPLE'S DIRECTION (already found in stage 1)
      //   2. BUT VERTEX GETS INTERREFLECTIONS FROM SHAPE HIT BY intn IN THIS DIRECTION
      // (You can get a speedup by "tagging" rays by what they hit in
      //  the first pass, but I didn't do that because it'd take quite a bit of memory overhead)

      // diffuse light has the same strength every dierction.

      // Use the barycentric coordinates of the intersection
      // to produce a NEW SH (temp) function AT THAT POINT, (weight the
      // sh function at the surrounding vertices).
      SHVector newsh ;
      // Get the 3 SH functions that will be blended,
      // FROM THE REMOTE MESH THAT YOU JUST HIT WITH THE FEELER RAY
      SHVector* shA = intn.getMesh()->verts[ intn.tri->iA ].shDiffuseAmbient->scaledCopy( intn.bary.x ) ;
      SHVector* shB = intn.getMesh()->verts[ intn.tri->iB ].shDiffuseAmbient->scaledCopy( intn.bary.y ) ;
      SHVector* shC = intn.getMesh()->verts[ intn.tri->iC ].shDiffuseAmbient->scaledCopy( intn.bary.z ) ;

      newsh.add( shA )->add( shB )->add( shC ) ;
      delete shA; delete shB; delete shC;
      // SCALE DOWN the rgb components by your ability 
      // (at local/sending mesh) to REFLECT LIGHT on each band.
      newsh.scale( dot * window->shSamps->dotScaleFactor * vertex.color[ ColorIndex::DiffuseMaterial ] ) ;
      
      /////window->scene->addVisualization( newsh.generateVisualization( 10, 10, intn->point, ColorBand::R ) ) ;
      /////X vertex.shDiffuseAmbient->add( &newsh ) ; // DO NOT do this, you can't add to the current proj now, 
      // because that will change the first pass results (which we don't want)

      // Use a separate variable, then add the interreflections
      // with the base shading afterwards
      vertex.shDiffuseInterreflected->add( &newsh ) ; // ADD IT, this is the contribution of only ONE ray.

      // Specular addition is expensive, so if the material isn't even specular,
      // can skip this part
      if( vertex.color[ ColorIndex::SpecularMaterial ].notAll( 0 ) )
      {
        SHMatrix* shMA = intn.getMesh()->verts[ intn.tri->iA ].shSpecularMatrix->scaledCopy( intn.bary.x ) ;
        SHMatrix* shMB = intn.getMesh()->verts[ intn.tri->iB ].shSpecularMatrix->scaledCopy( intn.bary.y ) ;
        SHMatrix* shMC = intn.getMesh()->verts[ intn.tri->iC ].shSpecularMatrix->scaledCopy( intn.bary.z ) ;
        SHMatrix newshm ;
        newshm.add( shMA )->add( shMB )->add( shMC ) ;
        delete shMA; delete shMB; delete shMC;
        newshm.scale( window->shSamps->solidAngleRay * vertex.color[ ColorIndex::SpecularMaterial ] ) ;
        vertex.shSpecularMatrixInterreflected->add( &newshm ) ;
      }
    } 
    // else { } // ray didn't hit any shapes
  } // end raycast

  /////info( "sh2::finished %d->%d of %s", startVertex, endVertex, shape->name.c_str() ) ;
}
bool DynamicsWorld::castRay(
	const btVector3 & origin,
	const btVector3 & direction,
	const btScalar length,
	const btCollisionObject * caster,
	COLLISION_CONTACT & contact) const
{
	btVector3 p = origin + direction * length;
	btVector3 n = -direction;
	btScalar d = length;
	int patch_id = -1;
	const BEZIER * b = 0;
	const TRACKSURFACE * s = TRACKSURFACE::None();
	btCollisionObject * c = 0;

	MyRayResultCallback ray(origin, p, caster);
	rayTest(origin, p, ray);

	// track geometry collision
	bool geometryHit = ray.hasHit();
	if (geometryHit)
	{
		p = ray.m_hitPointWorld;
		n = ray.m_hitNormalWorld;
		d = ray.m_closestHitFraction * length;
		c = ray.m_collisionObject;
		if (c->isStaticObject())
		{
			TRACKSURFACE* tsc = static_cast<TRACKSURFACE*>(c->getUserPointer());
			const std::vector<TRACKSURFACE> & surfaces = track->GetSurfaces();
			if (tsc >= &surfaces[0] && tsc <= &surfaces[surfaces.size()-1])
			{
				s = tsc;
			}
#ifndef EXTBULLET
			else if (c->getCollisionShape()->isCompound())
			{
				TRACKSURFACE* tss = static_cast<TRACKSURFACE*>(ray.m_shape->getUserPointer());
				if (tss >= &surfaces[0] && tss <= &surfaces[surfaces.size()-1])
				{
					s = tss;
				}
			}
#endif
			//std::cerr << "static object without surface" << std::endl;
		}

		// track bezierpatch collision
		if (track)
		{
			MATHVECTOR<float, 3> bezierspace_raystart(origin[1], origin[2], origin[0]);
			MATHVECTOR<float, 3> bezierspace_dir(direction[1], direction[2], direction[0]);
			MATHVECTOR<float, 3> colpoint;
			MATHVECTOR<float, 3> colnormal;
			patch_id = contact.GetPatchId();

			if (track->CastRay(bezierspace_raystart, bezierspace_dir, length,
				patch_id, colpoint, b, colnormal))
			{
				p = btVector3(colpoint[2], colpoint[0], colpoint[1]);
				n = btVector3(colnormal[2], colnormal[0], colnormal[1]);
				d = (colpoint - bezierspace_raystart).Magnitude();
			}
		}

		contact = COLLISION_CONTACT(p, n, d, patch_id, b, s, c);
		return true;
	}

	// should only happen on vehicle rollover
	contact = COLLISION_CONTACT(p, n, d, patch_id, b, s, c);
	return false;
}
Exemple #21
0
void Raycaster::vectorOccluders( AllVertex& vertex )
{
  // cast rays in every which direction, looking for specular reflectors
  // taht are unblocked in the reflection dirctino, and diffuse surfaces
  // that send me light
  vertex.voData = new VectorOccludersData() ;
  //real ffSum = 0.0 ;

  int startRay = randInt( 0, rc->n ) ;
  for( int i = 0 ; i < numRaysToUse ; i++ )
  {
    // Grab ray and make sure it's valid
    int idx = (startRay + i)%rc->n ;
    Vector dir = rc->v( idx ) ;

    // sample must be +hemisphere
    // Want samples ONLY on the upper hemisphere (with the normal at the center)
    real dot = vertex.norm • dir ; // angle acute, sample in upper hemisphere (centered around normal)
    if( dot < 0 )  continue ; // skip this sample if angle with normal is obtuse

    Ray ray( vertex.pos + EPS_MIN * vertex.norm, dir, 1000, window->scene->mediaEta, 1, 0 ) ;
    MeshIntersection mi ;

    if( window->scene->getClosestIntnMesh( ray, &mi ) ) // hit something
    {
      // whadja hit
      Mesh *mesh = mi.getMesh() ;  //if( !mesh ) { error( "No mesh" ) ; }

      // whadda form factor
      real ff = dot * dotScaleFactor ;  // The form factor of the ray,
      //ffSum += ff ;

      real aoff = mi.getAO() * ff ;    // reduced by ambient occlusion at sender

      // if the normal is NOT OBTUSE WITH the casting ray,
      // you need to turn it around because it's physically impossible to hit the
      // "inside" of a surface _first_ with a ray casted towards that surface.
      if( dir • mi.normal > 0 )  mi.normal = - mi.normal ;

      // NORMAL AT POINT OF INTERSECTION
      Vector diffuseNormal = aoff * mi.normal ;
      Vector specularityNormal = ff * mi.normal ; 
      Vector causticDir ; // starts 0 (assuming no caustic)
      
      // COLORS AT POINT OF INTERSECTION
      Vector diffuseColor = mi.getColor( ColorIndex::DiffuseMaterial ) ;
      Vector specularColor = mi.getColor( ColorIndex::SpecularMaterial ) ;

      // Check that the reflection angle is open
      if( window->scene->getClosestIntnMesh( Ray( mi.point + EPS_MIN*mi.normal, dir.reflectedCopy( mi.normal ), 1000 ), 0 ) )
        specularityNormal = Vector(0,0,0) ; // BLOCKED, NO SPECULAR. zero it out.

      // Does this something refract the ray?
      // If so, keep refracting until hit free space (thus creating causticDir),
      // if you CAN'T hit free space by refracting, then this direction is blocked to refraction.
      Vector transColor = mi.getColor( ColorIndex::Transmissive ) ; 
      if( transColor.nonzero() )
      {
        // The surface transmits

        // Going into the shape.
        ray = ray.refract( mi.normal, mi.shape->material.eta.x, mi.point, transColor ) ;

        // the termination conditions are:
        //  - HIT FREE SPACE OR
        //  - BECOME 0 POWER
        //  - BOUNCE TOO MANY TIMES
        while( ray.bounceNum < window->rtCore->maxBounces &&
               ray.power.len2() > window->rtCore->interreflectionThreshold² )
        {
          // diffract the ray again.
          MeshIntersection causticIntn; 
          if( !window->scene->getClosestIntnMesh( ray, &causticIntn ) )
          {
            // You hit nothing, this is the caustic source direction
            // it is weighed down by
            // form factor that it originally came from
            causticDir = ff * ray.direction ; // the caustic is in the last direction of diffraction.
            transColor = ray.power ; // color remaining in ray after passing thru all that geometry
            break ; // done loop
          }
          
          // otherwise, you hit ANOTHER surface.
          // The refract dir goes from current eta to new eta,
          // if the ray exits the material then the rays face the same way (and it will be turned around automatically)
          // the only case I don't detect is if I hit the backside of a 1-ply surface (eg a leaf).  then the diffraction is backwards,
          // but there's no way to fix this unless you _mark_ a surface as being 1-ply (in which case the normal should always be
          // "against" the incoming ray)
          ray = ray.refract( causticIntn.normal, causticIntn.shape->material.eta.x,
            causticIntn.point, ray.power*causticIntn.getColor(ColorIndex::Transmissive) ) ;

          // if the loop conditions are broken then
          // causticDir remains 0.
        }

        // at this point you hit free space or the contribution is nothing
        // (too many diffractions or power=0)
      }


      // I need also to represent shadow color
      // it's 1-transColor, no need to store that.

      // see if there's already an entry in reflectors
      map< Mesh*,VOVectors >::iterator iter = vertex.voData->reflectors.find( mesh )  ;
      if( iter == vertex.voData->reflectors.end() )
      {
        VOVectors posNNormal ;
        
        // say a shadow comes from the DIRECTION the ray was cast.
        // Nothing to do with the sruface normal.
        posNNormal.shadowDir = ff * dir ; // MUCH BETTER / Sharper
        //posNNormal.normShadow = ff * mi.normal ;  // use the normal.
        
        // If the transColor was 0, no point in adding it.
        if( causticDir.nonzero() )
        {
          // Only add this if the causticDir ended up being nonzero.
          posNNormal.causticDir = causticDir ;
          posNNormal.colorTrans = transColor ;
        }
        
        posNNormal.normDiffuse = diffuseNormal ;
        posNNormal.normSpecular = specularityNormal ;
        
        posNNormal.colorDiffuse = diffuseColor ;
        posNNormal.colorSpecular = specularColor ;
        posNNormal.pos = mi.point ;
        posNNormal.pos.w = 1 ; // set the count at 1
        
        vertex.voData->reflectors.insert( make_pair( mesh, posNNormal ) ) ;
      }
      else
      {
        iter->second.shadowDir += ff * dir ; // MUCH BETTER / Sharper
        //iter->second.normShadow += ff * mi.normal ; 
        if( causticDir.nonzero() )
        {
          iter->second.causticDir += causticDir ;
          iter->second.colorTrans += transColor ;
        }
        iter->second.normDiffuse += diffuseNormal ; // length of the vector will be strength of interreflecn
        iter->second.normSpecular += specularityNormal ; // length of the vector will be strength of interreflecn
        
        iter->second.colorDiffuse += diffuseColor ;
        iter->second.colorSpecular += specularColor ;
        iter->second.pos += mi.point ;  // summed position
        iter->second.pos.w++; // increase the count
      }
    }

    //else { }  // open, but ao already computed on previous pass
  }

  //printf( "FFSUm : %f\n", ffSum ) ;

  // done all gathering.  divide
  for( map< Mesh*,VOVectors >::iterator iter = vertex.voData->reflectors.begin() ;
  iter != vertex.voData->reflectors.end() ; ++iter )
  {
    iter->second.pos /= iter->second.pos.w ;
    // Normals are NOT divided, they are scaled by ao and ff.
    iter->second.colorDiffuse /= iter->second.pos.w ;
    iter->second.colorSpecular /= iter->second.pos.w ;
    iter->second.colorTrans /= iter->second.pos.w ;
    iter->second.pos.w = 1;
  }

}
TEST_F(FluidMediumManager_Test, getTraversedMedia) {
    FluidMediumManager manager(renderer);
    int traversed;
    FluidMediumSegment segments[10];
    class FakeMedium : public FluidMediumInterface {
    public:
        void setCut(double ymin, double ymax) {
            this->ymin = ymin;
            this->ymax = ymax;
        }

        virtual bool checkInfluence(SpaceSegment &segment) const override {
            return segment.intersectYInterval(this->ymin, this->ymax);
        }

    private:
        double ymin = -2.0;
        double ymax = -1.0;
    };
    SpaceSegment ray(Vector3(0.0, 0.0, 0.0), Vector3(8.0, 10.0, -4.0));

    // Empty manager
    traversed = manager.getTraversedMedia(segments, ray, 10);
    ASSERT_EQ(0, traversed);

    // Testing with 1 medium outside the range
    FakeMedium m1;
    manager.registerMedium(&m1);
    traversed = manager.getTraversedMedia(segments, ray, 10);
    ASSERT_EQ(0, traversed);

    // Setting the medium in range
    m1.setCut(1.0, 2.0);
    traversed = manager.getTraversedMedia(segments, ray, 10);
    ASSERT_EQ(1, traversed);
    EXPECT_EQ((FluidMediumInterface *)&m1, segments[0].medium);
    EXPECT_VECTOR3_COORDS(segments[0].segment.getStart(), 0.8, 1.0, -0.4);
    EXPECT_VECTOR3_COORDS(segments[0].segment.getEnd(), 1.6, 2.0, -0.8);

    // Testing with 2 media
    FakeMedium m2;
    m2.setCut(4.0, 12.0);
    manager.registerMedium(&m2);
    traversed = manager.getTraversedMedia(segments, ray, 10);
    ASSERT_EQ(2, traversed);
    EXPECT_EQ((FluidMediumInterface *)&m1, segments[0].medium);
    EXPECT_VECTOR3_COORDS(segments[0].segment.getStart(), 0.8, 1.0, -0.4);
    EXPECT_VECTOR3_COORDS(segments[0].segment.getEnd(), 1.6, 2.0, -0.8);
    EXPECT_EQ((FluidMediumInterface *)&m2, segments[1].medium);
    EXPECT_VECTOR3_COORDS(segments[1].segment.getStart(), 3.2, 4.0, -1.6);
    EXPECT_VECTOR3_COORDS(segments[1].segment.getEnd(), 8.0, 10.0, -4.0);

    // Testing with overlapping media
    FakeMedium m3;
    m3.setCut(3.0, 4.5);
    manager.registerMedium(&m3);
    traversed = manager.getTraversedMedia(segments, ray, 10);
    ASSERT_EQ(3, traversed);
    EXPECT_EQ((FluidMediumInterface *)&m1, segments[0].medium);
    EXPECT_VECTOR3_COORDS(segments[0].segment.getStart(), 0.8, 1.0, -0.4);
    EXPECT_VECTOR3_COORDS(segments[0].segment.getEnd(), 1.6, 2.0, -0.8);
    EXPECT_EQ((FluidMediumInterface *)&m2, segments[1].medium);
    EXPECT_VECTOR3_COORDS(segments[1].segment.getStart(), 3.2, 4.0, -1.6);
    EXPECT_VECTOR3_COORDS(segments[1].segment.getEnd(), 8.0, 10.0, -4.0);
    EXPECT_EQ((FluidMediumInterface *)&m3, segments[2].medium);
    EXPECT_VECTOR3_COORDS(segments[2].segment.getStart(), 2.4, 3.0, -1.2);
    EXPECT_VECTOR3_COORDS(segments[2].segment.getEnd(), 3.6, 4.5, -1.8);

    // Testing the segment count limit
    traversed = manager.getTraversedMedia(segments, ray, 2);
    ASSERT_EQ(2, traversed);
    EXPECT_EQ((FluidMediumInterface *)&m1, segments[0].medium);
    EXPECT_EQ((FluidMediumInterface *)&m2, segments[1].medium);

    // Testing after clear
    manager.clearMedia();
    traversed = manager.getTraversedMedia(segments, ray, 10);
    ASSERT_EQ(0, traversed);
}
Exemple #23
0
void Raycaster::wavelet_Stage2_Interreflection( AllVertex& vertex )
{
  // at each vertex, shoot rays and see what other polygons you hit.
  int si = randInt( 0, rc->n ) ;
  for( int j = 0 ; j < window->shSamps->nU ; j++ )
  {
    Vector &sampdir = rc->vAddr( si+j ) ;

    real dot = sampdir • vertex.norm ;
    if( dot < 0 )  continue ; // angle is obtuse, don't use it

    // Here ray ok to use
    Ray ray( vertex.pos + EPS_MIN*vertex.norm, sampdir, 1000 ) ;
    
    // shoot the ray in this direction using the raytracer
    Shape* closestShape=0 ;
    MeshIntersection intn ;
        
    // Force use the mesh. This is important because we need a mesh intersection only
    if( window->scene->getClosestIntnMesh( ray, &intn ) )
    {
      // Now that it hits some poly..

      // see angle of ray's direction with ___point I hit's___ normal.
      real dot = - (ray.direction • intn.normal) ;

      if( dot > 0 ) // acceptable
      {
        // Use the barycentric coordinates of the intersection
        // to produce a NEW WAVELET (temp) function AT THAT POINT, (weight the
        // wavelet function at the surrounding vertices).
        Eigen::SparseVector<Vector> newWavelet ;

        #if 0
        // Get the 3 wavelet functions that will be blended,
        // FROM THE REMOTE MESH THAT YOU JUST HIT WITH THE FEELER RAY
        CubeMap* senderCubemap = intn.getMesh()->verts[ intn.tri->iA ].cubeMap ;
        
        // this doesn't work, though i think it should: (I hate eigen)
        //Eigen::SparseVector<Vector> waveletA = intn.getMesh()->verts[ intn.tri->iA ].cubeMap->sparseTransformedColor * ( intn.bary.x ) ;
        //Eigen::SparseVector<Vector> waveletB = intn.getMesh()->verts[ intn.tri->iB ].cubeMap->sparseTransformedColor * ( intn.bary.y ) ;
        //Eigen::SparseVector<Vector> waveletC = intn.getMesh()->verts[ intn.tri->iC ].cubeMap->sparseTransformedColor * ( intn.bary.z ) ;

        // SCALE DOWN the rgb components by your ability 
        // (at local/sending mesh) to REFLECT LIGHT on each band.
        Vector m = dot * window->shSamps->dotScaleFactor * vertex.color[ ColorIndex::DiffuseMaterial ] ;
        
        Eigen::SparseVector<Vector> waveletA, waveletB, waveletC ;
        for( Eigen::SparseVector<Vector>::InnerIterator it( senderCubemap->sparseTransformedColor ); it; ++it )
        {
          waveletA.insert( it.index() ) = m*intn.bary.x*it.value() ; //printf( "v1[ %d ] = %f\n", it.index(), it.value() ) ;
          waveletB.insert( it.index() ) = m*intn.bary.y*it.value() ;
          waveletC.insert( it.index() ) = m*intn.bary.z*it.value() ;
        }

        // that's the interreflection
        vertex.cubeMap->newSparseTransformedColor += (waveletA + waveletB + waveletC) ;
        #else
        CubeMap* scA = intn.getMesh()->verts[ intn.tri->iA ].cubeMap ;
        CubeMap* scB = intn.getMesh()->verts[ intn.tri->iB ].cubeMap ;
        CubeMap* scC = intn.getMesh()->verts[ intn.tri->iC ].cubeMap ;

        Vector m = dot * window->shSamps->dotScaleFactor * vertex.color[ ColorIndex::DiffuseMaterial ] ;
        
        Eigen::SparseVector<Vector> waveletA, waveletB, waveletC ;
        for( Eigen::SparseVector<Vector>::InnerIterator it( scA->sparseTransformedColor ); it; ++it )
          waveletA.insert( it.index() ) = m*intn.bary.x*it.value() ;

        for( Eigen::SparseVector<Vector>::InnerIterator it( scB->sparseTransformedColor ); it; ++it )
          waveletB.insert( it.index() ) = m*intn.bary.y*it.value() ;
         
        for( Eigen::SparseVector<Vector>::InnerIterator it( scC->sparseTransformedColor ); it; ++it )
          waveletC.insert( it.index() ) = m*intn.bary.z*it.value() ;

        // that's the interreflection
        vertex.cubeMap->newSparseTransformedColor += (waveletA + waveletB + waveletC) ;
        #endif
        
      } else { } // dot < 0
    } else { } // ray didn't even hit the aabb, so total miss
  } // end raycast

  /////info( "sh2::finished %d->%d of %s", startVertex, endVertex, shape->name.c_str() ) ;
}
Exemple #24
0
Spectrum IrradianceCache::IndirectLo(const Point &p,
		const Normal &n, const Vector &wo, BSDF *bsdf,
		BxDFType flags, const Sample *sample,
		const Scene *scene) const {
	if (bsdf->NumComponents(flags) == 0)
		return Spectrum(0.);
	Spectrum E;
	if (!InterpolateIrradiance(scene, p, n, &E)) {
		// Compute irradiance at current point
		u_int scramble[2] = { RandomUInt(), RandomUInt() };
		float sumInvDists = 0.;
		for (int i = 0; i < nSamples; ++i) {
			// Trace ray to sample radiance for irradiance estimate
			// Update irradiance statistics for rays traced
			static StatsCounter nIrradiancePaths("Irradiance Cache",
				"Paths followed for irradiance estimates");
			++nIrradiancePaths;
			float u[2];
			Sample02(i, scramble, u);
			Vector w = CosineSampleHemisphere(u[0], u[1]);
			RayDifferential r(p, bsdf->LocalToWorld(w));
			if (Dot(r.d, n) < 0) r.d = -r.d;
			Spectrum L(0.);
			// Do path tracing to compute radiance along ray for estimate
			{
			// Declare common path integration variables
			Spectrum pathThroughput = 1.;
			RayDifferential ray(r);
			bool specularBounce = false;
			for (int pathLength = 0; ; ++pathLength) {
				// Find next vertex of path
				Intersection isect;
				if (!scene->Intersect(ray, &isect))
					break;
				if (pathLength == 0)
					r.maxt = ray.maxt;
				pathThroughput *= scene->Transmittance(ray);
				// Possibly add emitted light at path vertex
				if (specularBounce)
					L += pathThroughput * isect.Le(-ray.d);
				// Evaluate BSDF at hit point
				BSDF *bsdf = isect.GetBSDF(ray);
				// Sample illumination from lights to find path contribution
				const Point &p = bsdf->dgShading.p;
				const Normal &n = bsdf->dgShading.nn;
				Vector wo = -ray.d;
				L += pathThroughput *
					UniformSampleOneLight(scene, p, n, wo, bsdf, sample);
				if (pathLength+1 == maxIndirectDepth) break;
				// Sample BSDF to get new path direction
				// Get random numbers for sampling new direction, \mono{bs1}, \mono{bs2}, and \mono{bcs}
				float bs1 = RandomFloat(), bs2 = RandomFloat(), bcs = RandomFloat();
				Vector wi;
				float pdf;
				BxDFType flags;
				Spectrum f = bsdf->Sample_f(wo, &wi, bs1, bs2, bcs,
					&pdf, BSDF_ALL, &flags);
				if (f.Black() || pdf == 0.)
					break;
				specularBounce = (flags & BSDF_SPECULAR) != 0;
				pathThroughput *= f * AbsDot(wi, n) / pdf;
				ray = RayDifferential(p, wi);
				// Possibly terminate the path
				if (pathLength > 3) {
					float continueProbability = .5f;
					if (RandomFloat() > continueProbability)
						break;
					pathThroughput /= continueProbability;
				}
			}
			}
			E += L;
			float dist = r.maxt * r.d.Length();
			sumInvDists += 1.f / dist;
		}
		E *= M_PI / float(nSamples);
		// Add computed irradiance value to cache
		// Update statistics for new irradiance sample
		static StatsCounter nSamplesComputed("Irradiance Cache",
			"Irradiance estimates computed");
		++nSamplesComputed;
		// Compute bounding box of irradiance sample's contribution region
		static float minMaxDist =
			.001f * powf(scene->WorldBound().Volume(), 1.f/3.f);
		static float maxMaxDist =
			.125f * powf(scene->WorldBound().Volume(), 1.f/3.f);
		float maxDist = nSamples / sumInvDists;
		if (minMaxDist > 0.f)
			maxDist = Clamp(maxDist, minMaxDist, maxMaxDist);
		maxDist *= maxError;
		BBox sampleExtent(p);
		sampleExtent.Expand(maxDist);
		octree->Add(IrradianceSample(E, p, n, maxDist),
			sampleExtent);
	}
	return .5f * bsdf->rho(wo, flags) * E;
}
Exemple #25
0
void parse()	{ int baza=-1;
	bin[n++]=SYM; putch(' ');
	putch('\b'); putch('R'); // Radix sort
	memset(r,0,sizeof(trax));
	memset(rc,0,sizeof(trax));
	memset(bin+n,0xFF,TERM);
	//memset(p,0,n*4);
	for(i=0; i<n-2; i++)	{ r[bin[i]]++;
		if(bin[i] > bin[i+1])	{
			if(bin[i+1] > bin[i+2])
				rc[bin[i]]++;
			else r[bin[++i]]++;
		}	
	}//offset count
	for(i=0,ch=0; ch<=256; ch++)	{
		i+=r[ch],  r[ch] = i-r[ch];
		ra[ch] = r[ch];
		rc[ch] += r[ch];
		rb[ch] = rc[ch];
	}//shifting...
	for(i=0; i<n; i++)
		if(bin[i] > bin[i+1]  &&  bin[i+1] <= bin[i+2])
			(p[rc[bin[i]]++]=i, i++);
	putch('\b'); putch('D'); // Direct sort
	for(ch=0; ch<256; ch++)	{
		//part 2: (x)>y<=z
		if(STATS) w1 += rc[ch]-rb[ch];
		ray(rb[ch],rc[ch],bin+1);
	}
	putch('\b'); putch('W'); //Final waves
	for(ch=0; ch<256; ch++)	{
		//part 1: (x)>y>z
		j=rc[ch]; i=r[ch];
		for(; i<rc[ch]; i++)	{
			if(!p[i]) continue;
			sym = bin[p[i]-1];
			if(sym > ch)	{
				while(bin[p[rb[sym]]+1] < ch  &&  rb[sym] < rc[sym])
					p[ra[sym]++] = p[rb[sym]++];
				p[ra[sym]++] = p[i]-1;
			}else
			if(sym == ch)
				p[j++] = p[i]-1;
		}
		//part 3: (x)=y>=z
		for(; i<j; i++)
			if(p[i]  &&  bin[p[i]-1] == ch)
				p[j++] = p[i]-1;
		rc[ch] = j;
		ra[ch] = r[ch+1];
	}
	p[--ra[bin[n-1]]] = n-1;
	putc(bin[n-1],fo);
	for(ch=255; ch>=0; ch--)
		for(i=r[ch+1]-1; i>=r[ch]; i--)	{
			if(!p[i])	{
				putc(SYM,fo);
				baza = i; continue;
			}//finish it
			sym = bin[p[i]-1];
			putc(sym,fo);
			if(sym <= ch)
				p[--ra[sym]] = p[i]-1;
		}
	fwrite(&baza,4,1,fo);
}
Exemple #26
0
	void Agent::UpdateSensors(std::vector<Clarity::LineSegment2> polySections)
	{
		// I could do this section in a for loop and make it nice and clean...
		// Or I could unwrap the loop and be explicit about whats hapenning with the tests.
		// Im going to choose the latter...

		// Clear intersection depths.
		for (unsigned int i = 0; i < FEELER_COUNT; i++)
		{
			intersectionDepths[i] = FEELER_LENGTH;
		}


		// --------------------------------------------------------------------------------
		Clarity::Ray2 ray(Clarity::Vector2::ZERO, Clarity::Vector2::UNIT_X);
		float distance = 0;
		float bestDistance = 999999.0f; // Very large number for best distance tests...
		// --------------------------------------------------------------------------------

		
		// --------------------------------------------------------------------------------
		// EAST Feeler.
		ray.Set(position, sensor.feelers[FEELER_EAST]);
		for (unsigned int i = 0; i < polySections.size(); i++)
		{
			if (Clarity::Intersects(polySections[i], true, ray, &distance))
			{
				if (distance <= CarDemo::FEELER_LENGTH)
				{
					bestDistance =  distance;
				}
			}
		}

		if (bestDistance <= FEELER_LENGTH)
		{
			this->intersectionDepths[FEELER_EAST] = bestDistance;
		}
		// --------------------------------------------------------------------------------

		distance = 0;
		bestDistance = 999999.0f;
		// --------------------------------------------------------------------------------
		// NORTH_EAST Feeler.
		ray.Set(position, sensor.feelers[FEELER_NORTH_EAST]);
		for (unsigned int i = 0; i < polySections.size(); i++)
		{
			if (Clarity::Intersects(polySections[i], true, ray, &distance))
			{
				if (distance <= CarDemo::FEELER_LENGTH)
				{
					bestDistance =  distance;
				}
			}
		}

		if (bestDistance <= FEELER_LENGTH)
		{
			this->intersectionDepths[FEELER_NORTH_EAST] = bestDistance;
		}
		// --------------------------------------------------------------------------------

		distance = 0;
		bestDistance = 999999.0f;
		// --------------------------------------------------------------------------------
		// NORTH Feeler.
		ray.Set(position, sensor.feelers[FEELER_NORTH]);
		for (unsigned int i = 0; i < polySections.size(); i++)
		{

			if (Clarity::Intersects(polySections[i], true, ray, &distance))
			{
				if (distance <= CarDemo::FEELER_LENGTH)
				{
					bestDistance =  distance;
				}
			}
		}

		if (bestDistance <= FEELER_LENGTH)
		{
			this->intersectionDepths[FEELER_NORTH] = bestDistance;
		}
		// --------------------------------------------------------------------------------

		distance = 0;
		bestDistance = 999999.0f;
		// --------------------------------------------------------------------------------
		// NORTH WEST Feeler.
		ray.Set(position, sensor.feelers[FEELER_NORTH_WEST]);
		for (unsigned int i = 0; i < polySections.size(); i++)
		{
			if (Clarity::Intersects(polySections[i], true, ray, &distance))
			{
				if (distance <= CarDemo::FEELER_LENGTH)
				{
					bestDistance = distance;
				}
			}
		}

		if (bestDistance <= FEELER_LENGTH)
		{
			this->intersectionDepths[FEELER_NORTH_WEST] = bestDistance;
		}
		// --------------------------------------------------------------------------------

		distance = 0;
		bestDistance = 999999.0f;
		// --------------------------------------------------------------------------------
		// WEST Feeler.
		ray.Set(position, sensor.feelers[FEELER_WEST]);
		for (unsigned int i = 0; i < polySections.size(); i++)
		{

			if (Clarity::Intersects(polySections[i], true, ray, &distance))
			{
				if (distance <= CarDemo::FEELER_LENGTH)
				{
					bestDistance = distance;
				}
			}
		}

		if (bestDistance <= FEELER_LENGTH)
		{
			this->intersectionDepths[FEELER_WEST] = bestDistance;
		}
		// --------------------------------------------------------------------------------
	}
void dgCollisionScene::CollidePair (dgCollidingPairCollector::dgPair* const pair, dgCollisionParamProxy& proxy) const
{
	const dgNodeBase* stackPool[DG_COMPOUND_STACK_DEPTH];

	dgAssert (proxy.m_contactJoint == pair->m_contact);
	dgContact* const constraint = pair->m_contact;

	dgBody* const otherBody = constraint->GetBody0();
	dgBody* const sceneBody = constraint->GetBody1();
	dgAssert (sceneBody->GetCollision()->GetChildShape() == this);
	dgAssert (sceneBody->GetCollision()->IsType(dgCollision::dgCollisionScene_RTTI));

	dgCollisionInstance* const sceneInstance = sceneBody->m_collision;
	dgCollisionInstance* const otherInstance = otherBody->m_collision;

	dgAssert (sceneInstance->GetChildShape() == this);
	dgAssert (otherInstance->IsType (dgCollision::dgCollisionConvexShape_RTTI));

	const dgContactMaterial* const material = constraint->GetMaterial();

	const dgMatrix& myMatrix = sceneInstance->GetGlobalMatrix();
	const dgMatrix& otherMatrix = otherInstance->GetGlobalMatrix();
	dgMatrix matrix (otherMatrix * myMatrix.Inverse());

	const dgVector& hullVeloc = otherBody->m_veloc;
	dgFloat32 baseLinearSpeed = dgSqrt (hullVeloc % hullVeloc);

	dgFloat32 closestDist = dgFloat32 (1.0e10f);
	if (proxy.m_continueCollision && (baseLinearSpeed > dgFloat32 (1.0e-6f))) {
		dgVector p0;
		dgVector p1;
		otherInstance->CalcAABB (matrix, p0, p1);

		const dgVector& hullOmega = otherBody->m_omega;

		dgFloat32 minRadius = otherInstance->GetBoxMinRadius();
		dgFloat32 maxAngularSpeed = dgSqrt (hullOmega % hullOmega);
		dgFloat32 angularSpeedBound = maxAngularSpeed * (otherInstance->GetBoxMaxRadius() - minRadius);

		dgFloat32 upperBoundSpeed = baseLinearSpeed + dgSqrt (angularSpeedBound);
		dgVector upperBoundVeloc (hullVeloc.Scale3 (proxy.m_timestep * upperBoundSpeed / baseLinearSpeed));

		dgVector boxDistanceTravelInMeshSpace (myMatrix.UnrotateVector(upperBoundVeloc.CompProduct4(otherInstance->m_invScale)));

		dgInt32 stack = 1;
		stackPool[0] = m_root;
		dgFastRayTest ray (dgVector (dgFloat32 (0.0f)), boxDistanceTravelInMeshSpace);

		while (stack) {
			stack--;
			const dgNodeBase* const me = stackPool[stack];
			dgAssert (me);

			if (me->BoxIntersect (ray, p0, p1)) {
				if (me->m_type == m_leaf) {
					dgAssert (!me->m_right);
					bool processContacts = true;
					if (material->m_compoundAABBOverlap) {
						processContacts = material->m_compoundAABBOverlap (*material, sceneBody, me->m_myNode, otherBody, NULL, proxy.m_threadIndex);
					}

					if (processContacts) {
						const dgCollisionInstance* const myInstance =  me->GetShape();
						dgCollisionInstance childInstance (*myInstance, myInstance->GetChildShape());
						childInstance.SetGlobalMatrix(childInstance.GetLocalMatrix() * myMatrix);
						proxy.m_floatingCollision = &childInstance;
						dgInt32 count = pair->m_contactCount;
						m_world->SceneChildContacts (pair, proxy);
						if (pair->m_contactCount > count) {
							dgContactPoint* const buffer = proxy.m_contacts;
							for (dgInt32 i = count; i < pair->m_contactCount; i ++) {
								dgAssert (buffer[i].m_collision0 == proxy.m_referenceCollision);
								//if (buffer[i].m_collision1 == proxy.m_floatingCollision) {
								//	buffer[i].m_collision1 = myInstance;
								//}
								if (buffer[i].m_collision1->GetChildShape() == myInstance->GetChildShape()) {
									buffer[i].m_collision1 = myInstance;
								}
							}
						}
						closestDist = dgMin(closestDist, constraint->m_closestDistance);
					}

				} else {
					dgAssert (me->m_type == m_node);
					stackPool[stack] = me->m_left;
					stack++;
					dgAssert (stack < dgInt32 (sizeof (stackPool) / sizeof (dgNodeBase*)));

					stackPool[stack] = me->m_right;
					stack++;
					dgAssert (stack < dgInt32 (sizeof (stackPool) / sizeof (dgNodeBase*)));
				}
			}
		}

	} else {
		dgVector origin;
		dgVector size;


		otherInstance->CalcObb(origin, size);
		dgOOBBTestData data (matrix, origin, size);
		dgInt32 stack = 1;
		stackPool[0] = m_root;
		while (stack) {

			stack --;
			const dgNodeBase* const me = stackPool[stack];
			dgAssert (me);

			if (me->BoxTest (data)) {
				if (me->m_type == m_leaf) {
					dgAssert (!me->m_right);
					bool processContacts = true;
					if (material->m_compoundAABBOverlap) {
						processContacts = material->m_compoundAABBOverlap (*material, sceneBody, me->m_myNode, otherBody, NULL, proxy.m_threadIndex);
					}

					if (processContacts) {
						const dgCollisionInstance* const myInstance =  me->GetShape();
						dgCollisionInstance childInstance (*myInstance, myInstance->GetChildShape());
						childInstance.SetGlobalMatrix(childInstance.GetLocalMatrix() * myMatrix);
						proxy.m_floatingCollision = &childInstance;
						dgInt32 count = pair->m_contactCount;
						m_world->SceneChildContacts (pair, proxy);
						if (pair->m_contactCount > count) {
							dgContactPoint* const buffer = proxy.m_contacts;
							for (dgInt32 i = count; i < pair->m_contactCount; i ++) {
								dgAssert (buffer[i].m_collision0 == proxy.m_referenceCollision);
								//if (buffer[i].m_collision1 == proxy.m_floatingCollision) {
								//	buffer[i].m_collision1 = myInstance;
								//}
								if (buffer[i].m_collision1->GetChildShape() == myInstance->GetChildShape()) {
									buffer[i].m_collision1 = myInstance;
								}
							}
						} else if (pair->m_contactCount == -1) {
							break;
						}
						closestDist = dgMin(closestDist, constraint->m_closestDistance);
					}

				} else {
					dgAssert (me->m_type == m_node);
					stackPool[stack] = me->m_left;
					stack++;
					dgAssert (stack < dgInt32 (sizeof (stackPool) / sizeof (dgNodeBase*)));

					stackPool[stack] = me->m_right;
					stack++;
					dgAssert (stack < dgInt32 (sizeof (stackPool) / sizeof (dgNodeBase*)));
				}
			}
		}
	}
	constraint->m_closestDistance = closestDist;
}
Exemple #28
0
/***************************************************************************//*!
 * @brief Raycast from a point in to the scene.
 * @param[in] point		Point to analyse
 * @param[in] normal		Direction
 * @param[out] result	Result ( ONLY if return TRUE )
 * @return TRUE if somethings found => {result} NOT EMPTY
 */
bool OgreMeshRay::raycastFromPoint(const Ogre::Vector3& point,
		const Ogre::Vector3& normal, Ogre::Vector3& result,
		std::string entityName) {
	// create the ray to test
	Ogre::Ray ray(point, normal);

	if (!m_raySceneQuery)
		return false;

	// create a query object
	m_raySceneQuery->setRay(ray);

	// execute the query, returns a vector of hits
	if (m_raySceneQuery->execute().size() <= 0) {
		// raycast did not hit an objects bounding box
		return false;
	}

	// at this point we have raycast to a series of different objects bounding boxes.
	// we need to test these different objects to see which is the first polygon hit.
	// there are some minor optimizations (distance based) that mean we wont have to
	// check all of the objects most of the time, but the worst case scenario is that
	// we need to test every triangle of every object.
	Ogre::Real closest_distance = -1.0f;
	Ogre::Vector3 closest_result;
	Ogre::RaySceneQueryResult& query_result = m_raySceneQuery->getLastResults();
	for (size_t qr_idx = 0, size = query_result.size(); qr_idx < size;
			++qr_idx) {
		// stop checking if we have found a raycast hit that is closer
		// than all remaining entities
		if (closest_distance >= 0.0f
				&& closest_distance < query_result[qr_idx].distance)
			break;

		// only check this result if its a hit against an entity
		if (query_result[qr_idx].movable) {
			if (entityName != ""
					&& query_result[qr_idx].movable->getName() != entityName) {
				std::cout << query_result[qr_idx].movable->getName()
						<< "is not " << entityName << std::endl;
				continue;
			}
			std::cout << query_result[qr_idx].movable->getName() << "is truly "
					<< entityName << std::endl;
			const std::string& movableType =
					query_result[qr_idx].movable->getMovableType();
			// mesh data to retrieve
			size_t vertex_count;
			size_t index_count;
			Ogre::Vector3* vertices;
			unsigned long* indices;

			if (movableType == "ManualObject") {
				// get the entity to check
				Ogre::ManualObject* pentity =
						static_cast<Ogre::ManualObject*>(query_result[qr_idx].movable);
				// get the mesh information
				GetMeshInformation(pentity, vertex_count, vertices, index_count,
						indices,
						pentity->getParentNode()->_getDerivedPosition(),
						pentity->getParentNode()->_getDerivedOrientation(),
						pentity->getParentNode()->_getDerivedScale());
			} else if (movableType == "Entity") {
				// get the entity to check
				Ogre::Entity *pentity =
						static_cast<Ogre::Entity*>(query_result[qr_idx].movable);
				// get the mesh information
				GetMeshInformation(pentity, vertex_count, vertices, index_count,
						indices,
						pentity->getParentNode()->_getDerivedPosition(),
						pentity->getParentNode()->_getDerivedOrientation(),
						pentity->getParentNode()->_getDerivedScale());
			} else {
				continue;
			}

			// test for hitting individual triangles on the mesh
			bool new_closest_found = false;
			for (int i = 0; i < static_cast<int>(index_count); i += 3) {
				// check for a hit against this triangle
				std::pair<bool, Ogre::Real> hit = Ogre::Math::intersects(ray,
						vertices[indices[i]], vertices[indices[i + 1]],
						vertices[indices[i + 2]], true, false);

				// if it was a hit check if its the closest
				if (hit.first
						&& (closest_distance < 0.0f
								|| hit.second < closest_distance)) {
					// this is the closest so far, save it off
					closest_distance = hit.second;
					new_closest_found = true;
				}
			}

			// free the verticies and indicies memory
			delete[] vertices;
			delete[] indices;

			// if we found a new closest raycast for this object, update the
			// closest_result before moving on to the next object.
			if (new_closest_found)
				closest_result = ray.getPoint(closest_distance);
		}
	}

	// return the result
	if (closest_distance >= 0.0f) {
		// raycast success
		result = closest_result;
		return true;
	}
	// raycast failed
	return false;
}
Exemple #29
0
size_t generateVPLs(const Scene *scene, Random *random,
		size_t offset, size_t count, int maxDepth, bool prune, std::deque<VPL> &vpls) {
	if (maxDepth <= 1)
		return 0;

	static Sampler *sampler = NULL;
	if (!sampler) {
		Properties props("halton");
		props.setInteger("scramble", 0);
		sampler = static_cast<Sampler *> (PluginManager::getInstance()->
			createObject(MTS_CLASS(Sampler), props));
		sampler->configure();
	}

	const Sensor *sensor = scene->getSensor();
	Float time = sensor->getShutterOpen()
		+ 0.5f * sensor->getShutterOpenTime();

	const Frame stdFrame(Vector(1,0,0), Vector(0,1,0), Vector(0,0,1));

	while (vpls.size() < count) {
		sampler->setSampleIndex(++offset);

		PositionSamplingRecord pRec(time);
		DirectionSamplingRecord dRec;
		Spectrum weight = scene->sampleEmitterPosition(pRec,
			sampler->next2D());

		size_t start = vpls.size();

		/* Sample an emitted particle */
		const Emitter *emitter = static_cast<const Emitter *>(pRec.object);

		if (!emitter->isEnvironmentEmitter() && emitter->needsDirectionSample()) {
			VPL lumVPL(EPointEmitterVPL, weight);
			lumVPL.its.p = pRec.p;
			lumVPL.its.shFrame = pRec.n.isZero() ? stdFrame : Frame(pRec.n);
			lumVPL.emitter = emitter;
			appendVPL(scene, random, lumVPL, prune, vpls);

			weight *= emitter->sampleDirection(dRec, pRec, sampler->next2D());
		} else {
			/* Hack to get the proper information for directional VPLs */
			DirectSamplingRecord diRec(
				scene->getKDTree()->getAABB().getCenter(), pRec.time);

			Spectrum weight2 = emitter->sampleDirect(diRec, sampler->next2D())
				/ scene->pdfEmitterDiscrete(emitter);

			if (weight2.isZero())
				continue;

			VPL lumVPL(EDirectionalEmitterVPL, weight2);
			lumVPL.its.p = Point(0.0);
			lumVPL.its.shFrame = Frame(-diRec.d);
			lumVPL.emitter = emitter;
			appendVPL(scene, random, lumVPL, false, vpls);
			dRec.d = -diRec.d;

			Point2 offset = Warp::squareToUniformDiskConcentric(sampler->next2D());
			Vector perpOffset = Frame(diRec.d).toWorld(Vector(offset.x, offset.y, 0));
			BSphere geoBSphere = scene->getKDTree()->getAABB().getBSphere();
			pRec.p = geoBSphere.center + (perpOffset - dRec.d) * geoBSphere.radius;
			weight = weight2 * M_PI * geoBSphere.radius * geoBSphere.radius;
		}

		int depth = 2;
		Ray ray(pRec.p, dRec.d, time);
		Intersection its;

		while (!weight.isZero() && (depth < maxDepth || maxDepth == -1)) {
			if (!scene->rayIntersect(ray, its))
				break;

			const BSDF *bsdf = its.getBSDF();
			BSDFSamplingRecord bRec(its, sampler, EImportance);
			Spectrum bsdfVal = bsdf->sample(bRec, sampler->next2D());
			if (bsdfVal.isZero())
				break;

			/* Assuming that BSDF importance sampling is perfect,
				the following should equal the maximum albedo
				over all spectral samples */
			Float approxAlbedo = std::min((Float) 0.95f, bsdfVal.max());
			if (sampler->next1D() > approxAlbedo)
				break;
			else
				weight /= approxAlbedo;

			VPL vpl(ESurfaceVPL, weight);
			vpl.its = its;

			if (BSDF::getMeasure(bRec.sampledType) == ESolidAngle)
				appendVPL(scene, random, vpl, prune, vpls);

			weight *= bsdfVal;

			Vector wi = -ray.d, wo = its.toWorld(bRec.wo);
			ray = Ray(its.p, wo, 0.0f);

			/* Prevent light leaks due to the use of shading normals -- [Veach, p. 158] */
			Float wiDotGeoN = dot(its.geoFrame.n, wi),
				woDotGeoN = dot(its.geoFrame.n, wo);
			if (wiDotGeoN * Frame::cosTheta(bRec.wi) <= 0 ||
				woDotGeoN * Frame::cosTheta(bRec.wo) <= 0)
				break;

			/* Disabled for now -- this increases VPL weights
			   and accuracy is not really a big requirement */
			#if 0
				/* Adjoint BSDF for shading normals -- [Veach, p. 155] */
				weight *= std::abs(
					(Frame::cosTheta(bRec.wi) * woDotGeoN)/
					(Frame::cosTheta(bRec.wo) * wiDotGeoN));
			#endif

			++depth;
		}

		size_t end = vpls.size();
		for (size_t i=start; i<end; ++i)
			vpls[i].emitterScale = 1.0f / (end - start);
	}

	return offset;
}
Exemple #30
0
// PathIntegrator Method Definitions
Spectrum PathIntegrator::Li(const RayDifferential &r, const Scene &scene,
                            Sampler &sampler, MemoryArena &arena) const {
    Spectrum L(0.f);
    // Declare common path integration variables
    RayDifferential ray(r);
    Spectrum pathThroughput = Spectrum(1.f);
    bool specularBounce = false;
    for (int bounces = 0;; ++bounces) {
        // Store intersection into _isect_
        SurfaceInteraction isect;
        bool foundIntersection = scene.Intersect(ray, &isect);

        // Possibly add emitted light and terminate
        if (bounces == 0 || specularBounce) {
            // Add emitted light at path vertex or from the environment
            if (foundIntersection)
                L += pathThroughput * isect.Le(-ray.d);
            else
                for (const auto &light : scene.lights)
                    L += pathThroughput * light->Le(ray);
        }
        if (!foundIntersection || bounces >= maxDepth) break;

        // Compute scattering functions and skip over medium boundaries
        isect.ComputeScatteringFunctions(ray, arena, true);
        if (!isect.bsdf) {
            ray = isect.SpawnRay(ray.d);
            bounces--;
            continue;
        }

        // Sample illumination from lights to find path contribution
        L += pathThroughput *
             UniformSampleOneLight(isect, scene, sampler, arena);

        // Sample BSDF to get new path direction
        Vector3f wo = -ray.d, wi;
        Float pdf;
        BxDFType flags;
        Spectrum f = isect.bsdf->Sample_f(wo, &wi, sampler.Get2D(), &pdf,
                                          BSDF_ALL, &flags);

        if (f.IsBlack() || pdf == 0.f) break;
        pathThroughput *= f * AbsDot(wi, isect.shading.n) / pdf;
#ifndef NDEBUG
        Assert(std::isinf(pathThroughput.y()) == false);
#endif
        specularBounce = (flags & BSDF_SPECULAR) != 0;
        ray = isect.SpawnRay(wi);

        // Account for subsurface scattering, if applicable
        if (isect.bssrdf && (flags & BSDF_TRANSMISSION)) {
            // Importance sample the BSSRDF
            BSSRDFSample bssrdfSample;
            bssrdfSample.uDiscrete = sampler.Get1D();
            bssrdfSample.pos = sampler.Get2D();
            SurfaceInteraction isect_out = isect;
            pathThroughput *= isect.bssrdf->Sample_f(
                isect_out, scene, ray.time, bssrdfSample, arena, &isect, &pdf);
#ifndef NDEBUG
            Assert(std::isinf(pathThroughput.y()) == false);
#endif
            if (pathThroughput.IsBlack()) break;

            // Account for the direct subsurface scattering component
            isect.wo = Vector3f(isect.shading.n);

            // Sample illumination from lights to find path contribution
            L += pathThroughput *
                 UniformSampleOneLight(isect, scene, sampler, arena);

            // Account for the indirect subsurface scattering component
            Spectrum f = isect.bsdf->Sample_f(isect.wo, &wi, sampler.Get2D(),
                                              &pdf, BSDF_ALL, &flags);
            if (f.IsBlack() || pdf == 0.f) break;
            pathThroughput *= f * AbsDot(wi, isect.shading.n) / pdf;
#ifndef NDEBUG
            Assert(std::isinf(pathThroughput.y()) == false);
#endif
            specularBounce = (flags & BSDF_SPECULAR) != 0;
            ray = isect.SpawnRay(wi);
        }

        // Possibly terminate the path
        if (bounces > 3) {
            Float continueProbability = std::min((Float).5, pathThroughput.y());
            if (sampler.Get1D() > continueProbability) break;
            pathThroughput /= continueProbability;
            Assert(std::isinf(pathThroughput.y()) == false);
        }
    }
    return L;
}