@xeokit/xeokit-sdk 2.5.0-beta → 2.5.1-beta
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/dist/xeokit-sdk.cjs.js +136 -0
- package/dist/xeokit-sdk.es.js +136 -0
- package/dist/xeokit-sdk.es5.js +4 -4
- package/dist/xeokit-sdk.min.cjs.js +3 -3
- package/dist/xeokit-sdk.min.es.js +2 -2
- package/dist/xeokit-sdk.min.es5.js +2 -2
- package/package.json +1 -1
- package/src/plugins/AngleMeasurementsPlugin/AngleMeasurement.js +32 -0
- package/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsPlugin.js +1 -0
- package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js +44 -0
- package/src/plugins/lib/html/Dot.js +23 -0
- package/src/plugins/lib/html/Label.js +18 -0
- package/src/plugins/lib/html/Wire.js +18 -0
- package/src/plugins/LODCullingPlugin/LODCullingPlugin.js +0 -209
- package/src/plugins/LODCullingPlugin/LODManager.js +0 -82
- package/src/plugins/LODCullingPlugin/LODState.js +0 -130
- package/src/plugins/LODCullingPlugin/index.js +0 -1
- package/src/viewer/scene/model/vbo/BindableDataTexture.js +0 -31
- package/src/viewer/scene/model/vbo/DataTextureGenerator.js +0 -38
- package/src/viewer/scene/webgl/Renderer2.js +0 -1830
|
@@ -1,1830 +0,0 @@
|
|
|
1
|
-
import {FrameContext} from './FrameContext.js';
|
|
2
|
-
import {math} from '../math/math.js';
|
|
3
|
-
import {stats} from '../stats.js';
|
|
4
|
-
import {WEBGL_INFO} from '../webglInfo.js';
|
|
5
|
-
import {Map} from "../utils/Map.js";
|
|
6
|
-
import {PickResult} from "./PickResult.js";
|
|
7
|
-
import {OcclusionTester} from "./occlusion/OcclusionTester.js";
|
|
8
|
-
import {SAOOcclusionRenderer} from "./sao/SAOOcclusionRenderer.js";
|
|
9
|
-
import {createRTCViewMat} from "../math/rtcCoords.js";
|
|
10
|
-
import {SAODepthLimitedBlurRenderer} from "./sao/SAODepthLimitedBlurRenderer.js";
|
|
11
|
-
import {RenderBufferManager} from "./RenderBufferManager.js";
|
|
12
|
-
import {getExtension} from "./getExtension.js";
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @private
|
|
16
|
-
*/
|
|
17
|
-
const Renderer = function (scene, options) {
|
|
18
|
-
|
|
19
|
-
options = options || {};
|
|
20
|
-
|
|
21
|
-
const frameCtx = new FrameContext(scene);
|
|
22
|
-
const canvas = scene.canvas.canvas;
|
|
23
|
-
/**
|
|
24
|
-
* @type {WebGL2RenderingContext}
|
|
25
|
-
*/
|
|
26
|
-
const gl = scene.canvas.gl;
|
|
27
|
-
const canvasTransparent = (!!options.transparent);
|
|
28
|
-
const alphaDepthMask = options.alphaDepthMask;
|
|
29
|
-
|
|
30
|
-
const pickIDs = new Map({});
|
|
31
|
-
|
|
32
|
-
let drawableTypeInfo = {};
|
|
33
|
-
let drawables = {};
|
|
34
|
-
|
|
35
|
-
let drawableListDirty = true;
|
|
36
|
-
let stateSortDirty = true;
|
|
37
|
-
let imageDirty = true;
|
|
38
|
-
let shadowsDirty = true;
|
|
39
|
-
|
|
40
|
-
let transparentEnabled = true;
|
|
41
|
-
let edgesEnabled = true;
|
|
42
|
-
let saoEnabled = true;
|
|
43
|
-
let pbrEnabled = true;
|
|
44
|
-
let colorTextureEnabled = true;
|
|
45
|
-
|
|
46
|
-
const renderBufferManager = new RenderBufferManager(scene);
|
|
47
|
-
|
|
48
|
-
let snapshotBound = false;
|
|
49
|
-
|
|
50
|
-
const bindOutputFrameBuffer = null;
|
|
51
|
-
const unbindOutputFrameBuffer = null;
|
|
52
|
-
|
|
53
|
-
const saoOcclusionRenderer = new SAOOcclusionRenderer(scene);
|
|
54
|
-
const saoDepthLimitedBlurRenderer = new SAODepthLimitedBlurRenderer(scene);
|
|
55
|
-
|
|
56
|
-
this.scene = scene;
|
|
57
|
-
|
|
58
|
-
this._occlusionTester = null; // Lazy-created in #addMarker()
|
|
59
|
-
|
|
60
|
-
this.capabilities = {
|
|
61
|
-
astcSupported: !!getExtension(gl, 'WEBGL_compressed_texture_astc'),
|
|
62
|
-
etc1Supported: true, // WebGL2
|
|
63
|
-
etc2Supported: !!getExtension(gl, 'WEBGL_compressed_texture_etc'),
|
|
64
|
-
dxtSupported: !!getExtension(gl, 'WEBGL_compressed_texture_s3tc'),
|
|
65
|
-
bptcSupported: !!getExtension(gl, 'EXT_texture_compression_bptc'),
|
|
66
|
-
pvrtcSupported: !!(getExtension(gl, 'WEBGL_compressed_texture_pvrtc') || getExtension(gl, 'WEBKIT_WEBGL_compressed_texture_pvrtc'))
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
this.setTransparentEnabled = function (enabled) {
|
|
70
|
-
transparentEnabled = enabled;
|
|
71
|
-
imageDirty = true;
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
this.setEdgesEnabled = function (enabled) {
|
|
75
|
-
edgesEnabled = enabled;
|
|
76
|
-
imageDirty = true;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
this.setSAOEnabled = function (enabled) {
|
|
80
|
-
saoEnabled = enabled;
|
|
81
|
-
imageDirty = true;
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
this.setPBREnabled = function (enabled) {
|
|
85
|
-
pbrEnabled = enabled;
|
|
86
|
-
imageDirty = true;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
this.setColorTextureEnabled = function (enabled) {
|
|
90
|
-
colorTextureEnabled = enabled;
|
|
91
|
-
imageDirty = true;
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
this.needStateSort = function () {
|
|
95
|
-
stateSortDirty = true;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
this.shadowsDirty = function () {
|
|
99
|
-
shadowsDirty = true;
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
this.imageDirty = function () {
|
|
103
|
-
imageDirty = true;
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
this.webglContextLost = function () {
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
this.webglContextRestored = function (gl) {
|
|
110
|
-
|
|
111
|
-
// renderBufferManager.webglContextRestored(gl);
|
|
112
|
-
|
|
113
|
-
saoOcclusionRenderer.init();
|
|
114
|
-
saoDepthLimitedBlurRenderer.init();
|
|
115
|
-
|
|
116
|
-
imageDirty = true;
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Inserts a drawable into this renderer.
|
|
121
|
-
* @private
|
|
122
|
-
*/
|
|
123
|
-
this.addDrawable = function (id, drawable) {
|
|
124
|
-
const type = drawable.type;
|
|
125
|
-
if (!type) {
|
|
126
|
-
console.error("Renderer#addDrawable() : drawable with ID " + id + " has no 'type' - ignoring");
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
let drawableInfo = drawableTypeInfo[type];
|
|
130
|
-
if (!drawableInfo) {
|
|
131
|
-
drawableInfo = {
|
|
132
|
-
type: drawable.type,
|
|
133
|
-
count: 0,
|
|
134
|
-
isStateSortable: drawable.isStateSortable,
|
|
135
|
-
stateSortCompare: drawable.stateSortCompare,
|
|
136
|
-
drawableMap: {},
|
|
137
|
-
drawableListPreCull: [],
|
|
138
|
-
drawableList: []
|
|
139
|
-
};
|
|
140
|
-
drawableTypeInfo[type] = drawableInfo;
|
|
141
|
-
}
|
|
142
|
-
drawableInfo.count++;
|
|
143
|
-
drawableInfo.drawableMap[id] = drawable;
|
|
144
|
-
drawables[id] = drawable;
|
|
145
|
-
drawableListDirty = true;
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Removes a drawable from this renderer.
|
|
150
|
-
* @private
|
|
151
|
-
*/
|
|
152
|
-
this.removeDrawable = function (id) {
|
|
153
|
-
const drawable = drawables[id];
|
|
154
|
-
if (!drawable) {
|
|
155
|
-
console.error("Renderer#removeDrawable() : drawable not found with ID " + id + " - ignoring");
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
const type = drawable.type;
|
|
159
|
-
const drawableInfo = drawableTypeInfo[type];
|
|
160
|
-
if (--drawableInfo.count <= 0) {
|
|
161
|
-
delete drawableTypeInfo[type];
|
|
162
|
-
} else {
|
|
163
|
-
delete drawableInfo.drawableMap[id];
|
|
164
|
-
}
|
|
165
|
-
delete drawables[id];
|
|
166
|
-
drawableListDirty = true;
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Gets a unique pick ID for the given Pickable. A Pickable can be a {@link Mesh} or a {@link PerformanceMesh}.
|
|
171
|
-
* @returns {Number} New pick ID.
|
|
172
|
-
*/
|
|
173
|
-
this.getPickID = function (entity) {
|
|
174
|
-
return pickIDs.addItem(entity);
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Released a pick ID for reuse.
|
|
179
|
-
* @param {Number} pickID Pick ID to release.
|
|
180
|
-
*/
|
|
181
|
-
this.putPickID = function (pickID) {
|
|
182
|
-
pickIDs.removeItem(pickID);
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Clears the canvas.
|
|
187
|
-
* @private
|
|
188
|
-
*/
|
|
189
|
-
this.clear = function (params) {
|
|
190
|
-
params = params || {};
|
|
191
|
-
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
192
|
-
if (canvasTransparent) {
|
|
193
|
-
gl.clearColor(1, 1, 1, 1);
|
|
194
|
-
} else {
|
|
195
|
-
const backgroundColor = scene.canvas.backgroundColorFromAmbientLight ? this.lights.getAmbientColorAndIntensity() : scene.canvas.backgroundColor;
|
|
196
|
-
gl.clearColor(backgroundColor[0], backgroundColor[1], backgroundColor[2], 1.0);
|
|
197
|
-
}
|
|
198
|
-
if (bindOutputFrameBuffer) {
|
|
199
|
-
bindOutputFrameBuffer(params.pass);
|
|
200
|
-
}
|
|
201
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
202
|
-
if (unbindOutputFrameBuffer) {
|
|
203
|
-
unbindOutputFrameBuffer(params.pass);
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Returns true if the next call to render() will draw something
|
|
209
|
-
* @returns {Boolean}
|
|
210
|
-
*/
|
|
211
|
-
this.needsRender = function () {
|
|
212
|
-
const needsRender = (imageDirty || drawableListDirty || stateSortDirty);
|
|
213
|
-
return needsRender;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Renders inserted drawables.
|
|
218
|
-
* @private
|
|
219
|
-
*/
|
|
220
|
-
this.render = function (params) {
|
|
221
|
-
params = params || {};
|
|
222
|
-
if (params.force) {
|
|
223
|
-
imageDirty = true;
|
|
224
|
-
}
|
|
225
|
-
updateDrawlist();
|
|
226
|
-
if (imageDirty) {
|
|
227
|
-
draw(params);
|
|
228
|
-
stats.frame.frameCount++;
|
|
229
|
-
imageDirty = false;
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
function updateDrawlist() { // Prepares state-sorted array of drawables from maps of inserted drawables
|
|
234
|
-
if (drawableListDirty) {
|
|
235
|
-
buildDrawableList();
|
|
236
|
-
drawableListDirty = false;
|
|
237
|
-
stateSortDirty = true;
|
|
238
|
-
}
|
|
239
|
-
if (stateSortDirty) {
|
|
240
|
-
sortDrawableList();
|
|
241
|
-
stateSortDirty = false;
|
|
242
|
-
imageDirty = true;
|
|
243
|
-
}
|
|
244
|
-
if (imageDirty) { // Image is usually dirty because the camera moved
|
|
245
|
-
cullDrawableList();
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
function buildDrawableList() {
|
|
250
|
-
for (let type in drawableTypeInfo) {
|
|
251
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
252
|
-
const drawableInfo = drawableTypeInfo[type];
|
|
253
|
-
const drawableMap = drawableInfo.drawableMap;
|
|
254
|
-
const drawableListPreCull = drawableInfo.drawableListPreCull;
|
|
255
|
-
let lenDrawableList = 0;
|
|
256
|
-
for (let id in drawableMap) {
|
|
257
|
-
if (drawableMap.hasOwnProperty(id)) {
|
|
258
|
-
drawableListPreCull[lenDrawableList++] = drawableMap[id];
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
drawableListPreCull.length = lenDrawableList;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
function sortDrawableList() {
|
|
267
|
-
for (let type in drawableTypeInfo) {
|
|
268
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
269
|
-
const drawableInfo = drawableTypeInfo[type];
|
|
270
|
-
if (drawableInfo.isStateSortable) {
|
|
271
|
-
drawableInfo.drawableListPreCull.sort(drawableInfo.stateSortCompare);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function cullDrawableList() {
|
|
278
|
-
for (let type in drawableTypeInfo) {
|
|
279
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
280
|
-
const drawableInfo = drawableTypeInfo[type];
|
|
281
|
-
const drawableListPreCull = drawableInfo.drawableListPreCull;
|
|
282
|
-
const drawableList = drawableInfo.drawableList;
|
|
283
|
-
let lenDrawableList = 0;
|
|
284
|
-
for (let i = 0, len = drawableListPreCull.length; i < len; i++) {
|
|
285
|
-
const drawable = drawableListPreCull[i];
|
|
286
|
-
drawable.rebuildRenderFlags();
|
|
287
|
-
if (!drawable.renderFlags.culled) {
|
|
288
|
-
drawableList[lenDrawableList++] = drawable;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
drawableList.length = lenDrawableList;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
function draw(params) {
|
|
297
|
-
|
|
298
|
-
const sao = scene.sao;
|
|
299
|
-
|
|
300
|
-
if (saoEnabled && sao.possible) {
|
|
301
|
-
drawSAOBuffers(params);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
drawShadowMaps();
|
|
305
|
-
|
|
306
|
-
drawColor(params);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
function drawSAOBuffers(params) {
|
|
310
|
-
|
|
311
|
-
const sao = scene.sao;
|
|
312
|
-
|
|
313
|
-
// Render depth buffer
|
|
314
|
-
|
|
315
|
-
const saoDepthRenderBuffer = renderBufferManager.getRenderBuffer("saoDepth", {
|
|
316
|
-
depthTexture: true
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
saoDepthRenderBuffer.bind();
|
|
320
|
-
saoDepthRenderBuffer.clear();
|
|
321
|
-
drawDepth(params);
|
|
322
|
-
saoDepthRenderBuffer.unbind();
|
|
323
|
-
|
|
324
|
-
// Render occlusion buffer
|
|
325
|
-
|
|
326
|
-
const occlusionRenderBuffer1 = renderBufferManager.getRenderBuffer("saoOcclusion");
|
|
327
|
-
|
|
328
|
-
occlusionRenderBuffer1.bind();
|
|
329
|
-
occlusionRenderBuffer1.clear();
|
|
330
|
-
saoOcclusionRenderer.render(saoDepthRenderBuffer);
|
|
331
|
-
occlusionRenderBuffer1.unbind();
|
|
332
|
-
|
|
333
|
-
if (sao.blur) {
|
|
334
|
-
|
|
335
|
-
// Horizontally blur occlusion buffer 1 into occlusion buffer 2
|
|
336
|
-
|
|
337
|
-
const occlusionRenderBuffer2 = renderBufferManager.getRenderBuffer("saoOcclusion2");
|
|
338
|
-
|
|
339
|
-
occlusionRenderBuffer2.bind();
|
|
340
|
-
occlusionRenderBuffer2.clear();
|
|
341
|
-
saoDepthLimitedBlurRenderer.render(saoDepthRenderBuffer, occlusionRenderBuffer1, 0);
|
|
342
|
-
occlusionRenderBuffer2.unbind();
|
|
343
|
-
|
|
344
|
-
// Vertically blur occlusion buffer 2 back into occlusion buffer 1
|
|
345
|
-
|
|
346
|
-
occlusionRenderBuffer1.bind();
|
|
347
|
-
occlusionRenderBuffer1.clear();
|
|
348
|
-
saoDepthLimitedBlurRenderer.render(saoDepthRenderBuffer, occlusionRenderBuffer2, 1);
|
|
349
|
-
occlusionRenderBuffer1.unbind();
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
function drawDepth(params) {
|
|
354
|
-
|
|
355
|
-
frameCtx.reset();
|
|
356
|
-
frameCtx.pass = params.pass;
|
|
357
|
-
|
|
358
|
-
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
359
|
-
|
|
360
|
-
gl.clearColor(0, 0, 0, 0);
|
|
361
|
-
gl.enable(gl.DEPTH_TEST);
|
|
362
|
-
gl.frontFace(gl.CCW);
|
|
363
|
-
gl.enable(gl.CULL_FACE);
|
|
364
|
-
gl.depthMask(true);
|
|
365
|
-
|
|
366
|
-
if (params.clear !== false) {
|
|
367
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
for (let type in drawableTypeInfo) {
|
|
371
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
372
|
-
|
|
373
|
-
const drawableInfo = drawableTypeInfo[type];
|
|
374
|
-
const drawableList = drawableInfo.drawableList;
|
|
375
|
-
|
|
376
|
-
for (let i = 0, len = drawableList.length; i < len; i++) {
|
|
377
|
-
|
|
378
|
-
const drawable = drawableList[i];
|
|
379
|
-
|
|
380
|
-
if (drawable.culled === true || drawable.visible === false || !drawable.drawDepth || !drawable.saoEnabled) {
|
|
381
|
-
continue;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
if (drawable.renderFlags.colorOpaque) {
|
|
385
|
-
drawable.drawDepth(frameCtx);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// const numVertexAttribs = WEBGL_INFO.MAX_VERTEX_ATTRIBS; // Fixes https://github.com/xeokit/xeokit-sdk/issues/174
|
|
392
|
-
// for (let ii = 0; ii < numVertexAttribs; ii++) {
|
|
393
|
-
// gl.disableVertexAttribArray(ii);
|
|
394
|
-
// }
|
|
395
|
-
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
function drawShadowMaps() {
|
|
399
|
-
|
|
400
|
-
let lights = scene._lightsState.lights;
|
|
401
|
-
|
|
402
|
-
for (let i = 0, len = lights.length; i < len; i++) {
|
|
403
|
-
const light = lights[i];
|
|
404
|
-
if (!light.castsShadow) {
|
|
405
|
-
continue;
|
|
406
|
-
}
|
|
407
|
-
drawShadowMap(light);
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// const numVertexAttribs = WEBGL_INFO.MAX_VERTEX_ATTRIBS; // Fixes https://github.com/xeokit/xeokit-sdk/issues/174
|
|
411
|
-
// for (let ii = 0; ii < numVertexAttribs; ii++) {
|
|
412
|
-
// gl.disableVertexAttribArray(ii);
|
|
413
|
-
// }
|
|
414
|
-
//
|
|
415
|
-
shadowsDirty = false;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
function drawShadowMap(light) {
|
|
419
|
-
|
|
420
|
-
const castsShadow = light.castsShadow;
|
|
421
|
-
|
|
422
|
-
if (!castsShadow) {
|
|
423
|
-
return;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
const shadowRenderBuf = light.getShadowRenderBuf();
|
|
427
|
-
|
|
428
|
-
if (!shadowRenderBuf) {
|
|
429
|
-
return;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
shadowRenderBuf.bind();
|
|
433
|
-
|
|
434
|
-
frameCtx.reset();
|
|
435
|
-
|
|
436
|
-
frameCtx.backfaces = true;
|
|
437
|
-
frameCtx.frontface = true;
|
|
438
|
-
frameCtx.shadowViewMatrix = light.getShadowViewMatrix();
|
|
439
|
-
frameCtx.shadowProjMatrix = light.getShadowProjMatrix();
|
|
440
|
-
|
|
441
|
-
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
442
|
-
|
|
443
|
-
gl.clearColor(0, 0, 0, 1);
|
|
444
|
-
gl.enable(gl.DEPTH_TEST);
|
|
445
|
-
gl.disable(gl.BLEND);
|
|
446
|
-
|
|
447
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
448
|
-
|
|
449
|
-
for (let type in drawableTypeInfo) {
|
|
450
|
-
|
|
451
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
452
|
-
|
|
453
|
-
const drawableInfo = drawableTypeInfo[type];
|
|
454
|
-
const drawableList = drawableInfo.drawableList;
|
|
455
|
-
|
|
456
|
-
for (let i = 0, len = drawableList.length; i < len; i++) {
|
|
457
|
-
|
|
458
|
-
const drawable = drawableList[i];
|
|
459
|
-
|
|
460
|
-
if (drawable.visible === false || !drawable.castsShadow || !drawable.drawShadow) {
|
|
461
|
-
continue;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
if (drawable.renderFlags.colorOpaque) { // Transparent objects don't cast shadows (yet)
|
|
465
|
-
drawable.drawShadow(frameCtx);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
shadowRenderBuf.unbind();
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
function drawColor(params) {
|
|
475
|
-
|
|
476
|
-
const normalDrawSAOBin = [];
|
|
477
|
-
const normalEdgesOpaqueBin = [];
|
|
478
|
-
const normalFillTransparentBin = [];
|
|
479
|
-
const normalEdgesTransparentBin = [];
|
|
480
|
-
|
|
481
|
-
const xrayedFillOpaqueBin = [];
|
|
482
|
-
const xrayEdgesOpaqueBin = [];
|
|
483
|
-
const xrayedFillTransparentBin = [];
|
|
484
|
-
const xrayEdgesTransparentBin = [];
|
|
485
|
-
|
|
486
|
-
const highlightedFillOpaqueBin = [];
|
|
487
|
-
const highlightedEdgesOpaqueBin = [];
|
|
488
|
-
const highlightedFillTransparentBin = [];
|
|
489
|
-
const highlightedEdgesTransparentBin = [];
|
|
490
|
-
|
|
491
|
-
const selectedFillOpaqueBin = [];
|
|
492
|
-
const selectedEdgesOpaqueBin = [];
|
|
493
|
-
const selectedFillTransparentBin = [];
|
|
494
|
-
const selectedEdgesTransparentBin = [];
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
const ambientColorAndIntensity = scene._lightsState.getAmbientColorAndIntensity();
|
|
498
|
-
|
|
499
|
-
frameCtx.reset();
|
|
500
|
-
frameCtx.pass = params.pass;
|
|
501
|
-
frameCtx.withSAO = false;
|
|
502
|
-
frameCtx.pbrEnabled = pbrEnabled && !!scene.pbrEnabled;
|
|
503
|
-
frameCtx.colorTextureEnabled = colorTextureEnabled && !!scene.colorTextureEnabled;
|
|
504
|
-
|
|
505
|
-
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
506
|
-
|
|
507
|
-
if (canvasTransparent) {
|
|
508
|
-
gl.clearColor(0, 0, 0, 0);
|
|
509
|
-
} else {
|
|
510
|
-
const backgroundColor = scene.canvas.backgroundColorFromAmbientLight ? ambientColorAndIntensity : scene.canvas.backgroundColor;
|
|
511
|
-
gl.clearColor(backgroundColor[0], backgroundColor[1], backgroundColor[2], 1.0);
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
gl.enable(gl.DEPTH_TEST);
|
|
515
|
-
gl.frontFace(gl.CCW);
|
|
516
|
-
gl.enable(gl.CULL_FACE);
|
|
517
|
-
gl.depthMask(true);
|
|
518
|
-
gl.lineWidth(1);
|
|
519
|
-
|
|
520
|
-
frameCtx.lineWidth = 1;
|
|
521
|
-
|
|
522
|
-
const saoPossible = scene.sao.possible;
|
|
523
|
-
|
|
524
|
-
if (saoEnabled && saoPossible) {
|
|
525
|
-
const occlusionRenderBuffer1 = renderBufferManager.getRenderBuffer("saoOcclusion");
|
|
526
|
-
frameCtx.occlusionTexture = occlusionRenderBuffer1 ? occlusionRenderBuffer1.getTexture() : null;
|
|
527
|
-
} else {
|
|
528
|
-
frameCtx.occlusionTexture = null;
|
|
529
|
-
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
let i;
|
|
533
|
-
let len;
|
|
534
|
-
let drawable;
|
|
535
|
-
|
|
536
|
-
const startTime = Date.now();
|
|
537
|
-
|
|
538
|
-
if (bindOutputFrameBuffer) {
|
|
539
|
-
bindOutputFrameBuffer(params.pass);
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
if (params.clear !== false) {
|
|
543
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
let normalDrawSAOBinLen = 0;
|
|
547
|
-
let normalEdgesOpaqueBinLen = 0;
|
|
548
|
-
let normalFillTransparentBinLen = 0;
|
|
549
|
-
let normalEdgesTransparentBinLen = 0;
|
|
550
|
-
|
|
551
|
-
let xrayedFillOpaqueBinLen = 0;
|
|
552
|
-
let xrayEdgesOpaqueBinLen = 0;
|
|
553
|
-
let xrayedFillTransparentBinLen = 0;
|
|
554
|
-
let xrayEdgesTransparentBinLen = 0;
|
|
555
|
-
|
|
556
|
-
let highlightedFillOpaqueBinLen = 0;
|
|
557
|
-
let highlightedEdgesOpaqueBinLen = 0;
|
|
558
|
-
let highlightedFillTransparentBinLen = 0;
|
|
559
|
-
let highlightedEdgesTransparentBinLen = 0;
|
|
560
|
-
|
|
561
|
-
let selectedFillOpaqueBinLen = 0;
|
|
562
|
-
let selectedEdgesOpaqueBinLen = 0;
|
|
563
|
-
let selectedFillTransparentBinLen = 0;
|
|
564
|
-
let selectedEdgesTransparentBinLen = 0;
|
|
565
|
-
|
|
566
|
-
//------------------------------------------------------------------------------------------------------
|
|
567
|
-
// Render normal opaque solids, defer others to bins to render after
|
|
568
|
-
//------------------------------------------------------------------------------------------------------
|
|
569
|
-
|
|
570
|
-
for (let type in drawableTypeInfo) {
|
|
571
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
572
|
-
|
|
573
|
-
const drawableInfo = drawableTypeInfo[type];
|
|
574
|
-
const drawableList = drawableInfo.drawableList;
|
|
575
|
-
|
|
576
|
-
for (i = 0, len = drawableList.length; i < len; i++) {
|
|
577
|
-
|
|
578
|
-
drawable = drawableList[i];
|
|
579
|
-
|
|
580
|
-
if (drawable.culled === true || drawable.visible === false) {
|
|
581
|
-
continue;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
const renderFlags = drawable.renderFlags;
|
|
585
|
-
|
|
586
|
-
if (renderFlags.colorOpaque) {
|
|
587
|
-
if (saoEnabled && saoPossible && drawable.saoEnabled) {
|
|
588
|
-
normalDrawSAOBin[normalDrawSAOBinLen++] = drawable;
|
|
589
|
-
} else {
|
|
590
|
-
drawable.drawColorOpaque(frameCtx);
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
if (transparentEnabled) {
|
|
595
|
-
if (renderFlags.colorTransparent) {
|
|
596
|
-
normalFillTransparentBin[normalFillTransparentBinLen++] = drawable;
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
if (renderFlags.xrayedSilhouetteTransparent) {
|
|
601
|
-
xrayedFillTransparentBin[xrayedFillTransparentBinLen++] = drawable;
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
if (renderFlags.xrayedSilhouetteOpaque) {
|
|
605
|
-
xrayedFillOpaqueBin[xrayedFillOpaqueBinLen++] = drawable;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
if (renderFlags.highlightedSilhouetteTransparent) {
|
|
609
|
-
highlightedFillTransparentBin[highlightedFillTransparentBinLen++] = drawable;
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
if (renderFlags.highlightedSilhouetteOpaque) {
|
|
613
|
-
highlightedFillOpaqueBin[highlightedFillOpaqueBinLen++] = drawable;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
if (renderFlags.selectedSilhouetteTransparent) {
|
|
617
|
-
selectedFillTransparentBin[selectedFillTransparentBinLen++] = drawable;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
if (renderFlags.selectedSilhouetteOpaque) {
|
|
621
|
-
selectedFillOpaqueBin[selectedFillOpaqueBinLen++] = drawable;
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
if (edgesEnabled) {
|
|
625
|
-
if (renderFlags.edgesOpaque) {
|
|
626
|
-
normalEdgesOpaqueBin[normalEdgesOpaqueBinLen++] = drawable;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
if (renderFlags.edgesTransparent) {
|
|
630
|
-
normalEdgesTransparentBin[normalEdgesTransparentBinLen++] = drawable;
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
if (renderFlags.selectedEdgesTransparent) {
|
|
634
|
-
selectedEdgesTransparentBin[selectedEdgesTransparentBinLen++] = drawable;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
if (renderFlags.selectedEdgesOpaque) {
|
|
638
|
-
selectedEdgesOpaqueBin[selectedEdgesOpaqueBinLen++] = drawable;
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
if (renderFlags.xrayedEdgesTransparent) {
|
|
642
|
-
xrayEdgesTransparentBin[xrayEdgesTransparentBinLen++] = drawable;
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
if (renderFlags.xrayedEdgesOpaque) {
|
|
646
|
-
xrayEdgesOpaqueBin[xrayEdgesOpaqueBinLen++] = drawable;
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
if (renderFlags.highlightedEdgesTransparent) {
|
|
650
|
-
highlightedEdgesTransparentBin[highlightedEdgesTransparentBinLen++] = drawable;
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
if (renderFlags.highlightedEdgesOpaque) {
|
|
654
|
-
highlightedEdgesOpaqueBin[highlightedEdgesOpaqueBinLen++] = drawable;
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
//------------------------------------------------------------------------------------------------------
|
|
661
|
-
// Render deferred bins
|
|
662
|
-
//------------------------------------------------------------------------------------------------------
|
|
663
|
-
|
|
664
|
-
// Opaque color with SAO
|
|
665
|
-
|
|
666
|
-
if (normalDrawSAOBinLen > 0) {
|
|
667
|
-
frameCtx.withSAO = true;
|
|
668
|
-
for (i = 0; i < normalDrawSAOBinLen; i++) {
|
|
669
|
-
normalDrawSAOBin[i].drawColorOpaque(frameCtx);
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
// Opaque edges
|
|
674
|
-
|
|
675
|
-
if (normalEdgesOpaqueBinLen > 0) {
|
|
676
|
-
for (i = 0; i < normalEdgesOpaqueBinLen; i++) {
|
|
677
|
-
normalEdgesOpaqueBin[i].drawEdgesColorOpaque(frameCtx);
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
// Opaque X-ray fill
|
|
682
|
-
|
|
683
|
-
if (xrayedFillOpaqueBinLen > 0) {
|
|
684
|
-
for (i = 0; i < xrayedFillOpaqueBinLen; i++) {
|
|
685
|
-
xrayedFillOpaqueBin[i].drawSilhouetteXRayed(frameCtx);
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
// Opaque X-ray edges
|
|
690
|
-
|
|
691
|
-
if (xrayEdgesOpaqueBinLen > 0) {
|
|
692
|
-
for (i = 0; i < xrayEdgesOpaqueBinLen; i++) {
|
|
693
|
-
xrayEdgesOpaqueBin[i].drawEdgesXRayed(frameCtx);
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
// Transparent
|
|
698
|
-
|
|
699
|
-
if (xrayedFillTransparentBinLen > 0 || xrayEdgesTransparentBinLen > 0 || normalFillTransparentBinLen > 0 || normalEdgesTransparentBinLen > 0) {
|
|
700
|
-
gl.enable(gl.CULL_FACE);
|
|
701
|
-
gl.enable(gl.BLEND);
|
|
702
|
-
if (canvasTransparent) {
|
|
703
|
-
gl.blendEquation(gl.FUNC_ADD);
|
|
704
|
-
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
705
|
-
} else {
|
|
706
|
-
gl.blendEquation(gl.FUNC_ADD);
|
|
707
|
-
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
708
|
-
}
|
|
709
|
-
frameCtx.backfaces = false;
|
|
710
|
-
if (!alphaDepthMask) {
|
|
711
|
-
gl.depthMask(false);
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
// Transparent color edges
|
|
715
|
-
|
|
716
|
-
if (normalFillTransparentBinLen > 0 || normalEdgesTransparentBinLen > 0) {
|
|
717
|
-
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
718
|
-
}
|
|
719
|
-
if (normalEdgesTransparentBinLen > 0) {
|
|
720
|
-
for (i = 0; i < normalEdgesTransparentBinLen; i++) {
|
|
721
|
-
drawable = normalEdgesTransparentBin[i];
|
|
722
|
-
drawable.drawEdgesColorTransparent(frameCtx);
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
// Transparent color fill
|
|
727
|
-
|
|
728
|
-
if (normalFillTransparentBinLen > 0) {
|
|
729
|
-
for (i = 0; i < normalFillTransparentBinLen; i++) {
|
|
730
|
-
drawable = normalFillTransparentBin[i];
|
|
731
|
-
drawable.drawColorTransparent(frameCtx);
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
// Transparent X-ray edges
|
|
736
|
-
|
|
737
|
-
if (xrayEdgesTransparentBinLen > 0) {
|
|
738
|
-
for (i = 0; i < xrayEdgesTransparentBinLen; i++) {
|
|
739
|
-
xrayEdgesTransparentBin[i].drawEdgesXRayed(frameCtx);
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
// Transparent X-ray fill
|
|
744
|
-
|
|
745
|
-
if (xrayedFillTransparentBinLen > 0) {
|
|
746
|
-
for (i = 0; i < xrayedFillTransparentBinLen; i++) {
|
|
747
|
-
xrayedFillTransparentBin[i].drawSilhouetteXRayed(frameCtx);
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
gl.disable(gl.BLEND);
|
|
752
|
-
if (!alphaDepthMask) {
|
|
753
|
-
gl.depthMask(true);
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
// Opaque highlight
|
|
758
|
-
|
|
759
|
-
if (highlightedFillOpaqueBinLen > 0 || highlightedEdgesOpaqueBinLen > 0) {
|
|
760
|
-
frameCtx.lastProgramId = null;
|
|
761
|
-
if (scene.highlightMaterial.glowThrough) {
|
|
762
|
-
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
// Opaque highlighted edges
|
|
766
|
-
|
|
767
|
-
if (highlightedEdgesOpaqueBinLen > 0) {
|
|
768
|
-
for (i = 0; i < highlightedEdgesOpaqueBinLen; i++) {
|
|
769
|
-
highlightedEdgesOpaqueBin[i].drawEdgesHighlighted(frameCtx);
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
// Opaque highlighted fill
|
|
774
|
-
|
|
775
|
-
if (highlightedFillOpaqueBinLen > 0) {
|
|
776
|
-
for (i = 0; i < highlightedFillOpaqueBinLen; i++) {
|
|
777
|
-
highlightedFillOpaqueBin[i].drawSilhouetteHighlighted(frameCtx);
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
// Highlighted transparent
|
|
783
|
-
|
|
784
|
-
if (highlightedFillTransparentBinLen > 0 || highlightedEdgesTransparentBinLen > 0 || highlightedFillOpaqueBinLen > 0) {
|
|
785
|
-
frameCtx.lastProgramId = null;
|
|
786
|
-
if (scene.selectedMaterial.glowThrough) {
|
|
787
|
-
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
788
|
-
}
|
|
789
|
-
gl.enable(gl.BLEND);
|
|
790
|
-
if (canvasTransparent) {
|
|
791
|
-
gl.blendEquation(gl.FUNC_ADD);
|
|
792
|
-
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
793
|
-
} else {
|
|
794
|
-
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
795
|
-
}
|
|
796
|
-
gl.enable(gl.CULL_FACE);
|
|
797
|
-
|
|
798
|
-
// Highlighted transparent edges
|
|
799
|
-
|
|
800
|
-
if (highlightedEdgesTransparentBinLen > 0) {
|
|
801
|
-
for (i = 0; i < highlightedEdgesTransparentBinLen; i++) {
|
|
802
|
-
highlightedEdgesTransparentBin[i].drawEdgesHighlighted(frameCtx);
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
// Highlighted transparent fill
|
|
807
|
-
|
|
808
|
-
if (highlightedFillTransparentBinLen > 0) {
|
|
809
|
-
for (i = 0; i < highlightedFillTransparentBinLen; i++) {
|
|
810
|
-
highlightedFillTransparentBin[i].drawSilhouetteHighlighted(frameCtx);
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
gl.disable(gl.BLEND);
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
// Selected opaque
|
|
817
|
-
|
|
818
|
-
if (selectedFillOpaqueBinLen > 0 || selectedEdgesOpaqueBinLen > 0) {
|
|
819
|
-
frameCtx.lastProgramId = null;
|
|
820
|
-
if (scene.selectedMaterial.glowThrough) {
|
|
821
|
-
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
// Selected opaque fill
|
|
825
|
-
|
|
826
|
-
if (selectedEdgesOpaqueBinLen > 0) {
|
|
827
|
-
for (i = 0; i < selectedEdgesOpaqueBinLen; i++) {
|
|
828
|
-
selectedEdgesOpaqueBin[i].drawEdgesSelected(frameCtx);
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
// Selected opaque edges
|
|
833
|
-
|
|
834
|
-
if (selectedFillOpaqueBinLen > 0) {
|
|
835
|
-
for (i = 0; i < selectedFillOpaqueBinLen; i++) {
|
|
836
|
-
selectedFillOpaqueBin[i].drawSilhouetteSelected(frameCtx);
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
// Selected transparent
|
|
842
|
-
|
|
843
|
-
if (selectedFillTransparentBinLen > 0 || selectedEdgesTransparentBinLen > 0) {
|
|
844
|
-
frameCtx.lastProgramId = null;
|
|
845
|
-
if (scene.selectedMaterial.glowThrough) {
|
|
846
|
-
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
847
|
-
}
|
|
848
|
-
gl.enable(gl.CULL_FACE);
|
|
849
|
-
gl.enable(gl.BLEND);
|
|
850
|
-
if (canvasTransparent) {
|
|
851
|
-
gl.blendEquation(gl.FUNC_ADD);
|
|
852
|
-
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
853
|
-
} else {
|
|
854
|
-
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// Selected transparent edges
|
|
858
|
-
|
|
859
|
-
if (selectedEdgesTransparentBinLen > 0) {
|
|
860
|
-
for (i = 0; i < selectedEdgesTransparentBinLen; i++) {
|
|
861
|
-
selectedEdgesTransparentBin[i].drawEdgesSelected(frameCtx);
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
// Selected transparent fill
|
|
866
|
-
|
|
867
|
-
if (selectedFillTransparentBinLen > 0) {
|
|
868
|
-
for (i = 0; i < selectedFillTransparentBinLen; i++) {
|
|
869
|
-
selectedFillTransparentBin[i].drawSilhouetteSelected(frameCtx);
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
gl.disable(gl.BLEND);
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
const endTime = Date.now();
|
|
876
|
-
const frameStats = stats.frame;
|
|
877
|
-
|
|
878
|
-
frameStats.renderTime = (endTime - startTime) / 1000.0;
|
|
879
|
-
frameStats.drawElements = frameCtx.drawElements;
|
|
880
|
-
frameStats.drawArrays = frameCtx.drawArrays;
|
|
881
|
-
frameStats.useProgram = frameCtx.useProgram;
|
|
882
|
-
frameStats.bindTexture = frameCtx.bindTexture;
|
|
883
|
-
frameStats.bindArray = frameCtx.bindArray;
|
|
884
|
-
|
|
885
|
-
const numTextureUnits = WEBGL_INFO.MAX_TEXTURE_IMAGE_UNITS;
|
|
886
|
-
for (let ii = 0; ii < numTextureUnits; ii++) {
|
|
887
|
-
gl.activeTexture(gl.TEXTURE0 + ii);
|
|
888
|
-
}
|
|
889
|
-
gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
|
|
890
|
-
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
891
|
-
|
|
892
|
-
const numVertexAttribs = WEBGL_INFO.MAX_VERTEX_ATTRIBS; // Fixes https://github.com/xeokit/xeokit-sdk/issues/174
|
|
893
|
-
for (let ii = 0; ii < numVertexAttribs; ii++) {
|
|
894
|
-
gl.disableVertexAttribArray(ii);
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
if (unbindOutputFrameBuffer) {
|
|
898
|
-
unbindOutputFrameBuffer(params.pass);
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
/**
|
|
903
|
-
* Picks an Entity.
|
|
904
|
-
* @private
|
|
905
|
-
*/
|
|
906
|
-
this.pick = (function () {
|
|
907
|
-
|
|
908
|
-
const tempVec3a = math.vec3();
|
|
909
|
-
const tempMat4a = math.mat4();
|
|
910
|
-
const tempMat4b = math.mat4();
|
|
911
|
-
|
|
912
|
-
const randomVec3 = math.vec3();
|
|
913
|
-
const up = math.vec3([0, 1, 0]);
|
|
914
|
-
const _pickResult = new PickResult();
|
|
915
|
-
|
|
916
|
-
const nearAndFar = math.vec2();
|
|
917
|
-
|
|
918
|
-
const canvasPos = math.vec3();
|
|
919
|
-
|
|
920
|
-
const worldRayOrigin = math.vec3();
|
|
921
|
-
const worldRayDir = math.vec3();
|
|
922
|
-
const worldSurfacePos = math.vec3();
|
|
923
|
-
const worldSurfaceNormal = math.vec3();
|
|
924
|
-
|
|
925
|
-
return function (params, pickResult = _pickResult) {
|
|
926
|
-
|
|
927
|
-
pickResult.reset();
|
|
928
|
-
|
|
929
|
-
updateDrawlist();
|
|
930
|
-
|
|
931
|
-
let look;
|
|
932
|
-
let pickViewMatrix = null;
|
|
933
|
-
let pickProjMatrix = null;
|
|
934
|
-
|
|
935
|
-
pickResult.pickSurface = params.pickSurface;
|
|
936
|
-
|
|
937
|
-
if (params.canvasPos) {
|
|
938
|
-
|
|
939
|
-
canvasPos[0] = params.canvasPos[0];
|
|
940
|
-
canvasPos[1] = params.canvasPos[1];
|
|
941
|
-
|
|
942
|
-
pickViewMatrix = scene.camera.viewMatrix;
|
|
943
|
-
pickProjMatrix = scene.camera.projMatrix;
|
|
944
|
-
|
|
945
|
-
pickResult.canvasPos = params.canvasPos;
|
|
946
|
-
|
|
947
|
-
} else {
|
|
948
|
-
|
|
949
|
-
// Picking with arbitrary World-space ray
|
|
950
|
-
// Align camera along ray and fire ray through center of canvas
|
|
951
|
-
|
|
952
|
-
const pickFrustumMatrix = math.frustumMat4(-1, 1, -1, 1, 0.01, scene.camera.project.far, tempMat4a);
|
|
953
|
-
|
|
954
|
-
if (params.matrix) {
|
|
955
|
-
|
|
956
|
-
pickViewMatrix = params.matrix;
|
|
957
|
-
pickProjMatrix = pickFrustumMatrix;
|
|
958
|
-
|
|
959
|
-
} else {
|
|
960
|
-
|
|
961
|
-
worldRayOrigin.set(params.origin || [0, 0, 0]);
|
|
962
|
-
worldRayDir.set(params.direction || [0, 0, 1]);
|
|
963
|
-
|
|
964
|
-
look = math.addVec3(worldRayOrigin, worldRayDir, tempVec3a);
|
|
965
|
-
|
|
966
|
-
randomVec3[0] = Math.random();
|
|
967
|
-
randomVec3[1] = Math.random();
|
|
968
|
-
randomVec3[2] = Math.random();
|
|
969
|
-
|
|
970
|
-
math.normalizeVec3(randomVec3);
|
|
971
|
-
math.cross3Vec3(worldRayDir, randomVec3, up);
|
|
972
|
-
|
|
973
|
-
pickViewMatrix = math.lookAtMat4v(worldRayOrigin, look, up, tempMat4b);
|
|
974
|
-
pickProjMatrix = pickFrustumMatrix;
|
|
975
|
-
|
|
976
|
-
pickResult.origin = worldRayOrigin;
|
|
977
|
-
pickResult.direction = worldRayDir;
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
canvasPos[0] = canvas.clientWidth * 0.5;
|
|
981
|
-
canvasPos[1] = canvas.clientHeight * 0.5;
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
for (let type in drawableTypeInfo) {
|
|
985
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
986
|
-
const drawableList = drawableTypeInfo[type].drawableList;
|
|
987
|
-
for (let i = 0, len = drawableList.length; i < len; i++) {
|
|
988
|
-
const drawable = drawableList[i];
|
|
989
|
-
if (drawable.setPickMatrices) { // Eg. SceneModel, which needs pre-loading into texture
|
|
990
|
-
drawable.setPickMatrices(pickViewMatrix, pickProjMatrix);
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
const pickBuffer = renderBufferManager.getRenderBuffer("pick");
|
|
997
|
-
|
|
998
|
-
pickBuffer.bind();
|
|
999
|
-
|
|
1000
|
-
const pickable = gpuPickPickable(pickBuffer, canvasPos, pickViewMatrix, pickProjMatrix, params, pickResult);
|
|
1001
|
-
|
|
1002
|
-
if (!pickable) {
|
|
1003
|
-
pickBuffer.unbind();
|
|
1004
|
-
return null;
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
const pickedEntity = (pickable.delegatePickedEntity) ? pickable.delegatePickedEntity() : pickable;
|
|
1008
|
-
|
|
1009
|
-
if (!pickedEntity) {
|
|
1010
|
-
pickBuffer.unbind();
|
|
1011
|
-
return null;
|
|
1012
|
-
}
|
|
1013
|
-
|
|
1014
|
-
if (params.pickSurface) {
|
|
1015
|
-
|
|
1016
|
-
// GPU-based ray-picking
|
|
1017
|
-
|
|
1018
|
-
if (pickable.canPickTriangle && pickable.canPickTriangle()) {
|
|
1019
|
-
|
|
1020
|
-
gpuPickTriangle(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, pickResult);
|
|
1021
|
-
|
|
1022
|
-
pickable.pickTriangleSurface(pickViewMatrix, pickProjMatrix, pickResult);
|
|
1023
|
-
|
|
1024
|
-
pickResult.pickSurfacePrecision = false;
|
|
1025
|
-
|
|
1026
|
-
} else {
|
|
1027
|
-
|
|
1028
|
-
if (pickable.canPickWorldPos && pickable.canPickWorldPos()) {
|
|
1029
|
-
|
|
1030
|
-
nearAndFar[0] = scene.camera.project.near;
|
|
1031
|
-
nearAndFar[1] = scene.camera.project.far;
|
|
1032
|
-
|
|
1033
|
-
gpuPickWorldPos(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, nearAndFar, pickResult);
|
|
1034
|
-
|
|
1035
|
-
if (params.pickSurfaceNormal !== false) {
|
|
1036
|
-
gpuPickWorldNormal(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, pickResult);
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
pickResult.pickSurfacePrecision = false;
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
pickBuffer.unbind();
|
|
1044
|
-
pickResult.entity = pickedEntity;
|
|
1045
|
-
return pickResult;
|
|
1046
|
-
};
|
|
1047
|
-
})();
|
|
1048
|
-
|
|
1049
|
-
function gpuPickPickable(pickBuffer, canvasPos, pickViewMatrix, pickProjMatrix, params, pickResult) {
|
|
1050
|
-
|
|
1051
|
-
frameCtx.reset();
|
|
1052
|
-
frameCtx.backfaces = true;
|
|
1053
|
-
frameCtx.frontface = true; // "ccw"
|
|
1054
|
-
frameCtx.pickOrigin = pickResult.origin;
|
|
1055
|
-
frameCtx.pickViewMatrix = pickViewMatrix;
|
|
1056
|
-
frameCtx.pickProjMatrix = pickProjMatrix;
|
|
1057
|
-
frameCtx.pickInvisible = !!params.pickInvisible;
|
|
1058
|
-
|
|
1059
|
-
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
1060
|
-
|
|
1061
|
-
gl.clearColor(0, 0, 0, 0);
|
|
1062
|
-
gl.depthMask(true);
|
|
1063
|
-
gl.enable(gl.DEPTH_TEST);
|
|
1064
|
-
gl.disable(gl.CULL_FACE);
|
|
1065
|
-
gl.disable(gl.BLEND);
|
|
1066
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1067
|
-
|
|
1068
|
-
const includeEntityIds = params.includeEntityIds;
|
|
1069
|
-
const excludeEntityIds = params.excludeEntityIds;
|
|
1070
|
-
|
|
1071
|
-
for (let type in drawableTypeInfo) {
|
|
1072
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
1073
|
-
|
|
1074
|
-
const drawableInfo = drawableTypeInfo[type];
|
|
1075
|
-
const drawableList = drawableInfo.drawableList;
|
|
1076
|
-
|
|
1077
|
-
for (let i = 0, len = drawableList.length; i < len; i++) {
|
|
1078
|
-
|
|
1079
|
-
const drawable = drawableList[i];
|
|
1080
|
-
|
|
1081
|
-
if (!drawable.drawPickMesh || (params.pickInvisible !== true && drawable.visible === false) || drawable.pickable === false) {
|
|
1082
|
-
continue;
|
|
1083
|
-
}
|
|
1084
|
-
if (includeEntityIds && !includeEntityIds[drawable.id]) { // TODO: push this logic into drawable
|
|
1085
|
-
continue;
|
|
1086
|
-
}
|
|
1087
|
-
if (excludeEntityIds && excludeEntityIds[drawable.id]) {
|
|
1088
|
-
continue;
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
drawable.drawPickMesh(frameCtx);
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
const resolutionScale = scene.canvas.resolutionScale;
|
|
1096
|
-
const pix = pickBuffer.read(Math.round(canvasPos[0] * resolutionScale), Math.round(canvasPos[1] * resolutionScale));
|
|
1097
|
-
let pickID = pix[0] + (pix[1] * 256) + (pix[2] * 256 * 256) + (pix[3] * 256 * 256 * 256);
|
|
1098
|
-
|
|
1099
|
-
if (pickID < 0) {
|
|
1100
|
-
return;
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
const pickable = pickIDs.items[pickID];
|
|
1104
|
-
|
|
1105
|
-
return pickable;
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
function gpuPickTriangle(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, pickResult) {
|
|
1109
|
-
|
|
1110
|
-
if (!pickable.drawPickTriangles) {
|
|
1111
|
-
return;
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
frameCtx.reset();
|
|
1115
|
-
frameCtx.backfaces = true;
|
|
1116
|
-
frameCtx.frontface = true; // "ccw"
|
|
1117
|
-
frameCtx.pickOrigin = pickResult.origin;
|
|
1118
|
-
frameCtx.pickViewMatrix = pickViewMatrix; // Can be null
|
|
1119
|
-
frameCtx.pickProjMatrix = pickProjMatrix; // Can be null
|
|
1120
|
-
// frameCtx.pickInvisible = !!params.pickInvisible;
|
|
1121
|
-
|
|
1122
|
-
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
1123
|
-
|
|
1124
|
-
gl.clearColor(0, 0, 0, 0);
|
|
1125
|
-
gl.enable(gl.DEPTH_TEST);
|
|
1126
|
-
gl.disable(gl.CULL_FACE);
|
|
1127
|
-
gl.disable(gl.BLEND);
|
|
1128
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1129
|
-
|
|
1130
|
-
pickable.drawPickTriangles(frameCtx);
|
|
1131
|
-
|
|
1132
|
-
const resolutionScale = scene.canvas.resolutionScale;
|
|
1133
|
-
const pix = pickBuffer.read(Math.round(canvasPos[0] * resolutionScale), Math.round(canvasPos[1] * resolutionScale));
|
|
1134
|
-
|
|
1135
|
-
let primIndex = pix[0] + (pix[1] * 256) + (pix[2] * 256 * 256) + (pix[3] * 256 * 256 * 256);
|
|
1136
|
-
|
|
1137
|
-
primIndex *= 3; // Convert from triangle number to first vertex in indices
|
|
1138
|
-
|
|
1139
|
-
pickResult.primIndex = primIndex;
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
const gpuPickWorldPos = (function () {
|
|
1143
|
-
|
|
1144
|
-
const tempVec4a = math.vec4();
|
|
1145
|
-
const tempVec4b = math.vec4();
|
|
1146
|
-
const tempVec4c = math.vec4();
|
|
1147
|
-
const tempVec4d = math.vec4();
|
|
1148
|
-
const tempVec4e = math.vec4();
|
|
1149
|
-
const tempMat4a = math.mat4();
|
|
1150
|
-
const tempMat4b = math.mat4();
|
|
1151
|
-
const tempMat4c = math.mat4();
|
|
1152
|
-
|
|
1153
|
-
return function (pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, nearAndFar, pickResult) {
|
|
1154
|
-
|
|
1155
|
-
frameCtx.reset();
|
|
1156
|
-
frameCtx.backfaces = true;
|
|
1157
|
-
frameCtx.frontface = true; // "ccw"
|
|
1158
|
-
frameCtx.pickOrigin = pickResult.origin;
|
|
1159
|
-
frameCtx.pickViewMatrix = pickViewMatrix;
|
|
1160
|
-
frameCtx.pickProjMatrix = pickProjMatrix;
|
|
1161
|
-
frameCtx.pickZNear = nearAndFar[0];
|
|
1162
|
-
frameCtx.pickZFar = nearAndFar[1];
|
|
1163
|
-
frameCtx.pickElementsCount = pickable.pickElementsCount;
|
|
1164
|
-
frameCtx.pickElementsOffset = pickable.pickElementsOffset;
|
|
1165
|
-
|
|
1166
|
-
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
1167
|
-
|
|
1168
|
-
gl.clearColor(0, 0, 0, 0);
|
|
1169
|
-
gl.depthMask(true);
|
|
1170
|
-
gl.enable(gl.DEPTH_TEST);
|
|
1171
|
-
gl.disable(gl.CULL_FACE);
|
|
1172
|
-
gl.disable(gl.BLEND);
|
|
1173
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1174
|
-
|
|
1175
|
-
pickable.drawPickDepths(frameCtx); // Draw color-encoded fragment screen-space depths
|
|
1176
|
-
|
|
1177
|
-
const resolutionScale = scene.canvas.resolutionScale;
|
|
1178
|
-
const pix = pickBuffer.read(Math.round(canvasPos[0] * resolutionScale), Math.round(canvasPos[1] * resolutionScale));
|
|
1179
|
-
|
|
1180
|
-
const screenZ = unpackDepth(pix); // Get screen-space Z at the given canvas coords
|
|
1181
|
-
|
|
1182
|
-
// Calculate clip space coordinates, which will be in range of x=[-1..1] and y=[-1..1], with y=(+1) at top
|
|
1183
|
-
const x = (canvasPos[0] - canvas.clientWidth / 2) / (canvas.clientWidth / 2);
|
|
1184
|
-
const y = -(canvasPos[1] - canvas.clientHeight / 2) / (canvas.clientHeight / 2);
|
|
1185
|
-
|
|
1186
|
-
const origin = pickable.origin;
|
|
1187
|
-
let pvMat;
|
|
1188
|
-
|
|
1189
|
-
if (origin) {
|
|
1190
|
-
const rtcPickViewMat = createRTCViewMat(pickViewMatrix, origin, tempMat4a);
|
|
1191
|
-
pvMat = math.mulMat4(pickProjMatrix, rtcPickViewMat, tempMat4b);
|
|
1192
|
-
|
|
1193
|
-
} else {
|
|
1194
|
-
pvMat = math.mulMat4(pickProjMatrix, pickViewMatrix, tempMat4b);
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
const pvMatInverse = math.inverseMat4(pvMat, tempMat4c);
|
|
1198
|
-
|
|
1199
|
-
tempVec4a[0] = x;
|
|
1200
|
-
tempVec4a[1] = y;
|
|
1201
|
-
tempVec4a[2] = -1;
|
|
1202
|
-
tempVec4a[3] = 1;
|
|
1203
|
-
|
|
1204
|
-
let world1 = math.transformVec4(pvMatInverse, tempVec4a);
|
|
1205
|
-
world1 = math.mulVec4Scalar(world1, 1 / world1[3]);
|
|
1206
|
-
|
|
1207
|
-
tempVec4b[0] = x;
|
|
1208
|
-
tempVec4b[1] = y;
|
|
1209
|
-
tempVec4b[2] = 1;
|
|
1210
|
-
tempVec4b[3] = 1;
|
|
1211
|
-
|
|
1212
|
-
let world2 = math.transformVec4(pvMatInverse, tempVec4b);
|
|
1213
|
-
world2 = math.mulVec4Scalar(world2, 1 / world2[3]);
|
|
1214
|
-
|
|
1215
|
-
const dir = math.subVec3(world2, world1, tempVec4c);
|
|
1216
|
-
const worldPos = math.addVec3(world1, math.mulVec4Scalar(dir, screenZ, tempVec4d), tempVec4e);
|
|
1217
|
-
|
|
1218
|
-
if (origin) {
|
|
1219
|
-
math.addVec3(worldPos, origin);
|
|
1220
|
-
}
|
|
1221
|
-
|
|
1222
|
-
pickResult.worldPos = worldPos;
|
|
1223
|
-
}
|
|
1224
|
-
})();
|
|
1225
|
-
|
|
1226
|
-
function snapInitDepthBuf(frameCtx) {
|
|
1227
|
-
frameCtx.snapPickLayerParams = [];
|
|
1228
|
-
frameCtx.snapPickLayerNumber = 0;
|
|
1229
|
-
for (let type in drawableTypeInfo) {
|
|
1230
|
-
const drawableInfo = drawableTypeInfo[type];
|
|
1231
|
-
const drawableList = drawableInfo.drawableList;
|
|
1232
|
-
for (let i = 0, len = drawableList.length; i < len; i++) {
|
|
1233
|
-
const drawable = drawableList[i];
|
|
1234
|
-
if (drawable.drawSnapInitDepthBuf) {
|
|
1235
|
-
if (!drawable.culled && drawable.visible && drawable.pickable) {
|
|
1236
|
-
drawable.drawSnapInitDepthBuf(frameCtx);
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
|
-
return frameCtx.snapPickLayerParams;
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
function snapPickDrawSnapDepths(frameCtx) {
|
|
1245
|
-
frameCtx.snapPickLayerParams = frameCtx.snapPickLayerParams || [];
|
|
1246
|
-
frameCtx.snapPickLayerNumber = frameCtx.snapPickLayerParams.length;
|
|
1247
|
-
for (let type in drawableTypeInfo) {
|
|
1248
|
-
const drawableInfo = drawableTypeInfo[type];
|
|
1249
|
-
const drawableList = drawableInfo.drawableList;
|
|
1250
|
-
for (let i = 0, len = drawableList.length; i < len; i++) {
|
|
1251
|
-
const drawable = drawableList[i];
|
|
1252
|
-
if (drawable.drawSnapDepths) {
|
|
1253
|
-
if (!drawable.culled && drawable.visible && drawable.pickable) {
|
|
1254
|
-
drawable.drawSnapDepths(frameCtx);
|
|
1255
|
-
}
|
|
1256
|
-
}
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
return frameCtx.snapPickLayerParams;
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
function getClipPosX(pos, size) {
|
|
1263
|
-
return 2 * (pos / size) - 1;
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
function getClipPosY(pos, size) {
|
|
1267
|
-
return 1 - 2 * (pos / size);
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
/**
|
|
1271
|
-
* @param {[number, number]} canvasPos
|
|
1272
|
-
* @param {number} [snapRadiusInPixels=30]
|
|
1273
|
-
* @param {boolean} [snapVertex=true]
|
|
1274
|
-
* @param {boolean} [snapEdge=true]
|
|
1275
|
-
*
|
|
1276
|
-
* @returns {{worldPos:number[],snappedWorldPos:null|number[],snappedCanvasPos:null|number[], snapType:null|"vertex"|"edge"}}
|
|
1277
|
-
*/
|
|
1278
|
-
this.snapPick = function (canvasPos, snapRadiusInPixels = 30, snapVertex = true, snapEdge = true) {
|
|
1279
|
-
|
|
1280
|
-
if (!snapVertex && !snapEdge) {
|
|
1281
|
-
return this.pick({canvasPos, pickSurface: true});
|
|
1282
|
-
}
|
|
1283
|
-
|
|
1284
|
-
frameCtx.reset();
|
|
1285
|
-
frameCtx.backfaces = true;
|
|
1286
|
-
frameCtx.frontface = true; // "ccw"
|
|
1287
|
-
frameCtx.pickZNear = scene.camera.project.near;
|
|
1288
|
-
frameCtx.pickZFar = scene.camera.project.far;
|
|
1289
|
-
|
|
1290
|
-
let vertexPickBuffer = renderBufferManager.getRenderBuffer("uniquePickColors-aabs", {
|
|
1291
|
-
depthTexture: true,
|
|
1292
|
-
size: [
|
|
1293
|
-
2 * snapRadiusInPixels + 1,
|
|
1294
|
-
2 * snapRadiusInPixels + 1,
|
|
1295
|
-
]
|
|
1296
|
-
});
|
|
1297
|
-
|
|
1298
|
-
frameCtx.snapVectorA = [
|
|
1299
|
-
getClipPosX(canvasPos[0], gl.drawingBufferWidth),
|
|
1300
|
-
getClipPosY(canvasPos[1], gl.drawingBufferHeight),
|
|
1301
|
-
];
|
|
1302
|
-
|
|
1303
|
-
frameCtx.snapInvVectorAB = [
|
|
1304
|
-
gl.drawingBufferWidth / (2 * snapRadiusInPixels),
|
|
1305
|
-
gl.drawingBufferHeight / (2 * snapRadiusInPixels),
|
|
1306
|
-
];
|
|
1307
|
-
|
|
1308
|
-
// Bind and clear the snap render target
|
|
1309
|
-
|
|
1310
|
-
vertexPickBuffer.bind(gl.RGBA32I);
|
|
1311
|
-
gl.viewport(0, 0, vertexPickBuffer.size[0], vertexPickBuffer.size[1]);
|
|
1312
|
-
gl.enable(gl.DEPTH_TEST);
|
|
1313
|
-
gl.frontFace(gl.CCW);
|
|
1314
|
-
gl.disable(gl.CULL_FACE);
|
|
1315
|
-
gl.depthMask(true);
|
|
1316
|
-
gl.disable(gl.BLEND);
|
|
1317
|
-
gl.depthFunc(gl.LESS);
|
|
1318
|
-
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
1319
|
-
gl.clearBufferiv(gl.COLOR, 0, new Int32Array([0, 0, 0, 0]));
|
|
1320
|
-
|
|
1321
|
-
//////////////////////////////////
|
|
1322
|
-
// Set view and proj mats for VBO renderers
|
|
1323
|
-
///////////////////////////////////////
|
|
1324
|
-
|
|
1325
|
-
const pickViewMatrix = scene.camera.viewMatrix;
|
|
1326
|
-
const pickProjMatrix = scene.camera.projMatrix;
|
|
1327
|
-
|
|
1328
|
-
for (let type in drawableTypeInfo) {
|
|
1329
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
1330
|
-
const drawableList = drawableTypeInfo[type].drawableList;
|
|
1331
|
-
for (let i = 0, len = drawableList.length; i < len; i++) {
|
|
1332
|
-
const drawable = drawableList[i];
|
|
1333
|
-
if (drawable.setPickMatrices) { // Eg. SceneModel, which needs pre-loading into texture
|
|
1334
|
-
drawable.setPickMatrices(pickViewMatrix, pickProjMatrix);
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
|
-
}
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
|
-
// a) init z-buffer
|
|
1341
|
-
const layerParamsSurface = snapInitDepthBuf(frameCtx);
|
|
1342
|
-
|
|
1343
|
-
// b) snap-pick
|
|
1344
|
-
const layerParamsSnap = []
|
|
1345
|
-
frameCtx.snapPickLayerParams = layerParamsSnap;
|
|
1346
|
-
|
|
1347
|
-
gl.depthMask(false);
|
|
1348
|
-
|
|
1349
|
-
if (snapVertex && snapEdge) {
|
|
1350
|
-
frameCtx.snapMode = "edge";
|
|
1351
|
-
snapPickDrawSnapDepths(frameCtx);
|
|
1352
|
-
|
|
1353
|
-
frameCtx.snapMode = "vertex";
|
|
1354
|
-
frameCtx.snapPickLayerNumber++;
|
|
1355
|
-
|
|
1356
|
-
snapPickDrawSnapDepths(frameCtx);
|
|
1357
|
-
} else {
|
|
1358
|
-
frameCtx.snapMode = snapVertex ? "vertex" : "edge";
|
|
1359
|
-
|
|
1360
|
-
snapPickDrawSnapDepths(frameCtx);
|
|
1361
|
-
}
|
|
1362
|
-
|
|
1363
|
-
gl.depthMask(true);
|
|
1364
|
-
|
|
1365
|
-
// Read and decode the snapped coordinates
|
|
1366
|
-
|
|
1367
|
-
const snapPickResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.INT, Int32Array, 4);
|
|
1368
|
-
|
|
1369
|
-
vertexPickBuffer.unbind();
|
|
1370
|
-
|
|
1371
|
-
drawSnapDebbug(vertexPickBuffer.buffer.texture, layerParamsSurface.length);
|
|
1372
|
-
|
|
1373
|
-
// result 1) regular hi-precision world position
|
|
1374
|
-
|
|
1375
|
-
let worldPos = null;
|
|
1376
|
-
|
|
1377
|
-
const middleX = snapRadiusInPixels;
|
|
1378
|
-
const middleY = snapRadiusInPixels;
|
|
1379
|
-
const middleIndex = (middleX * 4) + (middleY * vertexPickBuffer.size[0] * 4);
|
|
1380
|
-
const pickResultMiddleXY = snapPickResultArray.slice(middleIndex, middleIndex + 4);
|
|
1381
|
-
|
|
1382
|
-
if (pickResultMiddleXY[3] !== 0) {
|
|
1383
|
-
const pickedLayerParmasSurface = layerParamsSurface[Math.abs(pickResultMiddleXY[3]) % layerParamsSurface.length];
|
|
1384
|
-
const origin = pickedLayerParmasSurface.origin;
|
|
1385
|
-
const scale = pickedLayerParmasSurface.coordinateScale;
|
|
1386
|
-
worldPos = [
|
|
1387
|
-
pickResultMiddleXY[0] * scale[0] + origin[0],
|
|
1388
|
-
pickResultMiddleXY[1] * scale[1] + origin[1],
|
|
1389
|
-
pickResultMiddleXY[2] * scale[2] + origin[2],
|
|
1390
|
-
];
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
// result 2) hi-precision snapped (to vertex/edge) world position
|
|
1394
|
-
|
|
1395
|
-
let snapPickResult = [];
|
|
1396
|
-
|
|
1397
|
-
for (let i = 0; i < snapPickResultArray.length; i += 4) {
|
|
1398
|
-
if (snapPickResultArray[i + 3] > 0) {
|
|
1399
|
-
const pixelNumber = Math.floor(i / 4);
|
|
1400
|
-
const w = vertexPickBuffer.size[0];
|
|
1401
|
-
const x = pixelNumber % w - Math.floor(w / 2);
|
|
1402
|
-
const y = Math.floor(pixelNumber / w) - Math.floor(w / 2);
|
|
1403
|
-
const dist = (Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));
|
|
1404
|
-
snapPickResult.push({
|
|
1405
|
-
x,
|
|
1406
|
-
y,
|
|
1407
|
-
dist,
|
|
1408
|
-
isVertex: snapVertex && snapEdge ? snapPickResultArray[i + 3] > layerParamsSnap.length / 2 : snapVertex,
|
|
1409
|
-
result: [
|
|
1410
|
-
snapPickResultArray[i + 0],
|
|
1411
|
-
snapPickResultArray[i + 1],
|
|
1412
|
-
snapPickResultArray[i + 2],
|
|
1413
|
-
snapPickResultArray[i + 3],
|
|
1414
|
-
]
|
|
1415
|
-
});
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1419
|
-
let snappedWorldPos = null;
|
|
1420
|
-
let snapType = null;
|
|
1421
|
-
|
|
1422
|
-
if (snapPickResult.length > 0) {
|
|
1423
|
-
// vertex snap first, then edge snap
|
|
1424
|
-
snapPickResult.sort((a, b) => {
|
|
1425
|
-
if (a.isVertex !== b.isVertex) {
|
|
1426
|
-
return a.isVertex ? -1 : 1;
|
|
1427
|
-
} else {
|
|
1428
|
-
return a.dist - b.dist;
|
|
1429
|
-
}
|
|
1430
|
-
});
|
|
1431
|
-
|
|
1432
|
-
snapType = snapPickResult[0].isVertex ? "vertex" : "edge";
|
|
1433
|
-
snapPickResult = snapPickResult[0].result;
|
|
1434
|
-
|
|
1435
|
-
const pickedLayerParmas = layerParamsSnap[snapPickResult[3]];
|
|
1436
|
-
|
|
1437
|
-
const origin = pickedLayerParmas.origin;
|
|
1438
|
-
const scale = pickedLayerParmas.coordinateScale;
|
|
1439
|
-
|
|
1440
|
-
snappedWorldPos = [
|
|
1441
|
-
snapPickResult[0] * scale[0] + origin[0],
|
|
1442
|
-
snapPickResult[1] * scale[1] + origin[1],
|
|
1443
|
-
snapPickResult[2] * scale[2] + origin[2],
|
|
1444
|
-
];
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
if (null === worldPos && null == snappedWorldPos) { // If neither regular pick or snap pick, return null
|
|
1448
|
-
return null;
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1451
|
-
let snappedCanvasPos = null;
|
|
1452
|
-
|
|
1453
|
-
if (null !== snappedWorldPos) {
|
|
1454
|
-
snappedCanvasPos = scene.camera.projectWorldPos(snappedWorldPos);
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
return {
|
|
1458
|
-
snapType,
|
|
1459
|
-
snappedToVertex: snapType === "vertex",
|
|
1460
|
-
snappedToEdge: snapType === "edge",
|
|
1461
|
-
worldPos,
|
|
1462
|
-
snappedWorldPos,
|
|
1463
|
-
snappedCanvasPos
|
|
1464
|
-
};
|
|
1465
|
-
};
|
|
1466
|
-
|
|
1467
|
-
function unpackDepth(depthZ) {
|
|
1468
|
-
const vec = [depthZ[0] / 256.0, depthZ[1] / 256.0, depthZ[2] / 256.0, depthZ[3] / 256.0];
|
|
1469
|
-
const bitShift = [1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0];
|
|
1470
|
-
return math.dotVec4(vec, bitShift);
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
function gpuPickWorldNormal(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, pickResult) {
|
|
1474
|
-
|
|
1475
|
-
frameCtx.reset();
|
|
1476
|
-
frameCtx.backfaces = true;
|
|
1477
|
-
frameCtx.frontface = true; // "ccw"
|
|
1478
|
-
frameCtx.pickOrigin = pickResult.origin;
|
|
1479
|
-
frameCtx.pickViewMatrix = pickViewMatrix;
|
|
1480
|
-
frameCtx.pickProjMatrix = pickProjMatrix;
|
|
1481
|
-
|
|
1482
|
-
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
1483
|
-
|
|
1484
|
-
gl.clearColor(0, 0, 0, 0);
|
|
1485
|
-
gl.enable(gl.DEPTH_TEST);
|
|
1486
|
-
gl.disable(gl.CULL_FACE);
|
|
1487
|
-
gl.disable(gl.BLEND);
|
|
1488
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1489
|
-
|
|
1490
|
-
pickable.drawPickNormals(frameCtx); // Draw color-encoded fragment World-space normals
|
|
1491
|
-
|
|
1492
|
-
const resolutionScale = scene.canvas.resolutionScale;
|
|
1493
|
-
const pix = pickBuffer.read(Math.round(canvasPos[0] * resolutionScale), Math.round(canvasPos[1] * resolutionScale));
|
|
1494
|
-
|
|
1495
|
-
const worldNormal = [(pix[0] / 256.0) - 0.5, (pix[1] / 256.0) - 0.5, (pix[2] / 256.0) - 0.5];
|
|
1496
|
-
|
|
1497
|
-
math.normalizeVec3(worldNormal);
|
|
1498
|
-
|
|
1499
|
-
pickResult.worldNormal = worldNormal;
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
/**
|
|
1503
|
-
* Adds a {@link Marker} for occlusion testing.
|
|
1504
|
-
* @param marker
|
|
1505
|
-
*/
|
|
1506
|
-
this.addMarker = function (marker) {
|
|
1507
|
-
this._occlusionTester = this._occlusionTester || new OcclusionTester(scene, renderBufferManager);
|
|
1508
|
-
this._occlusionTester.addMarker(marker);
|
|
1509
|
-
scene.occlusionTestCountdown = 0;
|
|
1510
|
-
};
|
|
1511
|
-
|
|
1512
|
-
/**
|
|
1513
|
-
* Notifies that a {@link Marker#worldPos} has updated.
|
|
1514
|
-
* @param marker
|
|
1515
|
-
*/
|
|
1516
|
-
this.markerWorldPosUpdated = function (marker) {
|
|
1517
|
-
this._occlusionTester.markerWorldPosUpdated(marker);
|
|
1518
|
-
};
|
|
1519
|
-
|
|
1520
|
-
/**
|
|
1521
|
-
* Removes a {@link Marker} from occlusion testing.
|
|
1522
|
-
* @param marker
|
|
1523
|
-
*/
|
|
1524
|
-
this.removeMarker = function (marker) {
|
|
1525
|
-
this._occlusionTester.removeMarker(marker);
|
|
1526
|
-
};
|
|
1527
|
-
|
|
1528
|
-
/**
|
|
1529
|
-
* Performs an occlusion test for all added {@link Marker}s, updating
|
|
1530
|
-
* their {@link Marker#visible} properties accordingly.
|
|
1531
|
-
*/
|
|
1532
|
-
this.doOcclusionTest = function () {
|
|
1533
|
-
|
|
1534
|
-
if (this._occlusionTester && this._occlusionTester.needOcclusionTest) {
|
|
1535
|
-
|
|
1536
|
-
updateDrawlist();
|
|
1537
|
-
|
|
1538
|
-
this._occlusionTester.bindRenderBuf();
|
|
1539
|
-
|
|
1540
|
-
frameCtx.reset();
|
|
1541
|
-
frameCtx.backfaces = true;
|
|
1542
|
-
frameCtx.frontface = true; // "ccw"
|
|
1543
|
-
|
|
1544
|
-
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
1545
|
-
gl.clearColor(0, 0, 0, 0);
|
|
1546
|
-
gl.enable(gl.DEPTH_TEST);
|
|
1547
|
-
gl.disable(gl.CULL_FACE);
|
|
1548
|
-
gl.disable(gl.BLEND);
|
|
1549
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1550
|
-
|
|
1551
|
-
for (let type in drawableTypeInfo) {
|
|
1552
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
1553
|
-
const drawableInfo = drawableTypeInfo[type];
|
|
1554
|
-
const drawableList = drawableInfo.drawableList;
|
|
1555
|
-
for (let i = 0, len = drawableList.length; i < len; i++) {
|
|
1556
|
-
const drawable = drawableList[i];
|
|
1557
|
-
if (!drawable.drawOcclusion || drawable.culled === true || drawable.visible === false || drawable.pickable === false) { // TODO: Option to exclude transparent?
|
|
1558
|
-
continue;
|
|
1559
|
-
}
|
|
1560
|
-
|
|
1561
|
-
drawable.drawOcclusion(frameCtx);
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
|
-
this._occlusionTester.drawMarkers(frameCtx);
|
|
1567
|
-
this._occlusionTester.doOcclusionTest(); // Updates Marker "visible" properties
|
|
1568
|
-
this._occlusionTester.unbindRenderBuf();
|
|
1569
|
-
}
|
|
1570
|
-
};
|
|
1571
|
-
|
|
1572
|
-
/**
|
|
1573
|
-
* Read pixels from the renderer's current output. Performs a force-render first.
|
|
1574
|
-
* @param pixels
|
|
1575
|
-
* @param colors
|
|
1576
|
-
* @param len
|
|
1577
|
-
* @param opaqueOnly
|
|
1578
|
-
* @private
|
|
1579
|
-
*/
|
|
1580
|
-
this.readPixels = function (pixels, colors, len, opaqueOnly) {
|
|
1581
|
-
const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
|
|
1582
|
-
snapshotBuffer.bind();
|
|
1583
|
-
snapshotBuffer.clear();
|
|
1584
|
-
this.render({force: true, opaqueOnly: opaqueOnly});
|
|
1585
|
-
let color;
|
|
1586
|
-
let i;
|
|
1587
|
-
let j;
|
|
1588
|
-
let k;
|
|
1589
|
-
for (i = 0; i < len; i++) {
|
|
1590
|
-
j = i * 2;
|
|
1591
|
-
k = i * 4;
|
|
1592
|
-
color = snapshotBuffer.read(pixels[j], pixels[j + 1]);
|
|
1593
|
-
colors[k] = color[0];
|
|
1594
|
-
colors[k + 1] = color[1];
|
|
1595
|
-
colors[k + 2] = color[2];
|
|
1596
|
-
colors[k + 3] = color[3];
|
|
1597
|
-
}
|
|
1598
|
-
snapshotBuffer.unbind();
|
|
1599
|
-
imageDirty = true;
|
|
1600
|
-
};
|
|
1601
|
-
|
|
1602
|
-
/**
|
|
1603
|
-
* Enter snapshot mode.
|
|
1604
|
-
*
|
|
1605
|
-
* Switches rendering to a hidden snapshot canvas.
|
|
1606
|
-
*
|
|
1607
|
-
* Exit snapshot mode using endSnapshot().
|
|
1608
|
-
*/
|
|
1609
|
-
this.beginSnapshot = function (params = {}) {
|
|
1610
|
-
const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
|
|
1611
|
-
if (params.width && params.height) {
|
|
1612
|
-
snapshotBuffer.setSize([params.width, params.height]);
|
|
1613
|
-
}
|
|
1614
|
-
snapshotBuffer.bind();
|
|
1615
|
-
snapshotBuffer.clear();
|
|
1616
|
-
snapshotBound = true;
|
|
1617
|
-
};
|
|
1618
|
-
|
|
1619
|
-
/**
|
|
1620
|
-
* When in snapshot mode, renders a frame of the current Scene state to the snapshot canvas.
|
|
1621
|
-
*/
|
|
1622
|
-
this.renderSnapshot = function () {
|
|
1623
|
-
if (!snapshotBound) {
|
|
1624
|
-
return;
|
|
1625
|
-
}
|
|
1626
|
-
const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
|
|
1627
|
-
snapshotBuffer.clear();
|
|
1628
|
-
this.render({force: true, opaqueOnly: false});
|
|
1629
|
-
imageDirty = true;
|
|
1630
|
-
};
|
|
1631
|
-
|
|
1632
|
-
/**
|
|
1633
|
-
* When in snapshot mode, gets an image of the snapshot canvas.
|
|
1634
|
-
*
|
|
1635
|
-
* @private
|
|
1636
|
-
* @returns {String} The image data URI.
|
|
1637
|
-
*/
|
|
1638
|
-
this.readSnapshot = function (params) {
|
|
1639
|
-
const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
|
|
1640
|
-
return snapshotBuffer.readImage(params);
|
|
1641
|
-
};
|
|
1642
|
-
|
|
1643
|
-
/**
|
|
1644
|
-
* Returns an HTMLCanvas containing an image of the snapshot canvas.
|
|
1645
|
-
*
|
|
1646
|
-
* - The HTMLCanvas has a CanvasRenderingContext2D.
|
|
1647
|
-
* - Expects the caller to draw more things on the HTMLCanvas (annotations etc).
|
|
1648
|
-
*
|
|
1649
|
-
* @returns {HTMLCanvasElement}
|
|
1650
|
-
*/
|
|
1651
|
-
this.readSnapshotAsCanvas = function () {
|
|
1652
|
-
const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
|
|
1653
|
-
return snapshotBuffer.readImageAsCanvas();
|
|
1654
|
-
};
|
|
1655
|
-
|
|
1656
|
-
/**
|
|
1657
|
-
* Exists snapshot mode.
|
|
1658
|
-
*
|
|
1659
|
-
* Switches rendering back to the main canvas.
|
|
1660
|
-
*/
|
|
1661
|
-
this.endSnapshot = function () {
|
|
1662
|
-
if (!snapshotBound) {
|
|
1663
|
-
return;
|
|
1664
|
-
}
|
|
1665
|
-
const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
|
|
1666
|
-
snapshotBuffer.unbind();
|
|
1667
|
-
snapshotBound = false;
|
|
1668
|
-
};
|
|
1669
|
-
|
|
1670
|
-
/**
|
|
1671
|
-
* Destroys this renderer.
|
|
1672
|
-
* @private
|
|
1673
|
-
*/
|
|
1674
|
-
this.destroy = function () {
|
|
1675
|
-
|
|
1676
|
-
drawableTypeInfo = {};
|
|
1677
|
-
drawables = {};
|
|
1678
|
-
|
|
1679
|
-
renderBufferManager.destroy();
|
|
1680
|
-
|
|
1681
|
-
saoOcclusionRenderer.destroy();
|
|
1682
|
-
saoDepthLimitedBlurRenderer.destroy();
|
|
1683
|
-
|
|
1684
|
-
if (this._occlusionTester) {
|
|
1685
|
-
this._occlusionTester.destroy();
|
|
1686
|
-
}
|
|
1687
|
-
};
|
|
1688
|
-
|
|
1689
|
-
let snapDebbugRenderer = null;
|
|
1690
|
-
|
|
1691
|
-
function drawSnapDebbug(texture, len) {
|
|
1692
|
-
if (!snapDebbugRenderer) {
|
|
1693
|
-
snapDebbugRenderer = makeSnapDebbugRenderer();
|
|
1694
|
-
}
|
|
1695
|
-
|
|
1696
|
-
snapDebbugRenderer.draw(texture, len);
|
|
1697
|
-
}
|
|
1698
|
-
|
|
1699
|
-
function makeSnapDebbugRenderer() {
|
|
1700
|
-
const vertexShaderSource = `\
|
|
1701
|
-
#version 300 es
|
|
1702
|
-
in vec2 position;
|
|
1703
|
-
in vec2 texCoord;
|
|
1704
|
-
|
|
1705
|
-
out vec2 v_texCoord;
|
|
1706
|
-
|
|
1707
|
-
void main() {
|
|
1708
|
-
v_texCoord = texCoord;
|
|
1709
|
-
|
|
1710
|
-
gl_Position = vec4(position, 0.0, 1.0);
|
|
1711
|
-
}
|
|
1712
|
-
`;
|
|
1713
|
-
|
|
1714
|
-
const fragmentShaderSource = `\
|
|
1715
|
-
#version 300 es
|
|
1716
|
-
precision highp float;
|
|
1717
|
-
precision highp isampler2D;
|
|
1718
|
-
|
|
1719
|
-
uniform isampler2D u_texture;
|
|
1720
|
-
uniform float u_len;
|
|
1721
|
-
|
|
1722
|
-
in vec2 v_texCoord;
|
|
1723
|
-
|
|
1724
|
-
out vec4 outColor;
|
|
1725
|
-
|
|
1726
|
-
void main() {
|
|
1727
|
-
vec4 color = vec4(texture(u_texture, v_texCoord));
|
|
1728
|
-
if (color.w > 0.0) {
|
|
1729
|
-
if (color.w < u_len) {
|
|
1730
|
-
color = vec4(1.0, 0.0, 0.0, 1.0);
|
|
1731
|
-
} else {
|
|
1732
|
-
color = vec4(0.0, 1.0, 0.0, 1.0);
|
|
1733
|
-
}
|
|
1734
|
-
}
|
|
1735
|
-
outColor = abs(color);
|
|
1736
|
-
}
|
|
1737
|
-
`;
|
|
1738
|
-
|
|
1739
|
-
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
|
|
1740
|
-
gl.shaderSource(vertexShader, vertexShaderSource);
|
|
1741
|
-
gl.compileShader(vertexShader);
|
|
1742
|
-
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
|
|
1743
|
-
throw new Error(gl.getShaderInfoLog(vertexShader));
|
|
1744
|
-
}
|
|
1745
|
-
|
|
1746
|
-
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
|
|
1747
|
-
gl.shaderSource(fragmentShader, fragmentShaderSource);
|
|
1748
|
-
gl.compileShader(fragmentShader);
|
|
1749
|
-
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
|
|
1750
|
-
throw new Error(gl.getShaderInfoLog(fragmentShader));
|
|
1751
|
-
}
|
|
1752
|
-
|
|
1753
|
-
const program = gl.createProgram();
|
|
1754
|
-
|
|
1755
|
-
gl.attachShader(program, vertexShader);
|
|
1756
|
-
gl.attachShader(program, fragmentShader);
|
|
1757
|
-
gl.linkProgram(program);
|
|
1758
|
-
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
1759
|
-
throw new Error(gl.getProgramInfoLog(program));
|
|
1760
|
-
}
|
|
1761
|
-
|
|
1762
|
-
const vao = gl.createVertexArray();
|
|
1763
|
-
gl.bindVertexArray(vao);
|
|
1764
|
-
|
|
1765
|
-
const positionLocation = gl.getAttribLocation(program, "position");
|
|
1766
|
-
const positions = new Float32Array([-1, -1, 1, -1, 1, 1, -1, 1]);
|
|
1767
|
-
|
|
1768
|
-
const positionBuffer = gl.createBuffer();
|
|
1769
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
1770
|
-
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
|
|
1771
|
-
|
|
1772
|
-
gl.enableVertexAttribArray(positionLocation);
|
|
1773
|
-
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
|
|
1774
|
-
|
|
1775
|
-
const texCoordLocation = gl.getAttribLocation(program, "texCoord");
|
|
1776
|
-
const textureCoordinates = new Float32Array([
|
|
1777
|
-
0, 0, 1, 0, 1, 1, 0, 1
|
|
1778
|
-
]);
|
|
1779
|
-
|
|
1780
|
-
const textureCoordinateBuffer = gl.createBuffer();
|
|
1781
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordinateBuffer);
|
|
1782
|
-
gl.bufferData(gl.ARRAY_BUFFER, textureCoordinates, gl.STATIC_DRAW);
|
|
1783
|
-
|
|
1784
|
-
gl.enableVertexAttribArray(texCoordLocation);
|
|
1785
|
-
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
|
|
1786
|
-
|
|
1787
|
-
const index = new Uint16Array([0, 1, 2, 0, 2, 3]);
|
|
1788
|
-
|
|
1789
|
-
const indexBuffer = gl.createBuffer();
|
|
1790
|
-
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
|
|
1791
|
-
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, index, gl.STATIC_DRAW);
|
|
1792
|
-
|
|
1793
|
-
const lenLocation = gl.getUniformLocation(program, "u_len");
|
|
1794
|
-
|
|
1795
|
-
gl.useProgram(null);
|
|
1796
|
-
gl.bindVertexArray(null);
|
|
1797
|
-
|
|
1798
|
-
return {
|
|
1799
|
-
async draw(texture, len) {
|
|
1800
|
-
gl.activeTexture(gl.TEXTURE0);
|
|
1801
|
-
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
1802
|
-
|
|
1803
|
-
gl.useProgram(program);
|
|
1804
|
-
gl.bindVertexArray(vao);
|
|
1805
|
-
|
|
1806
|
-
gl.uniform1f(lenLocation, len);
|
|
1807
|
-
|
|
1808
|
-
const width = gl.drawingBufferWidth / 2;
|
|
1809
|
-
const height = gl.drawingBufferHeight;
|
|
1810
|
-
|
|
1811
|
-
gl.enable(gl.SCISSOR_TEST);
|
|
1812
|
-
gl.scissor(0, 0, width, height);
|
|
1813
|
-
|
|
1814
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1815
|
-
|
|
1816
|
-
gl.viewport(0, 0, width, height);
|
|
1817
|
-
|
|
1818
|
-
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
|
|
1819
|
-
|
|
1820
|
-
gl.bindVertexArray(null);
|
|
1821
|
-
gl.useProgram(null);
|
|
1822
|
-
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
1823
|
-
gl.disable(gl.SCISSOR_TEST);
|
|
1824
|
-
gl.scissor(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
1825
|
-
}
|
|
1826
|
-
}
|
|
1827
|
-
}
|
|
1828
|
-
};
|
|
1829
|
-
|
|
1830
|
-
export {Renderer};
|