PerspectiveCamera class
@author mr.doob / http://mrdoob.com/ @author greggman / http://games.greggman.com/ @author zz85 / http://www.lab4games.net/zz85/blog
Ported to Dart from JS by: @author rob silverton / http://www.unwrong.com/
class PerspectiveCamera extends Camera {
double fov;
double aspect;
double _fullWidth;
double _fullHeight;
double _x;
double _y;
double _width;
double _height;
PerspectiveCamera( [this.fov = 50.0, this.aspect = 1.0, near = 0.1, far = 2000.0] )
: super(near, far){
updateProjectionMatrix();
}
/**
* Uses Focal Length (in mm) to estimate and set FOV
* 35mm (fullframe) camera is used if frame size is not specified;
* Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html
*/
void setLens( double focalLength, double frameSize ) {
frameSize = frameSize != null ? frameSize : 43.25; // 36x24mm
fov = 2.0 * Math.atan( frameSize / ( focalLength * 2.0 ) );
fov = 180.0 / Math.PI * fov;
updateProjectionMatrix();
}
/**
* Sets an offset in a larger frustum. This is useful for multi-window or
* multi-monitor/multi-machine setups.
*
* For example, if you have 3x2 monitors and each monitor is 1920x1080 and
* the monitors are in grid like this
*
* +---+---+---+
* | A | B | C |
* +---+---+---+
* | D | E | F |
* +---+---+---+
*
* then for each monitor you would call it like this
*
* var w = 1920;
* var h = 1080;
* var fullWidth = w * 3;
* var fullHeight = h * 2;
*
* --A--
* camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
* --B--
* camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
* --C--
* camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
* --D--
* camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
* --E--
* camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
* --F--
* camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
*
* Note there is no reason monitors have to be the same size or in a grid.
*/
void setViewOffset( double fullWidth, double fullHeight, double x, double y, double width, double height ) {
_fullWidth = fullWidth;
_fullHeight = fullHeight;
_x = x;
_y = y;
_width = width;
_height = height;
updateProjectionMatrix();
}
void updateProjectionMatrix() {
if ( _fullWidth != null ) {
double aspect = _fullWidth / _fullHeight;
double top = Math.tan( fov * Math.PI / 360.0 ) * near;
double bottom = -top;
double left = aspect * bottom;
double right = aspect * top;
double width = ( right - left ).abs();
double height = ( top - bottom ).abs();
setFrustumMatrix(projectionMatrix,
left + _x * width / _fullWidth,
left + ( _x + width ) * width / _fullWidth,
top - ( _y + height ) * height / _fullHeight,
top - _y * height / _fullHeight,
near,
far );
} else {
projectionMatrix = makePerspectiveMatrix(fov * (Math.PI / 180), aspect, near, far);
}
}
}
Extends
Object3D > Camera > PerspectiveCamera
Constructors
new PerspectiveCamera([double fov = 50.0, double aspect = 1.0, near = 0.1, far = 2000.0]) #
Creates a new Object instance.
Object instances have no meaningful state, and are only useful through their identity. An Object instance is equal to itself only.
PerspectiveCamera( [this.fov = 50.0, this.aspect = 1.0, near = 0.1, far = 2000.0] )
: super(near, far){
updateProjectionMatrix();
}
Properties
bool frustumCulled #
bool visible = false, castShadow = false, receiveShadow = false, frustumCulled = false
bool isDynamic #
bool get isDynamic => _dynamic;
set isDynamic(bool flag) => _dynamic = flag;
Matrix4 matrixRotationWorld #
Matrix4 matrix, matrixWorld, matrixRotationWorld
bool matrixWorldNeedsUpdate #
bool matrixAutoUpdate = false, matrixWorldNeedsUpdate = false
bool receiveShadow #
bool visible = false, castShadow = false, receiveShadow = false
Operators
Methods
void add(Object3D object) #
void add( Object3D object ) {
if ( object == this ) {
print( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' );
return;
}
if ( object.parent != null ) {
object.parent.remove( object );
}
object.parent = this;
children.add( object );
// add to scene
Object3D scene = this;
while ( scene.parent != null ) {
scene = scene.parent;
}
if ( scene is Scene ) {
scene.addObject( object );
}
}
void applyMatrix(Matrix4 matrix) #
void applyMatrix ( Matrix4 matrix ) {
this.matrix = matrix * this.matrix;
this.scale = getScaleFromMatrix( this.matrix );
Matrix4 mat = extractRotation(new Matrix4.identity(), this.matrix );
this.rotation = calcEulerFromRotationMatrix( mat, this.eulerOrder );
this.position = this.matrix.getTranslation();
}
Object3D getChildByName(String name, bool doRecurse) #
Object3D getChildByName( String name, bool doRecurse ) {
int c;
int cl = children.length;
Object3D child, recurseResult;
children.forEach((child){
if ( child.name == name ) {
return child;
}
if ( doRecurse ) {
recurseResult = child.getChildByName( name, doRecurse );
if ( recurseResult != null ) {
return recurseResult;
}
}
});
return null;
}
dynamic localToWorld(Vector3 vector) #
localToWorld(Vector3 vector) => vector.applyProjection(matrixWorld);
void lookAt(Vector3 vector) #
void lookAt(Vector3 vector ) {
// TODO: Add hierarchy support.
makeLookAt(matrix, position, vector, up);
if ( rotationAutoUpdate ) {
rotation = calcEulerFromRotationMatrix( matrix, eulerOrder );
}
}
void remove(Object3D object) #
void remove( Object3D object ) {
int index = children.indexOf( object );
if ( index != - 1 ){
object.parent = null;
children.removeAt(index);
// remove from scene
Object3D scene = this;
while ( scene.parent != null ) {
scene = scene.parent;
}
if (scene is Scene ) {
scene.removeObject( object );
}
}
}
void setLens(double focalLength, double frameSize) #
Uses Focal Length (in mm) to estimate and set FOV 35mm (fullframe) camera is used if frame size is not specified; Formula based on http://www.bobatkins.com/photography/technical/fieldofview.html
void setLens( double focalLength, double frameSize ) {
frameSize = frameSize != null ? frameSize : 43.25; // 36x24mm
fov = 2.0 * Math.atan( frameSize / ( focalLength * 2.0 ) );
fov = 180.0 / Math.PI * fov;
updateProjectionMatrix();
}
void setViewOffset(double fullWidth, double fullHeight, double x, double y, double width, double height) #
Sets an offset in a larger frustum. This is useful for multi-window or multi-monitor/multi-machine setups.
For example, if you have 3x2 monitors and each monitor is 1920x1080 and the monitors are in grid like this
+---+---+---+ | A | B | C | +---+---+---+ | D | E | F | +---+---+---+
then for each monitor you would call it like this
var w = 1920; var h = 1080; var fullWidth = w * 3; var fullHeight = h * 2;
--A-- camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); --B-- camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); --C-- camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); --D-- camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); --E-- camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); --F-- camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
Note there is no reason monitors have to be the same size or in a grid.
void setViewOffset( double fullWidth, double fullHeight, double x, double y, double width, double height ) {
_fullWidth = fullWidth;
_fullHeight = fullHeight;
_x = x;
_y = y;
_width = width;
_height = height;
updateProjectionMatrix();
}
void translate(num distance, Vector3 axis) #
void translate( num distance, Vector3 axis ) {
matrix.rotate3( axis );
axis.normalize();
position.add( axis.scale( distance ) );
}
void translateX(num distance) #
void translateX( num distance ) => translate( distance, _vector.setValues( 1.0, 0.0, 0.0 ) );
void translateY(num distance) #
void translateY( num distance ) => translate( distance, _vector.setValues( 0.0, 1.0, 0.0 ) );
void translateZ(num distance) #
void translateZ( num distance ) => translate( distance, _vector.setValues( 0.0, 0.0, 1.0 ) );
void updateMatrix() #
void updateMatrix() {
if ( useQuaternion ) {
setRotationFromQuaternion( matrix, quaternion );
} else {
setRotationFromEuler( matrix, rotation, eulerOrder );
}
matrix.setTranslation( position );
if ( scale.x != 1.0 || scale.y != 1.0 || scale.z != 1.0 ) {
matrix.scale( scale );
boundRadiusScale = Math.max( scale.x, Math.max( scale.y, scale.z ) );
}
matrixWorldNeedsUpdate = true;
}
void updateMatrixWorld({bool force: false}) #
void updateMatrixWorld( {bool force: false} ) {
if (matrixAutoUpdate) updateMatrix();
// update matrixWorld
if ( matrixWorldNeedsUpdate || force ) {
if ( parent != null ) {
matrixWorld = parent.matrixWorld * matrix;
} else {
matrixWorld = matrix.clone();
}
matrixWorldNeedsUpdate = false;
force = true;
}
// update children
children.forEach((c) => c.updateMatrixWorld( force: force ) );
}
void updateProjectionMatrix() #
void updateProjectionMatrix() {
if ( _fullWidth != null ) {
double aspect = _fullWidth / _fullHeight;
double top = Math.tan( fov * Math.PI / 360.0 ) * near;
double bottom = -top;
double left = aspect * bottom;
double right = aspect * top;
double width = ( right - left ).abs();
double height = ( top - bottom ).abs();
setFrustumMatrix(projectionMatrix,
left + _x * width / _fullWidth,
left + ( _x + width ) * width / _fullWidth,
top - ( _y + height ) * height / _fullHeight,
top - _y * height / _fullHeight,
near,
far );
} else {
projectionMatrix = makePerspectiveMatrix(fov * (Math.PI / 180), aspect, near, far);
}
}