blob: 3b8fac65f9258b247467804dd5d4e1992d52b5ed [file] [log] [blame]
// Copyright (c) 2015, Google Inc. Please see the AUTHORS file for details.
// All rights reserved. Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
part of vector_math_64;
/// Defines a frustum constructed out of six [Plane]s.
class Frustum {
final Plane _plane0;
final Plane _plane1;
final Plane _plane2;
final Plane _plane3;
final Plane _plane4;
final Plane _plane5;
/// The first plane that defines the bounds of this frustum.
Plane get plane0 => _plane0;
/// The second plane that defines the bounds of this frustum.
Plane get plane1 => _plane1;
/// The third plane that defines the bounds of this frustum.
Plane get plane2 => _plane2;
/// The fourth plane that defines the bounds of this frustum.
Plane get plane3 => _plane3;
/// The fifth plane that defines the bounds of this frustum.
Plane get plane4 => _plane4;
/// The sixed plane that defines the bounds of this frustum.
Plane get plane5 => _plane5;
/// Create a new frustum without initializing its bounds.
Frustum()
: _plane0 = Plane(),
_plane1 = Plane(),
_plane2 = Plane(),
_plane3 = Plane(),
_plane4 = Plane(),
_plane5 = Plane();
/// Create a new frustum as a copy of [other].
factory Frustum.copy(Frustum other) => Frustum()..copyFrom(other);
/// Create a new furstum from a [matrix].
factory Frustum.matrix(Matrix4 matrix) => Frustum()..setFromMatrix(matrix);
/// Copy the [other] frustum into this.
void copyFrom(Frustum other) {
_plane0.copyFrom(other._plane0);
_plane1.copyFrom(other._plane1);
_plane2.copyFrom(other._plane2);
_plane3.copyFrom(other._plane3);
_plane4.copyFrom(other._plane4);
_plane5.copyFrom(other._plane5);
}
/// Set this from [matrix].
void setFromMatrix(Matrix4 matrix) {
final me = matrix.storage;
final me0 = me[0], me1 = me[1], me2 = me[2], me3 = me[3];
final me4 = me[4], me5 = me[5], me6 = me[6], me7 = me[7];
final me8 = me[8], me9 = me[9], me10 = me[10], me11 = me[11];
final me12 = me[12], me13 = me[13], me14 = me[14], me15 = me[15];
_plane0
..setFromComponents(me3 - me0, me7 - me4, me11 - me8, me15 - me12)
..normalize();
_plane1
..setFromComponents(me3 + me0, me7 + me4, me11 + me8, me15 + me12)
..normalize();
_plane2
..setFromComponents(me3 + me1, me7 + me5, me11 + me9, me15 + me13)
..normalize();
_plane3
..setFromComponents(me3 - me1, me7 - me5, me11 - me9, me15 - me13)
..normalize();
_plane4
..setFromComponents(me3 - me2, me7 - me6, me11 - me10, me15 - me14)
..normalize();
_plane5
..setFromComponents(me3 + me2, me7 + me6, me11 + me10, me15 + me14)
..normalize();
}
/// Check if this contains a [point].
bool containsVector3(Vector3 point) {
if (_plane0.distanceToVector3(point) < 0.0) {
return false;
}
if (_plane1.distanceToVector3(point) < 0.0) {
return false;
}
if (_plane2.distanceToVector3(point) < 0.0) {
return false;
}
if (_plane3.distanceToVector3(point) < 0.0) {
return false;
}
if (_plane4.distanceToVector3(point) < 0.0) {
return false;
}
if (_plane5.distanceToVector3(point) < 0.0) {
return false;
}
return true;
}
/// Check if this intersects with [aabb].
bool intersectsWithAabb3(Aabb3 aabb) {
if (_intersectsWithAabb3CheckPlane(aabb, _plane0)) {
return false;
}
if (_intersectsWithAabb3CheckPlane(aabb, _plane1)) {
return false;
}
if (_intersectsWithAabb3CheckPlane(aabb, _plane2)) {
return false;
}
if (_intersectsWithAabb3CheckPlane(aabb, _plane3)) {
return false;
}
if (_intersectsWithAabb3CheckPlane(aabb, _plane4)) {
return false;
}
if (_intersectsWithAabb3CheckPlane(aabb, _plane5)) {
return false;
}
return true;
}
/// Check if this intersects with [sphere].
bool intersectsWithSphere(Sphere sphere) {
final negativeRadius = -sphere.radius;
final center = sphere.center;
if (_plane0.distanceToVector3(center) < negativeRadius) {
return false;
}
if (_plane1.distanceToVector3(center) < negativeRadius) {
return false;
}
if (_plane2.distanceToVector3(center) < negativeRadius) {
return false;
}
if (_plane3.distanceToVector3(center) < negativeRadius) {
return false;
}
if (_plane4.distanceToVector3(center) < negativeRadius) {
return false;
}
if (_plane5.distanceToVector3(center) < negativeRadius) {
return false;
}
return true;
}
/// Calculate the corners of this and write them into [corner0] to
// [corner7].
void calculateCorners(
Vector3 corner0,
Vector3 corner1,
Vector3 corner2,
Vector3 corner3,
Vector3 corner4,
Vector3 corner5,
Vector3 corner6,
Vector3 corner7) {
Plane.intersection(_plane0, _plane2, _plane4, corner0);
Plane.intersection(_plane0, _plane3, _plane4, corner1);
Plane.intersection(_plane0, _plane3, _plane5, corner2);
Plane.intersection(_plane0, _plane2, _plane5, corner3);
Plane.intersection(_plane1, _plane2, _plane4, corner4);
Plane.intersection(_plane1, _plane3, _plane4, corner5);
Plane.intersection(_plane1, _plane3, _plane5, corner6);
Plane.intersection(_plane1, _plane2, _plane5, corner7);
}
bool _intersectsWithAabb3CheckPlane(Aabb3 aabb, Plane plane) {
double outPx, outPy, outPz, outNx, outNy, outNz;
if (plane._normal.x < 0.0) {
outPx = aabb.min.x;
outNx = aabb.max.x;
} else {
outPx = aabb.max.x;
outNx = aabb.min.x;
}
if (plane._normal.y < 0.0) {
outPy = aabb.min.y;
outNy = aabb.max.y;
} else {
outPy = aabb.max.y;
outNy = aabb.min.y;
}
if (plane._normal.z < 0.0) {
outPz = aabb.min.z;
outNz = aabb.max.z;
} else {
outPz = aabb.max.z;
outNz = aabb.min.z;
}
final d1 = plane._normal.x * outPx +
plane._normal.y * outPy +
plane._normal.z * outPz +
plane.constant;
final d2 = plane._normal.x * outNx +
plane._normal.y * outNy +
plane._normal.z * outNz +
plane.constant;
return d1 < 0 && d2 < 0;
}
}