@pirireis/webglobeplugins 0.17.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Math/haversine.js +22 -0
- package/Math/methods.js +15 -2
- package/Math/tessellation/methods.js +4 -1
- package/Math/tessellation/nearest-value-padding.js +112 -0
- package/Math/tessellation/spherical-triangle-area.js +99 -0
- package/Math/tessellation/tile-merger.js +346 -215
- package/Math/tessellation/triangle-tessellation.js +381 -9
- package/Math/vec3.js +4 -0
- package/Math/xyz-tile.js +18 -0
- package/altitude-locator/plugin.js +1 -2
- package/investigation-tools/draw/tiles/adapters.js +2 -2
- package/investigation-tools/draw/tiles/tiles.js +2 -2
- package/package.json +1 -1
- package/programs/helpers/fadeaway.js +6 -1
- package/programs/point-on-globe/square-pixel-point.js +1 -0
- package/programs/polygon-on-globe/texture-dem-triangles.js +94 -116
- package/programs/totems/camera-totem-attactment-interface.js +1 -0
- package/programs/totems/camerauniformblock.js +33 -22
- package/programs/totems/dem-textures-manager.js +265 -0
- package/programs/vectorfields/logics/drawrectangleparticles.js +51 -18
- package/programs/vectorfields/logics/{ubo-new.js → particle-ubo.js} +5 -14
- package/programs/vectorfields/logics/pixelbased.js +42 -36
- package/programs/vectorfields/pingpongbuffermanager.js +34 -8
- package/semiplugins/shape-on-terrain/terrain-polygon/adapters.js +55 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/cache.js +102 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/index-polygon-map.js +45 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/manager.js +4 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/master-worker.js +177 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/polygon-to-triangles.js +100 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/random.js +121 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/types.js +1 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/worker-contact.js +63 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/data/worker.js +125 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/terrain-polygon.js +219 -0
- package/semiplugins/shape-on-terrain/terrain-polygon/types.js +8 -0
- package/semiplugins/shell/bbox-renderer/logic.js +18 -58
- package/semiplugins/shell/bbox-renderer/object.js +19 -9
- package/tracks/point-heat-map/point-to-heat-map-flow.js +1 -1
- package/tracks/point-tracks/plugin.js +13 -6
- package/tracks/timetracks/program-line-strip.js +1 -1
- package/util/account/single-attribute-buffer-management/buffer-manager.js +5 -3
- package/util/account/single-attribute-buffer-management/buffer-orchestrator.js +2 -2
- package/util/gl-util/uniform-block/manager.js +20 -10
- package/util/helper-methods.js +8 -0
- package/util/picking/fence.js +4 -2
- package/util/picking/picker-displayer.js +51 -9
- package/util/programs/draw-texture-on-canvas.js +18 -15
- package/util/shaderfunctions/geometrytransformations.js +67 -1
- package/vectorfield/waveparticles/plugin.js +241 -116
- package/vectorfield/wind/adapters/image-to-fields.js +61 -0
- package/vectorfield/wind/adapters/types.js +1 -0
- package/vectorfield/wind/imagetovectorfieldandmagnitude.js +6 -9
- package/vectorfield/wind/plugin-persistant copy.js +364 -0
- package/vectorfield/wind/plugin-persistant.js +375 -0
- package/vectorfield/wind/plugin.js +1 -1
- package/Math/tessellation/earcut/adapters.js +0 -37
- package/Math/tessellation/hybrid-triangle-tessellation-meta.js +0 -123
- package/Math/tessellation/shred-input.js +0 -18
- package/Math/tessellation/tiler.js +0 -50
- package/Math/tessellation/triangle-tessellation-meta.js +0 -523
- package/programs/polygon-on-globe/texture-dem-triangle-test-plugin-triangle.js +0 -328
- package/programs/vectorfields/logics/drawrectangleparticles1.js +0 -112
- package/semiplugins/shape-on-terrain/terrain-cover/texture-dem-cover.js +0 -1
- package/util/gl-util/uniform-block/types.js +0 -1
- package/util/webglobe/index.js +0 -2
- /package/Math/tessellation/{zoom-catch.js → constants.js} +0 -0
- /package/util/{webglobe/gldefaultstates.js → globe-default-gl-states.js} +0 -0
|
@@ -10,7 +10,9 @@ const typeSizes = {
|
|
|
10
10
|
'ivec2': 8,
|
|
11
11
|
'ivec3': 16,
|
|
12
12
|
'ivec4': 16,
|
|
13
|
-
'
|
|
13
|
+
'uvec4': 16,
|
|
14
|
+
'uint': 4,
|
|
15
|
+
'bool': 4,
|
|
14
16
|
};
|
|
15
17
|
const typeAlignments = {
|
|
16
18
|
'float': 4,
|
|
@@ -24,7 +26,9 @@ const typeAlignments = {
|
|
|
24
26
|
'ivec2': 8,
|
|
25
27
|
'ivec3': 16,
|
|
26
28
|
'ivec4': 16,
|
|
27
|
-
'
|
|
29
|
+
'uvec4': 16,
|
|
30
|
+
'uint': 4,
|
|
31
|
+
'bool': 4,
|
|
28
32
|
};
|
|
29
33
|
const typeArrayConstructors = {
|
|
30
34
|
'float': Float32Array,
|
|
@@ -38,8 +42,16 @@ const typeArrayConstructors = {
|
|
|
38
42
|
'ivec2': Int32Array,
|
|
39
43
|
'ivec3': Int32Array,
|
|
40
44
|
'ivec4': Int32Array,
|
|
41
|
-
'bool': Float32Array
|
|
45
|
+
'bool': Float32Array,
|
|
46
|
+
'uint': Uint32Array,
|
|
47
|
+
'uvec2': Uint32Array,
|
|
48
|
+
'uvec3': Uint32Array,
|
|
49
|
+
'uvec4': Uint32Array,
|
|
42
50
|
};
|
|
51
|
+
// TODO: the input types should be all same for a single block.
|
|
52
|
+
// no need to ask for typed array constructor in the constructor
|
|
53
|
+
// eacher remove it and raise error when different types are used in the same block
|
|
54
|
+
// or implicitly manage multiple blocks with different types
|
|
43
55
|
export class UniformBlockManager {
|
|
44
56
|
/**
|
|
45
57
|
*
|
|
@@ -104,20 +116,19 @@ export class UniformBlockManager {
|
|
|
104
116
|
if (offset === undefined) {
|
|
105
117
|
throw new Error(`Uniform block member ${key} not found in offset map.\nPossible members: ${Array.from(this.offsetMap.keys()).join(", ")}`);
|
|
106
118
|
}
|
|
107
|
-
|
|
108
|
-
const type = this.blockMembers.find(member => member.name === key).type;
|
|
119
|
+
const memberType = this.blockMembers.find(member => member.name === key).type;
|
|
109
120
|
let data;
|
|
110
121
|
if (Array.isArray(value)) {
|
|
111
|
-
data = new typeArrayConstructors[
|
|
122
|
+
data = new typeArrayConstructors[memberType](value);
|
|
112
123
|
}
|
|
113
124
|
else if (typeof value === 'number') {
|
|
114
|
-
data = new typeArrayConstructors[
|
|
125
|
+
data = new typeArrayConstructors[memberType]([value]);
|
|
115
126
|
}
|
|
116
127
|
else if (value instanceof ArrayBuffer) {
|
|
117
|
-
data = new typeArrayConstructors[
|
|
128
|
+
data = new typeArrayConstructors[memberType](value);
|
|
118
129
|
}
|
|
119
130
|
else if (ArrayBuffer.isView(value) && !(value instanceof DataView)) {
|
|
120
|
-
data = (typeof value === 'number') ? new typeArrayConstructors[
|
|
131
|
+
data = (typeof value === 'number') ? new typeArrayConstructors[memberType]([value]) : new typeArrayConstructors[memberType](value);
|
|
121
132
|
}
|
|
122
133
|
else {
|
|
123
134
|
throw new Error(`Unsupported value type for ${key}: ${typeof value}.\n Supported types are: number, Array, ArrayBuffer, TypedArray.`);
|
|
@@ -132,7 +143,6 @@ export class UniformBlockManager {
|
|
|
132
143
|
if (offset === undefined) {
|
|
133
144
|
throw new Error(`Uniform block member ${name} not found in offset map.\nPossible members: ${Array.from(this.offsetMap.keys()).join(", ")}`);
|
|
134
145
|
}
|
|
135
|
-
// @ts-ignore
|
|
136
146
|
const type = this.blockMembers.find(member => member.name === name).type;
|
|
137
147
|
let data;
|
|
138
148
|
if (Array.isArray(value)) {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function hashColorTo4IntArray(pickedColor) {
|
|
2
|
+
const pickedHex = pickedColor.replace('#', '');
|
|
3
|
+
const pickedR = parseInt(pickedHex.substring(0, 2), 16) / 255;
|
|
4
|
+
const pickedG = parseInt(pickedHex.substring(2, 4), 16) / 255;
|
|
5
|
+
const pickedB = parseInt(pickedHex.substring(4, 6), 16) / 255;
|
|
6
|
+
const pickedA = parseInt(pickedHex.substring(6, 8) || 'FF', 16) / 255;
|
|
7
|
+
return [pickedR, pickedG, pickedB, pickedA];
|
|
8
|
+
}
|
package/util/picking/fence.js
CHANGED
|
@@ -4,6 +4,10 @@ const fence = (gl) => new Promise((resolve, reject) => {
|
|
|
4
4
|
// This means JS can continue to work on other tasks while the read instruction
|
|
5
5
|
// completes.
|
|
6
6
|
const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
|
|
7
|
+
if (!sync) {
|
|
8
|
+
reject(new Error('Failed to create fence sync object.'));
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
7
11
|
gl.flush();
|
|
8
12
|
// There are TWO possible ways to check on the status of a WebGLSync object.
|
|
9
13
|
// 1. This will check it using clientWaitSync()
|
|
@@ -26,8 +30,6 @@ const fence = (gl) => new Promise((resolve, reject) => {
|
|
|
26
30
|
// 2. This will check with getSyncParameter(s, gl.SYNC_STATUS)
|
|
27
31
|
const checkStatus_v2 = () => {
|
|
28
32
|
const status = gl.getSyncParameter(sync, gl.SYNC_STATUS);
|
|
29
|
-
// There are only two possible values for status: SIGNALED and UNSIGNALED
|
|
30
|
-
// Note that there is no `error` signal, so there is no reason to use `reject()` here
|
|
31
33
|
if (status === gl.SIGNALED) {
|
|
32
34
|
gl.deleteSync(sync);
|
|
33
35
|
resolve();
|
|
@@ -6,15 +6,40 @@ import { textureOnCanvasProgramCache } from "../programs/draw-texture-on-canvas"
|
|
|
6
6
|
import { fence } from "./fence";
|
|
7
7
|
const ESCAPE_VALUE = -1;
|
|
8
8
|
class PickerDisplayer {
|
|
9
|
-
|
|
9
|
+
globe;
|
|
10
|
+
gl;
|
|
11
|
+
colorTexture;
|
|
12
|
+
indexTexture;
|
|
13
|
+
fbo;
|
|
14
|
+
_pbo;
|
|
15
|
+
_pboSize;
|
|
16
|
+
displayer;
|
|
17
|
+
_inProgress;
|
|
18
|
+
_indexType; // R32I for Integer, R32F for Float
|
|
19
|
+
_typedArrayConstructor;
|
|
20
|
+
constructor(globe, indexType = "R32I") {
|
|
10
21
|
this.globe = globe;
|
|
11
22
|
this.gl = globe.gl;
|
|
12
23
|
const gl = this.gl;
|
|
13
24
|
this.colorTexture = gl.createTexture(); // bind to color attachment 0
|
|
14
25
|
this.indexTexture = gl.createTexture(); // bind to color attachment 1
|
|
15
26
|
this.fbo = gl.createFramebuffer();
|
|
27
|
+
if (indexType === "R32F" && this.gl.getExtension("EXT_color_buffer_float") === null) {
|
|
28
|
+
throw new Error("EXT_color_buffer_float extension is required for R32F index type.");
|
|
29
|
+
}
|
|
30
|
+
this._indexType = indexType;
|
|
31
|
+
if (indexType === "R32I") {
|
|
32
|
+
this._typedArrayConstructor = Int32Array;
|
|
33
|
+
}
|
|
34
|
+
else if (indexType === "R32F") {
|
|
35
|
+
this._typedArrayConstructor = Float32Array;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
throw new Error("Invalid index type. Must be 'R32I' or 'R32F'.");
|
|
39
|
+
}
|
|
16
40
|
this._pbo = undefined;
|
|
17
41
|
this._pboSize = 0;
|
|
42
|
+
this._inProgress = false;
|
|
18
43
|
this.resize();
|
|
19
44
|
this.displayer = textureOnCanvasProgramCache.get(this.gl);
|
|
20
45
|
}
|
|
@@ -27,12 +52,13 @@ class PickerDisplayer {
|
|
|
27
52
|
gl.deleteTexture(colorTexture);
|
|
28
53
|
gl.deleteTexture(indexTexture);
|
|
29
54
|
const colorTextureNew = gl.createTexture();
|
|
55
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
30
56
|
gl.bindTexture(gl.TEXTURE_2D, colorTextureNew);
|
|
31
57
|
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, width, height);
|
|
32
58
|
const indexTextureNew = gl.createTexture();
|
|
59
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
33
60
|
gl.bindTexture(gl.TEXTURE_2D, indexTextureNew);
|
|
34
|
-
|
|
35
|
-
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.R32I, width, height);
|
|
61
|
+
gl.texStorage2D(gl.TEXTURE_2D, 1, gl[this._indexType], width, height); // gl.R32I or gl.R32F
|
|
36
62
|
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
37
63
|
this.colorTexture = colorTextureNew;
|
|
38
64
|
this.indexTexture = indexTextureNew;
|
|
@@ -41,7 +67,12 @@ class PickerDisplayer {
|
|
|
41
67
|
const { gl, colorTexture, indexTexture } = this;
|
|
42
68
|
gl.activeTexture(gl.TEXTURE1);
|
|
43
69
|
gl.bindTexture(gl.TEXTURE_2D, indexTexture);
|
|
44
|
-
|
|
70
|
+
if (this._indexType === "R32I") {
|
|
71
|
+
gl.clearBufferiv(gl.COLOR, 1, new Int32Array([-1, -1, -1, -1]));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
gl.clearBufferfv(gl.COLOR, 1, new Float32Array([-1, -1, -1, -1]));
|
|
75
|
+
}
|
|
45
76
|
gl.activeTexture(gl.TEXTURE0);
|
|
46
77
|
gl.bindTexture(gl.TEXTURE_2D, colorTexture);
|
|
47
78
|
gl.clearBufferfv(gl.COLOR, 0, new Float32Array([0, 0, 0, 0]));
|
|
@@ -57,20 +88,26 @@ class PickerDisplayer {
|
|
|
57
88
|
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.colorTexture, 0);
|
|
58
89
|
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, this.indexTexture, 0);
|
|
59
90
|
gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]);
|
|
91
|
+
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
|
|
92
|
+
if (status !== gl.FRAMEBUFFER_COMPLETE) {
|
|
93
|
+
throw new Error(`Framebuffer is not complete: ${status.toString(16)}`);
|
|
94
|
+
}
|
|
60
95
|
}
|
|
61
96
|
// call after drawing the scene with gl picker shader
|
|
62
97
|
drawColorTexture() {
|
|
63
98
|
const { gl, colorTexture } = this;
|
|
64
99
|
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
100
|
+
gl.disable(gl.DEPTH_TEST);
|
|
65
101
|
this.displayer.draw(colorTexture);
|
|
102
|
+
gl.enable(gl.DEPTH_TEST);
|
|
66
103
|
}
|
|
67
104
|
pickXY(x, y, selectionPointFilling = 1, callback = () => { }) {
|
|
68
105
|
const size = Math.pow(1 + 2 * selectionPointFilling, 2);
|
|
69
|
-
this._pick(size, x - selectionPointFilling, y - selectionPointFilling, 1 + 2 * selectionPointFilling, 1 + 2 * selectionPointFilling, callback);
|
|
106
|
+
return this._pick(size, x - selectionPointFilling, y - selectionPointFilling, 1 + 2 * selectionPointFilling, 1 + 2 * selectionPointFilling, callback);
|
|
70
107
|
}
|
|
71
108
|
pickBbox(left, top, right, bottom, callback) {
|
|
72
|
-
const size = (right - left) * (bottom - top)
|
|
73
|
-
this._pick(size, left, top, right - left, bottom - top, callback);
|
|
109
|
+
const size = (right - left) * (bottom - top);
|
|
110
|
+
return this._pick(size, left, top, right - left, bottom - top, callback);
|
|
74
111
|
}
|
|
75
112
|
_pick(size, startX, startY, lengthX, lengthY, callback) {
|
|
76
113
|
if (this._inProgress)
|
|
@@ -81,14 +118,16 @@ class PickerDisplayer {
|
|
|
81
118
|
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, _pbo);
|
|
82
119
|
this.bindFBO();
|
|
83
120
|
gl.readBuffer(gl.COLOR_ATTACHMENT1); // This is the attachment we want to read
|
|
121
|
+
const format = this._indexType === "R32I" ? gl.RED_INTEGER : gl.RED;
|
|
122
|
+
const type = this._indexType === "R32I" ? gl.INT : gl.FLOAT;
|
|
84
123
|
gl.readPixels(// This will read the pixels to the buffer asynchronously
|
|
85
|
-
startX, startY, lengthX, lengthY,
|
|
124
|
+
startX, startY, lengthX, lengthY, format, type, 0);
|
|
86
125
|
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
87
126
|
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
|
|
88
127
|
fence(this.gl).then(() => {
|
|
89
128
|
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, _pbo);
|
|
90
129
|
// const data = new Int16Array(size);
|
|
91
|
-
const data = new
|
|
130
|
+
const data = new this._typedArrayConstructor(size); // Int32Array or Float32Array
|
|
92
131
|
gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data);
|
|
93
132
|
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
|
|
94
133
|
const result = this._pickFromBuffer(data, size);
|
|
@@ -128,6 +167,9 @@ class PickerDisplayer {
|
|
|
128
167
|
gl.deleteTexture(colorTexture);
|
|
129
168
|
gl.deleteTexture(indexTexture);
|
|
130
169
|
gl.deleteFramebuffer(fbo);
|
|
170
|
+
if (this._pbo) {
|
|
171
|
+
gl.deleteBuffer(this._pbo);
|
|
172
|
+
}
|
|
131
173
|
textureOnCanvasProgramCache.release(this.gl);
|
|
132
174
|
}
|
|
133
175
|
}
|
|
@@ -15,7 +15,7 @@ const fs = `#version 300 es
|
|
|
15
15
|
precision highp float;
|
|
16
16
|
|
|
17
17
|
uniform sampler2D u_texture;
|
|
18
|
-
uniform float u_opacity;
|
|
18
|
+
uniform float u_opacity;
|
|
19
19
|
in vec2 v_texcoord;
|
|
20
20
|
out vec4 fragColor;
|
|
21
21
|
|
|
@@ -24,6 +24,13 @@ void main() {
|
|
|
24
24
|
fragColor.a *= u_opacity;
|
|
25
25
|
}`;
|
|
26
26
|
class TextureOnCanvasProgram {
|
|
27
|
+
gl;
|
|
28
|
+
vao;
|
|
29
|
+
buffer;
|
|
30
|
+
program;
|
|
31
|
+
uniforms;
|
|
32
|
+
_lastOpacity;
|
|
33
|
+
_isFreed = false;
|
|
27
34
|
constructor(gl) {
|
|
28
35
|
this.gl = gl;
|
|
29
36
|
this.vao = this.gl.createVertexArray();
|
|
@@ -41,20 +48,16 @@ class TextureOnCanvasProgram {
|
|
|
41
48
|
this.gl.bindVertexArray(null);
|
|
42
49
|
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);
|
|
43
50
|
this.program = createProgram(this.gl, vs, fs);
|
|
44
|
-
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
this.gl.useProgram(this.program);
|
|
55
|
-
this.gl.uniform1f(this.uniforms.opacity, this._lastOpacity);
|
|
56
|
-
this.gl.useProgram(currentProgram);
|
|
57
|
-
}
|
|
51
|
+
const { program } = this;
|
|
52
|
+
this.uniforms = {
|
|
53
|
+
texture: gl.getUniformLocation(program, "u_texture"),
|
|
54
|
+
opacity: gl.getUniformLocation(program, "u_opacity"),
|
|
55
|
+
};
|
|
56
|
+
this._lastOpacity = 1.0;
|
|
57
|
+
const currentProgram = this.gl.getParameter(this.gl.CURRENT_PROGRAM);
|
|
58
|
+
this.gl.useProgram(this.program);
|
|
59
|
+
this.gl.uniform1f(this.uniforms.opacity, this._lastOpacity);
|
|
60
|
+
this.gl.useProgram(currentProgram);
|
|
58
61
|
}
|
|
59
62
|
draw(texture, { opacity = 1.0 } = {}) {
|
|
60
63
|
const { gl, program, uniforms, vao } = this;
|
|
@@ -189,6 +189,34 @@ float circleCircumferenceInterPolationOf2PointsRadian(vec2 center, vec2 target,
|
|
|
189
189
|
return angle;
|
|
190
190
|
}
|
|
191
191
|
`;
|
|
192
|
+
export const slopeFromTexture = R + PI + `
|
|
193
|
+
float slopeFromTexture(highp sampler2DArray heightMap, vec3 uv, vec2 texelSize) {
|
|
194
|
+
float hL = texture(heightMap, uv - vec3(texelSize.x, 0.0, 0.0)).r;
|
|
195
|
+
float hR = texture(heightMap, uv + vec3(texelSize.x, 0.0, 0.0)).r;
|
|
196
|
+
float hD = texture(heightMap, uv - vec3(0.0, texelSize.y, 0.0)).r;
|
|
197
|
+
float hU = texture(heightMap, uv + vec3(0.0, texelSize.y, 0.0)).r;
|
|
198
|
+
float dX = (hR - hL) / (2.0 * texelSize.x);
|
|
199
|
+
float dY = (hU - hD) / (2.0 * texelSize.y);
|
|
200
|
+
float slope = sqrt(dX * dX + dY * dY);
|
|
201
|
+
return slope;
|
|
202
|
+
}
|
|
203
|
+
`;
|
|
204
|
+
export const normalFromTexture = `
|
|
205
|
+
vec3 normalFromTexture(highp sampler2DArray heightMap, vec3 uv, vec2 texelSize, float strength) {
|
|
206
|
+
float hL = texture(heightMap, uv - vec3(texelSize.x, 0.0, 0.0)).r;
|
|
207
|
+
float hR = texture(heightMap, uv + vec3(texelSize.x, 0.0, 0.0)).r;
|
|
208
|
+
float hD = texture(heightMap, uv - vec3(0.0, texelSize.y, 0.0)).r;
|
|
209
|
+
float hU = texture(heightMap, uv + vec3(0.0, texelSize.y, 0.0)).r;
|
|
210
|
+
|
|
211
|
+
// Calculate gradient
|
|
212
|
+
// Strength factor controls how "bumpy" the terrain looks
|
|
213
|
+
float dX = (hR - hL) * strength;
|
|
214
|
+
float dY = (hU - hD) * strength;
|
|
215
|
+
|
|
216
|
+
// Return normalized surface normal (-dX, -dY, 1.0)
|
|
217
|
+
return normalize(vec3(-dX, -dY, 1.0));
|
|
218
|
+
}
|
|
219
|
+
`;
|
|
192
220
|
export const realDistanceOnSphereR1 = `
|
|
193
221
|
float realDistanceOnSphereR1(vec2 longLat1, vec2 longLat2) {
|
|
194
222
|
float dLat = longLat2.y - longLat1.y;
|
|
@@ -200,7 +228,45 @@ float realDistanceOnSphereR1(vec2 longLat1, vec2 longLat2) {
|
|
|
200
228
|
`;
|
|
201
229
|
export const isPointInBBox = `
|
|
202
230
|
bool isPointInBBox(vec2 point, vec4 bbox) {
|
|
203
|
-
return point.x >= bbox.x && point.x <= bbox.z && point.y >= bbox.y && point.y <= bbox.w;
|
|
231
|
+
return point.x + ${EPSILON} >= bbox.x && point.x <= bbox.z + ${EPSILON}&& point.y + ${EPSILON} >= bbox.y && point.y <= bbox.w + ${EPSILON};
|
|
232
|
+
}
|
|
233
|
+
`;
|
|
234
|
+
export const relativeBBoxPositionRadian = `
|
|
235
|
+
${PI}
|
|
236
|
+
${isPointInBBox}
|
|
237
|
+
vec2 relativeBBoxPositionRadian(vec2 point, vec4 bbox) {
|
|
238
|
+
if ( bbox.z > bbox.x) {
|
|
239
|
+
if ( isPointInBBox(point, bbox) ) {
|
|
240
|
+
float x_ratio = (point.x - bbox.x) / (bbox.z - bbox.x);
|
|
241
|
+
float y_ratio = (point.y - bbox.y) / (bbox.w - bbox.y);
|
|
242
|
+
return vec2(x_ratio, y_ratio);
|
|
243
|
+
}
|
|
244
|
+
return vec2(-1.0, -1.0);
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
// BBox crosses the antimeridian
|
|
248
|
+
if ( isPointInBBox(point, vec4(bbox.x, bbox.y, PI , bbox.w) ) ) {
|
|
249
|
+
float x_ratio = (point.x - bbox.x) / (PI - bbox.x);
|
|
250
|
+
float y_ratio = (point.y - bbox.y) / (bbox.w - bbox.y);
|
|
251
|
+
return vec2(x_ratio, y_ratio);
|
|
252
|
+
}
|
|
253
|
+
else if ( isPointInBBox(point, vec4(-PI, bbox.y, bbox.z, bbox.w) ) ) {
|
|
254
|
+
float x_ratio = (point.x + PI) / (bbox.z + PI);
|
|
255
|
+
float y_ratio = (point.y - bbox.y) / (bbox.w - bbox.y);
|
|
256
|
+
return vec2(x_ratio, y_ratio);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return vec2(-1.0, -1.0);
|
|
260
|
+
}
|
|
261
|
+
`;
|
|
262
|
+
export const isPointInBBox2 = `
|
|
263
|
+
bool isPointInBBox(vec2 point, vec4 bbox) {
|
|
264
|
+
float horizontal_epsilon = (bbox.z - bbox.x) * 0.05;
|
|
265
|
+
float vertical_epsilon = (bbox.w - bbox.y) * 0.05;
|
|
266
|
+
return point.x + horizontal_epsilon >= bbox.x &&
|
|
267
|
+
point.x <= bbox.z + horizontal_epsilon &&
|
|
268
|
+
point.y + vertical_epsilon >= bbox.y &&
|
|
269
|
+
point.y <= bbox.w + vertical_epsilon;
|
|
204
270
|
}
|
|
205
271
|
`;
|
|
206
272
|
const pointsOnSphereBetween = `
|