Skip to content

Commit

Permalink
Merge 2fe50b6 into 32e6614
Browse files Browse the repository at this point in the history
  • Loading branch information
ibgreen committed Jul 24, 2019
2 parents 32e6614 + 2fe50b6 commit ffe3ad0
Show file tree
Hide file tree
Showing 20 changed files with 1,143 additions and 1,135 deletions.
3 changes: 2 additions & 1 deletion docs/whats-new.md
@@ -1,6 +1,6 @@
# What's New

## v2.4 (In Development)
## v3.0 (In Development)

Date: TBD, target end of June 2019

Expand Down Expand Up @@ -28,6 +28,7 @@ The API for transformations (i.e. multiplying vectors with matrices or quaternio

- New methods `Matrix*.setColumn()` and `Matrix*.getColumn()`
- New method `Matrix*.toString()`
- Improved method: `Matrix4.frustum()` now supports infinite `far` plane (parity with `Matrix4.perspective`, which already supported this).

#### Utility Functions

Expand Down
10 changes: 5 additions & 5 deletions modules/core/docs/api-reference/matrix4.md
Expand Up @@ -99,15 +99,15 @@ Sets the matrix to a transformation corresponding to the rotations represented b

### frustum

Generates a frustum matrix with the given bounds.
Generates a frustum matrix with the given bounds. The frustum far plane can be infinite.

`matrix4.frustum({left, right, bottom, top, near, far})`
* `left` (`Number`) - Left bound of the frustum
* `right` (`Number`) - Right bound of the frustum
* `bottom` (`Number`) - Bottom bound of the frustum
* `top` (`Number`) - Top bound of the frustum
* `near` (`Number`) - Near bound of the frustum
* `far` (`Number`) - Far bound of the frustum
* `far` (`Number`|`Infinity`) - Far bound of the frustum


### lookAt
Expand Down Expand Up @@ -151,7 +151,7 @@ as a perspective matrix (plus `focalDistance`).

### perspective

Generates a perspective projection matrix with the given bounds
Generates a perspective projection matrix with the given bounds. The frustum far plane can be infinite.

`matrix4.perspective({
fovy = 45 * Math.PI - / 180,
Expand All @@ -162,7 +162,7 @@ Generates a perspective projection matrix with the given bounds
* `fovy`=`45` (`Number`) - Vertical field of view in radians (default is 45 degrees specified in radians)
* `aspect`=`1` (`Number`) - Aspect ratio. typically viewport width/height
* `near`=`0.1` (`Number`) - Near bound of the frustum
* `far`=`500` (`Number`) - Far bound of the frustum
* `far`=`500` (`Number`|`Infinity`) - Far bound of the frustum


### determinant()
Expand Down Expand Up @@ -322,7 +322,7 @@ Returns `out`, or a newly minted `Vector2`, `Vector3` or `Vector4`

### transformByMatrix3(vector : Number[4]) : Number[4]

Transforms
Transforms

### transformByMatrix2(vector : Number[4]) : Number[4]

Expand Down
35 changes: 34 additions & 1 deletion modules/core/src/classes/matrix4.js
Expand Up @@ -189,10 +189,43 @@ export default class Matrix4 extends Matrix {
// near Number Near bound of the frustum
// far Number Far bound of the frustum
frustum({left, right, bottom, top, near, far}) {
mat4.frustum(this, left, right, bottom, top, near, far);
if (far === Infinity) {
Matrix4._computeInfinitePerspectiveOffCenter(this, left, right, bottom, top, near);
} else {
mat4.frustum(this, left, right, bottom, top, near, far);
}
return this.check();
}

// eslint-disable-next-line max-params
static _computeInfinitePerspectiveOffCenter(result, left, right, bottom, top, near) {
const column0Row0 = (2.0 * near) / (right - left);
const column1Row1 = (2.0 * near) / (top - bottom);
const column2Row0 = (right + left) / (right - left);
const column2Row1 = (top + bottom) / (top - bottom);
const column2Row2 = -1.0;
const column2Row3 = -1.0;
const column3Row2 = -2.0 * near;

result[0] = column0Row0;
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = 0.0;
result[5] = column1Row1;
result[6] = 0.0;
result[7] = 0.0;
result[8] = column2Row0;
result[9] = column2Row1;
result[10] = column2Row2;
result[11] = column2Row3;
result[12] = 0.0;
result[13] = 0.0;
result[14] = column3Row2;
result[15] = 0.0;
return result;
}

// Generates a look-at matrix with the given eye position, focal point,
// and up axis
// eye vec3 Position of the viewer
Expand Down
4 changes: 3 additions & 1 deletion modules/core/src/lib/math-utils.js
Expand Up @@ -24,5 +24,7 @@ export default {

PI_OVER_TWO: Math.PI / 2,
PI_OVER_FOUR: Math.PI / 4,
PI_OVER_SIX: Math.PI / 6
PI_OVER_SIX: Math.PI / 6,

TWO_PI: Math.PI * 2
};
28 changes: 28 additions & 0 deletions modules/core/test/classes/matrix4.spec.js
Expand Up @@ -288,6 +288,34 @@ test('Matrix4#frustum', t => {
t.end();
});

test('Matrix4#frustum() works', t => {
const expected = new Matrix4([2, 0, 3, 0, 0, 2, 5, 0, 0, 0, -3, -4, 0, 0, -1, 0]).transpose();
const returnedResult = new Matrix4().frustum({
left: 1,
right: 2,
bottom: 2,
top: 3,
near: 1,
far: 2
});
tapeEquals(t, returnedResult, expected);
t.end();
});

test('Matrix4#frustum(far: Infinity) works', t => {
const expected = new Matrix4([2, 0, 3, 0, 0, 2, 5, 0, 0, 0, -1, -2, 0, 0, -1, 0]).transpose();
const returnedResult = new Matrix4().frustum({
left: 1,
right: 2,
bottom: 2,
top: 3,
near: 1,
far: Infinity
});
tapeEquals(t, returnedResult, expected);
t.end();
});

test('Matrix4#ortho', t => {
const result = new Matrix4().ortho({left: -1, right: 1, bottom: -1, top: 1, near: -1, far: 1});
t.ok(result);
Expand Down
3 changes: 3 additions & 0 deletions modules/culling/src/index.js
Expand Up @@ -10,4 +10,7 @@ export {default as OrientedBoundingBox} from './lib/oriented-bounding-box';
export {default as CullingVolume} from './lib/culling-volume';
export {default as Plane} from './lib/plane';

export {default as _PerspectiveOffCenterFrustum} from './lib/perspective-off-center-frustum';
export {default as _PerspectiveFrustum} from './lib/perspective-frustum';

export {makeBoundingSphereFromPoints} from './algorithms/bounding-sphere-from-points';
6 changes: 3 additions & 3 deletions modules/culling/src/lib/axis-aligned-bounding-box.js
Expand Up @@ -2,7 +2,7 @@ import {Vector3} from 'math.gl';
import {Intersect} from '../constants';

const scratchVector = new Vector3();
const intersectScratch = new Vector3();
const scratchNormal = new Vector3();

/**
* Creates an instance of an AxisAlignedBoundingBox from the minimum and maximum points along the x, y, and z axes.
Expand Down Expand Up @@ -135,11 +135,11 @@ export default class AxisAlignedBoundingBox {
* intersects the plane.
*/
intersectPlane(plane) {
const h = intersectScratch
const h = scratchVector
.copy(this.maximum)
.subtract(this.minimum)
.scale(0.5); // The positive half diagonal
const normal = plane.normal;
const normal = scratchNormal.from(plane.normal);
const e = h.x * Math.abs(normal.x) + h.y * Math.abs(normal.y) + h.z * Math.abs(normal.z);
const s = this.center.dot(normal) + plane.distance; // signed distance from center

Expand Down
44 changes: 27 additions & 17 deletions modules/culling/src/lib/culling-volume.js
Expand Up @@ -3,7 +3,7 @@

/* eslint-disable */
import {Vector3, Vector4, assert} from 'math.gl';
import {INTERSECT, Intersect} from '../constants';
import {Intersect} from '../constants';
import Plane from './plane';

// X, Y, Z Unit vectors
Expand Down Expand Up @@ -36,6 +36,7 @@ export default class CullingVolume {
constructor(planes = []) {
// {Cartesian4[]} [planes] An array of clipping planes.
this.planes = planes;
assert(this.planes.every(plane => plane instanceof Plane));
}

// Constructs a culling volume from a bounding sphere. Creates six planes that create a box containing the sphere.
Expand All @@ -59,25 +60,32 @@ export default class CullingVolume {
plane1 = this.planes[planeIndex + 1] = new Vector4();
}

scratchPlaneCenter
const plane0Center = scratchPlaneCenter
.copy(faceNormal)
.scale(-radius)
.add(center);
const plane0Distance = -faceNormal.dot(plane0Center);

// plane0.fromNormalDistance(faceNormal, plane0Distance);
plane0.x = faceNormal.x;
plane0.y = faceNormal.y;
plane0.z = faceNormal.z;
plane0.w = -faceNormal.dot(scratchPlaneCenter);
plane0.w = plane0Distance;

scratchPlaneCenter
const plane1Center = scratchPlaneCenter
.copy(faceNormal)
.scale(radius)
.add(center);
plane1.x = -faceNormal.x;
plane1.y = -faceNormal.y;
plane1.z = -faceNormal.z;
plane0.w = -faceNormal.negate().dot(scratchPlaneCenter);
// plane1.w = -Vector3.dot(Vector3.negate(faceNormal, scratchPlaneNormal), scratchPlaneCenter);

const negatedFaceNormal = scratchPlaneNormal.copy(faceNormal).negate();

const plane1Distance = -negatedFaceNormal.dot(plane1Center);

// plane1.fromNormalDistance(negatedFaceNormal, plane1Distance);
plane1.x = negatedFaceNormal.x;
plane1.y = negatedFaceNormal.y;
plane1.z = negatedFaceNormal.z;
plane1.w = plane1Distance;

planeIndex += 2;
}
Expand All @@ -88,9 +96,10 @@ export default class CullingVolume {
// Determines whether a bounding volume intersects the culling volume.
computeVisibility(boundingVolume) {
assert(boundingVolume);
const planes = this.planes;
const intersect = Intersect.INSIDE;
for (const plane of this.planes) {
// const planes = this.planes;
let intersect = Intersect.INSIDE;
for (const planeCoefficients of this.planes) {
const plane = scratchPlane.fromCoefficients(...planeCoefficients);
const result = boundingVolume.intersectPlane(plane);
switch (result) {
case Intersect.OUTSIDE:
Expand All @@ -115,9 +124,10 @@ export default class CullingVolume {
* volume, such that if (planeMask & (1 << planeIndex) === 0), for k < 31, then
* the parent (and therefore this) volume is completely inside plane[planeIndex]
* and that plane check can be skipped.
*/
computeVisibilityWithPlaneMask(boundingVolume, parentPlaneMask) {
// assert(boundingVolume, 'boundingVolume is required.');
// assert(parentPlaneMask, 'parentPlaneMask is required.');
assert(boundingVolume, 'boundingVolume is required.');
assert(Number.isFinite(parentPlaneMask), 'parentPlaneMask is required.');

if (
parentPlaneMask === CullingVolume.MASK_OUTSIDE ||
Expand All @@ -129,7 +139,7 @@ export default class CullingVolume {

// Start with MASK_INSIDE (all zeros) so that after the loop, the return value can be compared with MASK_INSIDE.
// (Because if there are fewer than 31 planes, the upper bits wont be changed.)
const mask = CullingVolume.MASK_INSIDE;
let mask = CullingVolume.MASK_INSIDE;

const planes = this.planes;
for (let k = 0; k < this.planes.length; ++k) {
Expand All @@ -140,7 +150,8 @@ export default class CullingVolume {
continue;
}

const result = boundingVolume.intersectPlane(Plane.fromCartesian4(planes[k], scratchPlane));
const plane = scratchPlane.fromCoefficients(...planes[k]);
const result = boundingVolume.intersectPlane(plane);
if (result === Intersect.OUTSIDE) {
return CullingVolume.MASK_OUTSIDE;
} else if (result === Intersect.INTERSECTING) {
Expand All @@ -150,5 +161,4 @@ export default class CullingVolume {

return mask;
}
*/
}

0 comments on commit ffe3ad0

Please sign in to comment.