272 lines
7.2 KiB
C++
272 lines
7.2 KiB
C++
#include "CameraDefinition.h"
|
|
|
|
#include <cmath>
|
|
#include "Maths.h"
|
|
#include "PackStream.h"
|
|
#include "BoundingBox.h"
|
|
|
|
CameraDefinition::CameraDefinition(DefinitionNode *parent) : DefinitionNode(parent, "camera", "camera") {
|
|
location.x = 0.0;
|
|
location.y = 0.0;
|
|
location.z = 0.0;
|
|
direction.phi = 0.0;
|
|
direction.theta = 0.0;
|
|
direction.r = 1.0;
|
|
roll = 0.0;
|
|
|
|
width = 1.0;
|
|
height = 1.0;
|
|
perspective.yfov = 1.0;
|
|
perspective.xratio = 1.0;
|
|
perspective.znear = 0.5;
|
|
perspective.zfar = 20000.0;
|
|
|
|
validate();
|
|
}
|
|
|
|
void CameraDefinition::save(PackStream *stream) const {
|
|
location.save(stream);
|
|
stream->write(&direction.r);
|
|
stream->write(&direction.phi);
|
|
stream->write(&direction.theta);
|
|
stream->write(&roll);
|
|
stream->write(&perspective.yfov);
|
|
}
|
|
|
|
void CameraDefinition::load(PackStream *stream) {
|
|
location.load(stream);
|
|
stream->read(&direction.r);
|
|
stream->read(&direction.phi);
|
|
stream->read(&direction.theta);
|
|
stream->read(&roll);
|
|
stream->read(&perspective.yfov);
|
|
|
|
validate();
|
|
}
|
|
|
|
void CameraDefinition::copy(DefinitionNode *_destination) const {
|
|
CameraDefinition *destination = (CameraDefinition *)_destination;
|
|
|
|
destination->location = location;
|
|
destination->direction = direction;
|
|
destination->roll = roll;
|
|
|
|
destination->perspective = perspective;
|
|
|
|
destination->validate();
|
|
}
|
|
|
|
void CameraDefinition::validate() {
|
|
if (location.y > 300.0) {
|
|
location.y = 300.0;
|
|
}
|
|
|
|
forward.x = 1.0;
|
|
forward.y = 0.0;
|
|
forward.z = 0.0;
|
|
right.x = 0.0;
|
|
right.y = 0.0;
|
|
right.z = 1.0;
|
|
up.x = 0.0;
|
|
up.y = 1.0;
|
|
up.z = 0.0;
|
|
|
|
Matrix4 rotation = Matrix4::newRotateEuler(direction.phi, direction.theta, roll);
|
|
|
|
forward = rotation.multPoint(forward);
|
|
right = rotation.multPoint(right);
|
|
up = rotation.multPoint(up);
|
|
|
|
target = location.add(direction);
|
|
|
|
Matrix4 mperspective =
|
|
Matrix4::newPerspective(perspective.yfov, perspective.xratio, perspective.znear, perspective.zfar);
|
|
unperspective = mperspective.inversed();
|
|
|
|
projector = mperspective.mult(Matrix4::newLookAt(location, target, up));
|
|
unprojector = projector.inversed();
|
|
|
|
inv_x_factor = 1.0 / (0.5 * width);
|
|
inv_y_factor = 1.0 / (0.5 * height);
|
|
}
|
|
|
|
double CameraDefinition::getRealDepth(const Vector3 &projected) const {
|
|
Vector3 v(projected.x * inv_x_factor - 1.0, -(projected.y * inv_x_factor - 1.0), projected.z);
|
|
return unperspective.transform(v).z;
|
|
}
|
|
|
|
void CameraDefinition::setLocation(const Vector3 &location) {
|
|
this->location = location;
|
|
|
|
validate();
|
|
}
|
|
|
|
void CameraDefinition::setLocationCoords(double x, double y, double z) {
|
|
location = Vector3(x, y, z);
|
|
|
|
validate();
|
|
}
|
|
|
|
void CameraDefinition::setTarget(const Vector3 &target) {
|
|
Vector3 forward;
|
|
|
|
forward = target.sub(location);
|
|
if (forward.getNorm() < 0.0000001) {
|
|
return;
|
|
}
|
|
|
|
direction = forward.toSpherical();
|
|
|
|
validate();
|
|
}
|
|
|
|
void CameraDefinition::setTargetCoords(double x, double y, double z) {
|
|
setTarget(Vector3(x, y, z));
|
|
}
|
|
|
|
void CameraDefinition::setRoll(double angle) {
|
|
roll = angle;
|
|
|
|
validate();
|
|
}
|
|
|
|
void CameraDefinition::setZoomToTarget(double zoom) {
|
|
direction.r = zoom;
|
|
location = target.add(Vector3(direction).scale(-1.0));
|
|
|
|
validate();
|
|
}
|
|
|
|
void CameraDefinition::setFov(double fov) {
|
|
perspective.yfov = fov;
|
|
|
|
validate();
|
|
}
|
|
|
|
void CameraDefinition::strafeForward(double value) {
|
|
location = location.add(forward.scale(value));
|
|
|
|
validate();
|
|
}
|
|
|
|
void CameraDefinition::strafeRight(double value) {
|
|
location = location.add(right.scale(value));
|
|
|
|
validate();
|
|
}
|
|
|
|
void CameraDefinition::strafeUp(double value) {
|
|
location = location.add(up.scale(value));
|
|
|
|
validate();
|
|
}
|
|
|
|
void CameraDefinition::rotateYaw(double value) {
|
|
direction.phi += value;
|
|
|
|
validate();
|
|
}
|
|
|
|
void CameraDefinition::rotatePitch(double value) {
|
|
direction.theta += value;
|
|
|
|
validate();
|
|
}
|
|
|
|
void CameraDefinition::rotateRoll(double value) {
|
|
roll += value;
|
|
|
|
validate();
|
|
}
|
|
|
|
void CameraDefinition::setRenderSize(int width, int height) {
|
|
this->width = to_double(width);
|
|
this->height = to_double(height);
|
|
perspective.xratio = this->width / this->height;
|
|
|
|
validate();
|
|
}
|
|
|
|
Vector3 CameraDefinition::project(const Vector3 &point) const {
|
|
Vector3 tpoint = projector.transform(point);
|
|
if (tpoint.z < 1.0) {
|
|
tpoint.x = -tpoint.x;
|
|
tpoint.y = -tpoint.y;
|
|
}
|
|
tpoint.x = (tpoint.x + 1.0) * 0.5 * width;
|
|
tpoint.y = (-tpoint.y + 1.0) * 0.5 * height;
|
|
return tpoint;
|
|
}
|
|
|
|
Vector3 CameraDefinition::unproject(const Vector3 &point) const {
|
|
Vector3 tpoint(point.x / (0.5 * width) - 1.0, -(point.y / (0.5 * height) - 1.0), point.z);
|
|
if (tpoint.z < 1.0) {
|
|
tpoint.x = -tpoint.x;
|
|
tpoint.y = -tpoint.y;
|
|
}
|
|
return unprojector.transform(tpoint);
|
|
}
|
|
|
|
int CameraDefinition::isBoxInView(const Vector3 ¢er, double xsize, double ysize, double zsize) const {
|
|
BoundingBox box;
|
|
|
|
box.pushPoint(center.add(Vector3(-xsize, -ysize, -zsize)));
|
|
box.pushPoint(center.add(Vector3(xsize, ysize, zsize)));
|
|
|
|
return isUnprojectedBoxInView(box);
|
|
}
|
|
|
|
int CameraDefinition::isUnprojectedBoxInView(const BoundingBox &box) const {
|
|
BoundingBox projected;
|
|
|
|
projected.pushPoint(project(Vector3(box.xmin, box.ymin, box.zmin)));
|
|
projected.pushPoint(project(Vector3(box.xmax, box.ymin, box.zmin)));
|
|
projected.pushPoint(project(Vector3(box.xmin, box.ymax, box.zmin)));
|
|
projected.pushPoint(project(Vector3(box.xmax, box.ymax, box.zmin)));
|
|
projected.pushPoint(project(Vector3(box.xmin, box.ymin, box.zmax)));
|
|
projected.pushPoint(project(Vector3(box.xmax, box.ymin, box.zmax)));
|
|
projected.pushPoint(project(Vector3(box.xmin, box.ymax, box.zmax)));
|
|
projected.pushPoint(project(Vector3(box.xmax, box.ymax, box.zmax)));
|
|
|
|
return isProjectedBoxInView(projected);
|
|
}
|
|
|
|
int CameraDefinition::isProjectedBoxInView(const BoundingBox &box) const {
|
|
if (box.xmin <= width && box.xmax >= 0.0 && box.ymin <= height && box.ymax >= 0.0 &&
|
|
box.zmax >= perspective.znear) {
|
|
double dx = box.xmax - box.xmin;
|
|
double dy = box.ymax - box.ymin;
|
|
|
|
return ceil_to_int(dx) * ceil_to_int(dy);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
bool CameraDefinition::transitionToAnother(const CameraDefinition *wanted, double factor) {
|
|
double dx, dy, dz, dr, dphi, dtheta, droll;
|
|
|
|
dx = wanted->location.x - location.x;
|
|
dy = wanted->location.y - location.y;
|
|
dz = wanted->location.z - location.z;
|
|
dr = wanted->direction.r - direction.r;
|
|
dphi = Maths::modInRange(wanted->direction.phi - direction.phi, -Maths::PI, Maths::PI);
|
|
dtheta = Maths::modInRange(wanted->direction.theta - direction.theta, -Maths::PI, Maths::PI);
|
|
droll = Maths::modInRange(wanted->roll - roll, -Maths::PI, Maths::PI);
|
|
|
|
if (fabs(dx) < 0.000001 && fabs(dy) < 0.000001 && fabs(dz) < 0.000001 && fabs(dr) < 0.000001 &&
|
|
fabs(dphi) < 0.000001 && fabs(dtheta) < 0.000001 && fabs(droll) < 0.000001) {
|
|
return false;
|
|
} else {
|
|
location.x += dx * factor;
|
|
location.y += dy * factor;
|
|
location.z += dz * factor;
|
|
direction.r += dr * factor;
|
|
direction.phi += dphi * factor;
|
|
direction.theta += dtheta * factor;
|
|
roll += droll * factor;
|
|
|
|
validate();
|
|
return true;
|
|
}
|
|
}
|