@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
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { mergeMeshes } from "../../Math/tessellation/tile-merger";
|
|
2
|
+
import { globeBBoxToXYBBOX } from "../../Math/methods";
|
|
3
|
+
import { noRegisterGlobeProgramCache } from "../programcache";
|
|
4
|
+
import { CameraUniformBlockTotemCache } from "./camerauniformblock";
|
|
5
|
+
export const DEM_TEXTURE_BLOCK_STRING = `
|
|
6
|
+
layout(std140) uniform DemTextureUniformBlock {
|
|
7
|
+
vec4 u_demTextureBBOX[6]; // 96 bytes
|
|
8
|
+
vec4 u_textureDataCoverRatio[6]; // 96 bytes
|
|
9
|
+
vec2 u_textureResolution; // 8 bytes
|
|
10
|
+
int u_breakLoopIndex; // 4 bytes
|
|
11
|
+
};
|
|
12
|
+
uniform sampler2DArray u_demTexture;
|
|
13
|
+
`;
|
|
14
|
+
const MAXLAYERS = 6;
|
|
15
|
+
// Size calculation:
|
|
16
|
+
// BBOX: 6 * 16 bytes = 96
|
|
17
|
+
// CoverRatio: 6 * 16 bytes = 96
|
|
18
|
+
// Resolution: 8 bytes (offset 192)
|
|
19
|
+
// BreakLoopIndex: 4 bytes (offset 200)
|
|
20
|
+
// Total used: 204 bytes.
|
|
21
|
+
// std140 blocks are typically padded to 16 bytes alignment -> 208 bytes.
|
|
22
|
+
// 208 bytes / 4 bytes per float = 52 floats.
|
|
23
|
+
const uniformBlockData = new Float32Array(52);
|
|
24
|
+
function drawnedTilesHash(drawnTiles) {
|
|
25
|
+
let hash = 0;
|
|
26
|
+
for (const tile of drawnTiles) {
|
|
27
|
+
// Combine tile coordinates into a unique value
|
|
28
|
+
const val = (tile.level << 20) | (tile.x << 10) | tile.y;
|
|
29
|
+
hash = ((hash << 5) - hash) + val;
|
|
30
|
+
hash = hash | 0; // Convert to 32-bit integer
|
|
31
|
+
}
|
|
32
|
+
return hash;
|
|
33
|
+
}
|
|
34
|
+
function resCalculation(sourceResolution, mergeCount) {
|
|
35
|
+
return sourceResolution + (mergeCount - 1) * (sourceResolution - 1);
|
|
36
|
+
}
|
|
37
|
+
export class DemTextureManager {
|
|
38
|
+
_globe;
|
|
39
|
+
_mergeParameters = {
|
|
40
|
+
mergeCount: 20,
|
|
41
|
+
tileDimensionLength: 5,
|
|
42
|
+
processLimit: 6
|
|
43
|
+
};
|
|
44
|
+
STOP = false;
|
|
45
|
+
mergedData = [];
|
|
46
|
+
uniformBuffer = null;
|
|
47
|
+
demTexture = null;
|
|
48
|
+
textureWidth;
|
|
49
|
+
textureHeight;
|
|
50
|
+
cameraBlockTotem = null;
|
|
51
|
+
tilesHash = 0;
|
|
52
|
+
registry = new Set();
|
|
53
|
+
constructor(globe, { mergeCount = 20, tileDimensionLength = 5, processLimit = 6 } = {}) {
|
|
54
|
+
this._globe = globe;
|
|
55
|
+
this._mergeParameters.mergeCount = mergeCount;
|
|
56
|
+
this._mergeParameters.tileDimensionLength = tileDimensionLength;
|
|
57
|
+
this._mergeParameters.processLimit = processLimit;
|
|
58
|
+
this.textureWidth = this.textureHeight = resCalculation(tileDimensionLength, mergeCount);
|
|
59
|
+
this.cameraBlockTotem = CameraUniformBlockTotemCache.get(this._globe);
|
|
60
|
+
this.cameraBlockTotem.registerAttachment(this);
|
|
61
|
+
// Initialize uniform data buffer
|
|
62
|
+
this.initializeUniformBlock();
|
|
63
|
+
this.initializeTextureArray();
|
|
64
|
+
}
|
|
65
|
+
initializeUniformBlock() {
|
|
66
|
+
const gl = this._globe.gl;
|
|
67
|
+
if (!gl)
|
|
68
|
+
return;
|
|
69
|
+
// Create uniform buffer
|
|
70
|
+
this.uniformBuffer = gl.createBuffer();
|
|
71
|
+
gl.bindBuffer(gl.UNIFORM_BUFFER, this.uniformBuffer);
|
|
72
|
+
// Allocate buffer with correct size (52 floats * 4 bytes)
|
|
73
|
+
gl.bufferData(gl.UNIFORM_BUFFER, uniformBlockData.byteLength, gl.STREAM_COPY);
|
|
74
|
+
gl.bindBuffer(gl.UNIFORM_BUFFER, null);
|
|
75
|
+
}
|
|
76
|
+
initializeTextureArray() {
|
|
77
|
+
const gl = this._globe.gl;
|
|
78
|
+
if (!gl)
|
|
79
|
+
return;
|
|
80
|
+
// Create texture array
|
|
81
|
+
this.demTexture = gl.createTexture();
|
|
82
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, this.demTexture);
|
|
83
|
+
// Calculate correct size: tileDimensionLength + (mergeCount - 1) * (tileDimensionLength - 1)
|
|
84
|
+
// For tileDimensionLength=5, mergeCount=8: 5 + 7*4 = RESOLUTION
|
|
85
|
+
// gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.R32F, this.textureWidth, this.textureHeight, 6);
|
|
86
|
+
// // Allocate storage for texture array
|
|
87
|
+
gl.texImage3D(gl.TEXTURE_2D_ARRAY, 0, // mip level
|
|
88
|
+
gl.R32F, // internal format (32-bit float for DEM data)
|
|
89
|
+
this.textureWidth, this.textureHeight, MAXLAYERS, // number of layers
|
|
90
|
+
0, // border
|
|
91
|
+
gl.RED, // format
|
|
92
|
+
gl.FLOAT, // type
|
|
93
|
+
null // data (null to allocate)
|
|
94
|
+
);
|
|
95
|
+
const ext = gl.getExtension('OES_texture_float_linear');
|
|
96
|
+
if (!ext) {
|
|
97
|
+
throw new Error("OES_texture_float_linear extension is supported.");
|
|
98
|
+
}
|
|
99
|
+
// Set texture parameters
|
|
100
|
+
gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
101
|
+
gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
102
|
+
gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
103
|
+
gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
104
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, null);
|
|
105
|
+
}
|
|
106
|
+
assignBindingPoint(program, bindingPoint) {
|
|
107
|
+
const gl = this._globe.gl;
|
|
108
|
+
if (!gl || !this.uniformBuffer || !program) {
|
|
109
|
+
console.warn('Cannot bind uniform block: missing GL context, buffer, or program');
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
const uniformBlockIndex = gl.getUniformBlockIndex(program, 'DemTextureUniformBlock');
|
|
113
|
+
if (uniformBlockIndex === gl.INVALID_INDEX) {
|
|
114
|
+
// Uniform block might be optimized out - this is not necessarily an error
|
|
115
|
+
console.warn(`Uniform block 'DemTextureUniformBlock' not found in program (may be optimized out)`);
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
gl.uniformBlockBinding(program, uniformBlockIndex, bindingPoint);
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
register(obj) {
|
|
122
|
+
this.registry.add(obj);
|
|
123
|
+
obj.setMergedTiles(this.mergedData);
|
|
124
|
+
}
|
|
125
|
+
unregister(obj) {
|
|
126
|
+
this.registry.delete(obj);
|
|
127
|
+
}
|
|
128
|
+
update() {
|
|
129
|
+
if (this.STOP)
|
|
130
|
+
return;
|
|
131
|
+
const gl = this._globe.gl;
|
|
132
|
+
const tilesMetaData = this._globe.api_GetVisibleTilesInfo();
|
|
133
|
+
const newHash = drawnedTilesHash(tilesMetaData);
|
|
134
|
+
if (this.tilesHash === newHash) {
|
|
135
|
+
return; // No change in drawn tiles, skip update
|
|
136
|
+
}
|
|
137
|
+
this.tilesHash = newHash;
|
|
138
|
+
this.mergedData = mergeMeshes(tilesMetaData, this._mergeParameters.mergeCount, this._mergeParameters.tileDimensionLength, this._mergeParameters.processLimit, this._globe);
|
|
139
|
+
// Bind texture before updating
|
|
140
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, this.demTexture);
|
|
141
|
+
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
|
|
142
|
+
// turn off premultiply alpha
|
|
143
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
|
144
|
+
for (let i = 0; i < this.mergedData.length; i++) {
|
|
145
|
+
const { mesh, bbox, coverRatio } = this.mergedData[i];
|
|
146
|
+
gl.texSubImage3D(gl.TEXTURE_2D_ARRAY, 0, // mip level
|
|
147
|
+
0, // xoffset
|
|
148
|
+
0, // yoffset
|
|
149
|
+
i, // zoffset (layer index)
|
|
150
|
+
this.textureWidth, this.textureHeight, 1, // depth (1 layer)
|
|
151
|
+
gl.RED, gl.FLOAT, mesh);
|
|
152
|
+
const bboxXY = globeBBoxToXYBBOX(bbox);
|
|
153
|
+
uniformBlockData[i * 4 + 0] = bboxXY.ll[0];
|
|
154
|
+
uniformBlockData[i * 4 + 1] = bboxXY.ll[1];
|
|
155
|
+
uniformBlockData[i * 4 + 2] = bboxXY.ur[0];
|
|
156
|
+
uniformBlockData[i * 4 + 3] = bboxXY.ur[1];
|
|
157
|
+
uniformBlockData[24 + i * 4 + 0] = coverRatio.x;
|
|
158
|
+
uniformBlockData[24 + i * 4 + 1] = coverRatio.y;
|
|
159
|
+
}
|
|
160
|
+
// Set resolution (offset 192 bytes -> index 48)
|
|
161
|
+
uniformBlockData[48] = this.textureWidth;
|
|
162
|
+
uniformBlockData[49] = this.textureHeight;
|
|
163
|
+
// Set break loop index (offset 200 bytes -> index 50)
|
|
164
|
+
uniformBlockData[50] = this.mergedData.length;
|
|
165
|
+
// Unbind texture after updating
|
|
166
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, null);
|
|
167
|
+
gl.bindBuffer(gl.UNIFORM_BUFFER, this.uniformBuffer);
|
|
168
|
+
gl.bufferSubData(gl.UNIFORM_BUFFER, 0, uniformBlockData);
|
|
169
|
+
gl.bindBuffer(gl.UNIFORM_BUFFER, null);
|
|
170
|
+
for (const obj of this.registry) {
|
|
171
|
+
obj.setMergedTiles(this.mergedData);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
bindData(textureUnit, bindingPoint) {
|
|
175
|
+
const gl = this._globe.gl;
|
|
176
|
+
if (!gl)
|
|
177
|
+
return;
|
|
178
|
+
// Bind uniform buffer
|
|
179
|
+
gl.bindBufferBase(gl.UNIFORM_BUFFER, bindingPoint, this.uniformBuffer);
|
|
180
|
+
// Bind texture array
|
|
181
|
+
gl.activeTexture(gl.TEXTURE0 + textureUnit);
|
|
182
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, this.demTexture);
|
|
183
|
+
}
|
|
184
|
+
find(x, y, zoom) {
|
|
185
|
+
for (const data of this._globe.api_GetVisibleTilesInfo()) {
|
|
186
|
+
if (data.x === x && data.y === y && data.level === zoom) {
|
|
187
|
+
return data;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
showMergedDataInfo(zoomLevel) {
|
|
193
|
+
if (!this.mergedData[zoomLevel]) {
|
|
194
|
+
console.log(`No merged data at zoom level ${zoomLevel}`);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const { textureHeight, textureWidth } = this;
|
|
198
|
+
const { mesh, bbox, coverRatio } = this.mergedData[zoomLevel];
|
|
199
|
+
const result = [];
|
|
200
|
+
const xLength = Math.ceil(mesh.length / textureHeight * coverRatio.x);
|
|
201
|
+
const yLength = Math.ceil(mesh.length / textureWidth * coverRatio.y);
|
|
202
|
+
for (let y = 0; y < yLength; y++) {
|
|
203
|
+
const row = [];
|
|
204
|
+
for (let x = 0; x < xLength; x++) {
|
|
205
|
+
const index = y * textureWidth + x;
|
|
206
|
+
const value = mesh[index];
|
|
207
|
+
row.push(value);
|
|
208
|
+
}
|
|
209
|
+
result.push(new Float32Array(row));
|
|
210
|
+
}
|
|
211
|
+
return { mesh: result, bbox: bbox, coverRatio: coverRatio };
|
|
212
|
+
}
|
|
213
|
+
unbindData(textureUnit, bindingPoint) {
|
|
214
|
+
const gl = this._globe.gl;
|
|
215
|
+
if (!gl)
|
|
216
|
+
return;
|
|
217
|
+
// Unbind texture array
|
|
218
|
+
gl.activeTexture(gl.TEXTURE0 + textureUnit);
|
|
219
|
+
// Unbind
|
|
220
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, null);
|
|
221
|
+
// call this right after drawing
|
|
222
|
+
gl.bindBufferBase(gl.UNIFORM_BUFFER, bindingPoint, null);
|
|
223
|
+
}
|
|
224
|
+
get() {
|
|
225
|
+
return this.mergedData;
|
|
226
|
+
}
|
|
227
|
+
getBBoxes() {
|
|
228
|
+
const ressult = new Array(this.mergedData.length);
|
|
229
|
+
for (let i = 0; i < this.mergedData.length; i++) {
|
|
230
|
+
const { bbox, zoom } = this.mergedData[i];
|
|
231
|
+
ressult[i] = {
|
|
232
|
+
minX: bbox.ll.x,
|
|
233
|
+
minY: bbox.ll.y,
|
|
234
|
+
maxX: bbox.ur.x,
|
|
235
|
+
maxY: bbox.ur.y,
|
|
236
|
+
zoom
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
return ressult;
|
|
240
|
+
}
|
|
241
|
+
free() {
|
|
242
|
+
const gl = this._globe.gl;
|
|
243
|
+
this.cameraBlockTotem.unregisterAttachment(this);
|
|
244
|
+
if (gl) {
|
|
245
|
+
if (this.uniformBuffer) {
|
|
246
|
+
gl.deleteBuffer(this.uniformBuffer);
|
|
247
|
+
this.uniformBuffer = null;
|
|
248
|
+
}
|
|
249
|
+
if (this.demTexture) {
|
|
250
|
+
gl.deleteTexture(this.demTexture);
|
|
251
|
+
this.demTexture = null;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
export const DemTextureManagerCache = Object.freeze({
|
|
257
|
+
get: (globe) => {
|
|
258
|
+
const result = noRegisterGlobeProgramCache.getProgram(globe, DemTextureManager);
|
|
259
|
+
window.demManager = result;
|
|
260
|
+
return result;
|
|
261
|
+
},
|
|
262
|
+
release: (globe) => {
|
|
263
|
+
noRegisterGlobeProgramCache.releaseProgram(globe, DemTextureManager);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { createProgram } from "../../../util/webglobjectbuilders";
|
|
2
2
|
import { glProgramCache } from "../../programcache";
|
|
3
|
-
import {
|
|
3
|
+
import { ParticleUBO } from "./particle-ubo";
|
|
4
4
|
/**
|
|
5
5
|
* [+] ubo
|
|
6
6
|
*/
|
|
7
7
|
const vertexShaderSource = `#version 300 es
|
|
8
8
|
precision highp float;
|
|
9
|
-
` +
|
|
9
|
+
` + ParticleUBO.glslCode() + `
|
|
10
10
|
uniform sampler2D u_vector_field;
|
|
11
|
+
uniform sampler2D u_color_field;
|
|
12
|
+
uniform sampler2D u_speed_field;
|
|
11
13
|
in vec2 in_position;
|
|
12
|
-
out
|
|
14
|
+
out vec4 base_color;
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
vec2 read_value(const vec2 uv) {
|
|
@@ -37,7 +39,17 @@ vec2 lookup_wind(const vec2 uv) { // gerek kalmayabilir. sampler linear methodu
|
|
|
37
39
|
|
|
38
40
|
|
|
39
41
|
void main(){
|
|
40
|
-
|
|
42
|
+
if ( use_speed_field != 0.0 ) {
|
|
43
|
+
base_color = vec4(0.0);
|
|
44
|
+
return;
|
|
45
|
+
float speed = texture(u_speed_field, in_position).r;
|
|
46
|
+
if ( speed < min_speed_threshold || speed > max_speed_threshold ) {
|
|
47
|
+
base_color = vec4(0.0);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
vec2 direction_vector = lookup_wind(in_position);
|
|
41
53
|
if (direction_vector.r == 0.0 && direction_vector.g == 0.0) return;
|
|
42
54
|
|
|
43
55
|
|
|
@@ -45,31 +57,37 @@ void main(){
|
|
|
45
57
|
if ( 0 == gl_VertexID) { limp = -tail_wing_base_limp; }
|
|
46
58
|
else if ( 1 == gl_VertexID) { limp = vec2( tail_wing_base_limp.x, -tail_wing_base_limp.y); }
|
|
47
59
|
else if ( 2 == gl_VertexID) { limp = tail_wing_base_limp; }
|
|
48
|
-
else { limp = vec2(-tail_wing_base_limp.x, tail_wing_base_limp.y); }
|
|
49
|
-
|
|
60
|
+
else { limp = vec2(-tail_wing_base_limp.x, tail_wing_base_limp.y); }
|
|
50
61
|
limp = (limp * mat2(
|
|
51
62
|
direction_vector.x, -direction_vector.y,
|
|
52
63
|
direction_vector.y, direction_vector.x)) / draw_texture_size;
|
|
53
64
|
|
|
54
65
|
vec2 pos = in_position * 2.0 - 1.0;
|
|
55
66
|
gl_Position = vec4(pos + limp, 0.0, 1.0);
|
|
56
|
-
|
|
67
|
+
|
|
68
|
+
base_color = use_color_field != 0.0 ? texture(u_color_field, in_position).rgba : vec4(color, 1.0);
|
|
57
69
|
}`;
|
|
58
70
|
const fragmentShaderSource = `#version 300 es
|
|
59
71
|
precision highp float;
|
|
60
72
|
out vec4 outColor;
|
|
61
|
-
in
|
|
73
|
+
in vec4 base_color;
|
|
62
74
|
void main(){
|
|
63
|
-
outColor =
|
|
75
|
+
outColor = base_color;
|
|
64
76
|
}`;
|
|
65
|
-
class
|
|
77
|
+
export class DrawRectangleParticleProgram {
|
|
66
78
|
gl;
|
|
67
79
|
program;
|
|
68
80
|
_vector_field_location;
|
|
81
|
+
_color_texture_location;
|
|
82
|
+
_speed_field_location;
|
|
69
83
|
constructor(gl) {
|
|
70
84
|
this.gl = gl;
|
|
71
|
-
[this.program, this._vector_field_location] = this._createProgram();
|
|
72
85
|
// this.decoyBuffer = new DecoyBufferManager(gl);
|
|
86
|
+
const { program, _vector_field_location, _color_texture_location, _speed_field_location } = this._createProgram();
|
|
87
|
+
this.program = program;
|
|
88
|
+
this._vector_field_location = _vector_field_location;
|
|
89
|
+
this._color_texture_location = _color_texture_location;
|
|
90
|
+
this._speed_field_location = _speed_field_location;
|
|
73
91
|
}
|
|
74
92
|
_createProgram() {
|
|
75
93
|
const gl = this.gl;
|
|
@@ -77,23 +95,38 @@ class Logic {
|
|
|
77
95
|
// ubo point
|
|
78
96
|
// const ubo_location = gl.getUniformBlockIndex(program, 'UBO');
|
|
79
97
|
// gl.uniformBlockBinding(program, ubo_location, UBO_BINDING_POINT);
|
|
80
|
-
|
|
81
|
-
return
|
|
98
|
+
ParticleUBO.assignBindingPoint(gl, program);
|
|
99
|
+
return {
|
|
100
|
+
program,
|
|
101
|
+
_vector_field_location: gl.getUniformLocation(program, 'u_vector_field'),
|
|
102
|
+
_color_texture_location: gl.getUniformLocation(program, 'u_color_field'),
|
|
103
|
+
_speed_field_location: gl.getUniformLocation(program, 'u_speed_field')
|
|
104
|
+
};
|
|
82
105
|
}
|
|
83
106
|
/**
|
|
84
107
|
* @param bufferManager | PingPongBufferManager
|
|
85
|
-
* @param
|
|
108
|
+
* @param vectorFieldTexture | RG32F texture R: x, G: y
|
|
86
109
|
* @param uboManager | WaveParticalUboManager under ubo.js
|
|
87
110
|
*/
|
|
88
|
-
draw(bufferManager,
|
|
111
|
+
draw(bufferManager, vectorFieldTexture, uboManager, colorFieldTexture, speedFieldTexture) {
|
|
89
112
|
const { gl, program } = this;
|
|
90
113
|
gl.useProgram(program);
|
|
91
114
|
gl.bindVertexArray(bufferManager.getSourceVao());
|
|
92
115
|
// gl.bindVertexArray(this.decoyBuffer.getSourceVao());
|
|
93
116
|
uboManager.bind();
|
|
117
|
+
if (colorFieldTexture) {
|
|
118
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
119
|
+
gl.uniform1i(this._color_texture_location, 1);
|
|
120
|
+
gl.bindTexture(gl.TEXTURE_2D, colorFieldTexture);
|
|
121
|
+
}
|
|
122
|
+
if (speedFieldTexture) {
|
|
123
|
+
gl.activeTexture(gl.TEXTURE2);
|
|
124
|
+
gl.uniform1i(this._speed_field_location, 2);
|
|
125
|
+
gl.bindTexture(gl.TEXTURE_2D, speedFieldTexture);
|
|
126
|
+
}
|
|
94
127
|
gl.activeTexture(gl.TEXTURE0);
|
|
95
128
|
gl.uniform1i(this._vector_field_location, 0);
|
|
96
|
-
gl.bindTexture(gl.TEXTURE_2D,
|
|
129
|
+
gl.bindTexture(gl.TEXTURE_2D, vectorFieldTexture);
|
|
97
130
|
gl.drawArraysInstanced(gl.TRIANGLE_FAN, 0, 4, bufferManager.length);
|
|
98
131
|
gl.drawArraysInstanced(gl.POINTS, 0, 4, bufferManager.length);
|
|
99
132
|
gl.bindVertexArray(null);
|
|
@@ -106,9 +139,9 @@ class Logic {
|
|
|
106
139
|
}
|
|
107
140
|
export const drawRectangleParticlesProgramCache = Object.freeze({
|
|
108
141
|
getProgram: (gl) => {
|
|
109
|
-
return glProgramCache.getProgram(gl,
|
|
142
|
+
return glProgramCache.getProgram(gl, DrawRectangleParticleProgram);
|
|
110
143
|
},
|
|
111
144
|
releaseProgram: (gl) => {
|
|
112
|
-
glProgramCache.releaseProgram(gl,
|
|
145
|
+
glProgramCache.releaseProgram(gl, DrawRectangleParticleProgram);
|
|
113
146
|
}
|
|
114
147
|
});
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { UBO_BINDING_POINTS } from "./constants";
|
|
2
2
|
import { UniformBlockManager } from "../../../util/gl-util/uniform-block/manager";
|
|
3
3
|
const INITIAL_UBO_DATA = /*@__PURE__*/ new Float32Array([93.17, 0.2, 1.0, 7.0, 1.0, 1.0, 1.0, 0.05, 2000, 2000, 0]);
|
|
4
|
-
|
|
5
|
-
// {float random_seed;float range;vec2 tail_wing_base_limp;vec3 color;float drop_rate;vec2 draw_texture_size;float escape_value; }
|
|
6
|
-
export const SeaWaveUbo = /*@__PURE__*/ new UniformBlockManager("Seawave_UBO", [
|
|
4
|
+
export const ParticleUBO = /*@__PURE__*/ new UniformBlockManager("Seawave_UBO", [
|
|
7
5
|
{ name: "tail_wing_base_limp", type: "vec2", value: INITIAL_UBO_DATA.slice(2, 4) },
|
|
8
6
|
{ name: "draw_texture_size", type: "vec2", value: INITIAL_UBO_DATA.slice(8, 10) },
|
|
9
7
|
{ name: "random_seed", type: "float", value: INITIAL_UBO_DATA.slice(0, 1) },
|
|
@@ -11,15 +9,8 @@ export const SeaWaveUbo = /*@__PURE__*/ new UniformBlockManager("Seawave_UBO", [
|
|
|
11
9
|
{ name: "escape_value", type: "float", value: INITIAL_UBO_DATA.slice(10, 11) },
|
|
12
10
|
{ name: "drop_rate", type: "float", value: INITIAL_UBO_DATA.slice(7, 8) },
|
|
13
11
|
{ name: "color", type: "vec3", value: INITIAL_UBO_DATA.slice(4, 7) },
|
|
12
|
+
{ name: "use_color_field", type: "float", value: new Float32Array([0]) },
|
|
13
|
+
{ name: "use_speed_field", type: "float", value: new Float32Array([0]) },
|
|
14
|
+
{ name: "min_speed_threshold", type: "float", value: new Float32Array([0]) },
|
|
15
|
+
{ name: "max_speed_threshold", type: "float", value: new Float32Array([10000]) },
|
|
14
16
|
], UBO_BINDING_POINTS.SEAWAVE);
|
|
15
|
-
// window add properties
|
|
16
|
-
// const shaderUboSource = `
|
|
17
|
-
// layout(std140) uniform UBO {
|
|
18
|
-
// float random_seed;
|
|
19
|
-
// float range;
|
|
20
|
-
// vec2 tail_wing_base_limp;
|
|
21
|
-
// vec3 color;
|
|
22
|
-
// float drop_rate;
|
|
23
|
-
// vec2 draw_texture_size;
|
|
24
|
-
// float escape_value;
|
|
25
|
-
// };`;
|
|
@@ -1,22 +1,14 @@
|
|
|
1
1
|
import { createShader } from "../../../util/webglobjectbuilders";
|
|
2
2
|
import { glProgramCache } from "../../programcache";
|
|
3
|
-
import {
|
|
4
|
-
// program output is buffer
|
|
5
|
-
// TODO: Mechanism for randomness
|
|
6
|
-
// drop out mechanism
|
|
7
|
-
// random particle position mechanism
|
|
3
|
+
import { ParticleUBO } from "./particle-ubo";
|
|
8
4
|
const vertexShaderSource = `#version 300 es
|
|
9
|
-
` +
|
|
5
|
+
` + ParticleUBO.glslCode() + `
|
|
10
6
|
|
|
11
7
|
uniform sampler2D vector_field;
|
|
8
|
+
uniform sampler2D speed_field;
|
|
12
9
|
in vec2 in_position;
|
|
13
10
|
out vec2 out_position;
|
|
14
11
|
|
|
15
|
-
// float random(vec2 st){
|
|
16
|
-
// float t = dot(st, vec2(12.9898,78.233));
|
|
17
|
-
// return fract(sin(t) * (t+43758.5453123));
|
|
18
|
-
// }
|
|
19
|
-
|
|
20
12
|
|
|
21
13
|
const vec3 rand_constants = vec3(12.9898, 78.233, 4375.85453);
|
|
22
14
|
float random(const vec2 co) {
|
|
@@ -47,15 +39,10 @@ vec2 lookup_wind(const vec2 uv) {
|
|
|
47
39
|
return mix(mix(tl, tr, f.x), mix(bl, br, f.x), f.y);
|
|
48
40
|
}
|
|
49
41
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
42
|
vec2 random_position(vec2 st){
|
|
55
43
|
return vec2(random(st), random(st + 1.0));
|
|
56
44
|
}
|
|
57
45
|
|
|
58
|
-
|
|
59
46
|
void main(){
|
|
60
47
|
vec2 vec = lookup_wind(in_position).xy;
|
|
61
48
|
if (vec.x == 0.0 && vec.y == 0.0){
|
|
@@ -67,31 +54,43 @@ void main(){
|
|
|
67
54
|
out_position = random_position(in_position);
|
|
68
55
|
return;
|
|
69
56
|
}
|
|
70
|
-
|
|
57
|
+
float speed_multiplier = use_speed_field != 0.0 ? texture(speed_field, in_position).r : 1.0;
|
|
58
|
+
out_position = in_position + (vec / draw_texture_size) * range * speed_multiplier * tail_wing_base_limp.y;
|
|
71
59
|
}
|
|
72
60
|
`;
|
|
73
61
|
const fragmentShaderSource = `#version 300 es
|
|
74
62
|
precision highp float;
|
|
75
63
|
void main(){
|
|
76
64
|
}`;
|
|
77
|
-
class
|
|
65
|
+
export class MoveParticalProgram {
|
|
66
|
+
gl;
|
|
67
|
+
program;
|
|
68
|
+
_vector_field_location;
|
|
69
|
+
_speed_field_location;
|
|
78
70
|
constructor(gl) {
|
|
79
71
|
this.gl = gl;
|
|
80
|
-
[this.program, this._vector_field_location] = this._createProgram();
|
|
72
|
+
[this.program, this._vector_field_location, this._speed_field_location] = this._createProgram();
|
|
81
73
|
}
|
|
82
74
|
/**
|
|
83
|
-
* @param
|
|
84
|
-
* @param
|
|
85
|
-
* @param
|
|
75
|
+
* @param bufferManager - PingPongBufferManager
|
|
76
|
+
* @param vectorTexture - RG32F texture R: x, G: y
|
|
77
|
+
* @param uboManager - WaveParticalUboManager under ubo.js
|
|
86
78
|
*/
|
|
87
|
-
move(bufferManager, vectorTexture, uboManager) {
|
|
79
|
+
move(bufferManager, vectorTexture, uboManager, speedTexture) {
|
|
88
80
|
const { gl, program, _vector_field_location } = this;
|
|
81
|
+
if (!program)
|
|
82
|
+
return;
|
|
89
83
|
gl.useProgram(program);
|
|
90
84
|
gl.enable(gl.RASTERIZER_DISCARD);
|
|
91
85
|
gl.bindVertexArray(bufferManager.getSourceVao());
|
|
92
86
|
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, bufferManager.getTargetTF());
|
|
93
87
|
gl.beginTransformFeedback(gl.POINTS);
|
|
94
88
|
uboManager.bind();
|
|
89
|
+
if (speedTexture) {
|
|
90
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
91
|
+
gl.bindTexture(gl.TEXTURE_2D, speedTexture);
|
|
92
|
+
gl.uniform1i(this._speed_field_location, 1);
|
|
93
|
+
}
|
|
95
94
|
gl.activeTexture(gl.TEXTURE0);
|
|
96
95
|
gl.bindTexture(gl.TEXTURE_2D, vectorTexture);
|
|
97
96
|
gl.uniform1i(_vector_field_location, 0);
|
|
@@ -102,6 +101,17 @@ class Logic {
|
|
|
102
101
|
uboManager.unbind();
|
|
103
102
|
gl.disable(gl.RASTERIZER_DISCARD);
|
|
104
103
|
}
|
|
104
|
+
free() {
|
|
105
|
+
if (this.program) {
|
|
106
|
+
this.gl.deleteProgram(this.program);
|
|
107
|
+
this.program = null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
getInPositionLocation() {
|
|
111
|
+
if (!this.program)
|
|
112
|
+
return -1;
|
|
113
|
+
return this.gl.getAttribLocation(this.program, 'in_position');
|
|
114
|
+
}
|
|
105
115
|
// -- private methods
|
|
106
116
|
_createProgram() {
|
|
107
117
|
const gl = this.gl;
|
|
@@ -113,27 +123,23 @@ class Logic {
|
|
|
113
123
|
gl.transformFeedbackVaryings(program, ["out_position"], gl.SEPARATE_ATTRIBS);
|
|
114
124
|
gl.linkProgram(program);
|
|
115
125
|
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
116
|
-
throw new Error(gl.
|
|
126
|
+
throw new Error(gl.getProgramInfoLog(program) || 'Program link failed');
|
|
117
127
|
}
|
|
118
128
|
// const ubo_location = gl.getUniformBlockIndex(program, 'UBO');
|
|
119
129
|
// gl.uniformBlockBinding(program, ubo_location, UBO_BINDING_POINT);
|
|
120
|
-
|
|
121
|
-
return [
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
this.program = null;
|
|
127
|
-
}
|
|
128
|
-
getInPositionLocation() {
|
|
129
|
-
return this.gl.getAttribLocation(this.program, 'in_position');
|
|
130
|
+
ParticleUBO.assignBindingPoint(gl, program);
|
|
131
|
+
return [
|
|
132
|
+
program,
|
|
133
|
+
gl.getUniformLocation(program, 'vector_field'),
|
|
134
|
+
gl.getUniformLocation(program, 'speed_field'),
|
|
135
|
+
];
|
|
130
136
|
}
|
|
131
137
|
}
|
|
132
138
|
export const pixelBasedMoveProgramCache = Object.freeze({
|
|
133
139
|
getProgram: (gl) => {
|
|
134
|
-
return glProgramCache.getProgram(gl,
|
|
140
|
+
return glProgramCache.getProgram(gl, MoveParticalProgram);
|
|
135
141
|
},
|
|
136
142
|
releaseProgram: (gl) => {
|
|
137
|
-
glProgramCache.releaseProgram(gl,
|
|
143
|
+
glProgramCache.releaseProgram(gl, MoveParticalProgram);
|
|
138
144
|
}
|
|
139
145
|
});
|
|
@@ -6,12 +6,20 @@
|
|
|
6
6
|
* update coords and draw particles programs will use this class.
|
|
7
7
|
*/
|
|
8
8
|
export class PingPongBufferManager {
|
|
9
|
+
gl;
|
|
10
|
+
length;
|
|
11
|
+
_inPositionLocation;
|
|
12
|
+
_buffers;
|
|
13
|
+
_tfs;
|
|
14
|
+
_vaos;
|
|
15
|
+
_index;
|
|
9
16
|
constructor(gl, particleCount, inPositionLocation = 0) {
|
|
10
17
|
this.gl = gl;
|
|
11
18
|
this._inPositionLocation = inPositionLocation;
|
|
12
19
|
this._buffers = [gl.createBuffer(), gl.createBuffer()];
|
|
13
20
|
this._tfs = this._createTransformFeedbacksAndBindBuffers();
|
|
14
21
|
this._vaos = this._createVaos();
|
|
22
|
+
this.length = 0;
|
|
15
23
|
this.setParticleCount(particleCount);
|
|
16
24
|
this._index = 0;
|
|
17
25
|
}
|
|
@@ -27,7 +35,10 @@ export class PingPongBufferManager {
|
|
|
27
35
|
}
|
|
28
36
|
_createTransformFeedbacksAndBindBuffers() {
|
|
29
37
|
const gl = this.gl;
|
|
30
|
-
const tfs = [
|
|
38
|
+
const tfs = [
|
|
39
|
+
gl.createTransformFeedback(),
|
|
40
|
+
gl.createTransformFeedback()
|
|
41
|
+
];
|
|
31
42
|
tfs.forEach((tf, idx) => {
|
|
32
43
|
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
|
|
33
44
|
gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, this._buffers[idx]);
|
|
@@ -37,7 +48,10 @@ export class PingPongBufferManager {
|
|
|
37
48
|
}
|
|
38
49
|
_createVaos() {
|
|
39
50
|
const gl = this.gl;
|
|
40
|
-
const vaos = [
|
|
51
|
+
const vaos = [
|
|
52
|
+
gl.createVertexArray(),
|
|
53
|
+
gl.createVertexArray()
|
|
54
|
+
];
|
|
41
55
|
vaos.forEach((vao, idx) => {
|
|
42
56
|
gl.bindVertexArray(vao);
|
|
43
57
|
gl.bindBuffer(gl.ARRAY_BUFFER, this._buffers[idx]);
|
|
@@ -48,12 +62,24 @@ export class PingPongBufferManager {
|
|
|
48
62
|
});
|
|
49
63
|
return vaos;
|
|
50
64
|
}
|
|
51
|
-
getSourceVao() {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
65
|
+
getSourceVao() {
|
|
66
|
+
return this._vaos[this._index];
|
|
67
|
+
}
|
|
68
|
+
getTargetVao() {
|
|
69
|
+
return this._vaos[1 - this._index];
|
|
70
|
+
}
|
|
71
|
+
sourceBuffer() {
|
|
72
|
+
return this._buffers[this._index];
|
|
73
|
+
}
|
|
74
|
+
targetBuffer() {
|
|
75
|
+
return this._buffers[1 - this._index];
|
|
76
|
+
}
|
|
77
|
+
getTargetTF() {
|
|
78
|
+
return this._tfs[1 - this._index];
|
|
79
|
+
}
|
|
80
|
+
swap() {
|
|
81
|
+
this._index = 1 - this._index;
|
|
82
|
+
}
|
|
57
83
|
free() {
|
|
58
84
|
this.gl.deleteBuffer(this._buffers[0]);
|
|
59
85
|
this.gl.deleteBuffer(this._buffers[1]);
|