-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d5248e1
commit c1813da
Showing
5 changed files
with
230 additions
and
209 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
// @flow | ||
|
||
import {vec3, vec4} from 'gl-matrix'; | ||
import assert from 'assert'; | ||
|
||
type IntersectResult = 'none' | 'intersects' | 'contains'; | ||
|
||
class Frustum { | ||
points: Array<Array<number>>; | ||
planes: Array<Array<number>>; | ||
|
||
constructor(points_: Array<Array<number>>, planes_: Array<Array<number>>) { | ||
this.points = points_; | ||
this.planes = planes_; | ||
} | ||
|
||
static fromInvProjectionMatrix(invProj: Float64Array, worldSize: number, zoom: number): Frustum { | ||
const clipSpaceCorners = [ | ||
[-1, 1, -1, 1], | ||
[ 1, 1, -1, 1], | ||
[ 1, -1, -1, 1], | ||
[-1, -1, -1, 1], | ||
[-1, 1, 1, 1], | ||
[ 1, 1, 1, 1], | ||
[ 1, -1, 1, 1], | ||
[-1, -1, 1, 1] | ||
]; | ||
|
||
const scale = Math.pow(2, zoom); | ||
|
||
// Transform frustum corner points from clip space to tile space | ||
const frustumCoords = clipSpaceCorners | ||
.map(v => vec4.transformMat4([], v, invProj)) | ||
.map(v => vec4.scale([], v, 1.0 / v[3] / worldSize * scale)); | ||
|
||
const frustumPlanePointIndices = [ | ||
[0, 1, 2], // near | ||
[6, 5, 4], // far | ||
[0, 3, 7], // left | ||
[2, 1, 5], // right | ||
[3, 2, 6], // bottom | ||
[0, 4, 5] // top | ||
]; | ||
|
||
const frustumPlanes = frustumPlanePointIndices.map((p: Array<number>) => { | ||
const a = vec3.sub([], frustumCoords[p[0]], frustumCoords[p[1]]); | ||
const b = vec3.sub([], frustumCoords[p[2]], frustumCoords[p[1]]); | ||
const n = vec3.normalize([], vec3.cross([], a, b)); | ||
const d = -vec3.dot(n, frustumCoords[p[1]]); | ||
return n.concat(d); | ||
}); | ||
|
||
return new Frustum(frustumCoords, frustumPlanes); | ||
} | ||
} | ||
|
||
class Aabb { | ||
min: vec3; | ||
max: vec3; | ||
center: vec3; | ||
|
||
constructor(min_: vec3, max_: vec3) { | ||
this.min = min_; | ||
this.max = max_; | ||
this.center = vec3.scale([], vec3.add([], this.min, this.max), 0.5); | ||
} | ||
|
||
quadrant(index: number): Aabb { | ||
const split = [(index % 2) === 0, index < 2]; | ||
const qMin = vec3.clone(this.min); | ||
const qMax = vec3.clone(this.max); | ||
for (let axis = 0; axis < split.length; axis++) { | ||
qMin[axis] = split[axis] ? this.min[axis] : this.center[axis]; | ||
qMax[axis] = split[axis] ? this.center[axis] : this.max[axis]; | ||
} | ||
// Elevation is always constant, hence quadrant.max.z = this.max.z | ||
qMax[2] = this.max[2]; | ||
return new Aabb(qMin, qMax); | ||
} | ||
|
||
closestPoint(point: Array<number>): Array<number> { | ||
const x = Math.max(Math.min(this.max[0], point[0]), this.min[0]); | ||
const y = Math.max(Math.min(this.max[1], point[1]), this.min[1]); | ||
return [x, y]; | ||
} | ||
|
||
distanceXY(point: Array<number>): Array<number> { | ||
const aabbPoint = this.closestPoint(point); | ||
const dx = aabbPoint[0] - point[0]; | ||
const dy = aabbPoint[1] - point[1]; | ||
return [dx, dy]; | ||
} | ||
|
||
intersects(frustum: Frustum): IntersectResult { | ||
// Execute separating axis test between two convex objects to find intersections | ||
// Each frustum plane together with 3 major axes define the separating axes | ||
// Note: test only 4 points as both min and max points have equal elevation | ||
assert(this.min[2] === 0 && this.max[2] === 0); | ||
|
||
const aabbPoints = [ | ||
[this.min[0], this.min[1], 0.0, 1], | ||
[this.max[0], this.min[1], 0.0, 1], | ||
[this.max[0], this.max[1], 0.0, 1], | ||
[this.min[0], this.max[1], 0.0, 1] | ||
]; | ||
|
||
let fullyInside = true; | ||
|
||
for (let p = 0; p < frustum.planes.length; p++) { | ||
const plane = frustum.planes[p]; | ||
let pointsInside = 0; | ||
|
||
for (let i = 0; i < aabbPoints.length; i++) { | ||
pointsInside += vec4.dot(plane, aabbPoints[i]) >= 0; | ||
} | ||
|
||
if (pointsInside === 0) | ||
return 'none'; | ||
|
||
if (pointsInside !== aabbPoints.length) | ||
fullyInside = false; | ||
} | ||
|
||
if (fullyInside) | ||
return 'contains'; | ||
|
||
for (let axis = 0; axis < 3; axis++) { | ||
let projMin = Number.MAX_VALUE; | ||
let projMax = -Number.MAX_VALUE; | ||
|
||
for (let p = 0; p < frustum.points.length; p++) { | ||
const projectedPoint = frustum.points[p][axis] - this.min[axis]; | ||
|
||
projMin = Math.min(projMin, projectedPoint); | ||
projMax = Math.max(projMax, projectedPoint); | ||
} | ||
|
||
if (projMax < 0 || projMin > this.max[axis] - this.min[axis]) | ||
return 'none'; | ||
} | ||
|
||
return 'intersects'; | ||
} | ||
} | ||
export { | ||
Aabb, | ||
Frustum | ||
}; |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.