134 lines
3.2 KiB
C++
134 lines
3.2 KiB
C++
|
/**
|
||
|
@file Cone.cpp
|
||
|
|
||
|
Cone class
|
||
|
|
||
|
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||
|
|
||
|
@created 2001-07-09
|
||
|
@edited 2006-01-29
|
||
|
*/
|
||
|
|
||
|
#include "G3D/platform.h"
|
||
|
#include "G3D/Cone.h"
|
||
|
#include "G3D/Line.h"
|
||
|
#include "G3D/Sphere.h"
|
||
|
#include "G3D/Box.h"
|
||
|
|
||
|
namespace G3D {
|
||
|
|
||
|
|
||
|
float Cone::solidAngleFromHalfAngle(float halfAngle){
|
||
|
return 2.0f * pif() * (1 - cosf(halfAngle));
|
||
|
}
|
||
|
|
||
|
double Cone::solidAngleFromHalfAngle(double halfAngle){
|
||
|
return 2.0 * pi() * (1.0 - cos(halfAngle));
|
||
|
}
|
||
|
|
||
|
float Cone::halfAngleFromSolidAngle(float solidAngle){
|
||
|
return acos((1.0f - (solidAngle / (2.0f * pif()))));
|
||
|
}
|
||
|
|
||
|
double Cone::halfAngleFromSolidAngle(double solidAngle){
|
||
|
return aCos((1.0 - (solidAngle / (2.0 * pi()))));
|
||
|
}
|
||
|
|
||
|
|
||
|
Cone::Cone(const Vector3 &tip, const Vector3 &direction, float angle) {
|
||
|
this->tip = tip;
|
||
|
this->direction = direction.direction();
|
||
|
this->angle = angle;
|
||
|
|
||
|
debugAssert(angle >= 0);
|
||
|
debugAssert(angle <= pi());
|
||
|
}
|
||
|
|
||
|
Vector3 Cone::randomDirectionInCone(Random& rng) const {
|
||
|
const float cosThresh = cos(angle);
|
||
|
|
||
|
float cosAngle;
|
||
|
float normalizer;
|
||
|
Vector3 v;
|
||
|
do {
|
||
|
float vlenSquared;
|
||
|
|
||
|
// Sample uniformly on a sphere by rejection sampling and then normalizing
|
||
|
do {
|
||
|
v.x = rng.uniform(-1, 1);
|
||
|
v.y = rng.uniform(-1, 1);
|
||
|
v.z = rng.uniform(-1, 1);
|
||
|
|
||
|
// Sample uniformly on a cube
|
||
|
vlenSquared = v.squaredLength();
|
||
|
} while (vlenSquared > 1);
|
||
|
|
||
|
|
||
|
const float temp = v.dot(direction);
|
||
|
|
||
|
// Compute 1 / ||v||, but
|
||
|
// if the vector is in the wrong hemisphere, flip the sign
|
||
|
normalizer = rsqrt(vlenSquared) * sign(temp);
|
||
|
|
||
|
// Cosine of the angle between v and the light's negative-z axis
|
||
|
cosAngle = temp * normalizer;
|
||
|
|
||
|
} while (cosAngle < cosThresh);
|
||
|
|
||
|
// v was within the cone. Normalize it and maybe flip the hemisphere.
|
||
|
return v * normalizer;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
Forms the smallest cone that contains the box. Undefined if
|
||
|
the tip is inside or on the box.
|
||
|
*/
|
||
|
Cone::Cone(const Vector3& tip, const Box& box) {
|
||
|
this->tip = tip;
|
||
|
this->direction = (box.center() - tip).direction();
|
||
|
|
||
|
// Find the biggest angle
|
||
|
float smallestDotProduct = direction.dot((box.corner(0) - tip).direction());
|
||
|
|
||
|
for (int i = 1; i < 8; ++i) {
|
||
|
float dp = direction.dot((box.corner(i) - tip).direction());
|
||
|
|
||
|
debugAssert(dp > 0);
|
||
|
|
||
|
if (dp < smallestDotProduct) {
|
||
|
smallestDotProduct = dp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
angle = acosf(smallestDotProduct);
|
||
|
}
|
||
|
|
||
|
|
||
|
bool Cone::intersects(const Sphere& b) const {
|
||
|
// If the bounding sphere contains the tip, then
|
||
|
// they definitely touch.
|
||
|
if (b.contains(this->tip)) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Move the tip backwards, effectively making the cone bigger
|
||
|
// to account for the radius of the sphere.
|
||
|
|
||
|
Vector3 tip = this->tip - direction * b.radius / sinf(angle);
|
||
|
|
||
|
return Cone(tip, direction, angle).contains(b.center);
|
||
|
}
|
||
|
|
||
|
|
||
|
bool Cone::contains(const Vector3& v) const {
|
||
|
|
||
|
Vector3 d = (v - tip).direction();
|
||
|
|
||
|
float x = d.dot(direction);
|
||
|
|
||
|
return (x > 0) && (x >= cosf(angle));
|
||
|
}
|
||
|
|
||
|
}; // namespace
|