193 lines
6.2 KiB
C++
193 lines
6.2 KiB
C++
#include <mitsuba/render/camera.h>
|
|
#include <mitsuba/core/plugin.h>
|
|
|
|
MTS_NAMESPACE_BEGIN
|
|
|
|
Camera::Camera(const Properties &props)
|
|
: ConfigurableObject(props), m_properties(props) {
|
|
m_cameraToWorld = props.getTransform("toWorld", Transform());
|
|
m_worldToCamera = m_cameraToWorld.inverse();
|
|
m_position = m_cameraToWorld(Point(0,0,0));
|
|
}
|
|
|
|
Camera::Camera(Stream *stream, InstanceManager *manager)
|
|
: ConfigurableObject(stream, manager) {
|
|
m_film = static_cast<Film *>(manager->getInstance(stream));
|
|
m_sampler = static_cast<Sampler *>(manager->getInstance(stream));
|
|
m_worldToCamera = Transform(stream);
|
|
m_cameraToWorld = Transform(stream);
|
|
m_position = m_cameraToWorld(Point(0,0,0));
|
|
}
|
|
|
|
Camera::~Camera() {
|
|
}
|
|
|
|
void Camera::setParent(ConfigurableObject *parent) {
|
|
// Do not store the parent - this is useful in case
|
|
// the camera subtree needs to be serialized by itself.
|
|
}
|
|
|
|
Point Camera::getPosition(const Point2 &sample) const {
|
|
return m_position; // default impl.
|
|
}
|
|
|
|
void Camera::setFilm(Film *film) {
|
|
m_film = film;
|
|
configure();
|
|
}
|
|
|
|
void Camera::serialize(Stream *stream, InstanceManager *manager) const {
|
|
ConfigurableObject::serialize(stream, manager);
|
|
manager->serialize(stream, m_film.get());
|
|
manager->serialize(stream, m_sampler.get());
|
|
m_worldToCamera.serialize(stream);
|
|
m_cameraToWorld.serialize(stream);
|
|
}
|
|
|
|
void Camera::generateRayDifferential(const Point2 &sample,
|
|
const Point2 &lensSample, RayDifferential &ray) const {
|
|
|
|
generateRay(sample, lensSample, ray);
|
|
Point2 temp = sample; temp.x += 1;
|
|
generateRay(temp, lensSample, ray.rx);
|
|
temp = sample; temp.y += 1;
|
|
generateRay(temp, lensSample, ray.ry);
|
|
ray.hasDifferentials = true;
|
|
}
|
|
|
|
void Camera::addChild(const std::string &name, ConfigurableObject *child) {
|
|
if (child->getClass()->derivesFrom(Sampler::m_theClass)) {
|
|
Assert(m_sampler == NULL);
|
|
m_sampler = static_cast<Sampler *>(child);
|
|
} else if (child->getClass()->derivesFrom(Film::m_theClass)) {
|
|
Assert(m_film == NULL);
|
|
m_film = static_cast<Film *>(child);
|
|
} else {
|
|
Log(EError, "Camera: Invalid child node!");
|
|
}
|
|
}
|
|
|
|
ProjectiveCamera::ProjectiveCamera(Stream *stream, InstanceManager *manager)
|
|
: Camera(stream, manager) {
|
|
m_cameraToScreen = Transform(stream);
|
|
m_cameraToScreenGL = Transform(stream);
|
|
m_aspect = stream->readFloat();
|
|
}
|
|
|
|
void ProjectiveCamera::configure() {
|
|
if (m_film == NULL) {
|
|
/* Instantiate an EXR film by default */
|
|
m_film = static_cast<Film*> (PluginManager::getInstance()->
|
|
createObject(Film::m_theClass, Properties("exrfilm")));
|
|
m_film->configure();
|
|
}
|
|
|
|
if (m_sampler == NULL) {
|
|
/* No sampler has been selected - load an independent filter with 4 samples/pixel by default */
|
|
Properties props("independent");
|
|
props.setInteger("sampleCount", 4);
|
|
m_sampler = static_cast<Sampler *> (PluginManager::getInstance()->
|
|
createObject(Sampler::m_theClass, props));
|
|
m_sampler->configure();
|
|
}
|
|
m_aspect = (Float) m_film->getSize().x / (Float) m_film->getSize().y;
|
|
}
|
|
|
|
void ProjectiveCamera::serialize(Stream *stream, InstanceManager *manager) const {
|
|
Camera::serialize(stream, manager);
|
|
|
|
m_cameraToScreen.serialize(stream);
|
|
m_cameraToScreenGL.serialize(stream);
|
|
stream->writeFloat(m_aspect);
|
|
}
|
|
|
|
PinholeCamera::PinholeCamera(const Properties &props)
|
|
: ProjectiveCamera(props) {
|
|
/* Field of view of the camera (in degrees) */
|
|
m_fov = props.getFloat("fov", 90);
|
|
/* Specifies which side of the image plane should cover the
|
|
field of view specified in the <tt>fov</tt> parameter
|
|
*/
|
|
m_mapSmallerSide = props.getBoolean("mapSmallerSide", true);
|
|
}
|
|
|
|
PinholeCamera::PinholeCamera(Stream *stream, InstanceManager *manager)
|
|
: ProjectiveCamera(stream, manager) {
|
|
m_fov = stream->readFloat();
|
|
m_mapSmallerSide = stream->readBool();
|
|
}
|
|
|
|
void PinholeCamera::serialize(Stream *stream, InstanceManager *manager) const {
|
|
ProjectiveCamera::serialize(stream, manager);
|
|
|
|
stream->writeFloat(m_fov);
|
|
stream->writeBool(m_mapSmallerSide);
|
|
}
|
|
|
|
void PinholeCamera::configure() {
|
|
ProjectiveCamera::configure();
|
|
|
|
bool mapYToNDC01 = (m_aspect >= 1.0f);
|
|
if (!m_mapSmallerSide)
|
|
mapYToNDC01 = !mapYToNDC01;
|
|
|
|
if (mapYToNDC01) {
|
|
m_yfov = m_fov;
|
|
m_xfov = radToDeg(2 * std::atan(std::tan(degToRad(m_fov)/2) * m_aspect));
|
|
} else {
|
|
m_xfov = m_fov;
|
|
m_yfov = radToDeg(2 * std::atan(std::tan(degToRad(m_fov)/2) / m_aspect));
|
|
}
|
|
m_imagePlaneSize.x = 2 * std::tan(degToRad(m_xfov)/2);
|
|
m_imagePlaneSize.y = 2 * std::tan(degToRad(m_yfov)/2);
|
|
m_imagePlanePixelSize.x = m_imagePlaneSize.x / getFilm()->getSize().x;
|
|
m_imagePlanePixelSize.y = m_imagePlaneSize.y / getFilm()->getSize().y;
|
|
m_imagePlaneInvArea = 1 / (m_imagePlaneSize.x * m_imagePlaneSize.y);
|
|
}
|
|
|
|
Float PinholeCamera::importance(const Point2 &p) const {
|
|
Float x = (p.x * m_imagePlanePixelSize.x) - .5f * m_imagePlaneSize.x;
|
|
Float y = (p.y * m_imagePlanePixelSize.y) - .5f * m_imagePlaneSize.y;
|
|
|
|
return std::pow(1 + x*x+y*y, (Float) (3.0/2.0)) * m_imagePlaneInvArea;
|
|
}
|
|
|
|
Float PinholeCamera::solidAngle(Float xs, Float xe, Float ys, Float ye) const {
|
|
xs = (xs * m_imagePlanePixelSize.x) - .5f * m_imagePlaneSize.x;
|
|
ys = (ys * m_imagePlanePixelSize.y) - .5f * m_imagePlaneSize.y;
|
|
xe = (xe * m_imagePlanePixelSize.x) - .5f * m_imagePlaneSize.x;
|
|
ye = (ye * m_imagePlanePixelSize.y) - .5f * m_imagePlaneSize.y;
|
|
|
|
/* cos(theta) / d^2 with respect to the image plane integrated
|
|
over the specified footprint */
|
|
Float xs2 = xs*xs, xe2 = xe*xe, ys2 = ys*ys, ye2 = ye*ye;
|
|
Float atan1 = std::atan((xe*ye)/std::sqrt(1 + xe2 + ye2));
|
|
Float atan2 = std::atan((xs*ye)/std::sqrt(1 + xs2 + ye2));
|
|
Float atan3 = std::atan((xe*ys)/std::sqrt(1 + xe2 + ys2));
|
|
Float atan4 = std::atan((xs*ys)/std::sqrt(1 + xs2 + ys2));
|
|
return atan1 - atan2 - atan3 + atan4;
|
|
}
|
|
|
|
Float PinholeCamera::importance(const Vector &v) const {
|
|
Vector localV;
|
|
m_worldToCamera(v, localV);
|
|
if (localV.z <= 0.0f)
|
|
return 0.0f;
|
|
Float invZ = 1.0f / localV.z;
|
|
localV.x *= invZ; localV.y *= invZ;
|
|
if (2*std::abs(localV.x)>m_imagePlaneSize.x
|
|
|| 2*std::abs(localV.y)>m_imagePlaneSize.y)
|
|
return 0.0f;
|
|
return std::pow(1 + localV.x*localV.x+localV.y*localV.y,
|
|
(Float) (3.0/2.0)) * m_imagePlaneInvArea;
|
|
}
|
|
|
|
Vector2 PinholeCamera::getImagePlaneSize(Float dist) const {
|
|
return m_imagePlaneSize * dist;
|
|
}
|
|
|
|
MTS_IMPLEMENT_CLASS(Camera, true, ConfigurableObject)
|
|
MTS_IMPLEMENT_CLASS(ProjectiveCamera, true, Camera)
|
|
MTS_IMPLEMENT_CLASS(PinholeCamera, true, ProjectiveCamera)
|
|
MTS_NAMESPACE_END
|