207 lines
7.0 KiB
C++
207 lines
7.0 KiB
C++
// Filename: perspectiveProjection.cxx
|
|
// Created by: drose (18Feb99)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "geomLine.h"
|
|
#include "perspectiveProjection.h"
|
|
|
|
#include <boundingHexahedron.h>
|
|
|
|
|
|
TypeHandle PerspectiveProjection::_type_handle;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PerspectiveProjection::make_copy
|
|
// Access: Public, Virtual
|
|
// Description: Allocates a new Projection just like this one.
|
|
////////////////////////////////////////////////////////////////////
|
|
Projection *PerspectiveProjection::
|
|
make_copy() const {
|
|
return new PerspectiveProjection(*this);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PerspectiveProjection::get_projection_mat
|
|
// Access: Public, Virtual
|
|
// Description: This computes a transform matrix that performs the
|
|
// perspective transform defined by the frustum.
|
|
////////////////////////////////////////////////////////////////////
|
|
LMatrix4f PerspectiveProjection::
|
|
get_projection_mat(CoordinateSystem cs) const {
|
|
return _frustum.get_perspective_projection_mat(cs);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PerspectiveProjection::make_geometry
|
|
// Access: Public, Virtual
|
|
// Description: Creates a GeomLine that describes the shape of the
|
|
// frustum for this projection
|
|
////////////////////////////////////////////////////////////////////
|
|
Geom *PerspectiveProjection::
|
|
make_geometry(const Colorf &color,
|
|
CoordinateSystem cs) const {
|
|
Vertexf rtn, ltn, lbn, rbn;
|
|
Vertexf rtf, ltf, lbf, rbf;
|
|
|
|
// x, y, and z here refer to the right, forward, and up vectors,
|
|
// which are not necessarily the x, y, and z axes.
|
|
|
|
LVector3f x = LVector3f::right(cs);
|
|
LVector3f y = LVector3f::forward(cs);
|
|
LVector3f z = LVector3f::up(cs);
|
|
LPoint3f o = LPoint3f::origin(cs);
|
|
|
|
Vertexf xl = x * _frustum._l;
|
|
Vertexf xr = x * _frustum._r;
|
|
Vertexf zt = z * _frustum._t;
|
|
Vertexf zb = z * _frustum._b;
|
|
Vertexf yn = o + (y * _frustum._fnear);
|
|
|
|
rtn = yn + zt + xr;
|
|
ltn = yn + zt + xl;
|
|
lbn = yn + zb + xl;
|
|
rbn = yn + zb + xr;
|
|
|
|
float fs = _frustum._ffar / _frustum._fnear;
|
|
Vertexf yf = o + (y * _frustum._ffar);
|
|
|
|
rtf = yf + ((zt + xr) * fs);
|
|
ltf = yf + ((zt + xl) * fs);
|
|
lbf = yf + ((zb + xl) * fs);
|
|
rbf = yf + ((zb + xr) * fs);
|
|
|
|
PTA_Vertexf coords(0);
|
|
PTA_ushort vindex(0);
|
|
PTA_Colorf colors(0);
|
|
|
|
// We just specify overall color
|
|
colors.push_back(color);
|
|
|
|
coords.push_back(rtn);
|
|
coords.push_back(ltn);
|
|
coords.push_back(lbn);
|
|
coords.push_back(rbn);
|
|
coords.push_back(rtf);
|
|
coords.push_back(ltf);
|
|
coords.push_back(lbf);
|
|
coords.push_back(rbf);
|
|
coords.push_back(o);
|
|
|
|
// Draw the near plane
|
|
vindex.push_back(0); vindex.push_back(1);
|
|
vindex.push_back(1); vindex.push_back(2);
|
|
vindex.push_back(2); vindex.push_back(3);
|
|
vindex.push_back(3); vindex.push_back(0);
|
|
|
|
// Draw the far plane
|
|
vindex.push_back(4); vindex.push_back(5);
|
|
vindex.push_back(5); vindex.push_back(6);
|
|
vindex.push_back(6); vindex.push_back(7);
|
|
vindex.push_back(7); vindex.push_back(4);
|
|
|
|
// Draw lines from eye to the corners
|
|
vindex.push_back(8); vindex.push_back(4);
|
|
vindex.push_back(8); vindex.push_back(5);
|
|
vindex.push_back(8); vindex.push_back(6);
|
|
vindex.push_back(8); vindex.push_back(7);
|
|
|
|
GeomLine* gline = new GeomLine;
|
|
gline->set_coords(coords, G_PER_VERTEX, vindex);
|
|
gline->set_colors(colors, G_OVERALL);
|
|
gline->set_num_prims(12);
|
|
|
|
return gline;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PerspectiveProjection::make_bounds
|
|
// Access: Public, Virtual
|
|
// Description: Allocates and returns a new BoundingVolume that
|
|
// encloses the frustum used for this kind of
|
|
// projection, if possible. If a suitable bounding
|
|
// volume cannot be created, returns NULL.
|
|
////////////////////////////////////////////////////////////////////
|
|
BoundingVolume *PerspectiveProjection::
|
|
make_bounds(CoordinateSystem cs) const {
|
|
return new BoundingHexahedron(_frustum, false, cs);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PerspectiveProjection::extrude
|
|
// Access: Public, Virtual
|
|
// Description: Given a 2-d point in the range (-1,1) in both
|
|
// dimensions, where (0,0) is the center of the
|
|
// projection and (-1,-1) is the lower-left corner,
|
|
// compute the corresponding vector in space that maps
|
|
// to this point, if such a vector can be determined.
|
|
// Returns true if the vector is defined (in which case
|
|
// origin and direction are set to define the vector),
|
|
// or false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool PerspectiveProjection::
|
|
extrude(const LPoint2f &point2d, LPoint3f &origin, LVector3f &direction,
|
|
CoordinateSystem cs) const {
|
|
if (point2d[0] < -1 || point2d[0] > 1 ||
|
|
point2d[1] < -1 || point2d[1] > 1) {
|
|
// The point is off the near plane.
|
|
return false;
|
|
}
|
|
|
|
// Scale the point from (-1,1) to the range of the frustum.
|
|
|
|
LPoint2f scaled(_frustum._l + 0.5 * (point2d[0] + 1.0) *
|
|
(_frustum._r - _frustum._l),
|
|
_frustum._b + 0.5 * (point2d[1] + 1.0) *
|
|
(_frustum._t - _frustum._b));
|
|
|
|
LVector3f near_vector =
|
|
LVector3f::rfu(scaled[0], _frustum._fnear, scaled[1], cs);
|
|
LVector3f far_vector =
|
|
near_vector * _frustum._ffar / _frustum._fnear;
|
|
|
|
origin = LPoint3f::origin(cs) + near_vector;
|
|
direction = far_vector - near_vector;
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PerspectiveProjection::project
|
|
// Access: Public, Virtual
|
|
// Description: Given a 3-d point in space, determine the 2-d point
|
|
// this maps to, in the range (-1,1) in both dimensions,
|
|
// where (0,0) is the center of the projection and
|
|
// (-1,-1) is the lower-left corner. Returns true if
|
|
// the 3-d point is in front of the projection and
|
|
// within the viewing frustum (in which case point2d is
|
|
// filled in), or false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool PerspectiveProjection::
|
|
project(const LPoint3f &point3d, LPoint2f &point2d,
|
|
CoordinateSystem cs) const {
|
|
float f = point3d.dot(LVector3f::forward(cs));
|
|
if (f < _frustum._fnear || f > _frustum._ffar) {
|
|
// The point is outside the near or far clipping planes.
|
|
return false;
|
|
}
|
|
|
|
float r = point3d.dot(LVector3f::right(cs));
|
|
float u = point3d.dot(LVector3f::up(cs));
|
|
|
|
LPoint2f scaled(r * _frustum._fnear / f, u * _frustum._fnear / f);
|
|
|
|
if (scaled[0] < _frustum._l || scaled[0] > _frustum._r ||
|
|
scaled[1] < _frustum._b || scaled[1] > _frustum._t) {
|
|
// The point is outside of the edge planes.
|
|
return false;
|
|
}
|
|
|
|
point2d.set((scaled[0] - _frustum._l) * 2.0 /
|
|
(_frustum._r - _frustum._l) - 1.0,
|
|
(scaled[1] - _frustum._b) * 2.0 /
|
|
(_frustum._t - _frustum._b) - 1.0);
|
|
return true;
|
|
}
|