GeometryRayTestResult Intersects(const AxisAlignedBox& Box, const Ray& Cast) { // Code in this function is based on the equivalent in Ogre Vector3 CastDir = Cast.GetNormal(); Vector3 AbsoluteDir = CastDir; AbsoluteDir.X = MathTools::Abs( AbsoluteDir.X ); AbsoluteDir.Y = MathTools::Abs( AbsoluteDir.Y ); AbsoluteDir.Z = MathTools::Abs( AbsoluteDir.Z ); // A small fixed sized constant time sorting algorithm for sorting the length of each axis. Whole MaxAxis = 0, MidAxis = 1, MinAxis = 2; if( AbsoluteDir[0] < AbsoluteDir[2] ) { MaxAxis = 2; MinAxis = 1; }else if( AbsoluteDir[1] < AbsoluteDir[MinAxis] ) { MidAxis = MinAxis; MinAxis = 1; }else if( AbsoluteDir[1] > AbsoluteDir[MaxAxis] ) { MidAxis = MaxAxis; MaxAxis = 1; } if(IsInside(Box,Cast.Origin)) { Vector3 Intersects; Intersects[MinAxis] = 0; Intersects[MidAxis] = 0; Intersects[MaxAxis] = 1; /*Plane Side(Intersects,) if(CastDir[MaxAxis]>0) { }else{ } return GeometryRayTestResult(true,Ray(,Vector3));*/ } SegmentPosPair Distances(0,std::numeric_limits<Real>::infinity()); ::CalculateAxis(MaxAxis,Cast,Box,Distances); if( AbsoluteDir[MidAxis] < std::numeric_limits<Real>::epsilon() ) { if( Cast.GetOrigin()[MidAxis] < Box.MinExt[MidAxis] || Cast.GetOrigin()[MidAxis] > Box.MaxExt[MidAxis] || Cast.GetOrigin()[MinAxis] < Box.MinExt[MinAxis] || Cast.GetOrigin()[MinAxis] > Box.MaxExt[MinAxis] ) { return GeometryRayTestResult(false,Ray()); } }else{ ::CalculateAxis(MidAxis,Cast,Box,Distances); if( AbsoluteDir[MinAxis] < std::numeric_limits<Real>::epsilon() ) { if( Cast.GetOrigin()[MinAxis] < Box.MinExt[MinAxis] || Cast.GetOrigin()[MinAxis] > Box.MaxExt[MinAxis] ) { return GeometryRayTestResult(false,Ray()); } }else{ ::CalculateAxis(MinAxis,Cast,Box,Distances); } } Ray Ret( Cast.GetOrigin() + (CastDir * Distances.first), Cast.GetOrigin() + (CastDir * Distances.second) ); return GeometryRayTestResult(true,Ret); }
bool parseRay(Ray &ray, TiXmlElement* config) { ray.clear(); ray.type = VisualSensor::RAY; TiXmlElement *horizontal = config->FirstChildElement("horizontal"); if (horizontal) { const char* samples_char = horizontal->Attribute("samples"); if (samples_char) { try { ray.horizontal_samples = boost::lexical_cast<unsigned int>(samples_char); } catch (boost::bad_lexical_cast &e) { logError("Ray horizontal samples [%s] is not a valid float: %s", samples_char, e.what()); return false; } } const char* resolution_char = horizontal->Attribute("resolution"); if (resolution_char) { try { ray.horizontal_resolution = boost::lexical_cast<double>(resolution_char); } catch (boost::bad_lexical_cast &e) { logError("Ray horizontal resolution [%s] is not a valid float: %s", resolution_char, e.what()); return false; } } const char* min_angle_char = horizontal->Attribute("min_angle"); if (min_angle_char) { try { ray.horizontal_min_angle = boost::lexical_cast<double>(min_angle_char); } catch (boost::bad_lexical_cast &e) { logError("Ray horizontal min_angle [%s] is not a valid float: %s", min_angle_char, e.what()); return false; } } const char* max_angle_char = horizontal->Attribute("max_angle"); if (max_angle_char) { try { ray.horizontal_max_angle = boost::lexical_cast<double>(max_angle_char); } catch (boost::bad_lexical_cast &e) { logError("Ray horizontal max_angle [%s] is not a valid float: %s", max_angle_char, e.what()); return false; } } } TiXmlElement *vertical = config->FirstChildElement("vertical"); if (vertical) { const char* samples_char = vertical->Attribute("samples"); if (samples_char) { try { ray.vertical_samples = boost::lexical_cast<unsigned int>(samples_char); } catch (boost::bad_lexical_cast &e) { logError("Ray vertical samples [%s] is not a valid float: %s", samples_char, e.what()); return false; } } const char* resolution_char = vertical->Attribute("resolution"); if (resolution_char) { try { ray.vertical_resolution = boost::lexical_cast<double>(resolution_char); } catch (boost::bad_lexical_cast &e) { logError("Ray vertical resolution [%s] is not a valid float: %s", resolution_char, e.what()); return false; } } const char* min_angle_char = vertical->Attribute("min_angle"); if (min_angle_char) { try { ray.vertical_min_angle = boost::lexical_cast<double>(min_angle_char); } catch (boost::bad_lexical_cast &e) { logError("Ray vertical min_angle [%s] is not a valid float: %s", min_angle_char, e.what()); return false; } } const char* max_angle_char = vertical->Attribute("max_angle"); if (max_angle_char) { try { ray.vertical_max_angle = boost::lexical_cast<double>(max_angle_char); } catch (boost::bad_lexical_cast &e) { logError("Ray vertical max_angle [%s] is not a valid float: %s", max_angle_char, e.what()); return false; } } } return false; }
bool Sphere::hit(const Ray &ws_ray, float &thit, std::shared_ptr<DifferentialGeometry> &dg) const { float phi; Point phit; //UNCOMMENT FOR BROKEN BB if(!mImpl->bb.hit(ws_ray)) return false; // Transform the ray into object space Transform transform = worldToObjectSpace(); Ray os_ray = transform(ws_ray); // Do ray-sphere intersection in object space // Compute quadratic sphere coefficients float A = os_ray.dir().x() * os_ray.dir().x() + os_ray.dir().y() * os_ray.dir().y() + os_ray.dir().z() * os_ray.dir().z(); float B = 2.0 * (os_ray.dir().x() * os_ray.origin().x() + os_ray.dir().y() * os_ray.origin().y() + os_ray.dir().z() * os_ray.origin().z()); float C = os_ray.origin().x() * os_ray.origin().x() + os_ray.origin().y() * os_ray.origin().y() + os_ray.origin().z() * os_ray.origin().z() - mImpl->radius * mImpl->radius; // Solve quadratic equation for t values float t0, t1; if (!mImpl->Quadratic(A,B,C, &t0, &t1)) return false; // compute intersection distance along ray if (t0 > os_ray.maxt() || t1 < os_ray.mint()) return false; thit = t0; if (t0 < os_ray.mint()) { thit = t1; if (thit > os_ray.maxt()) return false; } // Compute sphere hit position and phi phit = os_ray(thit); if (phit.x() == 0.f && phit.y() == 0.f) phit.x(1e-5f * mImpl->radius); phi = atan2f(phit.y(), phit.x()); if (phi < 0.) phi += 2.f*M_PI; // Test against clipping parameters if ((mImpl->zmin > -mImpl->radius && phit.z() < mImpl->zmin) || (mImpl->zmax < mImpl->radius && phit.z() > mImpl->zmax) || phi > mImpl->phiMax) { if (thit == t1) return false; thit = t1; if ((mImpl->zmin > -mImpl->radius && phit.z() < mImpl->zmin) || (mImpl->zmax < mImpl->radius && phit.z() > mImpl->zmax) || phi > mImpl->phiMax) return false; } // find parametric representation of sphere float u = phi/mImpl->phiMax; float theta = acosf(Clamp(phit.z()/mImpl->radius, -1.f, 1.f)); float v = (theta - mImpl->thetaMin) / (mImpl->thetaMax - mImpl->thetaMin); float zradius = sqrtf(phit.x() * phit.x() + phit.y() * phit.y()); float invzradius = 1.f / zradius; float cosphi = phit.x() * invzradius; float sinphi = phit.y() * invzradius; Vector dpdu(-mImpl->phiMax * phit.y(), mImpl->phiMax * phit.x(), 0); Vector dpdv = (mImpl->thetaMax - mImpl->thetaMin) * Vector(phit.z() * cosphi, phit.z() * sinphi, -mImpl->radius * sinf(theta)); Vector d2Pduu = -mImpl->phiMax * mImpl->phiMax * Vector(phit.x(), phit.y(), 0.0f); Vector d2Pduv = (mImpl->thetaMax - mImpl->thetaMin) * phit.z() * mImpl->phiMax * Vector(-sinphi, cosphi, 0.0f); Vector d2Pdvv = -(mImpl->thetaMax - mImpl->thetaMin) * (mImpl->thetaMax - mImpl->thetaMin) * Vector(phit.x(), phit.y(), phit.z()); float E = dpdu.dot(dpdu); float F = dpdu.dot(dpdv); float G = dpdv.dot(dpdv); Vector N = dpdu.cross(dpdv).normalized(); float e = N.dot(d2Pduu); float f = N.dot(d2Pduv); float g = N.dot(d2Pdvv); float invEGF2 = 1.f/(E * G - F * F); Normal dndu = Normal((f * F - e * G) * invEGF2 * dpdu + (e * F - f * E) * invEGF2 * dpdv); Normal dndv = Normal((g * F - f * G) * invEGF2 * dpdu + (f*F - g * E) * invEGF2 * dpdv); // if the ray intersects the sphere return true std::shared_ptr<DifferentialGeometry> dg_temp(new DifferentialGeometry(mImpl->o2w(os_ray(thit)), mImpl->o2w(dpdu), mImpl->o2w(dpdv), mImpl->o2w(dndu), mImpl->o2w(dndv), u, v, this)); dg_temp->dir = ws_ray.dir(); dg = dg_temp; return true; }
void DefaultZone::_findNodes( const Ray &t, PCZSceneNodeList &list, PortalList &visitedPortals, bool includeVisitors, bool recurseThruPortals, PCZSceneNode *exclude ) { // if this zone has an enclosure, check against the enclosure AABB first if (mEnclosureNode) { std::pair<bool, Real> nsect = t.intersects(mEnclosureNode->_getWorldAABB()); if (!nsect.first) { // AABB of zone does not intersect t, just return. return; } } // check nodes at home in this zone PCZSceneNodeList::iterator it = mHomeNodeList.begin(); while ( it != mHomeNodeList.end() ) { PCZSceneNode * pczsn = *it; if ( pczsn != exclude ) { // make sure node is not already in the list (might have been added in another // zone it was visiting) PCZSceneNodeList::iterator it2 = list.find(pczsn); if (it2 == list.end()) { std::pair<bool, Real> nsect = t.intersects( pczsn -> _getWorldAABB() ); if ( nsect.first ) { list.insert( pczsn ); } } } ++it; } if (includeVisitors) { // check visitor nodes PCZSceneNodeList::iterator iter = mVisitorNodeList.begin(); while ( iter != mVisitorNodeList.end() ) { PCZSceneNode * pczsn = *iter; if ( pczsn != exclude ) { // make sure node is not already in the list (might have been added in another // zone it was visiting) PCZSceneNodeList::iterator it2 = list.find(pczsn); if (it2 == list.end()) { std::pair<bool, Real> nsect = t.intersects( pczsn -> _getWorldAABB() ); if ( nsect.first ) { list.insert( pczsn ); } } } ++iter; } } // if asked to, recurse through portals if (recurseThruPortals) { PortalList::iterator pit = mPortals.begin(); while ( pit != mPortals.end() ) { Portal * portal = *pit; // check portal versus bounding box if (portal->intersects(t)) { // make sure portal hasn't already been recursed through PortalList::iterator pit2 = std::find(visitedPortals.begin(), visitedPortals.end(), portal); if (pit2 == visitedPortals.end()) { // save portal to the visitedPortals list visitedPortals.push_front(portal); // recurse into the connected zone portal->getTargetZone()->_findNodes(t, list, visitedPortals, includeVisitors, recurseThruPortals, exclude); } } pit++; } } }
//---------------------------------------------------------------------() void Camera::getCameraToViewportBoxVolume(Real screenLeft, Real screenTop, Real screenRight, Real screenBottom, PlaneBoundedVolume* outVolume, bool includeFarPlane) { outVolume->planes.clear(); if (mProjType == PT_PERSPECTIVE) { // Use the corner rays to generate planes Ray ul = getCameraToViewportRay(screenLeft, screenTop); Ray ur = getCameraToViewportRay(screenRight, screenTop); Ray bl = getCameraToViewportRay(screenLeft, screenBottom); Ray br = getCameraToViewportRay(screenRight, screenBottom); Vector3 normal; // top plane normal = ul.getDirection().crossProduct(ur.getDirection()); normal.normalise(); outVolume->planes.push_back( Plane(normal, getDerivedPosition())); // right plane normal = ur.getDirection().crossProduct(br.getDirection()); normal.normalise(); outVolume->planes.push_back( Plane(normal, getDerivedPosition())); // bottom plane normal = br.getDirection().crossProduct(bl.getDirection()); normal.normalise(); outVolume->planes.push_back( Plane(normal, getDerivedPosition())); // left plane normal = bl.getDirection().crossProduct(ul.getDirection()); normal.normalise(); outVolume->planes.push_back( Plane(normal, getDerivedPosition())); } else { // ortho planes are parallel to frustum planes Ray ul = getCameraToViewportRay(screenLeft, screenTop); Ray br = getCameraToViewportRay(screenRight, screenBottom); updateFrustumPlanes(); outVolume->planes.push_back( Plane(mFrustumPlanes[FRUSTUM_PLANE_TOP].normal, ul.getOrigin())); outVolume->planes.push_back( Plane(mFrustumPlanes[FRUSTUM_PLANE_RIGHT].normal, br.getOrigin())); outVolume->planes.push_back( Plane(mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].normal, br.getOrigin())); outVolume->planes.push_back( Plane(mFrustumPlanes[FRUSTUM_PLANE_LEFT].normal, ul.getOrigin())); } // near & far plane applicable to both projection types outVolume->planes.push_back(getFrustumPlane(FRUSTUM_PLANE_NEAR)); if (includeFarPlane) outVolume->planes.push_back(getFrustumPlane(FRUSTUM_PLANE_FAR)); }
Vec3f PhongShader::shade(Ray& ray) { if (!scene) return Vec3f(); vector<Light*>::iterator lightIt; Vec3f color; Point3f iPoint = ray.getIntersectionPoint(); Vec3f N = ray.normal.normalized(); for (lightIt = scene->lights.begin(); lightIt != scene->lights.end(); ++lightIt) { Light* light = *lightIt; if (!light) { color += Vec3f(0.5,0.5,0.5); continue; } float invlightDist = 1.0f / (light->pos() - iPoint).length(); invlightDist *= invlightDist * light->intensity(); Vec3f L = ( light->pos()- iPoint).normalized(); color += ambient % light->ambient() * invlightDist; float angle = N * L; if (angle > 0.0f) { Vec3f diff = light->diffuse() % diffuse * angle * invlightDist; Vec3f E = ray.org.vec3f().normalized(); L = -L; float dotLN = N * L; Vec3f R = L - (2.0 * dotLN * N); float spec = pow(max( R * E , 0.0f ), shininess ); diff += light->specular() % specular * spec * invlightDist; if (light->shadows() > 0.0f) { Point3f rndPos(light->pos().x-(RND-0.5)*light->radius(), light->pos().y-(RND-0.5)*light->radius(), light->pos().z-(RND-0.5)*light->radius()); Ray shadowRay(rndPos,iPoint-rndPos); shadowRay.tmin = 0.01; shadowRay.tmax = 0.99; if (scene->traceShadowRay(shadowRay,(SceneObject*)ray.obj)) diff *= (1.0 - light->shadows()*(1.0-refract)*(1.0-reflect)); } color += diff; } } ray.color = color; if (ray.bounce < scene->maxBounce) { if (reflect > 0.0f) { Ray rayRefl = ray.reflect(); color += color*(1.0f - reflect) + scene->traceRay(rayRefl,(SceneObject*)ray.obj) * reflect; } if (refract > 0.0f) { Ray rayRefr = ray.refract(IOR); color += color*(1.0f - refract) + scene->traceRay(rayRefr,(SceneObject*)ray.obj) * refract; } } return color; }
std::pair<bool, float> Capsule::intersects(const Ray& ray) const { const Vector3& org = ray.getOrigin(); const Vector3& dir = ray.getDirection(); Vector3 segDir = mSegment.getEnd() - mSegment.getStart(); float segExtent = segDir.normalize() * 0.5f; Vector3 segCenter = mSegment.getStart() + segDir * segExtent; Vector3 basis[3]; basis[0] = segDir; basis[0].orthogonalComplement(basis[1], basis[2]); float rSqr = mRadius * mRadius; Vector3 diff = org - segCenter; Vector3 P(basis[1].dot(diff), basis[2].dot(diff), basis[0].dot(diff)); // Get the z-value, in capsule coordinates, of the incoming line's // unit-length direction. float dz = basis[0].dot(dir); if (std::abs(dz) == 1.0f) { // The line is parallel to the capsule axis. Determine whether the // line intersects the capsule hemispheres. float radialSqrDist = rSqr - P[0] * P[0] - P[1] * P[1]; if (radialSqrDist < 0.0f) { // The line is outside the cylinder of the capsule, so there is no // intersection. return std::make_pair(false, 0.0f); } // The line intersects the hemispherical caps. float zOffset = std::sqrt(radialSqrDist) + segExtent; if (dz > 0.0f) return std::make_pair(true, -P[2] - zOffset); else return std::make_pair(true, P[2] - zOffset); } // Convert the incoming line unit-length direction to capsule coordinates. Vector3 D(basis[1].dot(dir), basis[2].dot(dir), dz); // Test intersection of line with infinite cylinder float a0 = P[0] * P[0] + P[1] * P[1] - rSqr; float a1 = P[0] * D[0] + P[1] * D[1]; float a2 = D[0] * D[0] + D[1] * D[1]; float discr = a1*a1 - a0*a2; if (discr < 0.0f) { // The line does not intersect the infinite cylinder. return std::make_pair(false, 0.0f); } float root, inv, tValue, zValue; float nearestT = std::numeric_limits<float>::max(); bool foundOneIntersection = false; if (discr > 0.0f) { // The line intersects the infinite cylinder in two places. root = std::sqrt(discr); inv = 1.0f / a2; tValue = (-a1 - root)*inv; zValue = P[2] + tValue*D[2]; if (std::abs(zValue) <= segExtent) { nearestT = tValue; foundOneIntersection = true; } tValue = (-a1 + root)*inv; zValue = P[2] + tValue*D[2]; if (std::abs(zValue) <= segExtent) { if (foundOneIntersection) return std::make_pair(true, nearestT); else { nearestT = tValue; foundOneIntersection = true; } } } else { // The line is tangent to the infinite cylinder but intersects the // cylinder in a single point. tValue = -a1 / a2; zValue = P[2] + tValue*D[2]; if (std::abs(zValue) <= segExtent) return std::make_pair(true, tValue); } // Test intersection with bottom hemisphere. float PZpE = P[2] + segExtent; a1 += PZpE*D[2]; a0 += PZpE*PZpE; discr = a1*a1 - a0; if (discr > 0) { root = sqrt(discr); tValue = -a1 - root; zValue = P[2] + tValue*D[2]; if (zValue <= -segExtent) { if (foundOneIntersection) return std::make_pair(true, nearestT < tValue ? nearestT : tValue); else { nearestT = tValue; foundOneIntersection = true; } } tValue = -a1 + root; zValue = P[2] + tValue*D[2]; if (zValue <= -segExtent) { if (foundOneIntersection) return std::make_pair(true, nearestT < tValue ? nearestT : tValue); else { nearestT = tValue; foundOneIntersection = true; } } } else if (discr == 0.0f) { tValue = -a1; zValue = P[2] + tValue*D[2]; if (zValue <= -segExtent) { if (foundOneIntersection) return std::make_pair(true, nearestT < tValue ? nearestT : tValue); else { nearestT = tValue; foundOneIntersection = true; } } } // Test intersection with top hemisphere a1 -= 2.0f*segExtent*D[2]; a0 -= 4.0f*segExtent*P[2]; discr = a1*a1 - a0; if (discr > 0.0f) { root = sqrt(discr); tValue = -a1 - root; zValue = P[2] + tValue*D[2]; if (zValue >= segExtent) { if (foundOneIntersection) return std::make_pair(true, nearestT < tValue ? nearestT : tValue); else { nearestT = tValue; foundOneIntersection = true; } } tValue = -a1 + root; zValue = P[2] + tValue*D[2]; if (zValue >= segExtent) { if (foundOneIntersection) return std::make_pair(true, nearestT < tValue ? nearestT : tValue); else { nearestT = tValue; foundOneIntersection = true; } } } else if (discr == 0.0f) { tValue = -a1; zValue = P[2] + tValue*D[2]; if (zValue >= segExtent) { if (foundOneIntersection) return std::make_pair(true, nearestT < tValue ? nearestT : tValue); else { nearestT = tValue; foundOneIntersection = true; } } } if (foundOneIntersection) return std::make_pair(true, nearestT); return std::make_pair(false, 0.0f); }
void init(void) { float seconds = glutGet(GLUT_ELAPSED_TIME); Objects obj; float raysPerPixel = 9.0f; int rays = int(raysPerPixel); float X =2; float Y =2; float Z =0; float cornellDepth = 5.0f; //CornellBox Walls obj.createNewPlane(glm::vec3(-X,-Y,Z),glm::vec3(X,-Y,Z),glm::vec3(X,Y,Z),glm::vec3(-X,Y,Z)); obj.createNewPlane(glm::vec3(-X,-Y,Z+cornellDepth),glm::vec3(-X,-Y,Z),glm::vec3(-X,Y,Z),glm::vec3(-X,Y,Z+cornellDepth)); obj.createNewPlane(glm::vec3(-X,-Y,Z+cornellDepth),glm::vec3(X,-Y,Z+cornellDepth),glm::vec3(X,-Y,Z),glm::vec3(-X,-Y,Z)); obj.createNewPlane(glm::vec3(X,-Y,Z),glm::vec3(X,-Y,Z+cornellDepth),glm::vec3(X,Y,Z+cornellDepth),glm::vec3(X,Y,Z)); obj.createNewPlane(glm::vec3(-X,Y,Z),glm::vec3(X,Y,Z),glm::vec3(X,Y,Z+cornellDepth),glm::vec3(-X,Y,Z+cornellDepth)); //And their Colors obj.shapes[0]->material.color = GREEN; obj.shapes[1]->material.color = MAGENTA; obj.shapes[2]->material.color = YELLOW; obj.shapes[3]->material.color = BLUE; obj.shapes[4]->material.color = RED; //Box made up of 6 planes float boxY = 0.525; obj.createNewPlane(glm::vec3(-1.587,-2.0,1.819),glm::vec3(-0.361,-2.000,2.120),glm::vec3(-0.361,0.525,2.120),glm::vec3(-1.587,0.525,1.819)); obj.createNewPlane(glm::vec3(-0.361,-2.0,2.120),glm::vec3(-0.060,-2.000,0.894),glm::vec3(-0.060,0.525,0.894),glm::vec3(-0.361,0.525,2.120)); obj.createNewPlane(glm::vec3(-0.060,-2.0,0.894),glm::vec3(-1.286,-2.000,0.593),glm::vec3(-1.286,0.525,0.593),glm::vec3(-0.060,0.525,0.894)); obj.createNewPlane(glm::vec3(-1.286,-2.0,0.593),glm::vec3(-1.587,-2.000,1.819),glm::vec3(-1.587,0.525,1.819),glm::vec3(-1.286,0.525,0.593)); //top obj.createNewPlane(glm::vec3(-1.587,0.525,1.819),glm::vec3(-0.361,0.525,2.120),glm::vec3(-0.060,0.525,0.894),glm::vec3(-1.286,0.525,0.593)); float SphereRadius = 0.80; obj.createNewSphere(glm::mat4(0.0),glm::vec3(0.7,-2.0+SphereRadius,Z+3.0),SphereRadius); obj.shapes[5]->material.color = BLUE; obj.shapes[6]->material.color = RED; obj.shapes[7]->material.color = YELLOW; obj.shapes[8]->material.color = MAGENTA; obj.shapes[9]->material.color = CYAN; obj.shapes[10]->material.isDiffuse = false; obj.shapes[10]->material.isRefractive = true; obj.shapes[10]->material.refractiveIndex = 1.5f; //Originally 1.33f obj.shapes[10]->material.color = YELLOW; obj.createNewPlane(glm::vec3(-X*20,-Y*20,Z+7.7),glm::vec3(-X*20,Y*20,Z+7.7),glm::vec3(X*20,Y*20,Z+7.7),glm::vec3(X*20,-Y*20,Z+7.7)); obj.shapes[11]->material.color = CYAN; obj.shapes[5]->material.isDiffuse = false; obj.shapes[6]->material.isDiffuse = false; obj.shapes[7]->material.isDiffuse = false; obj.shapes[8]->material.isDiffuse = false; obj.shapes[9]->material.isDiffuse = false; obj.createNewSphere(glm::mat4(0.0),glm::vec3(-1.0,-2.0+0.6,Z+3.0),0.6); obj.shapes[12]->material.isDiffuse = false; //======== Main RayTracing Loop ======== glm::vec3 renderColor,pixelColor = BLACK; glm::vec3 lightSource =glm::vec3(0,1.75,2); float yFov = 0.5*renderHeight / (camera.position.z*sin(FieldOfView/2.0)); float xFov = 0.5*renderWidth / (camera.position.z*sin(FieldOfView*(renderWidth/renderHeight)/2.0)); float maxT = -10.0; float minT = 9999999.9; float SSx [9]; SSx[0] = -1.0/3.0; SSx[1] = 0.0; SSx[2] = 1.0/3.0; SSx[3] = -1.0/3.0; SSx[4] = 0.0; SSx[5] = 1.0/3.0; SSx[6] = -1.0/3.0; SSx[7] = 0.0; SSx[8] = 1.0/3.0; float SSy [9]; SSy[0] = 1.0/3.0; SSy[1] = 1.0/3.0; SSy[2] = 1.0/3.0; SSy[3] = 0.0; SSy[4] = 0.0; SSy[5] = 0.0; SSy[6] = -1.0/3.0; SSy[7] = -1.0/3.0; SSy[8] = -1.0/3.0; srand((unsigned)time(NULL)); float shadow = 1.0; for (int x=0; x<renderWidth; x++) { for (int y=0; y<renderHeight; y++) { shadow = 1.0; renderColor = glm::vec3(0); for (int i=0; i<rays; i++) { SSx[i] += 0.01*((((float)rand() / (float)RAND_MAX)/3.75) -1.0/7.5); SSy[i] += 0.01*((((float)rand() / (float)RAND_MAX)/3.75) -1.0/7.5); } for (int c=0; c<rays; c++) { pixelColor = glm::vec3(0); glm::vec3 rayDirection = glm::vec3((x+SSx[c]-renderWidth/2.0)/yFov,(y+SSy[c]-renderHeight/2.0)/yFov,pixelPlane) - camera.position; rayDirection = glm::normalize(rayDirection); bool insideObject = false; bool hitWall = false; int rayDepth = 1; float t = 999999.0; float tMin = 999999.0; int objectID = -1; float lastRefIndex = 1.3333; int maxDepth = 12; Ray ray = Ray(); ray.createRay(camera.position,rayDirection,1.0f,100.0f,maxDepth, false); ray.trace(obj,maxDepth); renderColor += ray.color; } renderColor.r = glm::min(renderColor.r/raysPerPixel,1.0f); renderColor.g = glm::min(renderColor.g/raysPerPixel,1.0f); renderColor.b = glm::min(renderColor.b/raysPerPixel,1.0f); pixels[3*(y*renderWidth+x)] = 255*renderColor.r; pixels[3*(y*renderWidth+x)+1] = 255*renderColor.g; pixels[3*(y*renderWidth+x)+2] = 255*renderColor.b; } std::cout << "progress: " << x << " / " << renderWidth << " done" << std::endl; } float ms = (glutGet(GLUT_ELAPSED_TIME) - seconds); std::cout << "RenderTime: " << ms << " milliseconds" << std::endl; // (0,480)----------------- (640,480) // | | // | The Screen | // | | // | | // (0,0)----------------- (640,0) printf("OpenGL Version:%s\n",glGetString(GL_VERSION)); printf("GLSL Version :%s\n\n",glGetString(GL_SHADING_LANGUAGE_VERSION)); glGenTextures( 1, &imageTexture ); glBindTexture( GL_TEXTURE_2D, imageTexture); }
Color trace(const Scene& scene, Ray ray, int depth) { const Color background(0,0,0); const int maxDepth = 3; if (depth >= maxDepth) return background; Color color(0,0,0); double distance = 0; const Primitive* prim = NULL; int intersectionType = 0; findNearsetIntersection(scene, ray, &prim, &distance, &intersectionType); if (prim != NULL) { if (prim->IsIlluminative()) { return prim->GetMaterial().GetColor(); } const Vector3 intersectionPoint = ray.GetPoint(distance); const Vector3 n = prim->GetNormal(intersectionPoint); if (prim->GetMaterial().GetDiffuse() > 0) { for (Scene::ConstIterator it = scene.Begin(); it != scene.End(); it++) { const double intensive = getIntensity((*it), intersectionPoint, n, scene); if (intensive != .0) { Vector3 x = (prim->GetMaterial().GetColor()); Vector3 y = ((*it)->GetMaterial().GetColor()); color = color + (intensive * prim->GetMaterial().GetDiffuse()) * x * y; } } } //refraction { const Vector3 x = ray.GetDirection(); const Vector3 y = intersectionType * (-n); double n; if (intersectionType == IntersectOutside) n = 1.0 / prim->GetMaterial().GetRefractionRate(); else n = prim->GetMaterial().GetRefractionRate(); const double sin_1 = sqrt(1 - Dot(x,y)); const double sin_2 = n * sin_1; if (sin_2 < 1) { const double cos_2 = sqrt(1 - sin_2); Vector3 xPerpendicular = x - Dot(x,y)*y; Vector3 z = cos_2 * y + sin_2 * xPerpendicular; z.Normalize(); if (prim->GetMaterial().GetRefraction() > 0) { if (intersectionType == IntersectInside) { color = color + prim->GetMaterial().GetRefraction() * exp(-prim->GetMaterial().GetAbsorptionRate()*distance) * trace(scene, Ray(intersectionPoint, z), depth + 1); } else color = color + prim->GetMaterial().GetRefraction() * trace(scene, Ray(intersectionPoint, z), depth + 1); } } } //reflection if (prim->GetMaterial().GetReflection() > 0) { const Vector3 a = ray.GetDirection(); Vector3 newA = a - 2 * (Dot(a,n)) * n; color = color + prim->GetMaterial().GetReflection() * trace(scene, Ray(intersectionPoint, newA), depth + 1); } } return color; }
bool BoundingBox::intersects(const Ray& ray) const { if (mNull) return false; switch (ray.getClassification()) { case Ray::MMM: // side(R,HD) < 0 or side(R,FB) > 0 or side(R,EF) > 0 or side(R,DC) < 0 or side(R,CB) < 0 or side(R,HE) > 0 to miss if ((ray.x() < mXMin) || (ray.y() < mYMin) || (ray.z() < mZMin) || (ray.R0() + ray.i() * mYMin - ray.j() * mXMax < 0) || (ray.R0() + ray.i() * mYMax - ray.j() * mXMin > 0) || (ray.R1() + ray.i() * mZMax - ray.k() * mXMin > 0) || (ray.R1() + ray.i() * mZMin - ray.k() * mXMax < 0) || (ray.R3() - ray.k() * mYMax + ray.j() * mZMin < 0) || (ray.R3() - ray.k() * mYMin + ray.j() * mZMax > 0)) return false; return true; case Ray::MMP: // side(R,HD) < 0 or side(R,FB) > 0 or side(R,HG) > 0 or side(R,AB) < 0 or side(R,DA) < 0 or side(R,GF) > 0 to miss if ((ray.x() < mXMin) || (ray.y() < mYMin) || (ray.z() > mZMax) || (ray.R0() + ray.i() * mYMin - ray.j() * mXMax < 0) || (ray.R0() + ray.i() * mYMax - ray.j() * mXMin > 0) || (ray.R1() + ray.i() * mZMax - ray.k() * mXMax > 0) || (ray.R1() + ray.i() * mZMin - ray.k() * mXMin < 0) || (ray.R3() - ray.k() * mYMin + ray.j() * mZMin < 0) || (ray.R3() - ray.k() * mYMax + ray.j() * mZMax > 0)) return false; return true; case Ray::MPM: // side(R,EA) < 0 or side(R,GC) > 0 or side(R,EF) > 0 or side(R,DC) < 0 or side(R,GF) < 0 or side(R,DA) > 0 to miss if ((ray.x() < mXMin) || (ray.y() > mYMax) || (ray.z() < mZMin) || (ray.R0() + ray.i() * mYMin - ray.j() * mXMin < 0) || (ray.R0() + ray.i() * mYMax - ray.j() * mXMax > 0) || (ray.R1() + ray.i() * mZMax - ray.k() * mXMin > 0) || (ray.R1() + ray.i() * mZMin - ray.k() * mXMax < 0) || (ray.R3() - ray.k() * mYMax + ray.j() * mZMax < 0) || (ray.R3() - ray.k() * mYMin + ray.j() * mZMin > 0)) return false; return true; case Ray::MPP: // side(R,EA) < 0 or side(R,GC) > 0 or side(R,HG) > 0 or side(R,AB) < 0 or side(R,HE) < 0 or side(R,CB) > 0 to miss if ((ray.x() < mXMin) || (ray.y() > mYMax) || (ray.z() > mZMax) || (ray.R0() + ray.i() * mYMin - ray.j() * mXMin < 0) || (ray.R0() + ray.i() * mYMax - ray.j() * mXMax > 0) || (ray.R1() + ray.i() * mZMax - ray.k() * mXMax > 0) || (ray.R1() + ray.i() * mZMin - ray.k() * mXMin < 0) || (ray.R3() - ray.k() * mYMin + ray.j() * mZMax < 0) || (ray.R3() - ray.k() * mYMax + ray.j() * mZMin > 0)) return false; return true; case Ray::PMM: // side(R,GC) < 0 or side(R,EA) > 0 or side(R,AB) > 0 or side(R,HG) < 0 or side(R,CB) < 0 or side(R,HE) > 0 to miss if ((ray.x() > mXMax) || (ray.y() < mYMin) || (ray.z() < mZMin) || (ray.R0() + ray.i() * mYMax - ray.j() * mXMax < 0) || (ray.R0() + ray.i() * mYMin - ray.j() * mXMin > 0) || (ray.R1() + ray.i() * mZMin - ray.k() * mXMin > 0) || (ray.R1() + ray.i() * mZMax - ray.k() * mXMax < 0) || (ray.R3() - ray.k() * mYMax + ray.j() * mZMin < 0) || (ray.R3() - ray.k() * mYMin + ray.j() * mZMax > 0)) return false; return true; case Ray::PMP: // side(R,GC) < 0 or side(R,EA) > 0 or side(R,DC) > 0 or side(R,EF) < 0 or side(R,DA) < 0 or side(R,GF) > 0 to miss if ((ray.x() > mXMax) || (ray.y() < mYMin) || (ray.z() > mZMax) || (ray.R0() + ray.i() * mYMax - ray.j() * mXMax < 0) || (ray.R0() + ray.i() * mYMin - ray.j() * mXMin > 0) || (ray.R1() + ray.i() * mZMin - ray.k() * mXMax > 0) || (ray.R1() + ray.i() * mZMax - ray.k() * mXMin < 0) || (ray.R3() - ray.k() * mYMin + ray.j() * mZMin < 0) || (ray.R3() - ray.k() * mYMax + ray.j() * mZMax > 0)) return false; return true; case Ray::PPM: // side(R,FB) < 0 or side(R,HD) > 0 or side(R,AB) > 0 or side(R,HG) < 0 or side(R,GF) < 0 or side(R,DA) > 0 to miss if ((ray.x() > mXMax) || (ray.y() > mYMax) || (ray.z() < mZMin) || (ray.R0() + ray.i() * mYMax - ray.j() * mXMin < 0) || (ray.R0() + ray.i() * mYMin - ray.j() * mXMax > 0) || (ray.R1() + ray.i() * mZMin - ray.k() * mXMin > 0) || (ray.R1() + ray.i() * mZMax - ray.k() * mXMax < 0) || (ray.R3() - ray.k() * mYMax + ray.j() * mZMax < 0) || (ray.R3() - ray.k() * mYMin + ray.j() * mZMin > 0)) return false; return true; case Ray::PPP: // side(R,FB) < 0 or side(R,HD) > 0 or side(R,DC) > 0 or side(R,EF) < 0 or side(R,HE) < 0 or side(R,CB) > 0 to miss if ((ray.x() > mXMax) || (ray.y() > mYMax) || (ray.z() > mZMax) || (ray.R0() + ray.i() * mYMax - ray.j() * mXMin < 0) || (ray.R0() + ray.i() * mYMin - ray.j() * mXMax > 0) || (ray.R1() + ray.i() * mZMin - ray.k() * mXMax > 0) || (ray.R1() + ray.i() * mZMax - ray.k() * mXMin < 0) || (ray.R3() - ray.k() * mYMin + ray.j() * mZMax < 0) || (ray.R3() - ray.k() * mYMax + ray.j() * mZMin > 0)) return false; return true; } return false; }
/* * Calculates the output ray \a outputRay for the \a incident ray for the intersection parameters \a dg. * * Returns FALSE if there is not output ray. */ bool MaterialAngleDependentSpecular::OutputRay( const Ray& incident, DifferentialGeometry* dg, RandomDeviate& rand, Ray* outputRay ) const { double reflectivity = 0.0; NormalVector dgNormal; if( dg->shapeFrontSide ) { if( !reflectivityFront.getValue() ) return ( false ); dgNormal = dg->normal; // Product double incidenceAngle = acos( DotProduct( -incident.direction(), dgNormal ) ); reflectivity = OutputPropertyValue( m_frontReflectivityIncidenceAngle, m_frontReflectivityValue, incidenceAngle ); } else { if( !reflectivityBack.getValue() ) return ( false ); dgNormal = - dg->normal; double incidenceAngle = acos( DotProduct( -incident.direction(), dgNormal) ); reflectivity = OutputPropertyValue( m_backReflectivityIncidenceAngle, m_backReflectivityValue, incidenceAngle ); } double randomNumber = rand.RandomDouble(); if ( randomNumber >= reflectivity ) return ( false ); //Compute reflected ray (local coordinates ) //Ray* reflected = new Ray(); //reflected.origin = dg->point; outputRay->origin = dg->point; NormalVector normalVector; double sSlope = sigmaSlope.getValue() / 1000; if( sSlope > 0.0 ) { NormalVector errorNormal; if ( distribution.getValue() == 0 ) { double phi = gc::TwoPi * rand.RandomDouble(); double theta = sSlope * rand.RandomDouble(); errorNormal.x = sin( theta ) * sin( phi ) ; errorNormal.y = cos( theta ); errorNormal.z = sin( theta ) * cos( phi ); } else if (distribution.getValue() == 1 ) { errorNormal.x = sSlope * tgf::AlternateBoxMuller( rand ); errorNormal.y = 1.0; errorNormal.z = sSlope * tgf::AlternateBoxMuller( rand ); } Vector3D r = dgNormal; Vector3D s = Normalize( dg->dpdu ); Vector3D t = Normalize( dg->dpdv ); Transform trasform( s.x, s.y, s.z, 0.0, r.x, r.y, r.z, 0.0, t.x, t.y, t.z, 0.0, 0.0, 0.0, 0.0, 1.0); NormalVector normalDirection = trasform.GetInverse()( errorNormal ); normalVector = Normalize( normalDirection ); } else { normalVector = dgNormal; } double cosTheta = DotProduct( normalVector, incident.direction() ); outputRay->setDirection( Normalize( incident.direction() - 2.0 * normalVector * cosTheta ) ); return ( true ); }
pair<int, float> Grid::trace(const Ray &ray, float tmin, float tmax, int ignored_id, int flags) const { float3 p1 = ray.at(tmin), p2 = ray.at(tmax); int2 pos = worldToGrid((int2)p1.xz()), end = worldToGrid((int2)p2.xz()); //TODO: verify for rays going out of grid space if(!isInsideGrid(pos) || !isInsideGrid(end)) return make_pair(-1, constant::inf); // Algorithm idea from: RTCD by Christer Ericson int dx = end.x > pos.x? 1 : end.x < pos.x? -1 : 0; int dz = end.y > pos.y? 1 : end.y < pos.y? -1 : 0; float cell_size = (float)node_size; float inv_cell_size = 1.0f / cell_size; float lenx = fabs(p2.x - p1.x); float lenz = fabs(p2.z - p1.z); float minx = float(node_size) * floorf(p1.x * inv_cell_size), maxx = minx + cell_size; float minz = float(node_size) * floorf(p1.z * inv_cell_size), maxz = minz + cell_size; float tx = (p1.x > p2.x? p1.x - minx : maxx - p1.x) / lenx; float tz = (p1.z > p2.z? p1.z - minz : maxz - p1.z) / lenz; float deltax = cell_size / lenx; float deltaz = cell_size / lenz; int out = -1; float out_dist = tmax + constant::epsilon; while(true) { int node_id = nodeAt(pos); const Node &node = m_nodes[node_id]; if(flagTest(node.obj_flags, flags) && intersection(ray, node.bbox) < out_dist) { const Object *objects[node.size]; int count = extractObjects(node_id, objects, ignored_id, flags); for(int n = 0; n < count; n++) { float dist = intersection(ray, objects[n]->bbox); if(dist < out_dist) { out_dist = dist; out = objects[n] - &m_objects[0]; } } if(node.is_dirty) updateNode(node_id); } if(tx <= tz || dz == 0) { if(pos.x == end.x) break; tx += deltax; pos.x += dx; } else { if(pos.y == end.y) break; tz += deltaz; pos.y += dz; } float ray_pos = tmin + max((tx - deltax) * lenx, (tz - deltaz) * lenz); if(ray_pos >= out_dist) break; } return make_pair(out, out_dist); }
bool AABB::Intersects( const Ray& r ) const { return r.Intersects( *this ); }
void StaticModelGroup::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results) { // If no bones or no bone-level testing, use the Drawable test RayQueryLevel level = query.level_; if (level < RAY_AABB) { Drawable::ProcessRayQuery(query, results); return; } // Check ray hit distance to AABB before proceeding with more accurate tests // GetWorldBoundingBox() updates the world transforms if (query.ray_.HitDistance(GetWorldBoundingBox()) >= query.maxDistance_) return; for (unsigned i = 0; i < numWorldTransforms_; ++i) { // Initial test using AABB float distance = query.ray_.HitDistance(boundingBox_.Transformed(worldTransforms_[i])); Vector3 normal = -query.ray_.direction_; // Then proceed to OBB and triangle-level tests if necessary if (level >= RAY_OBB && distance < query.maxDistance_) { Matrix3x4 inverse = worldTransforms_[i].Inverse(); Ray localRay = query.ray_.Transformed(inverse); distance = localRay.HitDistance(boundingBox_); if (level == RAY_TRIANGLE && distance < query.maxDistance_) { distance = M_INFINITY; for (unsigned j = 0; j < batches_.Size(); ++j) { Geometry* geometry = batches_[j].geometry_; if (geometry) { Vector3 geometryNormal; float geometryDistance = geometry->GetHitDistance(localRay, &geometryNormal); if (geometryDistance < query.maxDistance_ && geometryDistance < distance) { distance = geometryDistance; normal = (worldTransforms_[i] * Vector4(geometryNormal, 0.0f)).Normalized(); } } } } } if (distance < query.maxDistance_) { RayQueryResult result; result.position_ = query.ray_.origin_ + distance * query.ray_.direction_; result.normal_ = normal; result.distance_ = distance; result.drawable_ = this; result.node_ = node_; result.subObject_ = i; results.Push(result); } } }
Ray Renderable::transformRayWorldToModel(const Ray &ray) const { return ray.transformed(mTransformInv); }
/** * Computes normal for an intersection point on a sphere */ const glm::vec3 computeNormal(const Ray& r, const float& t) { glm::vec3 n = glm::normalize(((r.getOrigin() + t * r.getDirection()) - p) / this->r); return n; }
double Renderable::transformRayLambdaWorldToModel(const Ray &ray, const double lambda) const { Vec3d model_direction = mTransformInv.as3x3()*ray.direction(); return lambda * model_direction.length(); }
void operator()(const Ray& ray, const Triangle& tri, float& distance) { float d = ray.intersectionTime(tri); if (d > 0 && d < distance) { distance = d; } }
//------------------------------------------------------------------------ bool KdTreeNode::intersect(const Ray& ray, float min, float max, float* pDistance, const Sphere** ppSphere) const { ASSERT(pDistance != nullptr && ppSphere != nullptr); // Case 1: leaf has been reached if (isLeaf()) { if (m_Spheres->size() == 0) { return false; } *pDistance = std::numeric_limits<float>::max(); bool success = false; for (auto it = m_Spheres->begin(); it != m_Spheres->end(); it++) { const Sphere& s = **it; float d; if (s.intersect(ray, &d)) { if (d < *pDistance && d < max) { success = true; *pDistance = d; *ppSphere = &s; } } } return success; } float dirAxis = ray.getDirection().get(m_Axis); float tSplit = ray.planeIntersectionDistance(m_SplitDistance, m_Axis); KdTreeNode* minNode; // Node the closest to the ray origin KdTreeNode* maxNode; // Node the furthest to the ray origin if (dirAxis > 0) { minNode = getA(); maxNode = getB(); } else { minNode = getB(); maxNode = getA(); } // Case 2: ray is parallel to split plane if (dirAxis == 0) { float originPlane = ray.getOrigin().get(m_Axis); if (originPlane < m_SplitDistance) { return getA()->intersect(ray, min, max, pDistance, ppSphere); } if (m_SplitDistance < originPlane) { return getB()->intersect(ray, min, max, pDistance, ppSphere); } return false; } // Case 3: ray only crosses min node if (max < tSplit) { return minNode->intersect(ray, min, max, pDistance, ppSphere); } // Case 4: ray only crosses max node if (tSplit < min) { return maxNode->intersect(ray, min, max, pDistance, ppSphere); } // Case 5: ray crosses both nodes if (minNode->intersect(ray, min, tSplit, pDistance, ppSphere)) { return true; } return maxNode->intersect(ray, tSplit, max, pDistance, ppSphere); }
void testRayIntersect() { KDTree<Triangle> tree; Array<int> index; Array<Point3> vertex; printf(" (load model, "); fflush(stdout); ArticulatedModel::Ref model = ArticulatedModel::fromFile(System::findDataFile("cow.ifs")); extractTriangles(model, vertex, index); for (int i = 0; i < index.size(); i += 3) { int i0 = index[i]; int i1 = index[i + 1]; int i2 = index[i + 2]; tree.insert(Triangle(vertex[i0], vertex[i1], vertex[i2])); } printf("balance tree, "); fflush(stdout); tree.balance(); Vector3 origin = Vector3(0, 5, 0); IntersectCallback intersectCallback; printf("raytrace, "); fflush(stdout); for (int i = 0; i < 4000; ++i) { // Cast towards a random point near the cow surface Vector3 target = vertex.randomElement() + Vector3::random() * 0.0001f; Ray ray = Ray::fromOriginAndDirection(origin, (target - origin).direction()); // Exhaustively test against each triangle float exhaustiveDistance = inf(); { const KDTree<Triangle>::Iterator& end = tree.end(); KDTree<Triangle>::Iterator it = tree.begin(); while (it != end) { const Triangle& tri = *it; float d = ray.intersectionTime(tri); if (d > 0 && d < exhaustiveDistance) { exhaustiveDistance = d; } ++it; } } // Test using the ray iterator float treeDistance = inf(); tree.intersectRay(ray, intersectCallback, treeDistance, true); float treeDistance2 = inf(); tree.intersectRay(ray, intersectCallback, treeDistance2, false); debugAssertM(fuzzyEq(treeDistance, exhaustiveDistance), format("KDTree::intersectRay found a point at %f, " "exhaustive ray intersection found %f.", treeDistance, exhaustiveDistance)); debugAssertM(fuzzyEq(treeDistance2, exhaustiveDistance), format("KDTree::intersectRay found a point at %f, " "exhaustive ray intersection found %f.", treeDistance2, exhaustiveDistance)); } printf("done) "); }
Ray HeterogeneousVolume::scatter(Ray &inRay) const{ Ray outRay; outRay.isDeltaDirection = false; bool go_in_vol = inRay.intersectObj == this && inRay.insideObj != this; bool be_in_vol = inRay.insideObj == this; // CASE1: Go in volume. if(go_in_vol){ vec3f position = inRay.origin + inRay.direction*inRay.intersectDist; vec3f normal = inRay.intersectObj->getWorldNormal(inRay.intersectTriangleID, position); outRay.origin = position; outRay.direction = inRay.direction; vec3f reflDir = -normal.dot(inRay.direction)*normal*2 + inRay.direction; reflDir.normalize(); float theta = acos(inRay.direction.dot(normal)); AbstractObject* currentInsideObject = inRay.insideObj; AbstractObject* outSideObject = (AbstractObject*)this; float current_n = currentInsideObject ? currentInsideObject->getIOR() : 1; float next_n = outSideObject ? outSideObject->getIOR() : 1; float sin_phi = current_n / next_n * sin(theta); outRay.intersectObj = NULL; outRay.radiance = vec3f(1, 1, 1); outRay.directionProb = 1; outRay.contactObj = (AbstractObject*)this; outRay.contactTriangleID = inRay.intersectTriangleID; if(sin_phi > 1){ outRay.direction = reflDir; outRay.insideObj = inRay.insideObj; outRay.directionProb = 1; outRay.isDeltaDirection = true; outRay.photonType = Ray::NOUSE; } else{ float phi = asin(sin_phi); if(theta > PI/2) phi = PI - phi; vec3f axis = normal.cross(inRay.direction); axis.normalize(); outRay.direction = vec3f(RotateMatrix(axis, phi) * vec4f(normal, 0)); outRay.direction.normalize(); float cos_theta = abs(cos(theta)); float cos_phi = abs(cos(phi)); float esr = powf(abs(current_n*cos_theta-next_n*cos_phi)/(current_n*cos_theta+next_n*cos_phi),2); float epr = powf(abs(next_n*cos_theta-current_n*cos_phi)/(next_n*cos_theta+current_n*cos_phi),2); float er = (esr+epr)/2; float p = er; if(rng->genFloat() < p) { outRay.direction = reflDir; outRay.radiance *= er / outRay.cosineTerm(); outRay.directionProb = p; outRay.insideObj = inRay.insideObj; outRay.isDeltaDirection = true; outRay.photonType = Ray::NOUSE; } else { outRay.radiance *= (1-er) / outRay.cosineTerm(); outRay.directionProb = 1-p; outRay.contactObj = outRay.insideObj = (AbstractObject*)this; outRay.isDeltaDirection = true; outRay.photonType = Ray::HITVOL; } outRay.direction.normalize(); } return outRay; } float p_medium, P_surface, sampleDist; bool samplingState = sampleDistance(inRay, sampleDist, p_medium, P_surface); bool out_of_vol = samplingState == false;//sampleDist >= inRay.intersectDist; // CASE2: Be in volume. if(be_in_vol && !out_of_vol){ outRay.origin = inRay.origin + inRay.direction * sampleDist; outRay.radiance = bsdf->sampleBSDF(inRay.direction, outRay.direction, vec3f(), *rng, &outRay.directionProb); outRay.insideObj = (AbstractObject*)this; outRay.contactTriangleID = inRay.intersectTriangleID; float albedo = isSubsurface ? getAlbedo(outRay.origin) : getAlbedo(); float rander = rng->genFloat(); if(rander < albedo){ outRay.contactObj = NULL; outRay.directionProb *= albedo; outRay.originProb = p_medium;// pMedium(inRay, sampleDist);// outRay.isDeltaDirection = false; outRay.radiance *= isSubsurface ? lookUpSubSurfaceVolumeData(outRay.origin, SCATTERING) : scatteringCoeff * lookUpDensity(outRay.origin); outRay.photonType = Ray::INVOL; } else{ // terminate outRay.direction = vec3f(0, 0, 0); outRay.radiance = vec3f(0, 0, 0); outRay.directionProb = 1; outRay.originProb = p_medium;//pMedium(inRay, sampleDist);// outRay.insideObj = NULL; outRay.contactObj = NULL; outRay.isDeltaDirection = false; outRay.photonType = Ray::INVOL; //Ray::NOUSE;// } return outRay; } // CASE3: Go out of volume. if(be_in_vol && out_of_vol){ outRay = inRay; outRay.direction = inRay.direction; outRay.origin = inRay.origin + inRay.intersectDist * inRay.direction; outRay.contactObj = inRay.intersectObj; outRay.contactTriangleID = inRay.intersectTriangleID; outRay.insideObj = (AbstractObject*)this; outRay.directionProb = 1; outRay.radiance = vec3f(1,1,1); bool going_out = (inRay.intersectObj == this); if(going_out){ vec3f normal = inRay.intersectObj->getWorldNormal(inRay.intersectTriangleID, outRay.origin); vec3f reflDir = -normal.dot(inRay.direction)*normal*2 + inRay.direction; reflDir.normalize(); float theta = acos(inRay.direction.dot(normal)); AbstractObject* currentInsideObject = (AbstractObject*)this; AbstractObject* outSideObject = scene->findInsideObject(outRay, (AbstractObject*)this); float current_n = currentInsideObject ? currentInsideObject->getIOR() : 1; float next_n = outSideObject ? outSideObject->getIOR() : 1; float sin_phi = current_n / next_n * sin(theta); outRay.intersectObj = NULL; if(sin_phi > 1){ outRay.direction = reflDir; outRay.insideObj = inRay.insideObj; outRay.contactObj = (AbstractObject*)this; outRay.originProb = P_surface;// PSurface(inRay, inRay.intersectDist);// outRay.photonType = Ray::NOUSE; outRay.isDeltaDirection = true; } else{ float phi = asin(sin_phi); if(theta > PI/2) phi = PI - phi; vec3f axis = normal.cross(inRay.direction); axis.normalize(); outRay.direction = vec3f(RotateMatrix(axis, phi) * vec4f(normal, 0)); outRay.direction.normalize(); float cos_theta = abs(cos(theta)); float cos_phi = abs(cos(phi)); float esr = powf(abs(current_n*cos_theta-next_n*cos_phi)/(current_n*cos_theta+next_n*cos_phi),2); float epr = powf(abs(next_n*cos_theta-current_n*cos_phi)/(next_n*cos_theta+current_n*cos_phi),2); float er = (esr+epr)/2; float p = er; if(rng->genFloat() < p) { outRay.direction = reflDir; outRay.radiance *= er / outRay.cosineTerm(); outRay.directionProb = p; outRay.originProb = P_surface;// PSurface(inRay, inRay.intersectDist);// outRay.insideObj = inRay.insideObj; outRay.isDeltaDirection = true; outRay.photonType = Ray::NOUSE; } else { outRay.radiance *= (1-er) / outRay.cosineTerm(); outRay.directionProb = (1-p); outRay.originProb = P_surface;//PSurface(inRay, inRay.intersectDist);// outRay.insideObj = outSideObject; outRay.isDeltaDirection = true; outRay.photonType = Ray::NOUSE; } outRay.direction.normalize(); } } else{ outRay.contactObj = NULL; outRay.intersectDist = 0; outRay = inRay.intersectObj->scatter(outRay); outRay.originProb *= P_surface;//PSurface(inRay, inRay.intersectDist);// outRay.photonType = inRay.intersectObj->isVolume() ? Ray::NOUSE : Ray::OUTVOL; } return outRay; } return outRay; }
float Line::Distance(const Ray &other, float &d, float &d2) const { vec c = ClosestPoint(other, d, d2); return c.Distance(other.GetPoint(d2)); }
// Moeller-Trumbore bool Triangle::hit(const Ray& ray, const Ray_Tracer* rt, float t_min, float t_max, Ray_Hit& rh, bool shadow) const { // Absolute Triangle Vertex Positions V3& v0 = m->verts[inds[0]]; V3& v1 = m->verts[inds[1]]; V3& v2 = m->verts[inds[2]]; // Two edges of triangle V3 e0, e1; e0 = v1 - v0; e1 = v2 - v0; V3 p = ray.s.cross(e1); float deter = e0.dot(p); if (deter > -EPSILON && deter < EPSILON) return false; V3 t = ray.o - v0; // Store the inverse to reduce divisions float inv_deter = 1.0 / deter; float u = t.dot(p) * inv_deter; if (u < 0.0 || u > 1.0) return false; V3 q = t.cross(e0); float v = ray.s.dot(q) * inv_deter; if (v < 0.0 || u + v > 1.0) return false; float t_inter = e1.dot(q) * inv_deter; if (t_inter < t_min || t_inter > t_max) { //std::cout << "Cull: " << t_inter << '\t' <<t_min<< '\t' <<t_max<< std::endl; return false; } rh.t = t_inter; rh.col = 0.2*m->mat.col; rh.shape = m; if (shadow || ray.depth >= rt->depth_limit) return true; /* if (is_light) { rh.col = Color(1.0, 1.0, 1.0); return true; } */ V3 int_loc = ray.at(t_inter); // Shadow for (Shape* light : rt->lights) { // BIG ASSUMPTION THAT ALL LIGHTS ARE SPHERES Sphere* sph = static_cast<Sphere*>(light); // Make ray from intersection to light V3 int_to_light = sph->c - int_loc; float dist_to_light = int_to_light.norm(); int_to_light.normalize(); Ray shadow_ray(int_loc + EPSILON*int_to_light, int_to_light, ray.depth + 1); Ray_Hit shadow_hit; if (rt->kd->hit_helper(true, rt->kd->root, shadow_ray, rt, EPSILON, dist_to_light, shadow_hit, true, 0)) { if (!shadow_hit.shape->is_light) { continue; } } float inner = int_to_light.dot(normal); if (inner > 0.0) { rh.col += sph->mat.col *inner* m->mat.diff * m->mat.col; } } // Reflection V3 refl_dir = ray.s - 2.0f * (normal.dot(ray.s)) * normal; Ray refl_ray(int_loc + EPSILON*refl_dir, refl_dir, ray.depth + 1); Ray_Hit refl_hit; if (rt->kd->hit_helper(true, rt->kd->root, refl_ray, rt, EPSILON, FLT_MAX, refl_hit, false, 0)) { //if (rt->trace(refl_ray, EPSILON, FLT_MAX, refl_hit, false)) { rh.col += m->mat.refl*refl_hit.col * refl_hit.shape->mat.col; } return true; }
bool Cylindre::intersect(const Ray& ray, Hit& hit) const { /*bool top = topdisque()->intersect(ray,hit); bool bottom = bottomdisque()->intersect(ray,hit); return top || bottom; */ // Determination de l'intersection // J'appelle I le point intersection s'il existe, O le point d'origine du rayon, D sa direction, R1 et R1 les rayons du cylindre, h sa hauteur // C l'origine du repere basé à la base du cylindre // on place le ray dans le répère associé au cylindre Ray ray_associe_cylindre(frame().coordinatesOf(ray.start()), frame().transformOf(ray.direction())); Vec I; Vec O = ray_associe_cylindre.start(); const Vec& D = ray_associe_cylindre.direction(); float R1,R2; R1 = bottomradius_; R2 = topradius_; float h = height_; #ifdef DEBUG_INTERSEC std::cout << "TENTATIVE d'intersection du rayon :\n" << ray << "avec le cylindre\n" << *this << std::endl; #endif #ifdef DEBUG_INTERSEC std::cout << "rayon dans l'espace du cylindre : \n" << ray_associe_cylindre << std::endl; #endif // on vérifie que le ray pointe vers le cylindre if ( (frame().position() - ray.start())*ray.direction() < 0){ #ifdef DEBUG_INTERSEC std::cout << "PAS D'INTERSECTION : direction pointant en arrière" << std::endl; #endif return false; } // On se place dans les coordonnées du cylindre pour tous les calculs et on a les équations suivantes : // Ix = Ox + tDx // Iy = Oy + tDy // Iz = Oz + tDz // Ix² + Iy² = (Iz/h*(R2-R1)+R1)² <=> Ix² + Iy² = Iz²/h²*(R2-R1)² + R1² + 2*(R2-R1)*R1*Iz/h // on remplace Ix, Iy et Iz dans la 4e equation pour obtenir une equation du 2nd degré en t // (Dx² + Dy² - Dz²*(R2-R1)²/h²)*t² + (2OxDx + 2OyDy - (2OzDz)/h²*(R2-R1)² - 2Dz*(R2-R1)/h)*t + (Ox²+Oy²-Oz²/h²*(R2-R1)²-R1²-2*(R2-R1)*Oz/h = 0 float a, b ,c; if (R1>R2){ a = D.x*D.x + D.y*D.y -D.z*D.z*(R2-R1)*(R2-R1)/(h*h); b = 2*O.x*D.x+2*O.y*D.y - (2*O.z*D.z)*(R2-R1)*(R2-R1)/(h*h) - 2*D.z*R1*(R2-R1)/h; c = O.x*O.x+O.y*O.y-O.z*O.z*(R2-R1)*(R2-R1)/(h*h)-2*R1*(R2-R1)*O.z/h -R1*R1; }else { a = D.x*D.x + D.y*D.y -D.z*D.z*(R2-R1)*(R2-R1)/(h*h); b = 2*O.x*D.x+2*O.y*D.y - (2*O.z*D.z)*(R2-R1)*(R2-R1)/(h*h) - 2*D.z*R1*(R2-R1)/h; c = O.x*O.x+O.y*O.y-O.z*O.z*(R2-R1)*(R2-R1)/(h*h)-2*R1*(R2-R1)*O.z/h -R1*R1; } float delta = b*b-4*a*c; #ifdef DEBUG_INTERSEC cout << "a : " << a << endl << "b : " << b << endl << "c :" << c << endl << "delta : " << delta << endl; #endif if (delta < 0) { #ifdef DEBUG_INTERSEC cout << "delta est négatif, il n'y a pas de solution" << endl; #endif // pas de solution, il faut vérifier maintenant si on intersecte les disques supérieur ou inférieur bool inter_topdisque = topdisque_->intersect(ray,hit); bool inter_bottomdisque = bottomdisque_->intersect(ray,hit); return (inter_topdisque || inter_bottomdisque); } if (delta > 0) { #ifdef DEBUG_INTERSEC cout << "delta est positif, il y a deux solutions" << endl; #endif // deux solutions, le rayon entre et sort par la robe du cylindre float t; if (a == 0) { t = -c/b; } else{ t = (-b-sqrt(delta))/(2*a); } if ( t < 0 ){ #ifdef DEBUG_INTERSEC cout << "t < 0 " << endl; cout << "PAS D'INTERSECTION avec la robe du cylindre" << endl; #endif return false; } // on calcule le point d'intersection I.x = O.x + t*D.x; I.y = O.y + t*D.y; I.z = O.z + t*D.z; #ifdef DEBUG_INTERSEC cout <<"I : " << I << endl; #endif if (I.z < 0 || I.z > h) { #ifdef DEBUG_INTERSEC cout << "t vaut : " << t << endl << "I.z vaut : " << I.z << endl; //cout << "PAS D'INTERSECTION avec la robe du cylindre" << endl; #endif bool top = topdisque()->intersect(ray,hit); bool bottom = bottomdisque()->intersect(ray,hit); return top || bottom; } // on calcule la normale en ce point, dans les coordonnées du cylindre toujours float theta = 0; Vec normale; normale.x = I.x; normale.y = I.y; normale.z = 0; if (normale.norm() == 0) { cout << "la norme de la normale est nulle" << endl; } if (R1>=R2){ theta = atan((R1-R2)/h); normale = normale * (1/normale.norm())*cos(theta); normale = normale + Vec(0,0,sin(theta)); } else { theta = atan(h/(R2-R1)); normale = normale * (1/normale.norm())*sin(theta); normale = normale - Vec(0,0,cos(theta)); } if ( hit.time() > t){ hit.setTime(t); Vec locale = frame().inverseTransformOf(I); hit.setIntersection(locale); hit.setNormal(frame().inverseTransformOf(normale)); hit.setMaterial(material()); computeUV(hit); #ifdef DEBUG_INTERSEC displayIntersectionDebug(ray,hit,O,I,t); #endif topdisque()->intersect(ray,hit); bottomdisque()->intersect(ray,hit); return true; }else{ return false; } } if (delta ==0) { #ifdef DEBUG_INTERSEC cout << "delta est nul, il y a une solution" << endl; #endif // une solution, regarder si on intersecte les disques et comparer les time obtenu pour trouver le plus petit float t; if (a==0) { t = -c/b; } else { t=(-b/(2*a)); } if (t<0) { //l'objet est derrière moi #ifdef DEBUG_INTERSEC cout << "On est à l'intérieur de l'objet" << endl; #endif return false; } // on calcule le point d'intersection I.x = O.x + t*D.x; I.y = O.y + t*D.y; I.z = O.z + t*D.z; // on calcule la normale en ce point, dans les coordonnées du cylindre toujours float theta; Vec normale; theta = atan((R1-R2)/h); normale.x = I.x; normale.y = I.y; normale.z = 0; if (normale.norm() == 0) { cout << "la norme de la normale est nulle" << endl; } normale = normale * (1/normale.norm())*cos(theta); normale = normale + Vec(0,0,sin(theta)); if ( hit.time() > t){ hit.setTime(t); hit.setIntersection(frame().inverseCoordinatesOf(I)); hit.setNormal(frame().inverseCoordinatesOf(normale)); hit.setMaterial(material()); computeUV(hit); #ifdef DEBUG_INTERSEC displayIntersectionDebug(ray,hit,O,I,t); #endif topdisque()->intersect(ray,hit); bottomdisque()->intersect(ray,hit); return true; }else{ return false; } } #ifdef DEBUG cerr << "Erreur lors du calcul de l'intersection d'un objet avec un rayon" << endl; #endif return false; }
/// Computes the intersection of a ray and an infinite plane defined by three vertices RAYTRACER_EXPORTS static bool Helper1(const Ray& ray, const Vec3d &a, const Vec3d &b, const Vec3d &c, Vec3d& uvw, double & lambda) { // Barycentric approach according to lecture slides // Ray: x=o+t*d // Barycentric Triangle: x=a*u+b*v+c*w // Solve: o+t*d = u*a+v*b+w*c // This is an inhomogeneous linear system // (ax bx cx -dx) (u) = ox // (ay by cy -dy) (v) = oy // (az bz cz -dz) (w) = oz // (1 1 1 0 ) (t) = 1 // or in short: A*x = o // Then, solution is given by A^-1 * o = x // with x = (u,v,w,t)^T /* const Vec3& o = ray.origin(); const Vec3& d = ray.direction(); Mat4 A; A(0,0)=a[0];A(0,1)=b[0];A(0,2)=c[0];A(0,3)=-d[0]; A(1,0)=a[1];A(1,1)=b[1];A(1,2)=c[1];A(1,3)=-d[1]; A(2,0)=a[2];A(2,1)=b[2];A(2,2)=c[2];A(2,3)=-d[2]; A(3,0)=1 ;A(3,1)=1 ;A(3,2)=1 ;A(3,3)=0; A.invert(); Vec4 x=A*Vec4(o,1); uvw[0] = x[0]; uvw[1] = x[1]; uvw[2] = x[2]; lambda = x[3]; return true; */ ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //Approach by Moeller and Trumbore //see Fast, Minimum Storage RayTriangle Intersection // Ray: x=o+t*d // Barycentric Triangle: x=u*a+v*b+w*c // w=1-u-v // Therefore // x=u*a+v*b+(1-u-v)*c // Solve: o+t*d = u*a+v*b+(1-u-v)*c // Rearrange, then // (ax-cx bx-cx -dx) (u) = (ox-dx) // (ay-cy by-cy -dy) (v) = (oy-dy) // (az-cz bz-cz -dz) (t) = (oz-dz) // or in short: A*x = b // Then, solution is given by A^-1 * b = x // with x = (u,v,t)^T // This system can be solved using Cramer's rule // x_i = det(A_i) / det(A) // where the i-th column is replaced with b in the Matrix A_i // // e1 = a-c // e2 = b-c // tt = o-d // then // ( ) (u) // (e1 e2 -d) (v) = tt // ( ) (t) // with // (u) ( det(tt,e2,-d) ) // (v) = 1/det(e1,e2,-d)* ( det(e1,tt,-d) ) // (t) ( det(e1,e2,tt) ) //use triple scalar product // det(a,b,c) = a * (b x c) = b * (c x a) = c*(a x b) , and // a * (b x c) = -a * (c x b) // then // (u) ( tt * (e2 x -d) ) // (v) = e1*(e2 x -d) ( e1 * (tt x -d) ) // (t) ( e1 * (e2 x tt) ) //rearrange terms for u,t // (u) ( tt * (e2 x -d) ) // (v) = e1*(e2 x -d) ( -d * (e1 x tt) ) // (t) (-e2 * (e1 x tt) ) // reuse expensive terms // pp = e2 x -d // qq = e1 x tt // then // (u) ( tt * pp ) // (v) = e1*pp ( -d * qq ) // (t) (-e2 * qq ) const Vec3d& o = ray.origin(); const Vec3d& d = ray.direction(); Vec3d e1 = a-c; Vec3d e2 = b-c; Vec3d tt = o-c; Vec3d pp = cross(e2,-d); Vec3d qq = cross(e1,tt); double detA = dot(e1,pp); if(fabs(detA) < Math::safetyEps()) return false; uvw[0] = (dot( tt,pp))/detA; uvw[1] = (dot( -d,qq))/detA; uvw[2] = 1-uvw[0]-uvw[1]; lambda = (dot(-e2,qq))/detA; return true; }
//-------------------------------------------------------------------------------------------------- /// Intersect the drawable geo with the ray and return the closest intersection point and the face hit /// /// Returns true if anything was hit. //-------------------------------------------------------------------------------------------------- bool DrawableGeo::rayIntersect(const Ray& ray, Vec3d* intersectionPoint, uint* faceHit) const { CVF_ASSERT(intersectionPoint); bool anyHits = false; double minDistSquared = 1.0e300; cref<Vec3fArray> vertexArr = m_vertexBundle->vertexArray(); size_t numPrimitiveSets = m_primitiveSets.size(); size_t iPrimSet; int accumulatedFaceCount = 0; for (iPrimSet = 0; iPrimSet < numPrimitiveSets; iPrimSet++) { const PrimitiveSet* primSet = m_primitiveSets.at(iPrimSet); CVF_TIGHT_ASSERT(primSet); UIntArray conn; int numPrimFaces = static_cast<int>(primSet->faceCount()); #pragma omp parallel for private (conn) for (int i = 0; i < numPrimFaces; i++) { bool hitThisFace = false; Vec3d localIntersect; primSet->getFaceIndices(static_cast<size_t>(i), &conn); int numconn = static_cast<int>(conn.size()); CVF_TIGHT_ASSERT(numconn <= 3); if (numconn == 3) { hitThisFace = ray.triangleIntersect(Vec3d(vertexArr->get(conn[0])), Vec3d(vertexArr->get(conn[1])), Vec3d(vertexArr->get(conn[2])), &localIntersect); } if (hitThisFace) { double distSquared = (ray.origin() - localIntersect).lengthSquared(); #pragma omp critical { if (distSquared < minDistSquared) { *intersectionPoint = localIntersect; minDistSquared = distSquared; if (faceHit) { *faceHit = i + accumulatedFaceCount; } } anyHits = true; } } } // End omp parallel for accumulatedFaceCount += numPrimFaces; } return anyHits; }
Intersection Cube::GetIntersection(Ray r) { //Transform the ray Ray r_loc = r.GetTransformedCopy(transform.invT()); Intersection result; float t_n = -1000000.f; float t_f = 1000000.f; for(int i = 0; i < 3; i++){ //Ray parallel to slab check if(r_loc.direction[i] == 0){ if(r_loc.origin[i] < -0.5f || r_loc.origin[i] > 0.5f){ return result; } } //If not parallel, do slab intersect check float t0 = (-0.5f - r_loc.origin[i])/r_loc.direction[i]; float t1 = (0.5f - r_loc.origin[i])/r_loc.direction[i]; if(t0 > t1){ float temp = t1; t1 = t0; t0 = temp; } if(t0 > t_n){ t_n = t0; } if(t1 < t_f){ t_f = t1; } } float t_final = -1; if(t_n < t_f) { if(t_n >= 0) { t_final = t_n; } else if(t_f >= 0) { t_final = t_f; } } if(t_final >= 0) { //Lastly, transform the point found in object space by T glm::vec4 P = glm::vec4(r_loc.origin + t_final*r_loc.direction, 1); glm::vec4 N( glm::normalize( GetCubeNormal( P ) ) ); result.point = glm::vec3(transform.T() * P); result.normal = glm::normalize(glm::vec3(transform.invTransT() * N)); result.object_hit = this; result.t = glm::distance(result.point, r.origin); result.texture_color = Material::GetImageColorInterp(GetUVCoordinates(glm::vec3(P)), material->texture); //TODO: Store the tangent and bitangent glm::vec4 T( 0.f ), B( 0.f ); if( N[ 0 ] < -.9f ){ T = glm::vec4( 0.f, -1.f, 0.f, 0.f ); }else if( N[ 0 ] > .9f ){ T = glm::vec4( 0.f, 1.f, 0.f, 0.f ); }else if( N[ 1 ] < -.9f ){ T = glm::vec4( 0.f, 0.f, -1.f, 0.f ); }else if( N[ 1 ] > .9f ){ T = glm::vec4( 0.f, 0.f, 1.f, 0.f ); }else if( N[ 2 ] < -.9f ){ T = glm::vec4( -1.f, 0.f, 0.f, 0.f ); }else{ T = glm::vec4( 1.f, 0.f, 0.f, 0.f ); } B = glm::vec4( glm::cross( glm::vec3( N ), glm::vec3( T ) ), 0.f ); result.tangent = glm::normalize( glm::vec3( transform.T() * T ) ); result.bitangent = glm::normalize( glm::vec3( transform.T() * B ) ); return result; } else{ return result; } }
bool Box::intersect( const Ray& r, Hit& h, float tmin ) const { float maxToCam = (r.getOrigin() - this->m_max).length(); float minToCam = (r.getOrigin() - this->m_min).length(); Vec3f direction = r.getDirection(); Vec3f origin = r.getOrigin(); // Keep the direction values sane, we don't want to divide by zero if (direction.x == 0.0f) direction.x += EPSILON; if (direction.y == 0.0f) direction.y += EPSILON; if (direction.z == 0.0f) direction.z += EPSILON; float min, max, ymin, ymax, zmin, zmax; // Calculate the maximum and minimum on the x-axis float divx = 1.0f/direction.x; if (divx >= 0) { min = (this->m_min.x - origin.x) * divx; max = (this->m_max.x - origin.x) * divx; } else { min = (this->m_max.x - origin.x) * divx; max = (this->m_min.x - origin.x) * divx; } // Calculate the maximum and minimum on the y-axis float divy = 1.0f/direction.y; if (divy >= 0) { ymin = (this->m_min.y - origin.y) * divy; ymax = (this->m_max.y - origin.y) * divy; } else { ymin = (this->m_max.y - origin.y) * divy; ymax = (this->m_min.y - origin.y) * divy; } if ( (min > ymax) || (ymin > max) ) return false; // Make sure the tmin and tmax hold the most binding values if (ymin > min) min = ymin; if (ymax < max) max = ymax; // Calculate the maximum and minimum on the z-axis float divz = 1.0f/direction.z; if (divz >= 0) { zmin = (this->m_min.z - origin.z) * divz; zmax = (this->m_max.z - origin.z) * divz; } else { zmin = (this->m_max.z - origin.z) * divz; zmax = (this->m_min.z - origin.z) * divz; } if ( (min > zmax) || (zmin > max ) ) return false; // Make sure the tmin and tmax hold the most binding values if (zmin > min) min = zmin; if (zmax < max) max = zmax; if ( (min < h.getT() && (max > tmin)) ) { // Calculate the normal and set the values Vec3f point = r.pointAtParameter(min); Vec3f normal; if (FW::abs(point.x - this->m_min.x) < EPSILON) normal = Vec3f(-1.0f, 0.0f, 0.0f); else if (FW::abs(point.x - this->m_max.x) < EPSILON) normal = Vec3f(1.0f, 0.0f, 0.0f); else if (FW::abs(point.y - this->m_min.y) < EPSILON) normal = Vec3f(0.0f, -1.0f, 0.0f); else if (FW::abs(point.y - this->m_max.y) < EPSILON) normal = Vec3f(0.0f, 1.0f, 0.0f); else if (FW::abs(point.z - this->m_min.z) < EPSILON) normal = Vec3f(0.0f, 0.0f, -1.0f); else if (FW::abs(point.z - this->m_max.z) < EPSILON) normal = Vec3f(0.0f, 0.0f, 1.0f); else std::cerr << "ERROR: Could not calculate the normal in box intersect." << std::endl; h.set(min, this->m_material, normal); return true; } return false; }
Ray Renderable::transformRayWorldToModel(const Ray &ray) const { this->updateTransforms(); return ray.transformed(mTransformInv); }
int lua_Ray_setOrigin(lua_State* state) { // Get the number of parameters. int paramCount = lua_gettop(state); // Attempt to match the parameters to a valid binding. switch (paramCount) { case 2: { do { if ((lua_type(state, 1) == LUA_TUSERDATA) && (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TNIL)) { // Get parameter 1 off the stack. bool param1Valid; gameplay::ScriptUtil::LuaArray<Vector3> param1 = gameplay::ScriptUtil::getObjectPointer<Vector3>(2, "Vector3", true, ¶m1Valid); if (!param1Valid) break; Ray* instance = getInstance(state); instance->setOrigin(*param1); return 0; } } while (0); lua_pushstring(state, "lua_Ray_setOrigin - Failed to match the given parameters to a valid function signature."); lua_error(state); break; } case 4: { do { if ((lua_type(state, 1) == LUA_TUSERDATA) && lua_type(state, 2) == LUA_TNUMBER && lua_type(state, 3) == LUA_TNUMBER && lua_type(state, 4) == LUA_TNUMBER) { // Get parameter 1 off the stack. float param1 = (float)luaL_checknumber(state, 2); // Get parameter 2 off the stack. float param2 = (float)luaL_checknumber(state, 3); // Get parameter 3 off the stack. float param3 = (float)luaL_checknumber(state, 4); Ray* instance = getInstance(state); instance->setOrigin(param1, param2, param3); return 0; } } while (0); lua_pushstring(state, "lua_Ray_setOrigin - Failed to match the given parameters to a valid function signature."); lua_error(state); break; } default: { lua_pushstring(state, "Invalid number of parameters (expected 2 or 4)."); lua_error(state); break; } } return 0; }