You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1689 lines
52 KiB
1689 lines
52 KiB
|
1 year ago
|
|
||
|
|
const EPSILON14 = 0.00000000000001;
|
||
|
|
const PI_OVER_TWO = Math.PI / 2.0;
|
||
|
|
const SHIFT_LEFT_12 = Math.pow(2.0, 12.0);
|
||
|
|
const TerrainQuantization = {
|
||
|
|
NONE: 0,
|
||
|
|
BITS12: 1
|
||
|
|
}
|
||
|
|
function defined(target) {
|
||
|
|
return target !== undefined && target !== null;
|
||
|
|
}
|
||
|
|
|
||
|
|
function defaultValue(value, defaultValue) {
|
||
|
|
if (!defined(value)) return defaultValue;
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
function lerp(p, q, time) {
|
||
|
|
return (1.0 - time) * p + time * q;
|
||
|
|
};
|
||
|
|
function clamp(value, min, max) {
|
||
|
|
return value < min ? min : value > max ? max : value;
|
||
|
|
};
|
||
|
|
|
||
|
|
function equalsEpsilon(a, b, epsilon) {
|
||
|
|
return Math.abs(a - b) <= epsilon;
|
||
|
|
}
|
||
|
|
|
||
|
|
function sign(a) {
|
||
|
|
if (a == 0) return 0;
|
||
|
|
return Math.abs(a) === a ? 1.0 : -1.0;
|
||
|
|
}
|
||
|
|
class Vector3 {
|
||
|
|
constructor (x,y,z) {
|
||
|
|
this.x = x || 0;
|
||
|
|
this.y = y || 0;
|
||
|
|
this.z = z || 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static minimumByComponent(v1, v2, result) {
|
||
|
|
if (!defined(result)) result = new Vector3();
|
||
|
|
result.set(
|
||
|
|
Math.min(v1.x, v2.x),
|
||
|
|
Math.min(v1.y, v2.y),
|
||
|
|
Math.min(v1.z, v2.z)
|
||
|
|
)
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
static maximumByComponent(v1, v2, result) {
|
||
|
|
if (!defined(result)) result = new Vector3();
|
||
|
|
result.set(
|
||
|
|
Math.max(v1.x, v2.x),
|
||
|
|
Math.max(v1.y, v2.y),
|
||
|
|
Math.max(v1.z, v2.z)
|
||
|
|
);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
static maximumComponent(v) {
|
||
|
|
return Math.max(v.x, v.y, v.z);
|
||
|
|
}
|
||
|
|
|
||
|
|
static equals(v1, v2) {
|
||
|
|
return (v1.x == v2.x &&
|
||
|
|
v1.y == v2.x &&
|
||
|
|
v1.z == v2.z);
|
||
|
|
}
|
||
|
|
|
||
|
|
static equalsEpsilon(v1, v2, epsilon) {
|
||
|
|
return (Math.abs(v1.x - v2.x) <= epsilon &&
|
||
|
|
Math.abs(v1.y - v2.y) <= epsilon &&
|
||
|
|
Math.abs(v1.z - v2.z) <= epsilon
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
static unpack(array, startIndex, v) {
|
||
|
|
v.x = array[startIndex];
|
||
|
|
v.y = array[startIndex + 1];
|
||
|
|
v.z = array[startIndex + 2];
|
||
|
|
}
|
||
|
|
|
||
|
|
static multiplyByScalar(v, scalar, result) {
|
||
|
|
if (!defined(result)) result = new Vector3();
|
||
|
|
result.x = v.x * scalar;
|
||
|
|
result.y = v.y * scalar;
|
||
|
|
result.z = v.z * scalar;
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
static multiplyComponents(left, right, result) {
|
||
|
|
if (!defined(result)) result = new Vector3();
|
||
|
|
result.x = left.x * right.x;
|
||
|
|
result.y = left.y * right.y;
|
||
|
|
result.z = left.z * right.z;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
static divideByScalar(v, scalar, result) {
|
||
|
|
if (!defined(result)) result = new Vector3();
|
||
|
|
result.x = v.x / scalar;
|
||
|
|
result.y = v.y / scalar;
|
||
|
|
result.z = v.z / scalar;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
static subtract(left, right, result) {
|
||
|
|
if (!defined(result)) {
|
||
|
|
result = new Vector3();
|
||
|
|
}
|
||
|
|
|
||
|
|
result.set(
|
||
|
|
left.x - right.x,
|
||
|
|
left.y - right.y,
|
||
|
|
left.z - right.z
|
||
|
|
);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
static negate(v, result) {
|
||
|
|
if (!defined(result)) {
|
||
|
|
result = new Vector3();
|
||
|
|
}
|
||
|
|
|
||
|
|
result.set(
|
||
|
|
-v.x, -v.y, -v.z
|
||
|
|
);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
static dot(left, right) {
|
||
|
|
return left.x * right.x + left.y * right.y + left.z * right.z;
|
||
|
|
}
|
||
|
|
|
||
|
|
static cross(left, right, result) {
|
||
|
|
if (!defined(result)) result = new Vector3();
|
||
|
|
const leftX = left.x;
|
||
|
|
const leftY = left.y;
|
||
|
|
const leftZ = left.z;
|
||
|
|
const rightX = right.x;
|
||
|
|
const rightY = right.y;
|
||
|
|
const rightZ = right.z;
|
||
|
|
|
||
|
|
const x = leftY * rightZ - leftZ * rightY;
|
||
|
|
const y = leftZ * rightX - leftX * rightZ;
|
||
|
|
const z = leftX * rightY - leftY * rightX;
|
||
|
|
|
||
|
|
result.x = x;
|
||
|
|
result.y = y;
|
||
|
|
result.z = z;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
clone() {
|
||
|
|
return new Vector3(this.x, this.y, this.z);
|
||
|
|
}
|
||
|
|
|
||
|
|
static clone(source) {
|
||
|
|
return new Vector3(source.x, source.y, source.z);
|
||
|
|
}
|
||
|
|
|
||
|
|
copy(source) {
|
||
|
|
this.x = source.x;
|
||
|
|
this.y = source.y;
|
||
|
|
this.z = source.z;
|
||
|
|
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
|
||
|
|
length() {
|
||
|
|
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
||
|
|
}
|
||
|
|
|
||
|
|
lengthSquare() {
|
||
|
|
return this.x * this.x + this.y * this.y + this.z * this.z;
|
||
|
|
}
|
||
|
|
|
||
|
|
normalize() {
|
||
|
|
const length = this.length() || 1;
|
||
|
|
return Vector3.divideByScalar(this, length, this);
|
||
|
|
}
|
||
|
|
|
||
|
|
set(x, y, z) {
|
||
|
|
this.x = x;
|
||
|
|
this.y = y;
|
||
|
|
this.z = z;
|
||
|
|
}
|
||
|
|
|
||
|
|
static add(left, right, result) {
|
||
|
|
if (!defined(result)) result = new Vector3();
|
||
|
|
result.set(
|
||
|
|
left.x + right.x,
|
||
|
|
left.y + right.y,
|
||
|
|
left.z + right.z
|
||
|
|
);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
static normalize(v, result) {
|
||
|
|
if (!defined(result)) result = new Vector3();
|
||
|
|
const length = v.length() || 1.0;
|
||
|
|
return Vector3.divideByScalar(v, length, result);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
static ZERO = Object.freeze(new Vector3(0, 0, 0))
|
||
|
|
}
|
||
|
|
|
||
|
|
class Vector2 {
|
||
|
|
constructor(x, y) {
|
||
|
|
this.x = x || 0;
|
||
|
|
this.y = y || 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
set(x, y) {
|
||
|
|
this.x = x;
|
||
|
|
this.y = y;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class Matrix4 {
|
||
|
|
constructor(
|
||
|
|
column0Row0,
|
||
|
|
column1Row0,
|
||
|
|
column2Row0,
|
||
|
|
column3Row0,
|
||
|
|
column0Row1,
|
||
|
|
column1Row1,
|
||
|
|
column2Row1,
|
||
|
|
column3Row1,
|
||
|
|
column0Row2,
|
||
|
|
column1Row2,
|
||
|
|
column2Row2,
|
||
|
|
column3Row2,
|
||
|
|
column0Row3,
|
||
|
|
column1Row3,
|
||
|
|
column2Row3,
|
||
|
|
column3Row3
|
||
|
|
) {
|
||
|
|
this[0] = defaultValue(column0Row0, 0.0);
|
||
|
|
this[1] = defaultValue(column0Row1, 0.0);
|
||
|
|
this[2] = defaultValue(column0Row2, 0.0);
|
||
|
|
this[3] = defaultValue(column0Row3, 0.0);
|
||
|
|
this[4] = defaultValue(column1Row0, 0.0);
|
||
|
|
this[5] = defaultValue(column1Row1, 0.0);
|
||
|
|
this[6] = defaultValue(column1Row2, 0.0);
|
||
|
|
this[7] = defaultValue(column1Row3, 0.0);
|
||
|
|
this[8] = defaultValue(column2Row0, 0.0);
|
||
|
|
this[9] = defaultValue(column2Row1, 0.0);
|
||
|
|
this[10] = defaultValue(column2Row2, 0.0);
|
||
|
|
this[11] = defaultValue(column2Row3, 0.0);
|
||
|
|
this[12] = defaultValue(column3Row0, 0.0);
|
||
|
|
this[13] = defaultValue(column3Row1, 0.0);
|
||
|
|
this[14] = defaultValue(column3Row2, 0.0);
|
||
|
|
this[15] = defaultValue(column3Row3, 0.0);
|
||
|
|
}
|
||
|
|
static multiplyByPoint(matrix, cartesian, result) {
|
||
|
|
if (!defined(result)) result = new Vector3();
|
||
|
|
const vX = cartesian.x;
|
||
|
|
const vY = cartesian.y;
|
||
|
|
const vZ = cartesian.z;
|
||
|
|
|
||
|
|
const x = matrix[0] * vX + matrix[4] * vY + matrix[8] * vZ + matrix[12];
|
||
|
|
const y = matrix[1] * vX + matrix[5] * vY + matrix[9] * vZ + matrix[13];
|
||
|
|
const z = matrix[2] * vX + matrix[6] * vY + matrix[10] * vZ + matrix[14];
|
||
|
|
|
||
|
|
result.x = x;
|
||
|
|
result.y = y;
|
||
|
|
result.z = z;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
static inverseTransformation(matrix, result) {
|
||
|
|
if (!defined(result)) result = new Matrix4();
|
||
|
|
const matrix0 = matrix[0];
|
||
|
|
const matrix1 = matrix[1];
|
||
|
|
const matrix2 = matrix[2];
|
||
|
|
const matrix4 = matrix[4];
|
||
|
|
const matrix5 = matrix[5];
|
||
|
|
const matrix6 = matrix[6];
|
||
|
|
const matrix8 = matrix[8];
|
||
|
|
const matrix9 = matrix[9];
|
||
|
|
const matrix10 = matrix[10];
|
||
|
|
|
||
|
|
const vX = matrix[12];
|
||
|
|
const vY = matrix[13];
|
||
|
|
const vZ = matrix[14];
|
||
|
|
|
||
|
|
const x = -matrix0 * vX - matrix1 * vY - matrix2 * vZ;
|
||
|
|
const y = -matrix4 * vX - matrix5 * vY - matrix6 * vZ;
|
||
|
|
const z = -matrix8 * vX - matrix9 * vY - matrix10 * vZ;
|
||
|
|
|
||
|
|
result[0] = matrix0;
|
||
|
|
result[1] = matrix4;
|
||
|
|
result[2] = matrix8;
|
||
|
|
result[3] = 0.0;
|
||
|
|
result[4] = matrix1;
|
||
|
|
result[5] = matrix5;
|
||
|
|
result[6] = matrix9;
|
||
|
|
result[7] = 0.0;
|
||
|
|
result[8] = matrix2;
|
||
|
|
result[9] = matrix6;
|
||
|
|
result[10] = matrix10;
|
||
|
|
result[11] = 0.0;
|
||
|
|
result[12] = x;
|
||
|
|
result[13] = y;
|
||
|
|
result[14] = z;
|
||
|
|
result[15] = 1.0;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
static multiply(left, right, result) {
|
||
|
|
if (!defined(result)) {
|
||
|
|
result = new Matrix4();
|
||
|
|
}
|
||
|
|
|
||
|
|
const left0 = left[0];
|
||
|
|
const left1 = left[1];
|
||
|
|
const left2 = left[2];
|
||
|
|
const left3 = left[3];
|
||
|
|
const left4 = left[4];
|
||
|
|
const left5 = left[5];
|
||
|
|
const left6 = left[6];
|
||
|
|
const left7 = left[7];
|
||
|
|
const left8 = left[8];
|
||
|
|
const left9 = left[9];
|
||
|
|
const left10 = left[10];
|
||
|
|
const left11 = left[11];
|
||
|
|
const left12 = left[12];
|
||
|
|
const left13 = left[13];
|
||
|
|
const left14 = left[14];
|
||
|
|
const left15 = left[15];
|
||
|
|
|
||
|
|
const right0 = right[0];
|
||
|
|
const right1 = right[1];
|
||
|
|
const right2 = right[2];
|
||
|
|
const right3 = right[3];
|
||
|
|
const right4 = right[4];
|
||
|
|
const right5 = right[5];
|
||
|
|
const right6 = right[6];
|
||
|
|
const right7 = right[7];
|
||
|
|
const right8 = right[8];
|
||
|
|
const right9 = right[9];
|
||
|
|
const right10 = right[10];
|
||
|
|
const right11 = right[11];
|
||
|
|
const right12 = right[12];
|
||
|
|
const right13 = right[13];
|
||
|
|
const right14 = right[14];
|
||
|
|
const right15 = right[15];
|
||
|
|
|
||
|
|
const column0Row0 =
|
||
|
|
left0 * right0 + left4 * right1 + left8 * right2 + left12 * right3;
|
||
|
|
const column0Row1 =
|
||
|
|
left1 * right0 + left5 * right1 + left9 * right2 + left13 * right3;
|
||
|
|
const column0Row2 =
|
||
|
|
left2 * right0 + left6 * right1 + left10 * right2 + left14 * right3;
|
||
|
|
const column0Row3 =
|
||
|
|
left3 * right0 + left7 * right1 + left11 * right2 + left15 * right3;
|
||
|
|
|
||
|
|
const column1Row0 =
|
||
|
|
left0 * right4 + left4 * right5 + left8 * right6 + left12 * right7;
|
||
|
|
const column1Row1 =
|
||
|
|
left1 * right4 + left5 * right5 + left9 * right6 + left13 * right7;
|
||
|
|
const column1Row2 =
|
||
|
|
left2 * right4 + left6 * right5 + left10 * right6 + left14 * right7;
|
||
|
|
const column1Row3 =
|
||
|
|
left3 * right4 + left7 * right5 + left11 * right6 + left15 * right7;
|
||
|
|
|
||
|
|
const column2Row0 =
|
||
|
|
left0 * right8 + left4 * right9 + left8 * right10 + left12 * right11;
|
||
|
|
const column2Row1 =
|
||
|
|
left1 * right8 + left5 * right9 + left9 * right10 + left13 * right11;
|
||
|
|
const column2Row2 =
|
||
|
|
left2 * right8 + left6 * right9 + left10 * right10 + left14 * right11;
|
||
|
|
const column2Row3 =
|
||
|
|
left3 * right8 + left7 * right9 + left11 * right10 + left15 * right11;
|
||
|
|
|
||
|
|
const column3Row0 =
|
||
|
|
left0 * right12 + left4 * right13 + left8 * right14 + left12 * right15;
|
||
|
|
const column3Row1 =
|
||
|
|
left1 * right12 + left5 * right13 + left9 * right14 + left13 * right15;
|
||
|
|
const column3Row2 =
|
||
|
|
left2 * right12 + left6 * right13 + left10 * right14 + left14 * right15;
|
||
|
|
const column3Row3 =
|
||
|
|
left3 * right12 + left7 * right13 + left11 * right14 + left15 * right15;
|
||
|
|
|
||
|
|
result[0] = column0Row0;
|
||
|
|
result[1] = column0Row1;
|
||
|
|
result[2] = column0Row2;
|
||
|
|
result[3] = column0Row3;
|
||
|
|
result[4] = column1Row0;
|
||
|
|
result[5] = column1Row1;
|
||
|
|
result[6] = column1Row2;
|
||
|
|
result[7] = column1Row3;
|
||
|
|
result[8] = column2Row0;
|
||
|
|
result[9] = column2Row1;
|
||
|
|
result[10] = column2Row2;
|
||
|
|
result[11] = column2Row3;
|
||
|
|
result[12] = column3Row0;
|
||
|
|
result[13] = column3Row1;
|
||
|
|
result[14] = column3Row2;
|
||
|
|
result[15] = column3Row3;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
static fromTranslation(translation, result) {
|
||
|
|
if (!defined(result)) {
|
||
|
|
return new Matrix4(
|
||
|
|
1.0, 0.0, 0.0, translation.x,
|
||
|
|
0.0, 1.0, 0.0, translation.y,
|
||
|
|
0.0, 0.0, 1.0, translation.z,
|
||
|
|
0.0, 0.0, 0.0, 1.0
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
result[0] = 1.0;
|
||
|
|
result[1] = 0.0;
|
||
|
|
result[2] = 0.0;
|
||
|
|
result[3] = 0.0;
|
||
|
|
result[4] = 0.0;
|
||
|
|
result[5] = 1.0;
|
||
|
|
result[6] = 0.0;
|
||
|
|
result[7] = 0.0;
|
||
|
|
result[8] = 0.0;
|
||
|
|
result[9] = 0.0;
|
||
|
|
result[10] = 1.0;
|
||
|
|
result[11] = 0.0;
|
||
|
|
result[12] = translation.x;
|
||
|
|
result[13] = translation.y;
|
||
|
|
result[14] = translation.z;
|
||
|
|
result[15] = 1.0;
|
||
|
|
return result;
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
static fromRotationTranslation(rotation, translation, result) {
|
||
|
|
translation = defaultValue(translation, Vector3.ZERO);
|
||
|
|
|
||
|
|
if (!defined(result)) {
|
||
|
|
return new Matrix4(
|
||
|
|
rotation[0],
|
||
|
|
rotation[3],
|
||
|
|
rotation[6],
|
||
|
|
translation.x,
|
||
|
|
rotation[1],
|
||
|
|
rotation[4],
|
||
|
|
rotation[7],
|
||
|
|
translation.y,
|
||
|
|
rotation[2],
|
||
|
|
rotation[5],
|
||
|
|
rotation[8],
|
||
|
|
translation.z,
|
||
|
|
0.0,
|
||
|
|
0.0,
|
||
|
|
0.0,
|
||
|
|
1.0
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
result[0] = rotation[0];
|
||
|
|
result[1] = rotation[1];
|
||
|
|
result[2] = rotation[2];
|
||
|
|
result[3] = 0.0;
|
||
|
|
result[4] = rotation[3];
|
||
|
|
result[5] = rotation[4];
|
||
|
|
result[6] = rotation[5];
|
||
|
|
result[7] = 0.0;
|
||
|
|
result[8] = rotation[6];
|
||
|
|
result[9] = rotation[7];
|
||
|
|
result[10] = rotation[8];
|
||
|
|
result[11] = 0.0;
|
||
|
|
result[12] = translation.x;
|
||
|
|
result[13] = translation.y;
|
||
|
|
result[14] = translation.z;
|
||
|
|
result[15] = 1.0;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
static fromScale(scale, result) {
|
||
|
|
if (!defined(result)) {
|
||
|
|
return new Matrix4(
|
||
|
|
scale.x,
|
||
|
|
0.0,
|
||
|
|
0.0,
|
||
|
|
0.0,
|
||
|
|
0.0,
|
||
|
|
scale.y,
|
||
|
|
0.0,
|
||
|
|
0.0,
|
||
|
|
0.0,
|
||
|
|
0.0,
|
||
|
|
scale.z,
|
||
|
|
0.0,
|
||
|
|
0.0,
|
||
|
|
0.0,
|
||
|
|
0.0,
|
||
|
|
1.0
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
result[0] = scale.x;
|
||
|
|
result[1] = 0.0;
|
||
|
|
result[2] = 0.0;
|
||
|
|
result[3] = 0.0;
|
||
|
|
result[4] = 0.0;
|
||
|
|
result[5] = scale.y;
|
||
|
|
result[6] = 0.0;
|
||
|
|
result[7] = 0.0;
|
||
|
|
result[8] = 0.0;
|
||
|
|
result[9] = 0.0;
|
||
|
|
result[10] = scale.z;
|
||
|
|
result[11] = 0.0;
|
||
|
|
result[12] = 0.0;
|
||
|
|
result[13] = 0.0;
|
||
|
|
result[14] = 0.0;
|
||
|
|
result[15] = 1.0;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
static clone(matrix, result) {
|
||
|
|
if (!defined(result)) {
|
||
|
|
return new Matrix4(
|
||
|
|
matrix[0],
|
||
|
|
matrix[4],
|
||
|
|
matrix[8],
|
||
|
|
matrix[12],
|
||
|
|
matrix[1],
|
||
|
|
matrix[5],
|
||
|
|
matrix[9],
|
||
|
|
matrix[13],
|
||
|
|
matrix[2],
|
||
|
|
matrix[6],
|
||
|
|
matrix[10],
|
||
|
|
matrix[14],
|
||
|
|
matrix[3],
|
||
|
|
matrix[7],
|
||
|
|
matrix[11],
|
||
|
|
matrix[15]
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
result[0] = matrix[0];
|
||
|
|
result[1] = matrix[1];
|
||
|
|
result[2] = matrix[2];
|
||
|
|
result[3] = matrix[3];
|
||
|
|
result[4] = matrix[4];
|
||
|
|
result[5] = matrix[5];
|
||
|
|
result[6] = matrix[6];
|
||
|
|
result[7] = matrix[7];
|
||
|
|
result[8] = matrix[8];
|
||
|
|
result[9] = matrix[9];
|
||
|
|
result[10] = matrix[10];
|
||
|
|
result[11] = matrix[11];
|
||
|
|
result[12] = matrix[12];
|
||
|
|
result[13] = matrix[13];
|
||
|
|
result[14] = matrix[14];
|
||
|
|
result[15] = matrix[15];
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
static setTranslation(matrix, translation, result) {
|
||
|
|
if (!defined(result)) result = new Matrix4();
|
||
|
|
result[0] = matrix[0];
|
||
|
|
result[1] = matrix[1];
|
||
|
|
result[2] = matrix[2];
|
||
|
|
result[3] = matrix[3];
|
||
|
|
|
||
|
|
result[4] = matrix[4];
|
||
|
|
result[5] = matrix[5];
|
||
|
|
result[6] = matrix[6];
|
||
|
|
result[7] = matrix[7];
|
||
|
|
|
||
|
|
result[8] = matrix[8];
|
||
|
|
result[9] = matrix[9];
|
||
|
|
result[10] = matrix[10];
|
||
|
|
result[11] = matrix[11];
|
||
|
|
|
||
|
|
result[12] = translation.x;
|
||
|
|
result[13] = translation.y;
|
||
|
|
result[14] = translation.z;
|
||
|
|
result[15] = matrix[15];
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class Rectangle {
|
||
|
|
constructor(west, south, east, north) {
|
||
|
|
this.west = west || 0;
|
||
|
|
this.south = south || 0;
|
||
|
|
this.east = east || 0;
|
||
|
|
this.north = north || 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
clone(source) {
|
||
|
|
return new Rectangle(
|
||
|
|
source.west,
|
||
|
|
source.south,
|
||
|
|
source.east,
|
||
|
|
source.north
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class Cartographic {
|
||
|
|
constructor(longitude, latitude, height) {
|
||
|
|
this.longitude = longitude || 0;
|
||
|
|
this.latitude = latitude || 0;
|
||
|
|
this.height = height || 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
const scratchFirstArray = [0, 1, 0];
|
||
|
|
const scratchSecondArray = [-1, 0, 0];
|
||
|
|
const scratchThirdArray = [0, 0, 1];
|
||
|
|
|
||
|
|
const scratchFirstCartesian = new Vector3();
|
||
|
|
const scratchSecondCartesian = new Vector3();
|
||
|
|
const scratchThirdCartesian = new Vector3();
|
||
|
|
|
||
|
|
const scratchCalculateCartesian = {
|
||
|
|
east: new Vector3(),
|
||
|
|
north: new Vector3(),
|
||
|
|
up: new Vector3(),
|
||
|
|
west: new Vector3(),
|
||
|
|
south: new Vector3(),
|
||
|
|
down: new Vector3(),
|
||
|
|
}
|
||
|
|
|
||
|
|
class Transforms {
|
||
|
|
constructor(){}
|
||
|
|
|
||
|
|
static eastNorthUpToFixedFrame(origin, ellipsoid, result) {
|
||
|
|
|
||
|
|
if (!defined(result)) result = new Matrix4();
|
||
|
|
|
||
|
|
if (Vector3.equalsEpsilon(origin, Vector3.ZERO, EPSILON14)) {
|
||
|
|
Vector3.unpack(scratchFirstArray, 0, scratchFirstCartesian);
|
||
|
|
Vector3.unpack(scratchSecondArray, 0, scratchSecondCartesian);
|
||
|
|
Vector3.unpack(scratchThirdArray, 0, scratchThirdCartesian);
|
||
|
|
} else if (
|
||
|
|
equalsEpsilon(origin.x, 0.0, EPSILON14) &&
|
||
|
|
equalsEpsilon(origin.y, 0.0, EPSILON14)
|
||
|
|
) {
|
||
|
|
const sign = sign(origin.z);
|
||
|
|
|
||
|
|
Vector3.unpack(scratchFirstArray, 0, scratchFirstCartesian);
|
||
|
|
|
||
|
|
Vector3.unpack(scratchSecondArray, 0, scratchSecondCartesian);
|
||
|
|
Vector3.multiplyByScalar(scratchSecondCartesian, sign, scratchSecondCartesian);
|
||
|
|
|
||
|
|
Vector3.unpack(scratchThirdArray, 0, scratchThirdCartesian);
|
||
|
|
Vector3.multiplyByScalar(scratchThirdCartesian, sign, scratchThirdCartesian);
|
||
|
|
} else {
|
||
|
|
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
|
||
|
|
ellipsoid.geodeticSurfaceNormal(origin, scratchCalculateCartesian.up);
|
||
|
|
const up = scratchCalculateCartesian.up;
|
||
|
|
const east = scratchCalculateCartesian.east;
|
||
|
|
east.x = -origin.y;
|
||
|
|
east.y = origin.x;
|
||
|
|
east.z = 0.0;
|
||
|
|
Vector3.normalize(east, scratchCalculateCartesian.east);
|
||
|
|
Vector3.cross(up, east, scratchCalculateCartesian.north);
|
||
|
|
|
||
|
|
Vector3.multiplyByScalar(scratchCalculateCartesian.up, -1, scratchCalculateCartesian.down);
|
||
|
|
Vector3.multiplyByScalar(scratchCalculateCartesian.east, -1, scratchCalculateCartesian.west);
|
||
|
|
Vector3.multiplyByScalar(scratchCalculateCartesian.north, -1, scratchCalculateCartesian.south);
|
||
|
|
|
||
|
|
scratchFirstCartesian.copy(scratchCalculateCartesian.east);
|
||
|
|
scratchSecondCartesian.copy(scratchCalculateCartesian.north);
|
||
|
|
scratchThirdCartesian.copy(scratchCalculateCartesian.up);
|
||
|
|
}
|
||
|
|
|
||
|
|
result[0] = scratchFirstCartesian.x;
|
||
|
|
result[1] = scratchFirstCartesian.y;
|
||
|
|
result[2] = scratchFirstCartesian.z;
|
||
|
|
result[3] = 0.0;
|
||
|
|
result[4] = scratchSecondCartesian.x;
|
||
|
|
result[5] = scratchSecondCartesian.y;
|
||
|
|
result[6] = scratchSecondCartesian.z;
|
||
|
|
result[7] = 0.0;
|
||
|
|
result[8] = scratchThirdCartesian.x;
|
||
|
|
result[9] = scratchThirdCartesian.y;
|
||
|
|
result[10] = scratchThirdCartesian.z;
|
||
|
|
result[11] = 0.0;
|
||
|
|
result[12] = origin.x;
|
||
|
|
result[13] = origin.y;
|
||
|
|
result[14] = origin.z;
|
||
|
|
result[15] = 1.0;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class Ellipsoid {
|
||
|
|
constructor(x, y, z) {
|
||
|
|
x = x || 0;
|
||
|
|
y = y || 0;
|
||
|
|
z = z || 0;
|
||
|
|
|
||
|
|
this.x = x;
|
||
|
|
this.y = y;
|
||
|
|
this.z = z;
|
||
|
|
|
||
|
|
this.radii = new Vector3(x, y, z);
|
||
|
|
this.radiiSquared = new Vector3(x * x, y * y, z * z);
|
||
|
|
this.radiiToTheFourth = new Vector3(
|
||
|
|
x * x * x * x,
|
||
|
|
y * y * y * y,
|
||
|
|
z * z * z * z
|
||
|
|
);
|
||
|
|
this.oneOverRadii = new Vector3(
|
||
|
|
x === 0.0 ? 0.0 : 1.0 / x,
|
||
|
|
y === 0.0 ? 0.0 : 1.0 / y,
|
||
|
|
z === 0.0 ? 0.0 : 1.0 / z
|
||
|
|
);
|
||
|
|
|
||
|
|
this.oneOverRadiiSquared = new Vector3(
|
||
|
|
x === 0.0 ? 0.0 : 1.0 / (x * x),
|
||
|
|
y === 0.0 ? 0.0 : 1.0 / (y * y),
|
||
|
|
z === 0.0 ? 0.0 : 1.0 / (z * z)
|
||
|
|
);
|
||
|
|
|
||
|
|
this.minimumRadius = Math.min(x, y, z);
|
||
|
|
this.maximumRadius = Math.max(x, y, z);
|
||
|
|
this.centerToleranceSquared = 0.1;
|
||
|
|
this.squaredFirstEccentricity = 1 - (z * z) / (x * x);
|
||
|
|
|
||
|
|
if (this.radiiSquared.z !== 0) {
|
||
|
|
this.squaredXOverSquaredZ = this.radiiSquared.x / this.radiiSquared.z;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
transformPositionToScaledSpace(position, result) {
|
||
|
|
if (!defined(result)) {
|
||
|
|
result = new Vector3();
|
||
|
|
}
|
||
|
|
|
||
|
|
return Vector3.multiplyComponents(position, this.oneOverRadii, result);
|
||
|
|
}
|
||
|
|
|
||
|
|
geodeticSurfaceNormal(cartesian, result) {
|
||
|
|
if (Vector3.equalsEpsilon(cartesian, Vector3.ZERO, EPSILON14)) {
|
||
|
|
return undefined;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!defined(result)) result = new Vector3();
|
||
|
|
|
||
|
|
let temp = this.oneOverRadiiSquared.clone();
|
||
|
|
result = Vector3.multiplyComponents(cartesian, temp, result);
|
||
|
|
return result.normalize();
|
||
|
|
}
|
||
|
|
cartographicToCartesian(cartographic, result) {
|
||
|
|
|
||
|
|
if (!defined(result)) result = new Vector3();
|
||
|
|
|
||
|
|
const cartographicToCartesianNormal = new Vector3();
|
||
|
|
const cartographicToCartesianK = new Vector3();
|
||
|
|
|
||
|
|
this.geodeticSurfaceNormalCartographic(cartographic, cartographicToCartesianNormal);
|
||
|
|
|
||
|
|
Vector3.multiplyComponents(this.radiiSquared, cartographicToCartesianNormal, cartographicToCartesianK);
|
||
|
|
const gamma = Math.sqrt(Vector3.dot(cartographicToCartesianNormal, cartographicToCartesianK));
|
||
|
|
Vector3.divideByScalar(cartographicToCartesianK, gamma, cartographicToCartesianK);
|
||
|
|
Vector3.multiplyByScalar(cartographicToCartesianNormal, cartographic.height, cartographicToCartesianNormal);
|
||
|
|
|
||
|
|
return Vector3.add(cartographicToCartesianK, cartographicToCartesianNormal, result);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
geodeticSurfaceNormalCartographic(cartographic, result) {
|
||
|
|
if (!defined(result)) result = new Vector3();
|
||
|
|
const longitude = cartographic.longitude;
|
||
|
|
const latitude = cartographic.latitude;
|
||
|
|
const cosLatitude = Math.cos(latitude);
|
||
|
|
|
||
|
|
const x = cosLatitude * Math.cos(longitude);
|
||
|
|
const y = cosLatitude * Math.sin(longitude);
|
||
|
|
const z = Math.sin(latitude);
|
||
|
|
|
||
|
|
result.set(x, y, z);
|
||
|
|
return result.normalize();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
Ellipsoid.WGS84 = Object.freeze(new Ellipsoid(6378137.0, 6378137.0, 6356752.3142451793))
|
||
|
|
|
||
|
|
class WebMercatorProjection {
|
||
|
|
constructor(){}
|
||
|
|
static mercatorAngleToGeodeticLatitude(mercatorAngle) {
|
||
|
|
return PI_OVER_TWO - 2.0 * Math.atan(Math.exp(-mercatorAngle));
|
||
|
|
}
|
||
|
|
static geodeticLatitudeToMercatorAngle(latitude) {
|
||
|
|
if (latitude > WebMercatorProjection.MaximumLatitude) {
|
||
|
|
latitude = WebMercatorProjection.MaximumLatitude;
|
||
|
|
} else if (latitude < -WebMercatorProjection.MaximumLatitude) {
|
||
|
|
latitude = -WebMercatorProjection.MaximumLatitude;
|
||
|
|
}
|
||
|
|
const sinLatitude = Math.sin(latitude);
|
||
|
|
return 0.5 * Math.log((1.0 + sinLatitude) / (1.0 - sinLatitude));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
WebMercatorProjection.MaximumLatitude = WebMercatorProjection.mercatorAngleToGeodeticLatitude(Math.PI);
|
||
|
|
|
||
|
|
class EllipsoidalOccluder {
|
||
|
|
constructor(ellipsoid) {
|
||
|
|
this.ellipsoid = ellipsoid;
|
||
|
|
this.cameraPosition = new Vector3();
|
||
|
|
this.cameraPositionInScaledSpace = new Vector3();
|
||
|
|
this.distanceToLimbInScaledSquared = 0.0;
|
||
|
|
}
|
||
|
|
computeHorizonCullingPointPossiblyUnderEllipsoid(directionToPoint, positions, minimumHeight, result) {
|
||
|
|
const possiblyShrunkEllipsoid = EllipsoidalOccluder.getPossiblyShrunkEllipsoid(
|
||
|
|
this.ellipsoid,
|
||
|
|
minimumHeight
|
||
|
|
);
|
||
|
|
return EllipsoidalOccluder.computeHorizonCullingPointFromPositions(
|
||
|
|
possiblyShrunkEllipsoid,
|
||
|
|
directionToPoint,
|
||
|
|
positions,
|
||
|
|
result
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
static getPossiblyShrunkEllipsoid(ellipsoid, minimumHeight) {
|
||
|
|
if (defined(minimumHeight) &&
|
||
|
|
minimumHeight < 0.0 &&
|
||
|
|
ellipsoid.minimumRadius > - minimumHeight
|
||
|
|
) {
|
||
|
|
const ellipsoidShrunkRadii = new Vector3(
|
||
|
|
ellipsoid.radii.x + minimumHeight,
|
||
|
|
ellipsoid.radii.y + minimumHeight,
|
||
|
|
ellipsoid.radii.z + minimumHeight,
|
||
|
|
);
|
||
|
|
ellipsoid = new Ellipsoid(
|
||
|
|
ellipsoidShrunkRadii.x,
|
||
|
|
ellipsoidShrunkRadii.y,
|
||
|
|
ellipsoidShrunkRadii.z
|
||
|
|
);
|
||
|
|
}
|
||
|
|
return ellipsoid;
|
||
|
|
}
|
||
|
|
|
||
|
|
static computeHorizonCullingPointFromPositions(ellipsoid, directionToPoint, positions, result) {
|
||
|
|
if (!defined(result)) result = new Vector3();
|
||
|
|
const scaledSpaceDirectionToPoint = EllipsoidalOccluder.computeScaledSpaceDirectionToPoint(ellipsoid, directionToPoint);
|
||
|
|
|
||
|
|
let resultMagnitude = 0.0;
|
||
|
|
for (let i = 0, len = positions.length; i < len; ++i) {
|
||
|
|
const position = positions[i];
|
||
|
|
const candidateMagnitude = EllipsoidalOccluder.computeMagnitude(
|
||
|
|
ellipsoid,
|
||
|
|
position,
|
||
|
|
scaledSpaceDirectionToPoint
|
||
|
|
);
|
||
|
|
if (candidateMagnitude < 0.0) {
|
||
|
|
// all points should face the same direction, but this one doesn't, so return undefined
|
||
|
|
return undefined;
|
||
|
|
}
|
||
|
|
resultMagnitude = Math.max(resultMagnitude, candidateMagnitude);
|
||
|
|
}
|
||
|
|
|
||
|
|
return EllipsoidalOccluder.magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, result);
|
||
|
|
}
|
||
|
|
|
||
|
|
static computeScaledSpaceDirectionToPoint(ellipsoid, directionToPoint){
|
||
|
|
if (Vector3.equals(directionToPoint, Vector3.ZERO)) {
|
||
|
|
return directionToPoint;
|
||
|
|
}
|
||
|
|
|
||
|
|
const directionToPointScratch = ellipsoid.transformPositionToScaledSpace(
|
||
|
|
directionToPoint
|
||
|
|
);
|
||
|
|
|
||
|
|
return directionToPointScratch.normalize();
|
||
|
|
}
|
||
|
|
|
||
|
|
static computeMagnitude(ellipsoid, position, scaledSpaceDirectionToPoint) {
|
||
|
|
const scaledSpacePosition = ellipsoid.transformPositionToScaledSpace(
|
||
|
|
position
|
||
|
|
);
|
||
|
|
let magnitudeSquared = scaledSpacePosition.lengthSquare();
|
||
|
|
let magnitude = scaledSpacePosition.length();
|
||
|
|
const direction = Vector3.divideByScalar(scaledSpacePosition, magnitude);
|
||
|
|
|
||
|
|
magnitudeSquared = Math.max(1.0, magnitudeSquared);
|
||
|
|
magnitude = Math.max(1.0, magnitude);
|
||
|
|
|
||
|
|
const cosAlpha = Vector3.dot(direction, scaledSpaceDirectionToPoint);
|
||
|
|
const sinAlpha = Vector3.cross(direction, scaledSpaceDirectionToPoint, direction).length()
|
||
|
|
|
||
|
|
const cosBeta = 1.0 / magnitude;
|
||
|
|
const sinBeta = Math.sqrt(magnitudeSquared - 1.0) * cosBeta;
|
||
|
|
|
||
|
|
return 1.0 / (cosAlpha * cosBeta - sinAlpha * sinBeta);
|
||
|
|
}
|
||
|
|
|
||
|
|
static magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, result) {
|
||
|
|
if (resultMagnitude <= 0.0 ||
|
||
|
|
resultMagnitude === 1.0 / 0.0 ||
|
||
|
|
resultMagnitude !== resultMagnitude) {
|
||
|
|
return undefined;
|
||
|
|
}
|
||
|
|
|
||
|
|
return Vector3.multiplyByScalar(scaledSpaceDirectionToPoint, resultMagnitude, result);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class AxisAlignedBoundingBox {
|
||
|
|
constructor(minimum, maximum, center) {
|
||
|
|
this.minimum = defaultValue(minimum, Vector3.ZERO).clone();
|
||
|
|
this.maximum = defaultValue(maximum, Vector3.ZERO).clone();
|
||
|
|
if (!defined(center)) {
|
||
|
|
center = new Vector3(
|
||
|
|
(this.minimum.x + this.maximum.x) * 0.5,
|
||
|
|
(this.minimum.y + this.maximum.y) * 0.5,
|
||
|
|
(this.minimum.z + this.maximum.z) * 0.5
|
||
|
|
);
|
||
|
|
} else {
|
||
|
|
center = new Vector3(center.x, center.y, center.z);
|
||
|
|
}
|
||
|
|
this.center = center;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class TerrainEncoding {
|
||
|
|
constructor(
|
||
|
|
center,
|
||
|
|
axisAlignedBoundingBox,
|
||
|
|
minimumHeight,
|
||
|
|
maximumHeight,
|
||
|
|
fromENU,
|
||
|
|
hasVertexNormals,
|
||
|
|
hasWebMercatorT,
|
||
|
|
hasGeodeticSurfaceNormals,
|
||
|
|
exaggeration,
|
||
|
|
exaggerationRelativeHeight,
|
||
|
|
name
|
||
|
|
) {
|
||
|
|
|
||
|
|
let quantization = TerrainQuantization.NONE;
|
||
|
|
let toENU;
|
||
|
|
let matrix;
|
||
|
|
|
||
|
|
const cartesian3DimScratch = new Vector3();
|
||
|
|
|
||
|
|
if (
|
||
|
|
defined(axisAlignedBoundingBox) &&
|
||
|
|
defined(minimumHeight) &&
|
||
|
|
defined(maximumHeight) &&
|
||
|
|
defined(fromENU)
|
||
|
|
) {
|
||
|
|
const minimum = axisAlignedBoundingBox.minimum;
|
||
|
|
const maximum = axisAlignedBoundingBox.maximum;
|
||
|
|
|
||
|
|
const dimensions = Vector3.subtract(
|
||
|
|
maximum,
|
||
|
|
minimum,
|
||
|
|
cartesian3DimScratch
|
||
|
|
);
|
||
|
|
const hDim = maximumHeight - minimumHeight;
|
||
|
|
const maxDim = Math.max(Vector3.maximumComponent(dimensions), hDim);
|
||
|
|
|
||
|
|
if (maxDim < SHIFT_LEFT_12 - 1.0) {
|
||
|
|
quantization = TerrainQuantization.BITS12;
|
||
|
|
} else {
|
||
|
|
quantization = TerrainQuantization.NONE;
|
||
|
|
}
|
||
|
|
|
||
|
|
toENU = Matrix4.inverseTransformation(fromENU, new Matrix4());
|
||
|
|
const matrix4Scratch13T = new Matrix4();
|
||
|
|
const cartesian3Scratch13T = new Vector3();
|
||
|
|
const matrix4Scratch2 = new Matrix4();
|
||
|
|
|
||
|
|
const translation = Vector3.negate(minimum, cartesian3Scratch13T);
|
||
|
|
|
||
|
|
Matrix4.multiply(
|
||
|
|
Matrix4.fromTranslation(translation, matrix4Scratch13T),
|
||
|
|
toENU,
|
||
|
|
toENU
|
||
|
|
);
|
||
|
|
|
||
|
|
const scale = cartesian3Scratch13T;
|
||
|
|
scale.x = 1.0 / dimensions.x;
|
||
|
|
scale.y = 1.0 / dimensions.y;
|
||
|
|
scale.z = 1.0 / dimensions.z;
|
||
|
|
Matrix4.multiply(Matrix4.fromScale(scale, matrix4Scratch13T), toENU, toENU);
|
||
|
|
|
||
|
|
matrix = Matrix4.clone(fromENU);
|
||
|
|
Matrix4.setTranslation(matrix, Vector3.ZERO, matrix);
|
||
|
|
|
||
|
|
fromENU = Matrix4.clone(fromENU, new Matrix4());
|
||
|
|
|
||
|
|
|
||
|
|
const translationMatrix = Matrix4.fromTranslation(minimum, matrix4Scratch13T);
|
||
|
|
|
||
|
|
const scaleMatrix = Matrix4.fromScale(dimensions, matrix4Scratch2);
|
||
|
|
|
||
|
|
const st = Matrix4.multiply(translationMatrix, scaleMatrix, matrix4Scratch13T);
|
||
|
|
|
||
|
|
Matrix4.multiply(fromENU, st, fromENU);
|
||
|
|
|
||
|
|
Matrix4.multiply(matrix, st, matrix);
|
||
|
|
}
|
||
|
|
this.quantization = quantization;
|
||
|
|
this.minimumHeight = minimumHeight;
|
||
|
|
this.maximumHeight = maximumHeight;
|
||
|
|
this.center = Vector3.clone(center);
|
||
|
|
this.toScaledENU = toENU;
|
||
|
|
this.fromScaledENU = fromENU;
|
||
|
|
|
||
|
|
this.matrix = matrix;
|
||
|
|
this.hasVertexNormals = hasVertexNormals;
|
||
|
|
this.hasWebMercatorT = defaultValue(hasWebMercatorT, false);
|
||
|
|
this.hasGeodeticSurfaceNormals = defaultValue(
|
||
|
|
hasGeodeticSurfaceNormals,
|
||
|
|
false
|
||
|
|
);
|
||
|
|
this.exaggeration = defaultValue(exaggeration, 1.0);
|
||
|
|
this.exaggerationRelativeHeight = defaultValue(
|
||
|
|
exaggerationRelativeHeight,
|
||
|
|
0.0
|
||
|
|
);
|
||
|
|
|
||
|
|
this.stride = 0;
|
||
|
|
this._offsetGeodeticSurfaceNormal = 0;
|
||
|
|
this._offsetVertexNormal = 0;
|
||
|
|
this._calculateStrideAndOffsets();
|
||
|
|
}
|
||
|
|
_calculateStrideAndOffsets() {
|
||
|
|
let vertexStride = 0;
|
||
|
|
|
||
|
|
switch (this.quantization) {
|
||
|
|
case TerrainQuantization.BITS12:
|
||
|
|
vertexStride += 3;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
vertexStride += 6;
|
||
|
|
}
|
||
|
|
if (this.hasWebMercatorT) {
|
||
|
|
vertexStride += 1;
|
||
|
|
}
|
||
|
|
if (this.hasVertexNormals) {
|
||
|
|
this._offsetVertexNormal = vertexStride;
|
||
|
|
vertexStride += 1;
|
||
|
|
}
|
||
|
|
if (this.hasGeodeticSurfaceNormals) {
|
||
|
|
this._offsetGeodeticSurfaceNormal = vertexStride;
|
||
|
|
vertexStride += 3;
|
||
|
|
}
|
||
|
|
|
||
|
|
this.stride = vertexStride;
|
||
|
|
}
|
||
|
|
encode(vertexBuffer, bufferIndex, position, uv, height, normalToPack, webMercatorT, geodeticSurfaceNormal) {
|
||
|
|
const cartesian3Scratch13T = new Vector3();
|
||
|
|
const cartesian2Scratch = new Vector2();
|
||
|
|
const u = uv.x;
|
||
|
|
const v = uv.y;
|
||
|
|
if (this.quantization === TerrainQuantization.BITS12) {
|
||
|
|
position = Matrix4.multiplyByPoint(
|
||
|
|
this.toScaledENU,
|
||
|
|
position,
|
||
|
|
cartesian3Scratch13T
|
||
|
|
);
|
||
|
|
|
||
|
|
position.x = clamp(position.x, 0.0, 1.0);
|
||
|
|
position.y = clamp(position.y, 0.0, 1.0);
|
||
|
|
position.z = clamp(position.z, 0.0, 1.0);
|
||
|
|
|
||
|
|
const hDim = this.maximumHeight - this.minimumHeight;
|
||
|
|
const h = clamp((height - this.minimumHeight) / hDim, 0.0, 1.0);
|
||
|
|
|
||
|
|
cartesian2Scratch.set(position.x, position.y);
|
||
|
|
const compressed0 = AttributeCompression.compressTextureCoordinates(
|
||
|
|
cartesian2Scratch
|
||
|
|
);
|
||
|
|
|
||
|
|
cartesian2Scratch.set(position.z, h);
|
||
|
|
const compressed1 = AttributeCompression.compressTextureCoordinates(
|
||
|
|
cartesian2Scratch
|
||
|
|
);
|
||
|
|
|
||
|
|
cartesian2Scratch.set(u, v);
|
||
|
|
const compressed2 = AttributeCompression.compressTextureCoordinates(
|
||
|
|
cartesian2Scratch
|
||
|
|
);
|
||
|
|
|
||
|
|
vertexBuffer[bufferIndex++] = compressed0;
|
||
|
|
|
||
|
|
vertexBuffer[bufferIndex++] = compressed1;
|
||
|
|
|
||
|
|
vertexBuffer[bufferIndex++] = compressed2;
|
||
|
|
|
||
|
|
if (this.hasWebMercatorT) {
|
||
|
|
cartesian2Scratch.set(webMercatorT, 0.0);
|
||
|
|
const compressed3 = AttributeCompression.compressTextureCoordinates(
|
||
|
|
cartesian2Scratch
|
||
|
|
);
|
||
|
|
vertexBuffer[bufferIndex++] = compressed3;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
Vector3.subtract(position, this.center, cartesian3Scratch13T);
|
||
|
|
vertexBuffer[bufferIndex++] = cartesian3Scratch13T.x;
|
||
|
|
vertexBuffer[bufferIndex++] = cartesian3Scratch13T.y;
|
||
|
|
vertexBuffer[bufferIndex++] = cartesian3Scratch13T.z;
|
||
|
|
vertexBuffer[bufferIndex++] = height;
|
||
|
|
vertexBuffer[bufferIndex++] = u;
|
||
|
|
vertexBuffer[bufferIndex++] = v;
|
||
|
|
|
||
|
|
if (this.hasWebMercatorT) {
|
||
|
|
vertexBuffer[bufferIndex++] = webMercatorT;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
if (this.hasVertexNormals) {
|
||
|
|
vertexBuffer[bufferIndex++] = AttributeCompression.octPackFloat(
|
||
|
|
normalToPack
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (this.hasGeodeticSurfaceNormals) {
|
||
|
|
vertexBuffer[bufferIndex++] = geodeticSurfaceNormal.x;
|
||
|
|
vertexBuffer[bufferIndex++] = geodeticSurfaceNormal.y;
|
||
|
|
vertexBuffer[bufferIndex++] = geodeticSurfaceNormal.z;
|
||
|
|
}
|
||
|
|
|
||
|
|
return bufferIndex;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class IndexDatatype {
|
||
|
|
constructor() {}
|
||
|
|
static createTypedArray(numberOfVertices, indicesLengthOrArray) {
|
||
|
|
if (!defined(numberOfVertices)) {
|
||
|
|
throw new Error("numberOfVertices is required");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (numberOfVertices >= 6 * 1024 * 1024) {
|
||
|
|
return new Uint32Array(indicesLengthOrArray);
|
||
|
|
}
|
||
|
|
|
||
|
|
return new Uint16Array(indicesLengthOrArray);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class TerrainProvider {
|
||
|
|
constructor(){}
|
||
|
|
static addSkirtIndice(edgeIndices, vertexIndex, indices, offset) {
|
||
|
|
let previousIndex = edgeIndices[0];
|
||
|
|
const length = edgeIndices.length;
|
||
|
|
for (let i = 1; i < length; ++i) {
|
||
|
|
const index = edgeIndices[i];
|
||
|
|
indices[offset++] = previousIndex;
|
||
|
|
indices[offset++] = index;
|
||
|
|
indices[offset++] = vertexIndex;
|
||
|
|
indices[offset++] = vertexIndex;
|
||
|
|
indices[offset++] = index;
|
||
|
|
indices[offset++] = vertexIndex + 1;
|
||
|
|
previousIndex = index;
|
||
|
|
++vertexIndex;
|
||
|
|
}
|
||
|
|
return offset;
|
||
|
|
}
|
||
|
|
static addSkirtIndices(
|
||
|
|
westIndicesSouthToNorth,
|
||
|
|
southIndicesEastToWest,
|
||
|
|
eastIndicesNorthToSouth,
|
||
|
|
northIndicesWestToEast,
|
||
|
|
vertexCount,
|
||
|
|
indices,
|
||
|
|
offset
|
||
|
|
) {
|
||
|
|
let vertexIndex = vertexCount;
|
||
|
|
offset = TerrainProvider.addSkirtIndice(
|
||
|
|
westIndicesSouthToNorth,
|
||
|
|
vertexIndex,
|
||
|
|
indices,
|
||
|
|
offset
|
||
|
|
);
|
||
|
|
vertexIndex += westIndicesSouthToNorth.length;
|
||
|
|
offset = TerrainProvider.addSkirtIndice(
|
||
|
|
southIndicesEastToWest,
|
||
|
|
vertexIndex,
|
||
|
|
indices,
|
||
|
|
offset
|
||
|
|
);
|
||
|
|
vertexIndex += southIndicesEastToWest.length;
|
||
|
|
offset = TerrainProvider.addSkirtIndice(
|
||
|
|
eastIndicesNorthToSouth,
|
||
|
|
vertexIndex,
|
||
|
|
indices,
|
||
|
|
offset
|
||
|
|
);
|
||
|
|
vertexIndex += eastIndicesNorthToSouth.length;
|
||
|
|
TerrainProvider.addSkirtIndice(northIndicesWestToEast, vertexIndex, indices, offset);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// class Vertex {}
|
||
|
|
|
||
|
|
class AttributeCompression {
|
||
|
|
constructor(){}
|
||
|
|
static compressTextureCoordinates(textureCoordinates) {
|
||
|
|
const x = (textureCoordinates.x * 4095.0) | 0;
|
||
|
|
const y = (textureCoordinates.y * 4095.0) | 0;
|
||
|
|
return 4096 * x + y;
|
||
|
|
}
|
||
|
|
|
||
|
|
static octPackFloat(encoded) {
|
||
|
|
return 256.0 * encoded.x + encoded.y;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
const cartographicScratch = new Cartographic();
|
||
|
|
const cartesian3Scratch = new Vector3();
|
||
|
|
const toPack = new Vector2();
|
||
|
|
|
||
|
|
const maxShort = 32767;
|
||
|
|
const halfMaxShort = (maxShort / 2) || 0;
|
||
|
|
function createVerticesFromQuantizedTerrainMesh(parameters) {
|
||
|
|
const quantizedVertices = parameters.quantizedVertices;
|
||
|
|
const quantizedVerticeCount = quantizedVertices.length / 3;
|
||
|
|
const octEncodedNormals = parameters.octEncodedNormals;
|
||
|
|
const edgeVertexCount =
|
||
|
|
parameters.westIndices.length +
|
||
|
|
parameters.eastIndices.length +
|
||
|
|
parameters.southIndices.length +
|
||
|
|
parameters.northIndices.length;
|
||
|
|
const includeWebMercatorT = parameters.includeWebMercatorT;
|
||
|
|
const exaggeration = parameters.exaggeration;
|
||
|
|
const exaggerationRelativeHeight = parameters.exaggerationRelativeHeight;
|
||
|
|
const hasExaggeration = exaggeration !== 1.0;
|
||
|
|
const includeGeodeticSurfaceNormals = hasExaggeration;
|
||
|
|
|
||
|
|
const rectangle = new Rectangle().clone(parameters.rectangle);
|
||
|
|
const [west, east, north, south] = [rectangle.west, rectangle.east, rectangle.north, rectangle.south];
|
||
|
|
|
||
|
|
const ellipsoid = new Ellipsoid(parameters.ellipsoid.x, parameters.ellipsoid.y, parameters.ellipsoid.z); // parameters.ellipsoid
|
||
|
|
|
||
|
|
const minimumHeight = parameters.minimumHeight;
|
||
|
|
const maximumHeight = parameters.maximumHeight;
|
||
|
|
|
||
|
|
const center = parameters.relativeToCenter;
|
||
|
|
|
||
|
|
const fromENU = Transforms.eastNorthUpToFixedFrame(center, ellipsoid);
|
||
|
|
const name = parameters.name;
|
||
|
|
|
||
|
|
const toENU = Matrix4.inverseTransformation(fromENU);
|
||
|
|
|
||
|
|
let southMercatorY, oneOverMercatorHeight;
|
||
|
|
if (includeWebMercatorT) {
|
||
|
|
southMercatorY = WebMercatorProjection.geodeticLatitudeToMercatorAngle(south);
|
||
|
|
oneOverMercatorHeight = 1.0 / (WebMercatorProjection.geodeticLatitudeToMercatorAngle(north) - southMercatorY);
|
||
|
|
}
|
||
|
|
|
||
|
|
const uBuffer = quantizedVertices.subarray(0, quantizedVerticeCount);
|
||
|
|
const vBuffer = quantizedVertices.subarray(quantizedVerticeCount, quantizedVerticeCount * 2);
|
||
|
|
const heightBuffer = quantizedVertices.subarray(quantizedVerticeCount * 2, quantizedVerticeCount * 3);
|
||
|
|
const hasVertexNormals = defined(octEncodedNormals);
|
||
|
|
|
||
|
|
// 准备UV、高度、经纬度数组
|
||
|
|
const uvs = new Array(quantizedVerticeCount),
|
||
|
|
heights = new Array(quantizedVerticeCount),
|
||
|
|
positions = new Array(quantizedVerticeCount);
|
||
|
|
const webMercatorTs = includeWebMercatorT ? new Array(quantizedVerticeCount) : [];
|
||
|
|
const geodeticSurfaceNormals = includeGeodeticSurfaceNormals ? new Array(quantizedVerticeCount) : [];
|
||
|
|
|
||
|
|
let minimum = new Vector3(
|
||
|
|
Number.POSITIVE_INFINITY,
|
||
|
|
Number.POSITIVE_INFINITY,
|
||
|
|
Number.POSITIVE_INFINITY
|
||
|
|
);
|
||
|
|
let maximum = new Vector3(
|
||
|
|
Number.NEGATIVE_INFINITY,
|
||
|
|
Number.NEGATIVE_INFINITY,
|
||
|
|
Number.NEGATIVE_INFINITY
|
||
|
|
);
|
||
|
|
let minLongitude = Number.POSITIVE_INFINITY;
|
||
|
|
let maxLongitude = Number.NEGATIVE_INFINITY;
|
||
|
|
let minLatitude = Number.POSITIVE_INFINITY;
|
||
|
|
let maxLatitude = Number.NEGATIVE_INFINITY;
|
||
|
|
|
||
|
|
for (let i = 0; i < quantizedVerticeCount; ++i) {
|
||
|
|
const rawU = uBuffer[i];
|
||
|
|
const rawV = vBuffer[i];
|
||
|
|
|
||
|
|
const u = rawU / maxShort;
|
||
|
|
const v = rawV / maxShort;
|
||
|
|
const height = lerp(minimumHeight, maximumHeight, heightBuffer[i] / maxShort);
|
||
|
|
|
||
|
|
cartographicScratch.longitude = lerp(west, east, u);
|
||
|
|
cartographicScratch.latitude = lerp(south, north, v);
|
||
|
|
cartographicScratch.height = height;
|
||
|
|
|
||
|
|
minLongitude = Math.min(
|
||
|
|
cartographicScratch.longitude,
|
||
|
|
minLongitude
|
||
|
|
);
|
||
|
|
|
||
|
|
maxLongitude = Math.max(
|
||
|
|
cartographicScratch.longitude,
|
||
|
|
maxLongitude
|
||
|
|
);
|
||
|
|
|
||
|
|
minLatitude = Math.min(
|
||
|
|
cartographicScratch.latitude,
|
||
|
|
minLatitude
|
||
|
|
);
|
||
|
|
|
||
|
|
maxLatitude = Math.max(
|
||
|
|
cartographicScratch.latitude,
|
||
|
|
maxLatitude
|
||
|
|
);
|
||
|
|
|
||
|
|
const position = ellipsoid.cartographicToCartesian(cartographicScratch);
|
||
|
|
|
||
|
|
uvs[i] = new Vector3(u, v, 0);
|
||
|
|
heights[i] = height;
|
||
|
|
positions[i] = position;
|
||
|
|
|
||
|
|
if (includeWebMercatorT) {
|
||
|
|
webMercatorTs[i] = (
|
||
|
|
WebMercatorProjection.geodeticLatitudeToMercatorAngle(cartographicScratch.latitude)
|
||
|
|
-
|
||
|
|
southMercatorY
|
||
|
|
) * oneOverMercatorHeight;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (includeGeodeticSurfaceNormals) {
|
||
|
|
geodeticSurfaceNormals[i] = ellipsoid.geodeticSurfaceNormal(position);
|
||
|
|
}
|
||
|
|
|
||
|
|
Matrix4.multiplyByPoint(toENU, position, cartesian3Scratch);
|
||
|
|
Vector3.minimumByComponent(cartesian3Scratch, minimum, minimum);
|
||
|
|
Vector3.maximumByComponent(cartesian3Scratch, maximum, maximum);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
// 处理四条边的索引
|
||
|
|
const westIndicesSouthToNorth = copyAndSort(
|
||
|
|
parameters.westIndices,
|
||
|
|
function(a, b) { return uvs[a].y - uvs[b].y; }
|
||
|
|
);
|
||
|
|
|
||
|
|
const eastIndicesNorthToSouth = copyAndSort(
|
||
|
|
parameters.eastIndices,
|
||
|
|
function(a, b) { return uvs[b].y - uvs[a].y; }
|
||
|
|
);
|
||
|
|
const southIndicesEastToWest = copyAndSort(
|
||
|
|
parameters.southIndices,
|
||
|
|
function(a, b) { return uvs[b].x - uvs[a].x; }
|
||
|
|
);
|
||
|
|
const northIndicesWestToEast = copyAndSort(
|
||
|
|
parameters.northIndices,
|
||
|
|
function(a, b) { return uvs[a].x - uvs[b].x; }
|
||
|
|
);
|
||
|
|
|
||
|
|
// 处理地平线
|
||
|
|
let occludeePointInScaledSpace;
|
||
|
|
if (minimumHeight < 0.0) {
|
||
|
|
const occluder = new EllipsoidalOccluder(ellipsoid);
|
||
|
|
occludeePointInScaledSpace = occluder.computeHorizonCullingPointPossiblyUnderEllipsoid(center, positions, minimumHeight);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 处理高程
|
||
|
|
let hMin = minimumHeight;
|
||
|
|
hMin = Math.min(
|
||
|
|
hMin,
|
||
|
|
findMinMaxSkirts(
|
||
|
|
parameters.westIndices,
|
||
|
|
parameters.westSkirtHeight,
|
||
|
|
heights,
|
||
|
|
uvs,
|
||
|
|
rectangle,
|
||
|
|
ellipsoid,
|
||
|
|
toENU,
|
||
|
|
minimum,
|
||
|
|
maximum
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
hMin = Math.min(
|
||
|
|
hMin,
|
||
|
|
findMinMaxSkirts(
|
||
|
|
parameters.southIndices,
|
||
|
|
parameters.southSkirtHeight,
|
||
|
|
heights,
|
||
|
|
uvs,
|
||
|
|
rectangle,
|
||
|
|
ellipsoid,
|
||
|
|
toENU,
|
||
|
|
minimum,
|
||
|
|
maximum
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
hMin = Math.min(
|
||
|
|
hMin,
|
||
|
|
findMinMaxSkirts(
|
||
|
|
parameters.eastIndices,
|
||
|
|
parameters.eastSkirtHeight,
|
||
|
|
heights,
|
||
|
|
uvs,
|
||
|
|
rectangle,
|
||
|
|
ellipsoid,
|
||
|
|
toENU,
|
||
|
|
minimum,
|
||
|
|
maximum
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
hMin = Math.min(
|
||
|
|
hMin,
|
||
|
|
findMinMaxSkirts(
|
||
|
|
parameters.northIndices,
|
||
|
|
parameters.northSkirtHeight,
|
||
|
|
heights,
|
||
|
|
uvs,
|
||
|
|
rectangle,
|
||
|
|
ellipsoid,
|
||
|
|
toENU,
|
||
|
|
minimum,
|
||
|
|
maximum
|
||
|
|
)
|
||
|
|
);
|
||
|
|
const aaBox = new AxisAlignedBoundingBox(minimum, maximum, center);
|
||
|
|
// console.log(name, center, aaBox, hMin, maximumHeight, fromENU, hasVertexNormals, includeWebMercatorT, includeGeodeticSurfaceNormals, exaggeration, exaggerationRelativeHeight)
|
||
|
|
const encoding = new TerrainEncoding(center, aaBox, hMin, maximumHeight, fromENU, hasVertexNormals, includeWebMercatorT, includeGeodeticSurfaceNormals, exaggeration, exaggerationRelativeHeight, name);
|
||
|
|
const vertexStride = encoding.stride;
|
||
|
|
const size = (quantizedVerticeCount + edgeVertexCount) * vertexStride;
|
||
|
|
const vertexBuffer = new Float32Array(size);
|
||
|
|
|
||
|
|
let bufferIndex = 0;
|
||
|
|
|
||
|
|
for (let j = 0; j < quantizedVerticeCount; ++j) {
|
||
|
|
if (hasVertexNormals) {
|
||
|
|
const n = j * 2.0;
|
||
|
|
toPack.x = octEncodedNormals[n];
|
||
|
|
toPack.y = octEncodedNormals[n + 1];
|
||
|
|
}
|
||
|
|
|
||
|
|
bufferIndex = encoding.encode(
|
||
|
|
vertexBuffer,
|
||
|
|
bufferIndex,
|
||
|
|
positions[j],
|
||
|
|
uvs[j],
|
||
|
|
heights[j],
|
||
|
|
toPack,
|
||
|
|
webMercatorTs[j],
|
||
|
|
geodeticSurfaceNormals[j]
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
const edgeTraiangleCount = Math.max(0, (edgeVertexCount - 4) * 2);
|
||
|
|
const indexBufferLength = parameters.indices.length + edgeTraiangleCount * 3;
|
||
|
|
const indexBuffer = IndexDatatype.createTypedArray(quantizedVerticeCount + edgeVertexCount, indexBufferLength);
|
||
|
|
indexBuffer.set(parameters.indices, 0);
|
||
|
|
|
||
|
|
const percentage = 0.0001;
|
||
|
|
const lonOffset = (maxLongitude - minLongitude) * percentage;
|
||
|
|
const latOffset = (maxLatitude - minLatitude) * percentage;
|
||
|
|
const westLongitudeOffset = -lonOffset;
|
||
|
|
const westLatitudeOffset = 0.0;
|
||
|
|
const eastLongitudeOffset = lonOffset;
|
||
|
|
const eastLatitudeOffset = 0.0;
|
||
|
|
const northLongitudeOffset = 0.0;
|
||
|
|
const northLatitudeOffset = latOffset;
|
||
|
|
const southLongitudeOffset = 0.0;
|
||
|
|
const southLatitudeOffset = -latOffset;
|
||
|
|
|
||
|
|
// 添加裙边
|
||
|
|
let vertexBufferIndex = quantizedVerticeCount * vertexStride;
|
||
|
|
addSkirt(vertexBuffer, vertexBufferIndex, westIndicesSouthToNorth, encoding, heights, uvs, octEncodedNormals, ellipsoid, rectangle, parameters.westSkirtHeight, southMercatorY, oneOverMercatorHeight, westLongitudeOffset, westLatitudeOffset);
|
||
|
|
vertexBufferIndex += parameters.westIndices.length * vertexStride;
|
||
|
|
|
||
|
|
addSkirt(vertexBuffer, vertexBufferIndex, southIndicesEastToWest, encoding, heights, uvs, octEncodedNormals, ellipsoid, rectangle, parameters.southSkirtHeight, southMercatorY, oneOverMercatorHeight, southLongitudeOffset, southLatitudeOffset);
|
||
|
|
vertexBufferIndex += parameters.southIndices.length * vertexStride;
|
||
|
|
|
||
|
|
addSkirt(vertexBuffer, vertexBufferIndex, eastIndicesNorthToSouth, encoding, heights, uvs, octEncodedNormals, ellipsoid, rectangle, parameters.eastSkirtHeight, southMercatorY, oneOverMercatorHeight, eastLongitudeOffset, eastLatitudeOffset);
|
||
|
|
vertexBufferIndex += parameters.eastIndices.length * vertexStride;
|
||
|
|
|
||
|
|
addSkirt(vertexBuffer, vertexBufferIndex, northIndicesWestToEast, encoding, heights, uvs, octEncodedNormals, ellipsoid, rectangle, parameters.northSkirtHeight, southMercatorY, oneOverMercatorHeight, northLongitudeOffset, northLatitudeOffset);
|
||
|
|
|
||
|
|
TerrainProvider.addSkirtIndices(
|
||
|
|
westIndicesSouthToNorth,
|
||
|
|
southIndicesEastToWest,
|
||
|
|
eastIndicesNorthToSouth,
|
||
|
|
northIndicesWestToEast,
|
||
|
|
quantizedVerticeCount,
|
||
|
|
indexBuffer,
|
||
|
|
parameters.indices.length
|
||
|
|
);
|
||
|
|
|
||
|
|
return {
|
||
|
|
vertices: vertexBuffer.buffer,
|
||
|
|
indices: indexBuffer.buffer,
|
||
|
|
westIndicesSouthToNorth: westIndicesSouthToNorth,
|
||
|
|
southIndicesEastToWest: southIndicesEastToWest,
|
||
|
|
eastIndicesNorthToSouth: eastIndicesNorthToSouth,
|
||
|
|
northIndicesWestToEast: northIndicesWestToEast,
|
||
|
|
vertexStride: vertexStride,
|
||
|
|
center: center,
|
||
|
|
minimumHeight: minimumHeight,
|
||
|
|
maximumHeight: maximumHeight,
|
||
|
|
occludeePointInScaledSpace: occludeePointInScaledSpace,
|
||
|
|
encoding: encoding,
|
||
|
|
indexCountWithoutSkirts: parameters.indices.length
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function copyAndSort(typedArray, comparator) {
|
||
|
|
let copy;
|
||
|
|
if (typeof typedArray.slice === "function") {
|
||
|
|
copy = typedArray.slice();
|
||
|
|
if (typeof copy.sort !== "function") {
|
||
|
|
copy = undefined;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!defined(copy)) {
|
||
|
|
copy = Array.prototype.slice.call(typedArray);
|
||
|
|
}
|
||
|
|
|
||
|
|
copy.sort(comparator);
|
||
|
|
|
||
|
|
return copy;
|
||
|
|
}
|
||
|
|
|
||
|
|
function findMinMaxSkirts(
|
||
|
|
edgeIndices,
|
||
|
|
edgeHeight,
|
||
|
|
heights,
|
||
|
|
uvs,
|
||
|
|
rectangle,
|
||
|
|
ellipsoid,
|
||
|
|
toENU,
|
||
|
|
minimum,
|
||
|
|
maximum
|
||
|
|
) {
|
||
|
|
let hMin = Number.POSITIVE_INFINITY;
|
||
|
|
const north = rectangle.north;
|
||
|
|
const south = rectangle.south;
|
||
|
|
let east = rectangle.east;
|
||
|
|
const west = rectangle.west;
|
||
|
|
|
||
|
|
if (east < west) {
|
||
|
|
east += Math.PI * 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
const length = edgeIndices.length;
|
||
|
|
for (let i = 0; i < length; ++i) {
|
||
|
|
const index = edgeIndices[i];
|
||
|
|
const h = heights[index];
|
||
|
|
const uv = uvs[index];
|
||
|
|
|
||
|
|
cartographicScratch.longitude = lerp(west, east, uv.x);
|
||
|
|
cartographicScratch.latitude = lerp(south, north, uv.y);
|
||
|
|
cartographicScratch.height = h - edgeHeight;
|
||
|
|
|
||
|
|
const position = ellipsoid.cartographicToCartesian(
|
||
|
|
cartographicScratch,
|
||
|
|
cartesian3Scratch,
|
||
|
|
);
|
||
|
|
|
||
|
|
Matrix4.multiplyByPoint(toENU, position, position);
|
||
|
|
|
||
|
|
Vector3.minimumByComponent(position, minimum, minimum);
|
||
|
|
Vector3.maximumByComponent(position, maximum, maximum);
|
||
|
|
|
||
|
|
hMin = Math.min(hMin, cartographicScratch.height);
|
||
|
|
}
|
||
|
|
|
||
|
|
return hMin;
|
||
|
|
}
|
||
|
|
|
||
|
|
function addSkirt(
|
||
|
|
vertexBuffer,
|
||
|
|
vertexBufferIndex,
|
||
|
|
edgeVertices,
|
||
|
|
encoding,
|
||
|
|
heights,
|
||
|
|
uvs,
|
||
|
|
octEncodedNormals,
|
||
|
|
ellipsoid,
|
||
|
|
rectangle,
|
||
|
|
skirtLength,
|
||
|
|
southMercatorY,
|
||
|
|
oneOverMercatorHeight,
|
||
|
|
longitudeOffset,
|
||
|
|
latitudeOffset
|
||
|
|
) {
|
||
|
|
const hasVertexNormals = defined(octEncodedNormals);
|
||
|
|
const north = rectangle.north;
|
||
|
|
const south = rectangle.south;
|
||
|
|
let east = rectangle.east;
|
||
|
|
const west = rectangle.west;
|
||
|
|
|
||
|
|
if (east < west) {
|
||
|
|
east += Math.PI * 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
const length = edgeVertices.length;
|
||
|
|
for(let i = 0; i < length; ++i) {
|
||
|
|
const index = edgeVertices[i];
|
||
|
|
const h = heights[index];
|
||
|
|
const uv = uvs[index];
|
||
|
|
|
||
|
|
cartographicScratch.longitude = lerp(west, east, uv.x) + longitudeOffset;
|
||
|
|
cartographicScratch.latitude = lerp(south, north, uv.y) + latitudeOffset;
|
||
|
|
cartographicScratch.height = h - skirtLength;
|
||
|
|
|
||
|
|
const position = ellipsoid.cartographicToCartesian(
|
||
|
|
cartographicScratch,
|
||
|
|
cartesian3Scratch
|
||
|
|
);
|
||
|
|
|
||
|
|
if (hasVertexNormals) {
|
||
|
|
const n = index * 2.0;
|
||
|
|
toPack.x = octEncodedNormals[n];
|
||
|
|
toPack.y = octEncodedNormals[n + 1];
|
||
|
|
}
|
||
|
|
|
||
|
|
let webMercatorT;
|
||
|
|
if (encoding.hasWebMercatorT) {
|
||
|
|
webMercatorT = (
|
||
|
|
WebMercatorProjection.geodeticLatitudeToMercatorAngle(cartographicScratch.latitude)
|
||
|
|
-
|
||
|
|
southMercatorY
|
||
|
|
) * oneOverMercatorHeight;
|
||
|
|
}
|
||
|
|
|
||
|
|
let geodeticSurfaceNormal;
|
||
|
|
if (encoding.hasGeodeticSurfaceNormals) {
|
||
|
|
geodeticSurfaceNormal = ellipsoid.geodeticSurfaceNormal(position, geodeticSurfaceNormalScratch);
|
||
|
|
}
|
||
|
|
|
||
|
|
vertexBufferIndex = encoding.encode(
|
||
|
|
vertexBuffer,
|
||
|
|
vertexBufferIndex,
|
||
|
|
position,
|
||
|
|
uv,
|
||
|
|
cartographicScratch.height,
|
||
|
|
toPack,
|
||
|
|
webMercatorT,
|
||
|
|
geodeticSurfaceNormal
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
onmessage = function(e) {
|
||
|
|
const data = e.data;
|
||
|
|
const id = data.id;
|
||
|
|
const parameters = data.parameters;
|
||
|
|
const responseData = {
|
||
|
|
id: id,
|
||
|
|
result: undefined,
|
||
|
|
error: undefined
|
||
|
|
}
|
||
|
|
|
||
|
|
return Promise.resolve(
|
||
|
|
createVerticesFromQuantizedTerrainMesh(parameters)
|
||
|
|
).then(result => {
|
||
|
|
responseData.result = result
|
||
|
|
}).catch(e => {
|
||
|
|
if (e instanceof Error) {
|
||
|
|
responseData.error = {
|
||
|
|
name: e.name,
|
||
|
|
message: e.message,
|
||
|
|
stack: e.stack
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
responseData.error = e;
|
||
|
|
}
|
||
|
|
}).finally(() => {
|
||
|
|
postMessage(responseData);
|
||
|
|
})
|
||
|
|
}
|