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); }
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; }
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); } }
/** 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 */
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); }
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; }
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()); } } } } }
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(); } } }
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; }
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 ); } } }
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; }
/** * 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; }
// 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; }
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; }
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); }
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() ) ; }
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; }
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); }
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; }
/***************************************************************************//*! * @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; }
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; }
// 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; }