vec3 Sphere::closestPoint( const Ray &ray ) const { float t; vec3 diff = ray.getOrigin() - mCenter; float a = dot( ray.getDirection(), ray.getDirection() ); float b = 2 * dot( diff, ray.getDirection() ); float c = dot( diff, diff ) - mRadius * mRadius; float disc = b * b - 4 * a * c; if( disc > 0 ) { float e = math<float>::sqrt( disc ); float denom = 2 * a; t = (-b - e) / denom; // smaller root if( t > EPSILON_VALUE ) return ray.calcPosition( t ); t = (-b + e) / denom; // larger root if( t > EPSILON_VALUE ) return ray.calcPosition( t ); } // doesn't intersect; closest point on line t = dot( -diff, normalize(ray.getDirection()) ); vec3 onRay = ray.calcPosition( t ); return mCenter + normalize( onRay - mCenter ) * mRadius; // return ray.getDirection() * dot( ray.getDirection(), (mCenter - ray.getOrigin() ) ); }
float RayMarcher::marchSecondary( const Ray &ray ) { const float RAY_EPSILON = 0.50f; float boxTimes[2]; if( mBoundingBox.intersect( ray, boxTimes ) != 2 ) return 0; Vec3f pointOfDeparture; if( boxTimes[0] >= 0 ) pointOfDeparture = ray.calcPosition( boxTimes[0] ); else pointOfDeparture = ray.calcPosition( boxTimes[1] ); float span = ray.getOrigin().distance( pointOfDeparture ); int numSteps = (int)( span / RAY_EPSILON ); if( numSteps <= 0 ) return 0; Vec3f step( ray.getDirection() ); step *= RAY_EPSILON; Vec3f rayPos = ray.getOrigin(); float result = 0; for( int i = 0; i < numSteps; ++i ) { float D = sampleDensity( rayPos ) * RAY_EPSILON; result += D * ( 1.0f - result ); rayPos += step; } return result; }
ColorA RayMarcher::march( const Ray &ray ) { const float RAY_EPSILON = 0.25f; float boxTimes[2]; if( mBoundingBox.intersect( ray, boxTimes ) < 2 ) return ColorA::zero(); Vec3f pos0, pos1; if( boxTimes[0] < boxTimes[1] ) { pos0 = ray.calcPosition( boxTimes[0] ); pos1 = ray.calcPosition( boxTimes[1] ); } else { pos0 = ray.calcPosition( boxTimes[1] ); pos1 = ray.calcPosition( boxTimes[0] ); } float span = pos0.distance( pos1 ); int numSteps = (int)( span / RAY_EPSILON ); if( numSteps <= 0 ) return ColorA::zero(); Vec3f step( ray.getDirection() ); step *= RAY_EPSILON; Vec3f rayPos = pos0; Vec3f lightVec = mCamera->getModelViewMatrix().transformVec( Vec3f( 1, 1, 1 ).normalized() ); float transparency = 1.0f; ColorA result = ColorA::zero(); for( int i = 0; i < numSteps; ++i ) { ColorA sample; float D = sampleDensity( rayPos ) * RAY_EPSILON; if( D >= 0.001f ) { sample.a = D; float t = sample.a * ( 1.0f - result.a ); const float ambient = 0.45f; const float diffuse = 1.0f - ambient; float c = ambient + diffuse * ( 1.0f - marchSecondary( Ray( rayPos, lightVec ) ) ); result += ColorA( c * t, c * t, c * t, t ); if( transparency < 0.001f ) break; } rayPos += step; } if( result.r < 0 ) result.r = 0; if( result.r > 1 ) result.r = 1; if( result.g < 0 ) result.g = 0; if( result.g > 1 ) result.g = 1; if( result.b < 0 ) result.b = 0; if( result.b > 1 ) result.b = 1; return result; }
void RodSoundApp::mouseDown(MouseEvent event) { if (event.isRight()) { // Set targetPos to the ControlPoint we just clicked if (!r) return; Vec2i mouse = event.getPos(); Vec2i windowSize = getWindowSize(); Ray ray = cam.generateRay((real)mouse.x/windowSize.x, 1.0 - (real)mouse.y/windowSize.y, getWindowAspectRatio()); real tmin = INFINITY; bool any = false; for (int i=0; i<r->numCPs(); i++) { // A bit slow, but beats keeping a KD-Tree updated Sphere s(EtoC(r->cur().POS(i)), constants::radius * 1.5); float t; if (s.intersect(ray, &t) && t < tmin) { any = true; tmin = t; } } if (!any) return; targetPos = ray.calcPosition(tmin); cam.lookAt(targetPos); } else { if (!running) return; isMouseDown = true; mouseDrag(event); } }
void gpuPSApp::computeAttractorPosition() { // The attractor is positioned at the intersection of a ray // from the mouse to a plane perpendicular to the camera. float t = 0; Vec3f right, up; mMayaCam.getCamera().getBillboardVectors(&right, &up); CameraPersp cam = mMayaCam.getCamera(); float u = mMousePos.x / (float) getWindowWidth(); float v = mMousePos.y / (float) getWindowHeight(); Ray ray = cam.generateRay(u , 1.0f - v, cam.getAspectRatio() ); if (ray.calcPlaneIntersection(Vec3f(0.0f,0.0f,0.0f), right.cross(up), &t)) { mAttractor.set(ray.calcPosition(t)); } }
void RodSoundApp::mouseDrag(MouseEvent event) { if (!running) return; Vec2i mouse = event.getPos(); Vec2i windowSize = getWindowSize(); Ray r = cam.generateRay((real)mouse.x/windowSize.x, 1.0 - (real)mouse.y/windowSize.y, getWindowAspectRatio()); float t; if(!r.calcPlaneIntersection(targetPos, targetPos-eyePos, &t)) { std::cerr << "Mouse ray did not intersect plane!\n"; } mousePosition = r.calcPosition(t); }
//------------------------------------------------------------------------------ bool SceEllipsoid::RayCast(Ray const & ray, float & t, Vec3f & point, Vec3f & normal) const { float tIntersection; if (RayCast(ray, tIntersection)) { t = tIntersection; point = ray.calcPosition(tIntersection); normal = (mMatrixInvTInv * (point - mCenter)).normalized(); return true; } return false; }