@xeokit/xeokit-sdk 2.6.91 → 2.6.93
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 +13128 -44669
- package/dist/xeokit-sdk.es.js +13129 -44668
- package/dist/xeokit-sdk.es5.js +1414 -3498
- package/dist/xeokit-sdk.min.cjs.js +8 -8
- package/dist/xeokit-sdk.min.es.js +8 -8
- package/dist/xeokit-sdk.min.es5.js +7 -7
- package/package.json +1 -1
- package/src/plugins/AngleMeasurementsPlugin/AngleMeasurement.js +21 -1
- package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js +32 -6
- package/src/viewer/Viewer.js +55 -103
- package/src/viewer/scene/canvas/Canvas.js +3 -43
- package/src/viewer/scene/geometry/ReadableGeometry.js +0 -25
- package/src/viewer/scene/lights/CubeTexture.js +0 -13
- package/src/viewer/scene/lights/DirLight.js +2 -1
- package/src/viewer/scene/lights/PointLight.js +2 -1
- package/src/viewer/scene/materials/Texture.js +0 -9
- package/src/viewer/scene/math/rtcCoords.js +1 -38
- package/src/viewer/scene/mesh/Mesh.js +454 -212
- package/src/viewer/scene/mesh/draw/DrawShaderSource.js +305 -1504
- package/src/viewer/scene/mesh/draw/LambertShaderSource.js +35 -0
- package/src/viewer/scene/mesh/emphasis/EmphasisShaderSource.js +34 -0
- package/src/viewer/scene/mesh/occlusion/OcclusionShaderSource.js +9 -158
- package/src/viewer/scene/mesh/pick/PickMeshShaderSource.js +21 -151
- package/src/viewer/scene/mesh/pick/PickTriangleShaderSource.js +12 -124
- package/src/viewer/scene/mesh/shadow/ShadowShaderSource.js +22 -97
- package/src/viewer/scene/model/SceneModel.js +248 -852
- package/src/viewer/scene/model/SceneModelEntity.js +4 -4
- package/src/viewer/scene/model/SceneModelMesh.js +3 -3
- package/src/viewer/scene/model/layer/DTXLayer.js +940 -0
- package/src/viewer/scene/model/layer/Layer.js +788 -0
- package/src/viewer/scene/model/layer/VBOLayer.js +1019 -0
- package/src/viewer/scene/model/layer/programs/ColorProgram.js +35 -0
- package/src/viewer/scene/model/layer/programs/ColorTextureProgram.js +46 -0
- package/src/viewer/scene/model/layer/programs/DepthProgram.js +11 -0
- package/src/viewer/scene/model/layer/programs/EdgesProgram.js +12 -0
- package/src/viewer/scene/model/layer/programs/FlatColorProgram.js +24 -0
- package/src/viewer/scene/model/layer/programs/OcclusionProgram.js +12 -0
- package/src/viewer/scene/model/layer/programs/PBRProgram.js +180 -0
- package/src/viewer/scene/model/layer/programs/PickDepthProgram.js +30 -0
- package/src/viewer/scene/model/layer/programs/PickMeshProgram.js +12 -0
- package/src/viewer/scene/model/layer/programs/PickNormalsProgram.js +18 -0
- package/src/viewer/scene/model/layer/programs/ShadowProgram.js +23 -0
- package/src/viewer/scene/model/layer/programs/SilhouetteProgram.js +15 -0
- package/src/viewer/scene/model/layer/programs/SnapProgram.js +29 -0
- package/src/viewer/scene/scene/Scene.js +21 -38
- package/src/viewer/scene/webgl/ArrayBuf.js +5 -20
- package/src/viewer/scene/webgl/FrameContext.js +14 -86
- package/src/viewer/scene/webgl/RenderBuffer.js +62 -262
- package/src/viewer/scene/webgl/Renderer.js +880 -843
- package/src/viewer/scene/webgl/WebGLRenderer.js +612 -0
- package/src/viewer/scene/webgl/occlusion/OcclusionLayer.js +60 -132
- package/src/viewer/scene/webgl/occlusion/OcclusionTester.js +167 -328
- package/src/viewer/scene/mesh/draw/DrawRenderer.js +0 -998
- package/src/viewer/scene/mesh/emphasis/EmphasisEdgesRenderer.js +0 -259
- package/src/viewer/scene/mesh/emphasis/EmphasisEdgesShaderSource.js +0 -160
- package/src/viewer/scene/mesh/emphasis/EmphasisFillRenderer.js +0 -286
- package/src/viewer/scene/mesh/emphasis/EmphasisFillShaderSource.js +0 -263
- package/src/viewer/scene/mesh/occlusion/OcclusionRenderer.js +0 -221
- package/src/viewer/scene/mesh/pick/PickMeshRenderer.js +0 -223
- package/src/viewer/scene/mesh/pick/PickTriangleRenderer.js +0 -200
- package/src/viewer/scene/mesh/shadow/ShadowRenderer.js +0 -214
- package/src/viewer/scene/model/RENDER_PASSES.js +0 -34
- package/src/viewer/scene/model/dtx/BindableDataTexture.js +0 -31
- package/src/viewer/scene/model/dtx/lines/DTXLinesBuffer.js +0 -27
- package/src/viewer/scene/model/dtx/lines/DTXLinesLayer.js +0 -897
- package/src/viewer/scene/model/dtx/lines/DTXLinesState.js +0 -46
- package/src/viewer/scene/model/dtx/lines/DTXLinesTextureFactory.js +0 -411
- package/src/viewer/scene/model/dtx/lines/dataTextureRamStats.js +0 -49
- package/src/viewer/scene/model/dtx/lines/rebucketPositions.js +0 -208
- package/src/viewer/scene/model/dtx/lines/renderers/DTXLinesColorRenderer.js +0 -389
- package/src/viewer/scene/model/dtx/lines/renderers/DTXLinesRenderers.js +0 -65
- package/src/viewer/scene/model/dtx/triangles/DTXTrianglesLayer.js +0 -1399
- package/src/viewer/scene/model/dtx/triangles/lib/DTXTrianglesBuffer.js +0 -46
- package/src/viewer/scene/model/dtx/triangles/lib/DTXTrianglesState.js +0 -250
- package/src/viewer/scene/model/dtx/triangles/lib/DTXTrianglesTextureFactory.js +0 -518
- package/src/viewer/scene/model/dtx/triangles/lib/dataTextureRamStats.js +0 -54
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesColorRenderer.js +0 -639
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesDepthRenderer.js +0 -464
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesEdgesColorRenderer.js +0 -423
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesEdgesRenderer.js +0 -431
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesNormalsRenderer.js +0 -345
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesOcclusionRenderer.js +0 -436
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesPickDepthRenderer.js +0 -466
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesPickMeshRenderer.js +0 -437
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesPickNormalsFlatRenderer.js +0 -460
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesPickNormalsRenderer.js +0 -437
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesRenderers.js +0 -307
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesSilhouetteRenderer.js +0 -472
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesSnapInitRenderer.js +0 -474
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesSnapRenderer.js +0 -435
- package/src/viewer/scene/model/vbo/ScratchMemory.js +0 -63
- package/src/viewer/scene/model/vbo/VBORenderer.js +0 -664
- package/src/viewer/scene/model/vbo/batching/lines/VBOBatchingLinesLayer.js +0 -704
- package/src/viewer/scene/model/vbo/batching/lines/lib/VBOBatchingLinesBuffer.js +0 -19
- package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLineSnapInitRenderer.js +0 -318
- package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLinesColorRenderer.js +0 -114
- package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLinesRenderers.js +0 -99
- package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLinesSilhouetteRenderer.js +0 -124
- package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLinesSnapInitRenderer.js +0 -313
- package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLinesSnapRenderer.js +0 -311
- package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOSceneModelLineBatchingRenderer.js +0 -24
- package/src/viewer/scene/model/vbo/batching/points/VBOBatchingPointsLayer.js +0 -688
- package/src/viewer/scene/model/vbo/batching/points/VBOBatchingPointsRenderer.js +0 -24
- package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsColorRenderer.js +0 -168
- package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsOcclusionRenderer.js +0 -136
- package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsPickDepthRenderer.js +0 -156
- package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsPickMeshRenderer.js +0 -148
- package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsRenderers.js +0 -144
- package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsShadowRenderer.js +0 -107
- package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsSilhouetteRenderer.js +0 -146
- package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsSnapInitRenderer.js +0 -315
- package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsSnapRenderer.js +0 -305
- package/src/viewer/scene/model/vbo/batching/triangles/VBOBatchingTrianglesBuffer.js +0 -24
- package/src/viewer/scene/model/vbo/batching/triangles/VBOBatchingTrianglesLayer.js +0 -1346
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/EdgesColorRenderer.js +0 -131
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/EdgesEmphasisRenderer.js +0 -135
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/EdgesRenderer.js +0 -12
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/Renderers.js +0 -403
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesBatchingRenderer.js +0 -35
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesColorRenderer.js +0 -252
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesColorTextureRenderer.js +0 -294
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesDepthRenderer.js +0 -115
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesFlatColorRenderer.js +0 -246
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesNormalsRenderer.js +0 -139
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesOcclusionRenderer.js +0 -125
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesPBRRenderer.js +0 -561
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesPickDepthRenderer.js +0 -144
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesPickMeshRenderer.js +0 -130
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesPickNormalsFlatRenderer.js +0 -121
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesPickNormalsRenderer.js +0 -131
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesShadowRenderer.js +0 -107
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesSilhouetteRenderer.js +0 -144
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesSnapInitRenderer.js +0 -313
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesSnapRenderer.js +0 -312
- package/src/viewer/scene/model/vbo/float16.js +0 -760
- package/src/viewer/scene/model/vbo/instancing/lines/VBOInstancingLinesLayer.js +0 -711
- package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesColorRenderer.js +0 -148
- package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesRenderer.js +0 -26
- package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesRenderers.js +0 -139
- package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesSilhouetteRenderer.js +0 -127
- package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesSnapInitRenderer.js +0 -308
- package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesSnapRenderer.js +0 -299
- package/src/viewer/scene/model/vbo/instancing/points/VBOInstancingPointsLayer.js +0 -733
- package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsColorRenderer.js +0 -174
- package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsDepthRenderer.js +0 -156
- package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsOcclusionRenderer.js +0 -149
- package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsPickDepthRenderer.js +0 -170
- package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsPickMeshRenderer.js +0 -152
- package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsRenderer.js +0 -26
- package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsRenderers.js +0 -174
- package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsShadowRenderer.js +0 -119
- package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsSilhouetteRenderer.js +0 -154
- package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsSnapInitRenderer.js +0 -307
- package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsSnapRenderer.js +0 -293
- package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingTrianglesRenderer.js +0 -150
- package/src/viewer/scene/model/vbo/instancing/triangles/VBOInstancingTrianglesLayer.js +0 -1289
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/EdgesColorRenderer.js +0 -135
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/EdgesEmphasisRenderer.js +0 -137
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/EdgesRenderer.js +0 -12
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/Renderers.js +0 -403
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesColorRenderer.js +0 -267
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesColorTextureRenderer.js +0 -299
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesDepthRenderer.js +0 -126
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesFlatColorRenderer.js +0 -255
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesFlatNormalsRenderer.js +0 -130
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesInstancingRenderer.js +0 -32
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesNormalsRenderer.js +0 -138
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesOcclusionRenderer.js +0 -128
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesPBRRenderer.js +0 -561
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesPickDepthRenderer.js +0 -149
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesPickMeshRenderer.js +0 -136
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesPickNormalsFlatRenderer.js +0 -130
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesPickNormalsRenderer.js +0 -145
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesShadowRenderer.js +0 -113
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesSilhouetteRenderer.js +0 -148
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesSnapInitRenderer.js +0 -319
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesSnapRenderer.js +0 -310
- package/src/viewer/scene/webgl/Attribute.js +0 -23
- package/src/viewer/scene/webgl/Program.js +0 -181
- package/src/viewer/scene/webgl/RenderBufferManager.js +0 -34
- package/src/viewer/scene/webgl/Sampler.js +0 -18
- package/src/viewer/scene/webgl/Shader.js +0 -49
- package/src/viewer/scene/webgl/sao/SAODepthLimitedBlurRenderer.js +0 -324
- package/src/viewer/scene/webgl/sao/SAOOcclusionRenderer.js +0 -384
|
@@ -5,14 +5,27 @@ import {WEBGL_INFO} from '../webglInfo.js';
|
|
|
5
5
|
import {Map} from "../utils/Map.js";
|
|
6
6
|
import {PickResult} from "./PickResult.js";
|
|
7
7
|
import {OcclusionTester} from "./occlusion/OcclusionTester.js";
|
|
8
|
-
import {SAOOcclusionRenderer} from "./sao/SAOOcclusionRenderer.js";
|
|
9
8
|
import {createRTCViewMat} from "../math/rtcCoords.js";
|
|
10
|
-
import {
|
|
11
|
-
import {RenderBufferManager} from "./RenderBufferManager.js";
|
|
9
|
+
import {RenderBuffer} from "./RenderBuffer.js";
|
|
12
10
|
import {getExtension} from "./getExtension.js";
|
|
11
|
+
import {createProgramVariablesState} from "./WebGLRenderer.js";
|
|
12
|
+
import {ArrayBuf} from "./ArrayBuf.js";
|
|
13
|
+
|
|
14
|
+
const OCCLUSION_TEST_MODE = false;
|
|
13
15
|
|
|
14
16
|
const vec3_0 = math.vec3([0,0,0]);
|
|
15
17
|
|
|
18
|
+
const iota = (n) => { const ret = [ ]; for (let i = 0; i < n; ++i) ret.push(i); return ret; };
|
|
19
|
+
|
|
20
|
+
const bitShiftScreenZ = math.vec4([1.0 / (256.0 * 256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0]);
|
|
21
|
+
|
|
22
|
+
const pixelToInt = pix => pix[0] + (pix[1] << 8) + (pix[2] << 16) + (pix[3] << 24);
|
|
23
|
+
|
|
24
|
+
const toWorldNormal = (n) => math.normalizeVec3(math.divVec3Scalar(n, math.MAX_INT, math.vec3()));
|
|
25
|
+
const toWorldPos = (p, origin, scale) => math.vec3([ p[0] * scale[0] + origin[0],
|
|
26
|
+
p[1] * scale[1] + origin[1],
|
|
27
|
+
p[2] * scale[2] + origin[2] ]);
|
|
28
|
+
|
|
16
29
|
/**
|
|
17
30
|
* @private
|
|
18
31
|
*/
|
|
@@ -20,7 +33,7 @@ const Renderer = function (scene, options) {
|
|
|
20
33
|
|
|
21
34
|
options = options || {};
|
|
22
35
|
|
|
23
|
-
const frameCtx = new FrameContext(
|
|
36
|
+
const frameCtx = new FrameContext();
|
|
24
37
|
const canvas = scene.canvas.canvas;
|
|
25
38
|
/**
|
|
26
39
|
* @type {WebGL2RenderingContext}
|
|
@@ -49,15 +62,344 @@ const Renderer = function (scene, options) {
|
|
|
49
62
|
let pbrEnabled = true;
|
|
50
63
|
let colorTextureEnabled = true;
|
|
51
64
|
|
|
52
|
-
const renderBufferManager =
|
|
65
|
+
const renderBufferManager = (function() {
|
|
66
|
+
const renderBuffersBasic = {};
|
|
67
|
+
const renderBuffersScaled = {};
|
|
68
|
+
return {
|
|
69
|
+
getRenderBuffer: (id, colorFormats, hasDepthTexture) => {
|
|
70
|
+
const renderBuffers = (scene.canvas.resolutionScale === 1.0) ? renderBuffersBasic : renderBuffersScaled;
|
|
71
|
+
if (! renderBuffers[id]) {
|
|
72
|
+
renderBuffers[id] = new RenderBuffer(gl, colorFormats, hasDepthTexture);
|
|
73
|
+
}
|
|
74
|
+
return renderBuffers[id];
|
|
75
|
+
},
|
|
76
|
+
destroy: () => {
|
|
77
|
+
Object.values(renderBuffersBasic ).forEach(buf => buf.destroy());
|
|
78
|
+
Object.values(renderBuffersScaled).forEach(buf => buf.destroy());
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
})();
|
|
82
|
+
|
|
83
|
+
const SAOProgram = (gl, name, programVariablesState, createOutColorDefinition) => {
|
|
84
|
+
const programVariables = programVariablesState.programVariables;
|
|
85
|
+
|
|
86
|
+
const uViewportInv = programVariables.createUniform("vec2", "uViewportInv");
|
|
87
|
+
const uCameraNear = programVariables.createUniform("float", "uCameraNear");
|
|
88
|
+
const uCameraFar = programVariables.createUniform("float", "uCameraFar");
|
|
89
|
+
const uDepthTexture = programVariables.createUniform("sampler2D", "uDepthTexture");
|
|
90
|
+
|
|
91
|
+
const uv = programVariables.createAttribute("vec2", "uv");
|
|
92
|
+
const vUV = programVariables.createVarying("vec2", "vUV", () => uv);
|
|
93
|
+
const outColor = programVariables.createOutput("vec4", "outColor");
|
|
94
|
+
|
|
95
|
+
const getOutColor = programVariables.createFragmentDefinition(
|
|
96
|
+
"getOutColor",
|
|
97
|
+
(name, src) => {
|
|
98
|
+
const getDepth = "getDepth";
|
|
99
|
+
src.push(`
|
|
100
|
+
float ${getDepth}(const in vec2 uv) {
|
|
101
|
+
return texture(${uDepthTexture}, uv).r;
|
|
102
|
+
}
|
|
103
|
+
`);
|
|
104
|
+
src.push(createOutColorDefinition(name, vUV, uViewportInv, uCameraNear, uCameraFar, getDepth));
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const [program, errors] = programVariablesState.buildProgram(
|
|
108
|
+
gl,
|
|
109
|
+
name,
|
|
110
|
+
{
|
|
111
|
+
clipPos: `vec4(2.0 * ${uv} - 1.0, 0.0, 1.0)`,
|
|
112
|
+
appendFragmentOutputs: (src) => src.push(`${outColor} = ${getOutColor}();`)
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
if (errors) {
|
|
116
|
+
console.error(errors.join("\n"));
|
|
117
|
+
throw errors;
|
|
118
|
+
} else {
|
|
119
|
+
const uvs = new Float32Array([1,1, 0,1, 0,0, 1,0]);
|
|
120
|
+
const uvBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, uvs, uvs.length, 2, gl.STATIC_DRAW);
|
|
121
|
+
|
|
122
|
+
// Mitigation: if Uint8Array is used, the geometry is corrupted on OSX when using Chrome with data-textures
|
|
123
|
+
const indices = new Uint32Array([0, 1, 2, 0, 2, 3]);
|
|
124
|
+
const indicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, indices, indices.length, 1, gl.STATIC_DRAW);
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
destroy: program.destroy,
|
|
128
|
+
bind: (viewportSize, project, depthTexture) => {
|
|
129
|
+
program.bind();
|
|
130
|
+
uViewportInv.setInputValue([1 / viewportSize[0], 1 / viewportSize[1]]);
|
|
131
|
+
uCameraNear.setInputValue(project.near);
|
|
132
|
+
uCameraFar.setInputValue(project.far);
|
|
133
|
+
uDepthTexture.setInputValue(depthTexture);
|
|
134
|
+
uv.setInputValue(uvBuf);
|
|
135
|
+
},
|
|
136
|
+
draw: () => {
|
|
137
|
+
indicesBuf.bind();
|
|
138
|
+
gl.drawElements(gl.TRIANGLES, indicesBuf.numItems, indicesBuf.itemType, 0);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// SAO implementation inspired from previous SAO work in THREE.js by ludobaka / ludobaka.github.io and bhouston
|
|
145
|
+
const saoOcclusionRenderer = (function() {
|
|
146
|
+
let currentRenrerer = null;
|
|
147
|
+
let curNumSamples = null;
|
|
148
|
+
return {
|
|
149
|
+
destroy: () => currentRenrerer && currentRenrerer.destroy(),
|
|
150
|
+
render: (viewportSize, project, sao, depthTexture) => {
|
|
151
|
+
const numSamples = Math.floor(sao.numSamples);
|
|
152
|
+
if (curNumSamples !== numSamples) {
|
|
153
|
+
currentRenrerer && currentRenrerer.destroy();
|
|
154
|
+
|
|
155
|
+
const programVariablesState = createProgramVariablesState();
|
|
156
|
+
|
|
157
|
+
const programVariables = programVariablesState.programVariables;
|
|
158
|
+
|
|
159
|
+
const uProjectMatrix = programVariables.createUniform("mat4", "uProjectMatrix");
|
|
160
|
+
const uInvProjMatrix = programVariables.createUniform("mat4", "uInvProjMatrix");
|
|
161
|
+
const uPerspective = programVariables.createUniform("bool", "uPerspective");
|
|
162
|
+
const uScale = programVariables.createUniform("float", "uScale");
|
|
163
|
+
const uIntensity = programVariables.createUniform("float", "uIntensity");
|
|
164
|
+
const uBias = programVariables.createUniform("float", "uBias");
|
|
165
|
+
const uKernelRadius = programVariables.createUniform("float", "uKernelRadius");
|
|
166
|
+
const uMinResolution = programVariables.createUniform("float", "uMinResolution");
|
|
167
|
+
const uRandomSeed = programVariables.createUniform("float", "uRandomSeed");
|
|
168
|
+
|
|
169
|
+
const program = SAOProgram(
|
|
170
|
+
gl,
|
|
171
|
+
"SAOOcclusionRenderer",
|
|
172
|
+
programVariablesState,
|
|
173
|
+
(name, vUV, uViewportInv, uCameraNear, uCameraFar, getDepth) => {
|
|
174
|
+
return `
|
|
175
|
+
#define EPSILON 1e-6
|
|
176
|
+
#define PI 3.14159265359
|
|
177
|
+
#define PI2 6.28318530718
|
|
178
|
+
#define NUM_SAMPLES ${numSamples}
|
|
179
|
+
#define NUM_RINGS 4
|
|
180
|
+
|
|
181
|
+
const vec3 packFactors = vec3(256. * 256. * 256., 256. * 256., 256.);
|
|
182
|
+
|
|
183
|
+
vec4 packFloatToRGBA(const in float v) {
|
|
184
|
+
vec4 r = vec4(fract(v * packFactors), v);
|
|
185
|
+
r.yzw -= r.xyz / 256.;
|
|
186
|
+
return r * 256. / 255.;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
highp float rand(const in vec2 uv) {
|
|
190
|
+
const highp float a = 12.9898, b = 78.233, c = 43758.5453;
|
|
191
|
+
return fract(sin(mod(dot(uv, vec2(a, b)), PI)) * c);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
vec3 getViewPos(const in vec2 screenPos, const in float depth) {
|
|
195
|
+
float near = ${uCameraNear};
|
|
196
|
+
float far = ${uCameraFar};
|
|
197
|
+
float viewZ = (${uPerspective}
|
|
198
|
+
? ((near * far) / ((far - near) * depth - far))
|
|
199
|
+
: (depth * (near - far) - near));
|
|
200
|
+
float clipW = ${uProjectMatrix}[2][3] * viewZ + ${uProjectMatrix}[3][3];
|
|
201
|
+
return (${uInvProjMatrix} * (clipW * vec4((vec3(screenPos, depth) - 0.5) * 2.0, 1.0))).xyz;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
vec4 ${name}() {
|
|
205
|
+
float centerDepth = ${getDepth}(${vUV});
|
|
206
|
+
if (centerDepth >= (1.0 - EPSILON)) {
|
|
207
|
+
discard;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
vec3 centerViewPosition = getViewPos(${vUV}, centerDepth);
|
|
211
|
+
float scaleDividedByCameraFar = ${uScale} / ${uCameraFar};
|
|
212
|
+
float minResolutionMultipliedByCameraFar = ${uMinResolution} * ${uCameraFar};
|
|
213
|
+
vec3 centerViewNormal = normalize(cross(dFdx(centerViewPosition), dFdy(centerViewPosition)));
|
|
214
|
+
|
|
215
|
+
vec2 radiusStep = ${uKernelRadius} * ${uViewportInv} / float(NUM_SAMPLES);
|
|
216
|
+
vec2 radius = radiusStep;
|
|
217
|
+
const float angleStep = PI2 * float(NUM_RINGS) / float(NUM_SAMPLES);
|
|
218
|
+
float angle = PI2 * rand(${vUV} + ${uRandomSeed});
|
|
219
|
+
|
|
220
|
+
float occlusionSum = 0.0;
|
|
221
|
+
float weightSum = 0.0;
|
|
222
|
+
|
|
223
|
+
for (int i = 0; i < NUM_SAMPLES; i++) {
|
|
224
|
+
vec2 sampleUv = ${vUV} + vec2(cos(angle), sin(angle)) * radius;
|
|
225
|
+
radius += radiusStep;
|
|
226
|
+
angle += angleStep;
|
|
227
|
+
|
|
228
|
+
float sampleDepth = ${getDepth}(sampleUv);
|
|
229
|
+
if (sampleDepth >= (1.0 - EPSILON)) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
vec3 sampleViewPosition = getViewPos(sampleUv, sampleDepth);
|
|
234
|
+
vec3 viewDelta = sampleViewPosition - centerViewPosition;
|
|
235
|
+
float scaledScreenDistance = scaleDividedByCameraFar * length(viewDelta);
|
|
236
|
+
occlusionSum += max(0.0, (dot(centerViewNormal, viewDelta) - minResolutionMultipliedByCameraFar) / scaledScreenDistance - ${uBias}) / (1.0 + scaledScreenDistance * scaledScreenDistance );
|
|
237
|
+
weightSum += 1.0;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return packFloatToRGBA(1.0 - occlusionSum * ${uIntensity} / weightSum);
|
|
241
|
+
}`;
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
currentRenrerer = {
|
|
245
|
+
destroy: program.destroy,
|
|
246
|
+
render: (viewportSize, project, sao, depthTexture) => {
|
|
247
|
+
program.bind(viewportSize, project, depthTexture);
|
|
248
|
+
|
|
249
|
+
uProjectMatrix.setInputValue(project.matrix);
|
|
250
|
+
uInvProjMatrix.setInputValue(project.inverseMatrix);
|
|
251
|
+
uPerspective.setInputValue(project.type === "Perspective");
|
|
252
|
+
uScale.setInputValue(sao.scale * project.far / 5);
|
|
253
|
+
uIntensity.setInputValue(sao.intensity);
|
|
254
|
+
uBias.setInputValue(sao.bias);
|
|
255
|
+
uKernelRadius.setInputValue(sao.kernelRadius);
|
|
256
|
+
uMinResolution.setInputValue(sao.minResolution);
|
|
257
|
+
uRandomSeed.setInputValue(Math.random());
|
|
258
|
+
|
|
259
|
+
program.draw();
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
curNumSamples = numSamples;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
currentRenrerer.render(viewportSize, project, sao, depthTexture);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
})();
|
|
270
|
+
|
|
271
|
+
const saoDepthLimitedBlurRenderer = (function() {
|
|
272
|
+
const blurStdDev = 4;
|
|
273
|
+
const blurDepthCutoff = 0.01;
|
|
274
|
+
const KERNEL_RADIUS = 16;
|
|
275
|
+
|
|
276
|
+
const createSampleOffsets = (uvIncrement) => {
|
|
277
|
+
const offsets = [];
|
|
278
|
+
for (let i = 0; i <= KERNEL_RADIUS + 1; i++) {
|
|
279
|
+
offsets.push(uvIncrement[0] * i);
|
|
280
|
+
offsets.push(uvIncrement[1] * i);
|
|
281
|
+
}
|
|
282
|
+
return new Float32Array(offsets);
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const sampleOffsetsVer = createSampleOffsets([0, 1]);
|
|
286
|
+
const sampleOffsetsHor = createSampleOffsets([1, 0]);
|
|
287
|
+
|
|
288
|
+
const gaussian = (i, stdDev) => Math.exp(-(i * i) / (2.0 * (stdDev * stdDev))) / (Math.sqrt(2.0 * Math.PI) * stdDev);
|
|
289
|
+
const sampleWeights = new Float32Array(iota(KERNEL_RADIUS + 1).map(i => gaussian(i, blurStdDev))); // TODO: Optimize
|
|
290
|
+
|
|
291
|
+
const programVariablesState = createProgramVariablesState();
|
|
53
292
|
|
|
54
|
-
|
|
293
|
+
const programVariables = programVariablesState.programVariables;
|
|
55
294
|
|
|
56
|
-
|
|
57
|
-
|
|
295
|
+
const uDepthCutoff = programVariables.createUniform("float", "uDepthCutoff");
|
|
296
|
+
const uSampleOffsets = programVariables.createUniformArray("vec2", "uSampleOffsets", KERNEL_RADIUS + 1);
|
|
297
|
+
const uSampleWeights = programVariables.createUniformArray("float", "uSampleWeights", KERNEL_RADIUS + 1);
|
|
58
298
|
|
|
59
|
-
|
|
60
|
-
|
|
299
|
+
const uOcclusionTex = programVariables.createUniform("sampler2D", "uOcclusionTex");
|
|
300
|
+
|
|
301
|
+
const program = SAOProgram(
|
|
302
|
+
gl,
|
|
303
|
+
"SAODepthLimitedBlurRenderer",
|
|
304
|
+
programVariablesState,
|
|
305
|
+
(name, vUV, uViewportInv, uCameraNear, uCameraFar, getDepth) => {
|
|
306
|
+
return `
|
|
307
|
+
#define EPSILON 1e-6
|
|
308
|
+
|
|
309
|
+
const vec3 packFactors = vec3(256. * 256. * 256., 256. * 256., 256.);
|
|
310
|
+
|
|
311
|
+
vec4 packFloatToRGBA(const in float v) {
|
|
312
|
+
vec4 r = vec4(fract(v * packFactors), v);
|
|
313
|
+
r.yzw -= r.xyz / 256.;
|
|
314
|
+
return r * 256. / 255.;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
float getOcclusion(const in vec2 uv) {
|
|
318
|
+
vec4 v = texture(${uOcclusionTex}, uv);
|
|
319
|
+
return dot(floor(v * 255.0 + 0.5) / 255.0, 255. / 256. / vec4(packFactors, 1.)); // unpackRGBAToFloat
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
float getViewZ(const in float depth) {
|
|
323
|
+
return (${uCameraNear} * ${uCameraFar}) / ((${uCameraFar} - ${uCameraNear}) * depth - ${uCameraFar});
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
vec4 ${name}() {
|
|
327
|
+
float centerDepth = ${getDepth}(${vUV});
|
|
328
|
+
if (centerDepth >= (1.0 - EPSILON)) {
|
|
329
|
+
discard;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
float centerViewZ = getViewZ(centerDepth);
|
|
333
|
+
bool rBreak = false;
|
|
334
|
+
bool lBreak = false;
|
|
335
|
+
|
|
336
|
+
float weightSum = ${uSampleWeights}[0];
|
|
337
|
+
float occlusionSum = getOcclusion(${vUV}) * weightSum;
|
|
338
|
+
|
|
339
|
+
for (int i = 1; i <= ${KERNEL_RADIUS}; i++) {
|
|
340
|
+
float sampleWeight = ${uSampleWeights}[i];
|
|
341
|
+
vec2 sampleUVOffset = ${uSampleOffsets}[i] * ${uViewportInv};
|
|
342
|
+
|
|
343
|
+
if (! rBreak) {
|
|
344
|
+
vec2 rSampleUV = ${vUV} + sampleUVOffset;
|
|
345
|
+
if (abs(centerViewZ - getViewZ(${getDepth}(rSampleUV))) > ${uDepthCutoff}) {
|
|
346
|
+
rBreak = true;
|
|
347
|
+
} else {
|
|
348
|
+
occlusionSum += getOcclusion(rSampleUV) * sampleWeight;
|
|
349
|
+
weightSum += sampleWeight;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (! lBreak) {
|
|
354
|
+
vec2 lSampleUV = ${vUV} - sampleUVOffset;
|
|
355
|
+
if (abs(centerViewZ - getViewZ(${getDepth}(lSampleUV))) > ${uDepthCutoff}) {
|
|
356
|
+
lBreak = true;
|
|
357
|
+
} else {
|
|
358
|
+
occlusionSum += getOcclusion(lSampleUV) * sampleWeight;
|
|
359
|
+
weightSum += sampleWeight;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return packFloatToRGBA(occlusionSum / weightSum);
|
|
365
|
+
}`;
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
destroy: program.destroy,
|
|
370
|
+
render: (viewportSize, project, direction, depthTexture, occlusionTexture) => {
|
|
371
|
+
program.bind(viewportSize, project, depthTexture);
|
|
372
|
+
|
|
373
|
+
uDepthCutoff.setInputValue(blurDepthCutoff);
|
|
374
|
+
uSampleOffsets.setInputValue((direction === 0) ? sampleOffsetsHor : sampleOffsetsVer);
|
|
375
|
+
uSampleWeights.setInputValue(sampleWeights);
|
|
376
|
+
uOcclusionTex.setInputValue(occlusionTexture);
|
|
377
|
+
|
|
378
|
+
program.draw();
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
})();
|
|
382
|
+
|
|
383
|
+
const getSceneCameraViewParams = (function() {
|
|
384
|
+
let params = null; // scene.camera not defined yet
|
|
385
|
+
return function() {
|
|
386
|
+
if (! params) {
|
|
387
|
+
const camera = scene.camera;
|
|
388
|
+
params = {
|
|
389
|
+
get eye() { return camera.eye; },
|
|
390
|
+
get far() { return camera.project.far; },
|
|
391
|
+
get projMatrix() { return camera.projMatrix; },
|
|
392
|
+
get viewMatrix() { return camera.viewMatrix; },
|
|
393
|
+
get viewNormalMatrix() { return camera.viewNormalMatrix; }
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
return params;
|
|
397
|
+
};
|
|
398
|
+
})();
|
|
399
|
+
|
|
400
|
+
const getNearPlaneHeight = (camera, drawingBufferHeight) => ((camera.projection === "ortho")
|
|
401
|
+
? 1.0
|
|
402
|
+
: (drawingBufferHeight / (2 * Math.tan(0.5 * camera.perspective.fov * Math.PI / 180.0))));
|
|
61
403
|
|
|
62
404
|
this.scene = scene;
|
|
63
405
|
|
|
@@ -109,19 +451,6 @@ const Renderer = function (scene, options) {
|
|
|
109
451
|
imageDirty = true;
|
|
110
452
|
};
|
|
111
453
|
|
|
112
|
-
this.webglContextLost = function () {
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
this.webglContextRestored = function (gl) {
|
|
116
|
-
|
|
117
|
-
// renderBufferManager.webglContextRestored(gl);
|
|
118
|
-
|
|
119
|
-
saoOcclusionRenderer.init();
|
|
120
|
-
saoDepthLimitedBlurRenderer.init();
|
|
121
|
-
|
|
122
|
-
imageDirty = true;
|
|
123
|
-
};
|
|
124
|
-
|
|
125
454
|
/**
|
|
126
455
|
* Inserts a drawable into this renderer.
|
|
127
456
|
* @private
|
|
@@ -201,13 +530,7 @@ const Renderer = function (scene, options) {
|
|
|
201
530
|
const backgroundColor = scene.canvas.backgroundColorFromAmbientLight ? this.lights.getAmbientColorAndIntensity() : scene.canvas.backgroundColor;
|
|
202
531
|
gl.clearColor(backgroundColor[0], backgroundColor[1], backgroundColor[2], 1.0);
|
|
203
532
|
}
|
|
204
|
-
if (bindOutputFrameBuffer) {
|
|
205
|
-
bindOutputFrameBuffer(params.pass);
|
|
206
|
-
}
|
|
207
533
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
208
|
-
if (unbindOutputFrameBuffer) {
|
|
209
|
-
unbindOutputFrameBuffer(params.pass);
|
|
210
|
-
}
|
|
211
534
|
};
|
|
212
535
|
|
|
213
536
|
/**
|
|
@@ -223,14 +546,10 @@ const Renderer = function (scene, options) {
|
|
|
223
546
|
* Renders inserted drawables.
|
|
224
547
|
* @private
|
|
225
548
|
*/
|
|
226
|
-
this.render = function
|
|
227
|
-
params = params || {};
|
|
228
|
-
if (params.force) {
|
|
229
|
-
imageDirty = true;
|
|
230
|
-
}
|
|
549
|
+
this.render = function(pass, clear) {
|
|
231
550
|
updateDrawlist();
|
|
232
551
|
if (imageDirty) {
|
|
233
|
-
draw(
|
|
552
|
+
draw(pass, clear);
|
|
234
553
|
stats.frame.frameCount++;
|
|
235
554
|
imageDirty = false;
|
|
236
555
|
}
|
|
@@ -238,243 +557,175 @@ const Renderer = function (scene, options) {
|
|
|
238
557
|
|
|
239
558
|
function updateDrawlist() { // Prepares state-sorted array of drawables from maps of inserted drawables
|
|
240
559
|
if (drawableListDirty) {
|
|
241
|
-
|
|
560
|
+
Object.values(drawableTypeInfo).forEach(drawableInfo => {
|
|
561
|
+
const drawableListPreCull = drawableInfo.drawableListPreCull;
|
|
562
|
+
let lenDrawableList = 0;
|
|
563
|
+
Object.values(drawableInfo.drawableMap).forEach(drawable => { drawableListPreCull[lenDrawableList++] = drawable; });
|
|
564
|
+
drawableListPreCull.length = lenDrawableList;
|
|
565
|
+
});
|
|
242
566
|
drawableListDirty = false;
|
|
243
567
|
stateSortDirty = true;
|
|
244
568
|
}
|
|
245
569
|
if (stateSortDirty) {
|
|
246
|
-
|
|
570
|
+
let lenDrawableList = 0;
|
|
571
|
+
Object.values(drawableTypeInfo).forEach(drawableInfo => {
|
|
572
|
+
drawableInfo.drawableListPreCull.forEach(drawable => { postSortDrawableList[lenDrawableList++] = drawable; });
|
|
573
|
+
});
|
|
574
|
+
postSortDrawableList.length = lenDrawableList;
|
|
575
|
+
postSortDrawableList.sort((a, b) => a.renderOrder - b.renderOrder);
|
|
247
576
|
stateSortDirty = false;
|
|
248
577
|
imageDirty = true;
|
|
249
578
|
}
|
|
250
579
|
if (imageDirty) { // Image is usually dirty because the camera moved
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const drawableListPreCull = drawableInfo.drawableListPreCull;
|
|
261
|
-
let lenDrawableList = 0;
|
|
262
|
-
for (let id in drawableMap) {
|
|
263
|
-
if (drawableMap.hasOwnProperty(id)) {
|
|
264
|
-
drawableListPreCull[lenDrawableList++] = drawableMap[id];
|
|
580
|
+
let lenDrawableList = 0;
|
|
581
|
+
let lenUiList = 0;
|
|
582
|
+
postSortDrawableList.forEach(drawable => {
|
|
583
|
+
drawable.rebuildRenderFlags();
|
|
584
|
+
if (!drawable.renderFlags.culled) {
|
|
585
|
+
if (drawable.isUI) {
|
|
586
|
+
uiDrawableList[lenUiList++] = drawable;
|
|
587
|
+
} else {
|
|
588
|
+
postCullDrawableList[lenDrawableList++] = drawable;
|
|
265
589
|
}
|
|
266
590
|
}
|
|
267
|
-
|
|
268
|
-
|
|
591
|
+
});
|
|
592
|
+
postCullDrawableList.length = lenDrawableList;
|
|
593
|
+
uiDrawableList.length = lenUiList;
|
|
269
594
|
}
|
|
270
595
|
}
|
|
271
596
|
|
|
272
|
-
function
|
|
273
|
-
let lenDrawableList = 0;
|
|
274
|
-
for (let type in drawableTypeInfo) {
|
|
275
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
276
|
-
const drawableInfo = drawableTypeInfo[type];
|
|
277
|
-
const drawableListPreCull = drawableInfo.drawableListPreCull;
|
|
278
|
-
for (let i = 0, len = drawableListPreCull.length; i < len; i++) {
|
|
279
|
-
const drawable = drawableListPreCull[i];
|
|
280
|
-
postSortDrawableList[lenDrawableList++] = drawable;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
postSortDrawableList.length = lenDrawableList;
|
|
285
|
-
postSortDrawableList.sort((a, b) => {
|
|
286
|
-
return a.renderOrder - b.renderOrder;
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function cullDrawableList() {
|
|
291
|
-
let lenDrawableList = 0;
|
|
292
|
-
let lenUiList = 0;
|
|
293
|
-
for (let i = 0, len = postSortDrawableList.length; i < len; i++) {
|
|
294
|
-
const drawable = postSortDrawableList[i];
|
|
295
|
-
drawable.rebuildRenderFlags();
|
|
296
|
-
if (!drawable.renderFlags.culled) {
|
|
297
|
-
if (drawable.isUI) {
|
|
298
|
-
uiDrawableList[lenUiList++] = drawable;
|
|
299
|
-
} else {
|
|
300
|
-
postCullDrawableList[lenDrawableList++] = drawable;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
postCullDrawableList.length = lenDrawableList;
|
|
305
|
-
uiDrawableList.length = lenUiList;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
function draw(params) {
|
|
597
|
+
function draw(pass, clear) {
|
|
309
598
|
|
|
310
599
|
const sao = scene.sao;
|
|
600
|
+
const occlusionTexture = saoEnabled && sao.possible && (sao.numSamples >= 1) && drawSAOBuffers(pass);
|
|
601
|
+
|
|
602
|
+
scene._lightsState.lights.forEach(light => {
|
|
603
|
+
|
|
604
|
+
if (light.castsShadow) {
|
|
605
|
+
const shadowRenderBuf = light.getShadowRenderBuf();
|
|
606
|
+
shadowRenderBuf.bind();
|
|
607
|
+
|
|
608
|
+
frameCtx.reset();
|
|
609
|
+
frameCtx.backfaces = true;
|
|
610
|
+
frameCtx.frontface = true;
|
|
611
|
+
frameCtx.viewParams.viewMatrix = light.getShadowViewMatrix();
|
|
612
|
+
frameCtx.viewParams.projMatrix = light.getShadowProjMatrix();
|
|
613
|
+
frameCtx.nearPlaneHeight = getNearPlaneHeight(scene.camera, gl.drawingBufferHeight);
|
|
614
|
+
|
|
615
|
+
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
616
|
+
|
|
617
|
+
gl.clearColor(0, 0, 0, 1);
|
|
618
|
+
gl.enable(gl.DEPTH_TEST);
|
|
619
|
+
gl.disable(gl.BLEND);
|
|
620
|
+
|
|
621
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
622
|
+
|
|
623
|
+
Object.values(drawableTypeInfo).forEach(
|
|
624
|
+
drawableInfo => {
|
|
625
|
+
drawableInfo.drawableList.forEach(
|
|
626
|
+
drawable => {
|
|
627
|
+
if ((drawable.visible !== false) && drawable.castsShadow && drawable.drawShadow) {
|
|
628
|
+
if (drawable.renderFlags.colorOpaque) { // Transparent objects don't cast shadows (yet)
|
|
629
|
+
drawable.drawShadow(frameCtx);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
});
|
|
633
|
+
});
|
|
311
634
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}
|
|
635
|
+
shadowRenderBuf.unbind();
|
|
636
|
+
}
|
|
637
|
+
});
|
|
315
638
|
|
|
316
|
-
|
|
639
|
+
// const numVertexAttribs = WEBGL_INFO.MAX_VERTEX_ATTRIBS; // Fixes https://github.com/xeokit/xeokit-sdk/issues/174
|
|
640
|
+
// for (let ii = 0; ii < numVertexAttribs; ii++) {
|
|
641
|
+
// gl.disableVertexAttribArray(ii);
|
|
642
|
+
// }
|
|
643
|
+
//
|
|
644
|
+
shadowsDirty = false;
|
|
317
645
|
|
|
318
|
-
drawColor(
|
|
646
|
+
drawColor(pass, clear, occlusionTexture);
|
|
319
647
|
}
|
|
320
648
|
|
|
321
|
-
function drawSAOBuffers(
|
|
649
|
+
function drawSAOBuffers(pass) {
|
|
322
650
|
|
|
323
651
|
const sao = scene.sao;
|
|
324
652
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
const saoDepthRenderBuffer = renderBufferManager.getRenderBuffer("saoDepth", {
|
|
328
|
-
depthTexture: true
|
|
329
|
-
});
|
|
653
|
+
const size = [gl.drawingBufferWidth, gl.drawingBufferHeight];
|
|
330
654
|
|
|
655
|
+
// Render depth buffer
|
|
656
|
+
const saoDepthRenderBuffer = renderBufferManager.getRenderBuffer("saoDepth", [], true);
|
|
657
|
+
saoDepthRenderBuffer.setSize(size);
|
|
331
658
|
saoDepthRenderBuffer.bind();
|
|
332
|
-
|
|
333
|
-
drawDepth(params);
|
|
334
|
-
saoDepthRenderBuffer.unbind();
|
|
335
|
-
|
|
336
|
-
// Render occlusion buffer
|
|
337
|
-
|
|
338
|
-
const occlusionRenderBuffer1 = renderBufferManager.getRenderBuffer("saoOcclusion");
|
|
339
|
-
|
|
340
|
-
occlusionRenderBuffer1.bind();
|
|
341
|
-
occlusionRenderBuffer1.clear();
|
|
342
|
-
saoOcclusionRenderer.render(saoDepthRenderBuffer);
|
|
343
|
-
occlusionRenderBuffer1.unbind();
|
|
344
|
-
|
|
345
|
-
if (sao.blur) {
|
|
346
|
-
|
|
347
|
-
// Horizontally blur occlusion buffer 1 into occlusion buffer 2
|
|
348
|
-
|
|
349
|
-
const occlusionRenderBuffer2 = renderBufferManager.getRenderBuffer("saoOcclusion2");
|
|
350
|
-
|
|
351
|
-
occlusionRenderBuffer2.bind();
|
|
352
|
-
occlusionRenderBuffer2.clear();
|
|
353
|
-
saoDepthLimitedBlurRenderer.render(saoDepthRenderBuffer, occlusionRenderBuffer1, 0);
|
|
354
|
-
occlusionRenderBuffer2.unbind();
|
|
355
|
-
|
|
356
|
-
// Vertically blur occlusion buffer 2 back into occlusion buffer 1
|
|
357
|
-
|
|
358
|
-
occlusionRenderBuffer1.bind();
|
|
359
|
-
occlusionRenderBuffer1.clear();
|
|
360
|
-
saoDepthLimitedBlurRenderer.render(saoDepthRenderBuffer, occlusionRenderBuffer2, 1);
|
|
361
|
-
occlusionRenderBuffer1.unbind();
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
function drawDepth(params) {
|
|
659
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
366
660
|
|
|
367
661
|
frameCtx.reset();
|
|
368
|
-
frameCtx.pass =
|
|
662
|
+
frameCtx.pass = pass;
|
|
663
|
+
frameCtx.viewParams = getSceneCameraViewParams();
|
|
664
|
+
frameCtx.nearPlaneHeight = getNearPlaneHeight(scene.camera, gl.drawingBufferHeight);
|
|
369
665
|
|
|
370
666
|
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
371
|
-
|
|
372
667
|
gl.clearColor(0, 0, 0, 0);
|
|
373
668
|
gl.enable(gl.DEPTH_TEST);
|
|
374
669
|
gl.frontFace(gl.CCW);
|
|
375
670
|
gl.enable(gl.CULL_FACE);
|
|
376
671
|
gl.depthMask(true);
|
|
672
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
377
673
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
}
|
|
381
|
-
for (let i = 0, len = postCullDrawableList.length; i < len; i++) {
|
|
382
|
-
|
|
383
|
-
const drawable = postCullDrawableList[i];
|
|
384
|
-
|
|
385
|
-
if (drawable.culled === true || drawable.visible === false || !drawable.drawDepth || !drawable.saoEnabled) {
|
|
386
|
-
continue;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
if (drawable.renderFlags.colorOpaque) {
|
|
674
|
+
postCullDrawableList.forEach(drawable => {
|
|
675
|
+
if (!drawable.culled && drawable.visible && drawable.drawDepth && drawable.saoEnabled && drawable.renderFlags.colorOpaque) {
|
|
390
676
|
drawable.drawDepth(frameCtx);
|
|
391
677
|
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// const numVertexAttribs = WEBGL_INFO.MAX_VERTEX_ATTRIBS; // Fixes https://github.com/xeokit/xeokit-sdk/issues/174
|
|
395
|
-
// for (let ii = 0; ii < numVertexAttribs; ii++) {
|
|
396
|
-
// gl.disableVertexAttribArray(ii);
|
|
397
|
-
// }
|
|
398
|
-
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
function drawShadowMaps() {
|
|
402
|
-
|
|
403
|
-
let lights = scene._lightsState.lights;
|
|
404
|
-
|
|
405
|
-
for (let i = 0, len = lights.length; i < len; i++) {
|
|
406
|
-
const light = lights[i];
|
|
407
|
-
if (!light.castsShadow) {
|
|
408
|
-
continue;
|
|
409
|
-
}
|
|
410
|
-
drawShadowMap(light);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
// const numVertexAttribs = WEBGL_INFO.MAX_VERTEX_ATTRIBS; // Fixes https://github.com/xeokit/xeokit-sdk/issues/174
|
|
414
|
-
// for (let ii = 0; ii < numVertexAttribs; ii++) {
|
|
415
|
-
// gl.disableVertexAttribArray(ii);
|
|
416
|
-
// }
|
|
417
|
-
//
|
|
418
|
-
shadowsDirty = false;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
function drawShadowMap(light) {
|
|
422
|
-
|
|
423
|
-
const castsShadow = light.castsShadow;
|
|
424
|
-
|
|
425
|
-
if (!castsShadow) {
|
|
426
|
-
return;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
const shadowRenderBuf = light.getShadowRenderBuf();
|
|
430
|
-
|
|
431
|
-
if (!shadowRenderBuf) {
|
|
432
|
-
return;
|
|
433
|
-
}
|
|
678
|
+
});
|
|
434
679
|
|
|
435
|
-
|
|
680
|
+
saoDepthRenderBuffer.unbind();
|
|
436
681
|
|
|
437
|
-
|
|
682
|
+
const depthTexture = saoDepthRenderBuffer.depthTexture;
|
|
438
683
|
|
|
439
|
-
|
|
440
|
-
frameCtx.frontface = true;
|
|
441
|
-
frameCtx.shadowViewMatrix = light.getShadowViewMatrix();
|
|
442
|
-
frameCtx.shadowProjMatrix = light.getShadowProjMatrix();
|
|
684
|
+
// Render occlusion buffer
|
|
443
685
|
|
|
444
|
-
|
|
686
|
+
const occlusionRenderBuffer1 = renderBufferManager.getRenderBuffer("saoOcclusion");
|
|
687
|
+
occlusionRenderBuffer1.setSize(size);
|
|
688
|
+
occlusionRenderBuffer1.bind();
|
|
445
689
|
|
|
690
|
+
gl.viewport(0, 0, size[0], size[1]);
|
|
446
691
|
gl.clearColor(0, 0, 0, 1);
|
|
447
|
-
gl.
|
|
692
|
+
gl.disable(gl.DEPTH_TEST);
|
|
448
693
|
gl.disable(gl.BLEND);
|
|
694
|
+
gl.frontFace(gl.CCW);
|
|
695
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
449
696
|
|
|
450
|
-
|
|
697
|
+
saoOcclusionRenderer.render(size, scene.camera.project, sao, depthTexture);
|
|
451
698
|
|
|
452
|
-
|
|
699
|
+
occlusionRenderBuffer1.unbind();
|
|
453
700
|
|
|
454
|
-
|
|
701
|
+
if (sao.blur) {
|
|
702
|
+
const occlusionRenderBuffer2 = renderBufferManager.getRenderBuffer("saoOcclusion2");
|
|
703
|
+
occlusionRenderBuffer2.setSize(size);
|
|
455
704
|
|
|
456
|
-
|
|
457
|
-
|
|
705
|
+
const blurSAO = (src, dst, direction) => {
|
|
706
|
+
dst.bind();
|
|
458
707
|
|
|
459
|
-
|
|
708
|
+
gl.viewport(0, 0, size[0], size[1]);
|
|
709
|
+
gl.clearColor(0, 0, 0, 1);
|
|
710
|
+
gl.enable(gl.DEPTH_TEST);
|
|
711
|
+
gl.disable(gl.BLEND);
|
|
712
|
+
gl.frontFace(gl.CCW);
|
|
713
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
460
714
|
|
|
461
|
-
|
|
715
|
+
const project = scene.camera.project;
|
|
716
|
+
saoDepthLimitedBlurRenderer.render(size, project, direction, depthTexture, src.colorTextures[0]);
|
|
462
717
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
}
|
|
718
|
+
dst.unbind();
|
|
719
|
+
};
|
|
466
720
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
}
|
|
721
|
+
blurSAO(occlusionRenderBuffer1, occlusionRenderBuffer2, 0); // horizontally
|
|
722
|
+
blurSAO(occlusionRenderBuffer2, occlusionRenderBuffer1, 1); // vertically
|
|
472
723
|
}
|
|
473
724
|
|
|
474
|
-
|
|
725
|
+
return occlusionRenderBuffer1.colorTextures[0];
|
|
475
726
|
}
|
|
476
727
|
|
|
477
|
-
function drawColor(
|
|
728
|
+
function drawColor(pass, clear, occlusionTexture) {
|
|
478
729
|
|
|
479
730
|
const normalDrawSAOBin = [];
|
|
480
731
|
const normalEdgesOpaqueBin = [];
|
|
@@ -500,10 +751,12 @@ const Renderer = function (scene, options) {
|
|
|
500
751
|
const ambientColorAndIntensity = scene._lightsState.getAmbientColorAndIntensity();
|
|
501
752
|
|
|
502
753
|
frameCtx.reset();
|
|
503
|
-
frameCtx.pass =
|
|
754
|
+
frameCtx.pass = pass;
|
|
504
755
|
frameCtx.withSAO = false;
|
|
505
756
|
frameCtx.pbrEnabled = pbrEnabled && !!scene.pbrEnabled;
|
|
506
757
|
frameCtx.colorTextureEnabled = colorTextureEnabled && !!scene.colorTextureEnabled;
|
|
758
|
+
frameCtx.viewParams = getSceneCameraViewParams();
|
|
759
|
+
frameCtx.nearPlaneHeight = getNearPlaneHeight(scene.camera, gl.drawingBufferHeight);
|
|
507
760
|
|
|
508
761
|
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
509
762
|
|
|
@@ -522,15 +775,9 @@ const Renderer = function (scene, options) {
|
|
|
522
775
|
|
|
523
776
|
frameCtx.lineWidth = 1;
|
|
524
777
|
|
|
525
|
-
const
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
const occlusionRenderBuffer1 = renderBufferManager.getRenderBuffer("saoOcclusion");
|
|
529
|
-
frameCtx.occlusionTexture = occlusionRenderBuffer1 ? occlusionRenderBuffer1.getTexture() : null;
|
|
530
|
-
} else {
|
|
531
|
-
frameCtx.occlusionTexture = null;
|
|
532
|
-
|
|
533
|
-
}
|
|
778
|
+
const sao = scene.sao;
|
|
779
|
+
frameCtx.saoParams = [gl.drawingBufferWidth, gl.drawingBufferHeight, scene.sao.blendCutoff, scene.sao.blendFactor];
|
|
780
|
+
frameCtx.occlusionTexture = occlusionTexture;
|
|
534
781
|
|
|
535
782
|
let i;
|
|
536
783
|
let len;
|
|
@@ -538,11 +785,7 @@ const Renderer = function (scene, options) {
|
|
|
538
785
|
|
|
539
786
|
const startTime = Date.now();
|
|
540
787
|
|
|
541
|
-
if (
|
|
542
|
-
bindOutputFrameBuffer(params.pass);
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
if (params.clear !== false) {
|
|
788
|
+
if (clear) {
|
|
546
789
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
547
790
|
}
|
|
548
791
|
|
|
@@ -582,7 +825,7 @@ const Renderer = function (scene, options) {
|
|
|
582
825
|
const renderFlags = drawable.renderFlags;
|
|
583
826
|
|
|
584
827
|
if (renderFlags.colorOpaque) {
|
|
585
|
-
if (saoEnabled &&
|
|
828
|
+
if (drawable.saoEnabled && occlusionTexture) {
|
|
586
829
|
normalDrawSAOBin[normalDrawSAOBinLen++] = drawable;
|
|
587
830
|
} else {
|
|
588
831
|
drawable.drawColorOpaque(frameCtx);
|
|
@@ -723,7 +966,7 @@ const Renderer = function (scene, options) {
|
|
|
723
966
|
// Transparent color fill
|
|
724
967
|
|
|
725
968
|
if (normalFillTransparentBinLen > 0) {
|
|
726
|
-
const eye = frameCtx.
|
|
969
|
+
const eye = frameCtx.viewParams.eye;
|
|
727
970
|
normalFillTransparentBin.length = normalFillTransparentBinLen; // normalFillTransparentBin reused by renderDrawables calls, so needs to be truncated if necessary
|
|
728
971
|
const byDist = normalFillTransparentBin.map(d => ({ drawable: d, distSq: math.distVec3(d.origin || vec3_0, eye) }));
|
|
729
972
|
byDist.sort((a, b) => b.distSq - a.distSq);
|
|
@@ -901,12 +1144,30 @@ const Renderer = function (scene, options) {
|
|
|
901
1144
|
for (let ii = 0; ii < numVertexAttribs; ii++) {
|
|
902
1145
|
gl.disableVertexAttribArray(ii);
|
|
903
1146
|
}
|
|
904
|
-
|
|
905
|
-
if (unbindOutputFrameBuffer) {
|
|
906
|
-
unbindOutputFrameBuffer(params.pass);
|
|
907
|
-
}
|
|
908
1147
|
}
|
|
909
1148
|
|
|
1149
|
+
const resetPickFrameCtx = (canvasPos, clipTransformDiv, camera, eye, projMatrix, viewMatrix, frameCtx) => {
|
|
1150
|
+
frameCtx.reset();
|
|
1151
|
+
frameCtx.backfaces = true;
|
|
1152
|
+
frameCtx.frontface = true; // "ccw"
|
|
1153
|
+
|
|
1154
|
+
frameCtx.viewParams.eye = eye;
|
|
1155
|
+
frameCtx.viewParams.projMatrix = projMatrix;
|
|
1156
|
+
frameCtx.viewParams.viewMatrix = viewMatrix;
|
|
1157
|
+
frameCtx.nearPlaneHeight = getNearPlaneHeight(camera, gl.drawingBufferHeight);
|
|
1158
|
+
|
|
1159
|
+
const resolutionScale = scene.canvas.resolutionScale;
|
|
1160
|
+
frameCtx.pickClipPos = [
|
|
1161
|
+
canvasPos ? ( 2 * canvasPos[0] * resolutionScale / gl.drawingBufferWidth - 1) : 0,
|
|
1162
|
+
canvasPos ? (1 - 2 * canvasPos[1] * resolutionScale / gl.drawingBufferHeight) : 0
|
|
1163
|
+
];
|
|
1164
|
+
|
|
1165
|
+
frameCtx.pickClipPosInv = [
|
|
1166
|
+
gl.drawingBufferWidth / clipTransformDiv,
|
|
1167
|
+
gl.drawingBufferHeight / clipTransformDiv
|
|
1168
|
+
];
|
|
1169
|
+
};
|
|
1170
|
+
|
|
910
1171
|
/**
|
|
911
1172
|
* Picks an Entity.
|
|
912
1173
|
* @private
|
|
@@ -914,11 +1175,18 @@ const Renderer = function (scene, options) {
|
|
|
914
1175
|
this.pick = (function () {
|
|
915
1176
|
|
|
916
1177
|
const tempVec3a = math.vec3();
|
|
1178
|
+
const tempVec3b = math.vec3();
|
|
1179
|
+
const tempVec4a = math.vec4();
|
|
1180
|
+
const tempVec4b = math.vec4();
|
|
1181
|
+
const tempVec4c = math.vec4();
|
|
1182
|
+
const tempVec4d = math.vec4();
|
|
1183
|
+
const tempVec4e = math.vec4();
|
|
917
1184
|
const tempMat4a = math.mat4();
|
|
918
1185
|
const tempMat4b = math.mat4();
|
|
1186
|
+
const tempMat4c = math.mat4();
|
|
1187
|
+
const tempMat4d = math.mat4();
|
|
919
1188
|
|
|
920
|
-
const
|
|
921
|
-
const up = math.vec3([0, 1, 0]);
|
|
1189
|
+
const upVec = math.vec3([0, 1, 0]);
|
|
922
1190
|
const _pickResult = new PickResult();
|
|
923
1191
|
|
|
924
1192
|
const nearAndFar = math.vec2();
|
|
@@ -930,16 +1198,22 @@ const Renderer = function (scene, options) {
|
|
|
930
1198
|
const worldSurfacePos = math.vec3();
|
|
931
1199
|
const worldSurfaceNormal = math.vec3();
|
|
932
1200
|
|
|
1201
|
+
const pickBuffer = new RenderBuffer(gl);
|
|
1202
|
+
pickBuffer.setSize([1, 1]);
|
|
1203
|
+
|
|
1204
|
+
const pickNormalBuffer = new RenderBuffer(gl, [gl.RGBA32I]);
|
|
1205
|
+
pickNormalBuffer.setSize([3, 3]);
|
|
1206
|
+
|
|
933
1207
|
return function (params, pickResult = _pickResult) {
|
|
934
1208
|
|
|
935
1209
|
pickResult.reset();
|
|
936
1210
|
|
|
937
1211
|
updateDrawlist();
|
|
938
1212
|
|
|
939
|
-
let look;
|
|
940
1213
|
let pickViewMatrix = null;
|
|
941
1214
|
let pickProjMatrix = null;
|
|
942
1215
|
let projection = null;
|
|
1216
|
+
const camera = scene.camera;
|
|
943
1217
|
|
|
944
1218
|
pickResult.pickSurface = params.pickSurface;
|
|
945
1219
|
|
|
@@ -948,12 +1222,12 @@ const Renderer = function (scene, options) {
|
|
|
948
1222
|
canvasPos[0] = params.canvasPos[0];
|
|
949
1223
|
canvasPos[1] = params.canvasPos[1];
|
|
950
1224
|
|
|
951
|
-
pickViewMatrix =
|
|
952
|
-
pickProjMatrix =
|
|
953
|
-
projection =
|
|
1225
|
+
pickViewMatrix = camera.viewMatrix;
|
|
1226
|
+
pickProjMatrix = camera.projMatrix;
|
|
1227
|
+
projection = camera.projection;
|
|
954
1228
|
|
|
955
|
-
nearAndFar[0] =
|
|
956
|
-
nearAndFar[1] =
|
|
1229
|
+
nearAndFar[0] = camera.project.near;
|
|
1230
|
+
nearAndFar[1] = camera.project.far;
|
|
957
1231
|
|
|
958
1232
|
pickResult.canvasPos = params.canvasPos;
|
|
959
1233
|
|
|
@@ -965,33 +1239,37 @@ const Renderer = function (scene, options) {
|
|
|
965
1239
|
if (params.matrix) {
|
|
966
1240
|
|
|
967
1241
|
pickViewMatrix = params.matrix;
|
|
968
|
-
pickProjMatrix =
|
|
969
|
-
projection =
|
|
1242
|
+
pickProjMatrix = camera.projMatrix;
|
|
1243
|
+
projection = camera.projection;
|
|
970
1244
|
|
|
971
|
-
nearAndFar[0] =
|
|
972
|
-
nearAndFar[1] =
|
|
1245
|
+
nearAndFar[0] = camera.project.near;
|
|
1246
|
+
nearAndFar[1] = camera.project.far;
|
|
973
1247
|
|
|
974
1248
|
} else {
|
|
975
1249
|
|
|
976
1250
|
worldRayOrigin.set(params.origin || [0, 0, 0]);
|
|
977
1251
|
worldRayDir.set(params.direction || [0, 0, 1]);
|
|
978
1252
|
|
|
979
|
-
look = math.addVec3(worldRayOrigin, worldRayDir, tempVec3a);
|
|
980
|
-
|
|
981
|
-
randomVec3[0] = Math.random();
|
|
982
|
-
randomVec3[1] = Math.random();
|
|
983
|
-
randomVec3[2] = Math.random();
|
|
1253
|
+
const look = math.addVec3(worldRayOrigin, worldRayDir, tempVec3a);
|
|
1254
|
+
const up = tempVec3b;
|
|
984
1255
|
|
|
985
|
-
math.
|
|
986
|
-
|
|
1256
|
+
if (Math.abs(math.dotVec3(worldRayDir, upVec)) > (1 - 1e-6)) { // worldRayDir aligned with Y axis
|
|
1257
|
+
up[0] = 0;
|
|
1258
|
+
up[1] = 0;
|
|
1259
|
+
up[2] = Math.sign(worldRayDir[1]);
|
|
1260
|
+
} else {
|
|
1261
|
+
math.cross3Vec3(worldRayDir, upVec, up);
|
|
1262
|
+
math.cross3Vec3(up, worldRayDir, up);
|
|
1263
|
+
math.normalizeVec3(up, up);
|
|
1264
|
+
}
|
|
987
1265
|
|
|
988
1266
|
pickViewMatrix = math.lookAtMat4v(worldRayOrigin, look, up, tempMat4b);
|
|
989
|
-
// pickProjMatrix =
|
|
990
|
-
pickProjMatrix =
|
|
1267
|
+
// pickProjMatrix = camera.projMatrix;
|
|
1268
|
+
pickProjMatrix = camera.ortho.matrix;
|
|
991
1269
|
projection = "ortho";
|
|
992
1270
|
|
|
993
|
-
nearAndFar[0] =
|
|
994
|
-
nearAndFar[1] =
|
|
1271
|
+
nearAndFar[0] = camera.ortho.near;
|
|
1272
|
+
nearAndFar[1] = camera.ortho.far;
|
|
995
1273
|
|
|
996
1274
|
pickResult.origin = worldRayOrigin;
|
|
997
1275
|
pickResult.direction = worldRayDir;
|
|
@@ -1001,23 +1279,42 @@ const Renderer = function (scene, options) {
|
|
|
1001
1279
|
canvasPos[1] = canvas.clientHeight * 0.5;
|
|
1002
1280
|
}
|
|
1003
1281
|
|
|
1004
|
-
|
|
1005
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
1006
|
-
const drawableList = drawableTypeInfo[type].drawableList;
|
|
1007
|
-
for (let i = 0, len = drawableList.length; i < len; i++) {
|
|
1008
|
-
const drawable = drawableList[i];
|
|
1009
|
-
if (drawable.setPickMatrices) { // Eg. SceneModel, which needs pre-loading into texture
|
|
1010
|
-
drawable.setPickMatrices(pickViewMatrix, pickProjMatrix);
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1282
|
+
pickBuffer.bind();
|
|
1015
1283
|
|
|
1016
|
-
const
|
|
1284
|
+
const resetFrameCtx = (clipTransformDiv) => resetPickFrameCtx(canvasPos, clipTransformDiv, camera, pickResult.origin || camera.eye, pickProjMatrix || camera.projMatrix, pickViewMatrix || camera.viewMatrix, frameCtx);
|
|
1017
1285
|
|
|
1018
|
-
|
|
1286
|
+
// gpuPickPickable
|
|
1287
|
+
resetFrameCtx(1);
|
|
1288
|
+
frameCtx.pickInvisible = !!params.pickInvisible;
|
|
1289
|
+
|
|
1290
|
+
gl.viewport(0, 0, 1, 1);
|
|
1291
|
+
gl.depthMask(true);
|
|
1292
|
+
gl.enable(gl.DEPTH_TEST);
|
|
1293
|
+
gl.disable(gl.CULL_FACE);
|
|
1294
|
+
gl.disable(gl.BLEND);
|
|
1295
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1296
|
+
|
|
1297
|
+
const includeEntityIds = params.includeEntityIds;
|
|
1298
|
+
const excludeEntityIds = params.excludeEntityIds;
|
|
1299
|
+
|
|
1300
|
+
const renderDrawables = function(drawables) {
|
|
1301
|
+
drawables.forEach(drawable => {
|
|
1302
|
+
if (!drawable.culled && drawable.visible && drawable.pickable && drawable.drawPickMesh // TODO: push this logic into drawable
|
|
1303
|
+
&& ((! includeEntityIds) || includeEntityIds[drawable.id])
|
|
1304
|
+
&& ((! excludeEntityIds) || (! excludeEntityIds[drawable.id]))) {
|
|
1305
|
+
drawable.drawPickMesh(frameCtx);
|
|
1306
|
+
}
|
|
1307
|
+
});
|
|
1308
|
+
};
|
|
1309
|
+
|
|
1310
|
+
renderDrawables(postCullDrawableList);
|
|
1311
|
+
if (uiDrawableList.length > 0) {
|
|
1312
|
+
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
1313
|
+
renderDrawables(uiDrawableList);
|
|
1314
|
+
}
|
|
1019
1315
|
|
|
1020
|
-
const
|
|
1316
|
+
const pickID = pixelToInt(pickBuffer.read(0, 0));
|
|
1317
|
+
const pickable = (pickID >= 0) && pickIDs.items[pickID];
|
|
1021
1318
|
|
|
1022
1319
|
if (!pickable) {
|
|
1023
1320
|
pickBuffer.unbind();
|
|
@@ -1037,265 +1334,108 @@ const Renderer = function (scene, options) {
|
|
|
1037
1334
|
|
|
1038
1335
|
if (pickable.canPickTriangle && pickable.canPickTriangle()) {
|
|
1039
1336
|
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1337
|
+
if (pickable.drawPickTriangles) {
|
|
1338
|
+
resetFrameCtx(1);
|
|
1339
|
+
// frameCtx.pickInvisible = !!params.pickInvisible;
|
|
1043
1340
|
|
|
1044
|
-
|
|
1341
|
+
gl.viewport(0, 0, 1, 1);
|
|
1342
|
+
gl.clearColor(0, 0, 0, 0);
|
|
1343
|
+
gl.enable(gl.DEPTH_TEST);
|
|
1344
|
+
gl.disable(gl.CULL_FACE);
|
|
1345
|
+
gl.disable(gl.BLEND);
|
|
1346
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1045
1347
|
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
if (pickable.canPickWorldPos && pickable.canPickWorldPos()) {
|
|
1049
|
-
|
|
1050
|
-
gpuPickWorldPos(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, nearAndFar, pickResult);
|
|
1051
|
-
|
|
1052
|
-
if (params.pickSurfaceNormal !== false) {
|
|
1053
|
-
gpuPickWorldNormal(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, pickResult);
|
|
1054
|
-
}
|
|
1348
|
+
pickable.drawPickTriangles(frameCtx);
|
|
1055
1349
|
|
|
1056
|
-
pickResult.
|
|
1350
|
+
pickResult.primIndex = 3 * pixelToInt(pickBuffer.read(0, 0)); // Convert from triangle number to first vertex in indices
|
|
1057
1351
|
}
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
pickBuffer.unbind();
|
|
1061
|
-
pickResult.entity = pickedEntity;
|
|
1062
|
-
return pickResult;
|
|
1063
|
-
};
|
|
1064
|
-
})();
|
|
1065
|
-
|
|
1066
|
-
function gpuPickPickable(pickBuffer, canvasPos, pickViewMatrix, pickProjMatrix, params, pickResult) {
|
|
1067
|
-
|
|
1068
|
-
const resolutionScale = scene.canvas.resolutionScale;
|
|
1069
|
-
|
|
1070
|
-
frameCtx.reset();
|
|
1071
|
-
frameCtx.backfaces = true;
|
|
1072
|
-
frameCtx.frontface = true; // "ccw"
|
|
1073
|
-
frameCtx.pickOrigin = pickResult.origin;
|
|
1074
|
-
frameCtx.pickViewMatrix = pickViewMatrix;
|
|
1075
|
-
frameCtx.pickProjMatrix = pickProjMatrix;
|
|
1076
|
-
frameCtx.pickInvisible = !!params.pickInvisible;
|
|
1077
|
-
frameCtx.pickClipPos = [
|
|
1078
|
-
getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
|
|
1079
|
-
getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight)
|
|
1080
|
-
];
|
|
1081
|
-
|
|
1082
|
-
gl.viewport(0, 0, 1, 1);
|
|
1083
|
-
gl.depthMask(true);
|
|
1084
|
-
gl.enable(gl.DEPTH_TEST);
|
|
1085
|
-
gl.disable(gl.CULL_FACE);
|
|
1086
|
-
gl.disable(gl.BLEND);
|
|
1087
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1088
|
-
|
|
1089
|
-
const includeEntityIds = params.includeEntityIds;
|
|
1090
|
-
const excludeEntityIds = params.excludeEntityIds;
|
|
1091
|
-
|
|
1092
|
-
const renderDrawables = function(drawables) {
|
|
1093
|
-
for (let i = 0, len = drawables.length; i < len; i++) {
|
|
1094
|
-
const drawable = drawables[i];
|
|
1095
|
-
if (drawable.culled === true || drawable.visible === false) {
|
|
1096
|
-
continue;
|
|
1097
|
-
}
|
|
1098
|
-
if (!drawable.drawPickMesh || (params.pickInvisible !== true && drawable.visible === false) || drawable.pickable === false) {
|
|
1099
|
-
continue;
|
|
1100
|
-
}
|
|
1101
|
-
if (includeEntityIds && !includeEntityIds[drawable.id]) { // TODO: push this logic into drawable
|
|
1102
|
-
continue;
|
|
1103
|
-
}
|
|
1104
|
-
if (excludeEntityIds && excludeEntityIds[drawable.id]) {
|
|
1105
|
-
continue;
|
|
1106
|
-
}
|
|
1107
|
-
drawable.drawPickMesh(frameCtx);
|
|
1108
|
-
}
|
|
1109
|
-
};
|
|
1110
|
-
|
|
1111
|
-
renderDrawables(postCullDrawableList);
|
|
1112
|
-
if (uiDrawableList.length > 0) {
|
|
1113
|
-
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
1114
|
-
renderDrawables(uiDrawableList);
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
const pix = pickBuffer.read(0, 0);
|
|
1118
|
-
const pickID = pix[0] + (pix[1] << 8) + (pix[2] << 16) + (pix[3] << 24);
|
|
1119
|
-
|
|
1120
|
-
if (pickID < 0) {
|
|
1121
|
-
return;
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
const pickable = pickIDs.items[pickID];
|
|
1125
|
-
|
|
1126
|
-
return pickable;
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
function gpuPickTriangle(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, pickResult) {
|
|
1130
|
-
|
|
1131
|
-
if (!pickable.drawPickTriangles) {
|
|
1132
|
-
return;
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
const resolutionScale = scene.canvas.resolutionScale;
|
|
1136
|
-
|
|
1137
|
-
frameCtx.reset();
|
|
1138
|
-
frameCtx.backfaces = true;
|
|
1139
|
-
frameCtx.frontface = true; // "ccw"
|
|
1140
|
-
frameCtx.pickOrigin = pickResult.origin;
|
|
1141
|
-
frameCtx.pickViewMatrix = pickViewMatrix; // Can be null
|
|
1142
|
-
frameCtx.pickProjMatrix = pickProjMatrix; // Can be null
|
|
1143
|
-
// frameCtx.pickInvisible = !!params.pickInvisible;
|
|
1144
|
-
frameCtx.pickClipPos = [
|
|
1145
|
-
getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
|
|
1146
|
-
getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight)
|
|
1147
|
-
];
|
|
1148
1352
|
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
gl.clearColor(0, 0, 0, 0);
|
|
1152
|
-
gl.enable(gl.DEPTH_TEST);
|
|
1153
|
-
gl.disable(gl.CULL_FACE);
|
|
1154
|
-
gl.disable(gl.BLEND);
|
|
1155
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1156
|
-
|
|
1157
|
-
pickable.drawPickTriangles(frameCtx);
|
|
1158
|
-
|
|
1159
|
-
const pix = pickBuffer.read(0, 0);
|
|
1160
|
-
|
|
1161
|
-
let primIndex = pix[0] + (pix[1] * 256) + (pix[2] * 256 * 256) + (pix[3] * 256 * 256 * 256);
|
|
1162
|
-
|
|
1163
|
-
primIndex *= 3; // Convert from triangle number to first vertex in indices
|
|
1164
|
-
|
|
1165
|
-
pickResult.primIndex = primIndex;
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
const gpuPickWorldPos = (function () {
|
|
1169
|
-
|
|
1170
|
-
const tempVec4a = math.vec4();
|
|
1171
|
-
const tempVec4b = math.vec4();
|
|
1172
|
-
const tempVec4c = math.vec4();
|
|
1173
|
-
const tempVec4d = math.vec4();
|
|
1174
|
-
const tempVec4e = math.vec4();
|
|
1175
|
-
const tempMat4a = math.mat4();
|
|
1176
|
-
const tempMat4b = math.mat4();
|
|
1177
|
-
const tempMat4c = math.mat4();
|
|
1178
|
-
|
|
1179
|
-
return function (pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, nearAndFar, pickResult) {
|
|
1180
|
-
|
|
1181
|
-
const resolutionScale = scene.canvas.resolutionScale;
|
|
1182
|
-
|
|
1183
|
-
frameCtx.reset();
|
|
1184
|
-
frameCtx.backfaces = true;
|
|
1185
|
-
frameCtx.frontface = true; // "ccw"
|
|
1186
|
-
frameCtx.pickOrigin = pickResult.origin;
|
|
1187
|
-
frameCtx.pickViewMatrix = pickViewMatrix;
|
|
1188
|
-
frameCtx.pickProjMatrix = pickProjMatrix;
|
|
1189
|
-
frameCtx.pickZNear = nearAndFar[0];
|
|
1190
|
-
frameCtx.pickZFar = nearAndFar[1];
|
|
1191
|
-
frameCtx.pickElementsCount = pickable.pickElementsCount;
|
|
1192
|
-
frameCtx.pickElementsOffset = pickable.pickElementsOffset;
|
|
1193
|
-
frameCtx.pickClipPos = [
|
|
1194
|
-
getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
|
|
1195
|
-
getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight)
|
|
1196
|
-
];
|
|
1353
|
+
pickable.pickTriangleSurface(pickViewMatrix, pickProjMatrix, projection, pickResult);
|
|
1197
1354
|
|
|
1198
|
-
|
|
1355
|
+
pickResult.pickSurfacePrecision = false;
|
|
1199
1356
|
|
|
1200
|
-
|
|
1201
|
-
gl.depthMask(true);
|
|
1202
|
-
gl.enable(gl.DEPTH_TEST);
|
|
1203
|
-
gl.disable(gl.CULL_FACE);
|
|
1204
|
-
gl.disable(gl.BLEND);
|
|
1205
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1357
|
+
} else {
|
|
1206
1358
|
|
|
1207
|
-
|
|
1359
|
+
if (pickable.canPickWorldPos && pickable.canPickWorldPos()) {
|
|
1208
1360
|
|
|
1209
|
-
|
|
1361
|
+
// pickWorldPos
|
|
1362
|
+
resetFrameCtx(1);
|
|
1363
|
+
frameCtx.viewParams.near = nearAndFar[0];
|
|
1364
|
+
frameCtx.viewParams.far = nearAndFar[1];
|
|
1210
1365
|
|
|
1211
|
-
|
|
1366
|
+
gl.viewport(0, 0, 1, 1);
|
|
1212
1367
|
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1368
|
+
gl.clearColor(0, 0, 0, 0);
|
|
1369
|
+
gl.depthMask(true);
|
|
1370
|
+
gl.enable(gl.DEPTH_TEST);
|
|
1371
|
+
gl.disable(gl.CULL_FACE);
|
|
1372
|
+
gl.disable(gl.BLEND);
|
|
1373
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1216
1374
|
|
|
1217
|
-
|
|
1218
|
-
let pvMat;
|
|
1375
|
+
pickable.drawPickDepths(frameCtx); // Draw color-encoded fragment screen-space depths
|
|
1219
1376
|
|
|
1220
|
-
|
|
1221
|
-
const rtcPickViewMat = createRTCViewMat(pickViewMatrix, origin, tempMat4a);
|
|
1222
|
-
pvMat = math.mulMat4(pickProjMatrix, rtcPickViewMat, tempMat4b);
|
|
1377
|
+
const screenZ = math.dotVec4(pickBuffer.read(0, 0), bitShiftScreenZ);
|
|
1223
1378
|
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1379
|
+
// Calculate clip space coordinates, which will be in range of x=[-1..1] and y=[-1..1], with y=(+1) at top
|
|
1380
|
+
const x = (canvasPos[0] - canvas.clientWidth / 2) / (canvas.clientWidth / 2);
|
|
1381
|
+
const y = -(canvasPos[1] - canvas.clientHeight / 2) / (canvas.clientHeight / 2);
|
|
1227
1382
|
|
|
1228
|
-
|
|
1383
|
+
const origin = pickable.origin;
|
|
1229
1384
|
|
|
1230
|
-
|
|
1231
|
-
tempVec4a[1] = y;
|
|
1232
|
-
tempVec4a[2] = -1;
|
|
1233
|
-
tempVec4a[3] = 1;
|
|
1385
|
+
const pvMatInverse = math.inverseMat4(math.mulMat4(pickProjMatrix, (origin ? createRTCViewMat(pickViewMatrix, origin, tempMat4a) : pickViewMatrix), tempMat4c), tempMat4d);
|
|
1234
1386
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1387
|
+
const toWorld = (z, dst) => {
|
|
1388
|
+
dst[0] = x;
|
|
1389
|
+
dst[1] = y;
|
|
1390
|
+
dst[2] = z;
|
|
1391
|
+
dst[3] = 1;
|
|
1392
|
+
math.transformVec4(pvMatInverse, dst, dst);
|
|
1393
|
+
return math.mulVec4Scalar(dst, 1 / dst[3]);
|
|
1394
|
+
};
|
|
1237
1395
|
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
tempVec4b[2] = 1;
|
|
1241
|
-
tempVec4b[3] = 1;
|
|
1396
|
+
const world1 = toWorld(-1, tempVec4a);
|
|
1397
|
+
const world2 = toWorld( 1, tempVec4b);
|
|
1242
1398
|
|
|
1243
|
-
|
|
1244
|
-
|
|
1399
|
+
const dir = math.subVec3(world2, world1, tempVec4c);
|
|
1400
|
+
const worldPos = math.addVec3(world1, math.mulVec4Scalar(dir, screenZ, tempVec4d), tempVec4e);
|
|
1245
1401
|
|
|
1246
|
-
|
|
1247
|
-
|
|
1402
|
+
if (origin) {
|
|
1403
|
+
math.addVec3(worldPos, origin);
|
|
1404
|
+
}
|
|
1248
1405
|
|
|
1249
|
-
|
|
1250
|
-
math.addVec3(worldPos, origin);
|
|
1251
|
-
}
|
|
1406
|
+
pickResult.worldPos = worldPos;
|
|
1252
1407
|
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1408
|
+
if (params.pickSurfaceNormal !== false) {
|
|
1409
|
+
// gpuPickWorldNormal
|
|
1410
|
+
resetFrameCtx(3);
|
|
1256
1411
|
|
|
1257
|
-
|
|
1258
|
-
frameCtx.snapPickLayerParams = [];
|
|
1259
|
-
frameCtx.snapPickLayerNumber = 0;
|
|
1412
|
+
pickNormalBuffer.bind();
|
|
1260
1413
|
|
|
1261
|
-
|
|
1414
|
+
gl.viewport(0, 0, pickNormalBuffer.size[0], pickNormalBuffer.size[1]);
|
|
1415
|
+
gl.enable(gl.DEPTH_TEST);
|
|
1416
|
+
gl.disable(gl.CULL_FACE);
|
|
1417
|
+
gl.disable(gl.BLEND);
|
|
1418
|
+
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
1419
|
+
gl.clearBufferiv(gl.COLOR, 0, new Int32Array([0, 0, 0, 0]));
|
|
1262
1420
|
|
|
1263
|
-
|
|
1421
|
+
pickable.drawPickNormals(frameCtx); // Draw color-encoded fragment World-space normals
|
|
1264
1422
|
|
|
1265
|
-
|
|
1266
|
-
if (!drawable.culled && drawable.visible && drawable.pickable) {
|
|
1267
|
-
drawable.drawSnapInit(frameCtx);
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
return frameCtx.snapPickLayerParams;
|
|
1272
|
-
}
|
|
1423
|
+
const pix = pickNormalBuffer.read(1, 1, gl.RGBA_INTEGER, gl.INT, Int32Array, 4);
|
|
1273
1424
|
|
|
1274
|
-
|
|
1275
|
-
frameCtx.snapPickLayerParams = frameCtx.snapPickLayerParams || [];
|
|
1276
|
-
frameCtx.snapPickLayerNumber = frameCtx.snapPickLayerParams.length;
|
|
1277
|
-
for (let i = 0, len = postCullDrawableList.length; i < len; i++) {
|
|
1425
|
+
pickNormalBuffer.unbind();
|
|
1278
1426
|
|
|
1279
|
-
|
|
1427
|
+
pickResult.worldNormal = toWorldNormal(pix);
|
|
1428
|
+
}
|
|
1280
1429
|
|
|
1281
|
-
|
|
1282
|
-
if (drawable.drawSnap) {
|
|
1283
|
-
if (!drawable.culled && drawable.visible && drawable.pickable) {
|
|
1284
|
-
drawable.drawSnap(frameCtx);
|
|
1430
|
+
pickResult.pickSurfacePrecision = false;
|
|
1285
1431
|
}
|
|
1286
1432
|
}
|
|
1287
1433
|
}
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
return 2 * (pos / size) - 1;
|
|
1294
|
-
}
|
|
1295
|
-
|
|
1296
|
-
function getClipPosY(pos, size) {
|
|
1297
|
-
return 1 - 2 * (pos / size);
|
|
1298
|
-
}
|
|
1434
|
+
pickBuffer.unbind();
|
|
1435
|
+
pickResult.entity = pickedEntity;
|
|
1436
|
+
return pickResult;
|
|
1437
|
+
};
|
|
1438
|
+
})();
|
|
1299
1439
|
|
|
1300
1440
|
/**
|
|
1301
1441
|
* @param {[number, number]} canvasPos
|
|
@@ -1309,6 +1449,18 @@ const Renderer = function (scene, options) {
|
|
|
1309
1449
|
|
|
1310
1450
|
const _pickResult = new PickResult();
|
|
1311
1451
|
|
|
1452
|
+
const getVertexPickBuffer = (function() {
|
|
1453
|
+
const cache = { };
|
|
1454
|
+
return (snapRadiusInPixels) => {
|
|
1455
|
+
if (! (snapRadiusInPixels in cache)) {
|
|
1456
|
+
const buf = new RenderBuffer(gl, [gl.RGBA32I, gl.RGBA32I, gl.RGBA8UI], true);
|
|
1457
|
+
buf.setSize([2 * snapRadiusInPixels + 1, 2 * snapRadiusInPixels + 1]);
|
|
1458
|
+
cache[snapRadiusInPixels] = buf;
|
|
1459
|
+
}
|
|
1460
|
+
return cache[snapRadiusInPixels];
|
|
1461
|
+
};
|
|
1462
|
+
})();
|
|
1463
|
+
|
|
1312
1464
|
return function (params, pickResult = _pickResult) {
|
|
1313
1465
|
|
|
1314
1466
|
const {canvasPos, origin, direction, snapRadius, snapToVertex, snapToEdge} = params;
|
|
@@ -1317,40 +1469,21 @@ const Renderer = function (scene, options) {
|
|
|
1317
1469
|
return this.pick({canvasPos, pickSurface: true});
|
|
1318
1470
|
}
|
|
1319
1471
|
|
|
1320
|
-
const
|
|
1321
|
-
|
|
1322
|
-
frameCtx.reset();
|
|
1323
|
-
frameCtx.backfaces = true;
|
|
1324
|
-
frameCtx.frontface = true; // "ccw"
|
|
1325
|
-
frameCtx.pickZNear = scene.camera.project.near;
|
|
1326
|
-
frameCtx.pickZFar = scene.camera.project.far;
|
|
1327
|
-
|
|
1472
|
+
const camera = scene.camera;
|
|
1328
1473
|
const snapRadiusInPixels = snapRadius || 30;
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
]
|
|
1338
|
-
}
|
|
1339
|
-
);
|
|
1340
|
-
|
|
1341
|
-
frameCtx.snapVectorA = [
|
|
1342
|
-
canvasPos ? getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth) : 0,
|
|
1343
|
-
canvasPos ? getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight) : 0,
|
|
1344
|
-
];
|
|
1345
|
-
|
|
1346
|
-
frameCtx.snapInvVectorAB = [
|
|
1347
|
-
gl.drawingBufferWidth / (2 * snapRadiusInPixels),
|
|
1348
|
-
gl.drawingBufferHeight / (2 * snapRadiusInPixels),
|
|
1349
|
-
];
|
|
1474
|
+
const viewMatrix = (canvasPos
|
|
1475
|
+
? camera.viewMatrix
|
|
1476
|
+
: math.lookAtMat4v(
|
|
1477
|
+
origin,
|
|
1478
|
+
math.addVec3(origin, direction, math.vec3()),
|
|
1479
|
+
math.vec3([0, 1, 0]),
|
|
1480
|
+
math.mat4()));
|
|
1481
|
+
resetPickFrameCtx(canvasPos, 2 * snapRadiusInPixels, camera, camera.eye, camera.projMatrix, viewMatrix, frameCtx);
|
|
1350
1482
|
|
|
1351
1483
|
// Bind and clear the snap render target
|
|
1352
1484
|
|
|
1353
|
-
vertexPickBuffer
|
|
1485
|
+
const vertexPickBuffer = getVertexPickBuffer(snapRadiusInPixels);
|
|
1486
|
+
vertexPickBuffer.bind();
|
|
1354
1487
|
gl.viewport(0, 0, vertexPickBuffer.size[0], vertexPickBuffer.size[1]);
|
|
1355
1488
|
gl.enable(gl.DEPTH_TEST);
|
|
1356
1489
|
gl.frontFace(gl.CCW);
|
|
@@ -1363,64 +1496,59 @@ const Renderer = function (scene, options) {
|
|
|
1363
1496
|
gl.clearBufferiv(gl.COLOR, 1, new Int32Array([0, 0, 0, 0]));
|
|
1364
1497
|
gl.clearBufferuiv(gl.COLOR, 2, new Uint32Array([0, 0, 0, 0]));
|
|
1365
1498
|
|
|
1366
|
-
//////////////////////////////////
|
|
1367
|
-
// Set view and proj mats for VBO renderers
|
|
1368
|
-
///////////////////////////////////////
|
|
1369
|
-
|
|
1370
|
-
frameCtx.pickViewMatrix = (canvasPos
|
|
1371
|
-
? scene.camera.viewMatrix
|
|
1372
|
-
: math.lookAtMat4v(
|
|
1373
|
-
origin,
|
|
1374
|
-
math.addVec3(origin, direction, math.vec3()),
|
|
1375
|
-
math.vec3([0, 1, 0]),
|
|
1376
|
-
math.mat4()));
|
|
1377
|
-
|
|
1378
|
-
const pickProjMatrix = scene.camera.projMatrix;
|
|
1379
|
-
|
|
1380
|
-
for (let type in drawableTypeInfo) {
|
|
1381
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
1382
|
-
const drawableList = drawableTypeInfo[type].drawableList;
|
|
1383
|
-
for (let i = 0, len = drawableList.length; i < len; i++) {
|
|
1384
|
-
const drawable = drawableList[i];
|
|
1385
|
-
if (drawable.setPickMatrices) { // Eg. SceneModel, which needs pre-loading into texture
|
|
1386
|
-
drawable.setPickMatrices(frameCtx.pickViewMatrix, pickProjMatrix);
|
|
1387
|
-
}
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
1499
|
// a) init z-buffer
|
|
1393
1500
|
gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2]);
|
|
1394
|
-
|
|
1501
|
+
|
|
1502
|
+
frameCtx.snapPickLayerParams = [];
|
|
1503
|
+
frameCtx.snapPickLayerParams.push(null); // This recreates previous situation, which relied on snapPickLayerNumber
|
|
1504
|
+
postCullDrawableList.forEach(drawable => {
|
|
1505
|
+
if (!drawable.culled && drawable.visible && drawable.pickable && drawable.drawSnapInit) {
|
|
1506
|
+
drawable.drawSnapInit(frameCtx);
|
|
1507
|
+
}
|
|
1508
|
+
});
|
|
1509
|
+
|
|
1510
|
+
const layerParamsSurface = frameCtx.snapPickLayerParams;
|
|
1395
1511
|
|
|
1396
1512
|
// b) snap-pick
|
|
1397
|
-
|
|
1398
|
-
frameCtx.snapPickLayerParams = layerParamsSnap;
|
|
1513
|
+
frameCtx.snapPickLayerParams = [];
|
|
1399
1514
|
|
|
1400
1515
|
gl.depthMask(false);
|
|
1401
1516
|
gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
|
|
1402
1517
|
|
|
1403
|
-
|
|
1404
|
-
frameCtx.snapMode =
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
}
|
|
1412
|
-
frameCtx.snapMode = snapToVertex ? "vertex" : "edge";
|
|
1518
|
+
const drawSnap = (snapMode) => {
|
|
1519
|
+
frameCtx.snapMode = snapMode;
|
|
1520
|
+
frameCtx.snapPickLayerParams.push(null); // This recreates previous situation, which relied on snapPickLayerNumber
|
|
1521
|
+
postCullDrawableList.forEach(drawable => {
|
|
1522
|
+
if (!drawable.culled && drawable.visible && drawable.pickable && drawable.drawSnap) {
|
|
1523
|
+
drawable.drawSnap(frameCtx);
|
|
1524
|
+
}
|
|
1525
|
+
});
|
|
1526
|
+
};
|
|
1413
1527
|
|
|
1414
|
-
|
|
1528
|
+
if (snapToEdge) {
|
|
1529
|
+
drawSnap("edge");
|
|
1530
|
+
}
|
|
1531
|
+
if (snapToVertex) {
|
|
1532
|
+
drawSnap("vertex");
|
|
1415
1533
|
}
|
|
1416
1534
|
|
|
1417
1535
|
gl.depthMask(true);
|
|
1418
1536
|
|
|
1537
|
+
const layerParamsSnap = frameCtx.snapPickLayerParams;
|
|
1538
|
+
|
|
1419
1539
|
// Read and decode the snapped coordinates
|
|
1540
|
+
const readSnapPickBuffer = (source, arrayType, glType) => {
|
|
1541
|
+
const w = vertexPickBuffer.buffer.width;
|
|
1542
|
+
const h = vertexPickBuffer.buffer.height;
|
|
1543
|
+
const pix = new arrayType(4 * w * h);
|
|
1544
|
+
gl.readBuffer(source);
|
|
1545
|
+
gl.readPixels(0, 0, w, h, gl.RGBA_INTEGER, glType, pix, 0);
|
|
1546
|
+
return pix;
|
|
1547
|
+
};
|
|
1420
1548
|
|
|
1421
|
-
const snapPickResultArray
|
|
1422
|
-
const snapPickNormalResultArray =
|
|
1423
|
-
const snapPickIdResultArray
|
|
1549
|
+
const snapPickResultArray = readSnapPickBuffer(gl.COLOR_ATTACHMENT0, Int32Array, gl.INT);
|
|
1550
|
+
const snapPickNormalResultArray = readSnapPickBuffer(gl.COLOR_ATTACHMENT1, Int32Array, gl.INT);
|
|
1551
|
+
const snapPickIdResultArray = readSnapPickBuffer(gl.COLOR_ATTACHMENT2, Uint32Array, gl.UNSIGNED_INT);
|
|
1424
1552
|
|
|
1425
1553
|
vertexPickBuffer.unbind();
|
|
1426
1554
|
|
|
@@ -1439,195 +1567,76 @@ const Renderer = function (scene, options) {
|
|
|
1439
1567
|
|
|
1440
1568
|
if (pickResultMiddleXY[3] !== 0) {
|
|
1441
1569
|
const pickedLayerParmasSurface = layerParamsSurface[Math.abs(pickResultMiddleXY[3]) % layerParamsSurface.length];
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
pickResultMiddleXY[1] * scale[1] + origin[1],
|
|
1447
|
-
pickResultMiddleXY[2] * scale[2] + origin[2],
|
|
1448
|
-
];
|
|
1449
|
-
worldNormal = math.normalizeVec3([
|
|
1450
|
-
pickNormalResultMiddleXY[0] / math.MAX_INT,
|
|
1451
|
-
pickNormalResultMiddleXY[1] / math.MAX_INT,
|
|
1452
|
-
pickNormalResultMiddleXY[2] / math.MAX_INT,
|
|
1453
|
-
]);
|
|
1454
|
-
|
|
1455
|
-
const pickID =
|
|
1456
|
-
pickPickableResultMiddleXY[0]
|
|
1457
|
-
+ (pickPickableResultMiddleXY[1] << 8)
|
|
1458
|
-
+ (pickPickableResultMiddleXY[2] << 16)
|
|
1459
|
-
+ (pickPickableResultMiddleXY[3] << 24);
|
|
1460
|
-
|
|
1461
|
-
pickable = pickIDs.items[pickID];
|
|
1570
|
+
worldPos = toWorldPos(pickResultMiddleXY, pickedLayerParmasSurface.origin, pickedLayerParmasSurface.coordinateScale);
|
|
1571
|
+
worldNormal = toWorldNormal(pickNormalResultMiddleXY);
|
|
1572
|
+
|
|
1573
|
+
pickable = pickIDs.items[pixelToInt(pickPickableResultMiddleXY)];
|
|
1462
1574
|
}
|
|
1463
1575
|
|
|
1464
1576
|
// result 2) hi-precision snapped (to vertex/edge) world position
|
|
1465
1577
|
|
|
1466
|
-
|
|
1467
|
-
|
|
1578
|
+
const snapPickResult = [ ];
|
|
1468
1579
|
for (let i = 0; i < snapPickResultArray.length; i += 4) {
|
|
1469
|
-
|
|
1580
|
+
const layerNumber = snapPickResultArray[i + 3];
|
|
1581
|
+
if (layerNumber > 0) {
|
|
1470
1582
|
const pixelNumber = Math.floor(i / 4);
|
|
1471
1583
|
const w = vertexPickBuffer.size[0];
|
|
1472
1584
|
const x = pixelNumber % w - Math.floor(w / 2);
|
|
1473
1585
|
const y = Math.floor(pixelNumber / w) - Math.floor(w / 2);
|
|
1474
|
-
const dist = (Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));
|
|
1475
1586
|
snapPickResult.push({
|
|
1476
|
-
x,
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
snapPickResultArray[i + 0],
|
|
1482
|
-
snapPickResultArray[i + 1],
|
|
1483
|
-
snapPickResultArray[i + 2],
|
|
1484
|
-
snapPickResultArray[i + 3],
|
|
1485
|
-
],
|
|
1486
|
-
normal: [
|
|
1487
|
-
snapPickNormalResultArray[i + 0],
|
|
1488
|
-
snapPickNormalResultArray[i + 1],
|
|
1489
|
-
snapPickNormalResultArray[i + 2],
|
|
1490
|
-
snapPickNormalResultArray[i + 3],
|
|
1491
|
-
],
|
|
1492
|
-
id: [
|
|
1493
|
-
snapPickIdResultArray[i + 0],
|
|
1494
|
-
snapPickIdResultArray[i + 1],
|
|
1495
|
-
snapPickIdResultArray[i + 2],
|
|
1496
|
-
snapPickIdResultArray[i + 3],
|
|
1497
|
-
]
|
|
1587
|
+
dist: math.lenVec2([ x, y ]),
|
|
1588
|
+
isVertex: (snapToVertex && snapToEdge) ? (layerNumber > layerParamsSnap.length / 2) : snapToVertex,
|
|
1589
|
+
result: snapPickResultArray.subarray(i, i+4),
|
|
1590
|
+
normal: snapPickNormalResultArray.subarray(i, i+4),
|
|
1591
|
+
id: snapPickIdResultArray.subarray(i, i+4)
|
|
1498
1592
|
});
|
|
1499
1593
|
}
|
|
1500
1594
|
}
|
|
1501
1595
|
|
|
1502
|
-
|
|
1503
|
-
let snappedWorldNormal = null;
|
|
1504
|
-
let snappedPickable = null;
|
|
1505
|
-
let snapType = null;
|
|
1596
|
+
const getPickedEntity = pickable => (pickable && pickable.delegatePickedEntity) ? pickable.delegatePickedEntity() : pickable;
|
|
1506
1597
|
|
|
1507
1598
|
if (snapPickResult.length > 0) {
|
|
1508
|
-
// vertex snap first, then edge snap
|
|
1509
|
-
snapPickResult.
|
|
1510
|
-
|
|
1511
|
-
return a.isVertex ? -1 : 1;
|
|
1512
|
-
} else {
|
|
1513
|
-
return a.dist - b.dist;
|
|
1514
|
-
}
|
|
1515
|
-
});
|
|
1516
|
-
|
|
1517
|
-
snapType = snapPickResult[0].isVertex ? "vertex" : "edge";
|
|
1518
|
-
const snapPick = snapPickResult[0].result;
|
|
1519
|
-
const snapPickNormal = snapPickResult[0].normal;
|
|
1520
|
-
const snapPickId = snapPickResult[0].id;
|
|
1521
|
-
|
|
1599
|
+
// closest vertex snap first, then closest edge snap
|
|
1600
|
+
const res = snapPickResult.reduce((a,b) => ((((a.isVertex-b.isVertex) || (b.dist-a.dist)) > 0) ? a : b));
|
|
1601
|
+
const snapPick = res.result;
|
|
1522
1602
|
const pickedLayerParmas = layerParamsSnap[snapPick[3]];
|
|
1603
|
+
const snappedWorldPos = toWorldPos(snapPick, pickedLayerParmas.origin, pickedLayerParmas.coordinateScale);
|
|
1604
|
+
const snappedCanvasPos = camera.projectWorldPos(snappedWorldPos);
|
|
1605
|
+
|
|
1606
|
+
pickResult.reset();
|
|
1607
|
+
pickResult.snappedToEdge = !res.isVertex;
|
|
1608
|
+
pickResult.snappedToVertex = res.isVertex;
|
|
1609
|
+
pickResult.worldPos = snappedWorldPos;
|
|
1610
|
+
pickResult.worldNormal = toWorldNormal(res.normal);
|
|
1611
|
+
pickResult.entity = getPickedEntity(pickIDs.items[pixelToInt(res.id)]);
|
|
1612
|
+
pickResult.canvasPos = canvasPos || (worldPos && camera.projectWorldPos(worldPos)) || snappedCanvasPos;
|
|
1613
|
+
pickResult.snappedCanvasPos = snappedCanvasPos;
|
|
1614
|
+
return pickResult;
|
|
1615
|
+
|
|
1616
|
+
} else if (worldPos) {
|
|
1617
|
+
|
|
1618
|
+
pickResult.reset();
|
|
1619
|
+
pickResult.snappedToEdge = false;
|
|
1620
|
+
pickResult.snappedToVertex = false;
|
|
1621
|
+
pickResult.worldPos = worldPos;
|
|
1622
|
+
pickResult.worldNormal = worldNormal;
|
|
1623
|
+
pickResult.entity = getPickedEntity(pickable);
|
|
1624
|
+
pickResult.canvasPos = canvasPos || camera.projectWorldPos(worldPos);
|
|
1625
|
+
pickResult.snappedCanvasPos = canvasPos;
|
|
1626
|
+
return pickResult;
|
|
1523
1627
|
|
|
1524
|
-
|
|
1525
|
-
const scale = pickedLayerParmas.coordinateScale;
|
|
1526
|
-
|
|
1527
|
-
snappedWorldNormal = math.normalizeVec3([
|
|
1528
|
-
snapPickNormal[0] / math.MAX_INT,
|
|
1529
|
-
snapPickNormal[1] / math.MAX_INT,
|
|
1530
|
-
snapPickNormal[2] / math.MAX_INT,
|
|
1531
|
-
]);
|
|
1532
|
-
|
|
1533
|
-
snappedWorldPos = [
|
|
1534
|
-
snapPick[0] * scale[0] + origin[0],
|
|
1535
|
-
snapPick[1] * scale[1] + origin[1],
|
|
1536
|
-
snapPick[2] * scale[2] + origin[2],
|
|
1537
|
-
];
|
|
1538
|
-
|
|
1539
|
-
snappedPickable = pickIDs.items[
|
|
1540
|
-
snapPickId[0]
|
|
1541
|
-
+ (snapPickId[1] << 8)
|
|
1542
|
-
+ (snapPickId[2] << 16)
|
|
1543
|
-
+ (snapPickId[3] << 24)
|
|
1544
|
-
];
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1547
|
-
if (null === worldPos && null == snappedWorldPos) { // If neither regular pick or snap pick, return null
|
|
1628
|
+
} else {
|
|
1548
1629
|
return null;
|
|
1549
1630
|
}
|
|
1550
|
-
|
|
1551
|
-
let snappedCanvasPos = null;
|
|
1552
|
-
|
|
1553
|
-
if (null !== snappedWorldPos) {
|
|
1554
|
-
snappedCanvasPos = scene.camera.projectWorldPos(snappedWorldPos);
|
|
1555
|
-
}
|
|
1556
|
-
|
|
1557
|
-
const snappedEntity = (snappedPickable && snappedPickable.delegatePickedEntity) ? snappedPickable.delegatePickedEntity() : snappedPickable;
|
|
1558
|
-
if (!snappedEntity && pickable) {
|
|
1559
|
-
pickable = pickable.delegatePickedEntity ? pickable.delegatePickedEntity() : pickable;
|
|
1560
|
-
}
|
|
1561
|
-
|
|
1562
|
-
pickResult.reset();
|
|
1563
|
-
pickResult.snappedToEdge = (snapType === "edge");
|
|
1564
|
-
pickResult.snappedToVertex = (snapType === "vertex");
|
|
1565
|
-
pickResult.worldPos = snappedWorldPos || worldPos;
|
|
1566
|
-
pickResult.worldNormal = snappedWorldNormal || worldNormal;
|
|
1567
|
-
pickResult.entity = snappedEntity || pickable;
|
|
1568
|
-
pickResult.canvasPos = canvasPos || scene.camera.projectWorldPos(worldPos || snappedWorldPos);
|
|
1569
|
-
pickResult.snappedCanvasPos = snappedCanvasPos || canvasPos;
|
|
1570
|
-
|
|
1571
|
-
return pickResult;
|
|
1572
1631
|
};
|
|
1573
1632
|
})();
|
|
1574
1633
|
|
|
1575
|
-
function unpackDepth(depthZ) {
|
|
1576
|
-
const vec = [depthZ[0] / 256.0, depthZ[1] / 256.0, depthZ[2] / 256.0, depthZ[3] / 256.0];
|
|
1577
|
-
const bitShift = [1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0];
|
|
1578
|
-
return math.dotVec4(vec, bitShift);
|
|
1579
|
-
}
|
|
1580
|
-
|
|
1581
|
-
function gpuPickWorldNormal(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, pickResult) {
|
|
1582
|
-
|
|
1583
|
-
const resolutionScale = scene.canvas.resolutionScale;
|
|
1584
|
-
|
|
1585
|
-
frameCtx.reset();
|
|
1586
|
-
frameCtx.backfaces = true;
|
|
1587
|
-
frameCtx.frontface = true; // "ccw"
|
|
1588
|
-
frameCtx.pickOrigin = pickResult.origin;
|
|
1589
|
-
frameCtx.pickViewMatrix = pickViewMatrix;
|
|
1590
|
-
frameCtx.pickProjMatrix = pickProjMatrix;
|
|
1591
|
-
frameCtx.pickClipPos = [
|
|
1592
|
-
getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
|
|
1593
|
-
getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight),
|
|
1594
|
-
];
|
|
1595
|
-
|
|
1596
|
-
const pickNormalBuffer = renderBufferManager.getRenderBuffer("pick-normal", {size: [3, 3]});
|
|
1597
|
-
|
|
1598
|
-
pickNormalBuffer.bind(gl.RGBA32I);
|
|
1599
|
-
|
|
1600
|
-
gl.viewport(0, 0, pickNormalBuffer.size[0], pickNormalBuffer.size[1]);
|
|
1601
|
-
|
|
1602
|
-
gl.enable(gl.DEPTH_TEST);
|
|
1603
|
-
gl.disable(gl.CULL_FACE);
|
|
1604
|
-
gl.disable(gl.BLEND);
|
|
1605
|
-
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
1606
|
-
gl.clearBufferiv(gl.COLOR, 0, new Int32Array([0, 0, 0, 0]));
|
|
1607
|
-
|
|
1608
|
-
pickable.drawPickNormals(frameCtx); // Draw color-encoded fragment World-space normals
|
|
1609
|
-
|
|
1610
|
-
const pix = pickNormalBuffer.read(1, 1, gl.RGBA_INTEGER, gl.INT, Int32Array, 4);
|
|
1611
|
-
|
|
1612
|
-
pickNormalBuffer.unbind();
|
|
1613
|
-
|
|
1614
|
-
const worldNormal = [
|
|
1615
|
-
pix[0] / math.MAX_INT,
|
|
1616
|
-
pix[1] / math.MAX_INT,
|
|
1617
|
-
pix[2] / math.MAX_INT,
|
|
1618
|
-
];
|
|
1619
|
-
|
|
1620
|
-
math.normalizeVec3(worldNormal);
|
|
1621
|
-
|
|
1622
|
-
pickResult.worldNormal = worldNormal;
|
|
1623
|
-
}
|
|
1624
|
-
|
|
1625
1634
|
/**
|
|
1626
1635
|
* Adds a {@link Marker} for occlusion testing.
|
|
1627
1636
|
* @param marker
|
|
1628
1637
|
*/
|
|
1629
1638
|
this.addMarker = function (marker) {
|
|
1630
|
-
this._occlusionTester = this._occlusionTester || new OcclusionTester(scene
|
|
1639
|
+
this._occlusionTester = this._occlusionTester || new OcclusionTester(scene);
|
|
1631
1640
|
this._occlusionTester.addMarker(marker);
|
|
1632
1641
|
scene.occlusionTestCountdown = 0;
|
|
1633
1642
|
};
|
|
@@ -1658,11 +1667,17 @@ const Renderer = function (scene, options) {
|
|
|
1658
1667
|
|
|
1659
1668
|
updateDrawlist();
|
|
1660
1669
|
|
|
1661
|
-
|
|
1670
|
+
const readPixelBuf = (! OCCLUSION_TEST_MODE) && renderBufferManager.getRenderBuffer("occlusionReadPix");
|
|
1671
|
+
if (readPixelBuf) {
|
|
1672
|
+
readPixelBuf.setSize([gl.drawingBufferWidth, gl.drawingBufferHeight]);
|
|
1673
|
+
readPixelBuf.bind();
|
|
1674
|
+
}
|
|
1662
1675
|
|
|
1663
1676
|
frameCtx.reset();
|
|
1664
1677
|
frameCtx.backfaces = true;
|
|
1665
1678
|
frameCtx.frontface = true; // "ccw"
|
|
1679
|
+
frameCtx.viewParams = getSceneCameraViewParams();
|
|
1680
|
+
frameCtx.nearPlaneHeight = getNearPlaneHeight(scene.camera, gl.drawingBufferHeight);
|
|
1666
1681
|
|
|
1667
1682
|
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
1668
1683
|
gl.clearColor(0, 0, 0, 0);
|
|
@@ -1671,121 +1686,143 @@ const Renderer = function (scene, options) {
|
|
|
1671
1686
|
gl.disable(gl.BLEND);
|
|
1672
1687
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1673
1688
|
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
const drawable = postCullDrawableList[i];
|
|
1678
|
-
|
|
1679
|
-
if (!drawable.drawOcclusion || drawable.culled === true || drawable.visible === false || drawable.pickable === false) { // TODO: Option to exclude transparent?
|
|
1680
|
-
continue;
|
|
1689
|
+
postCullDrawableList.forEach(drawable => {
|
|
1690
|
+
if (!drawable.culled && drawable.visible && drawable.pickable && drawable.drawOcclusion) { // TODO: Option to exclude transparent?
|
|
1691
|
+
drawable.drawOcclusion(frameCtx);
|
|
1681
1692
|
}
|
|
1693
|
+
});
|
|
1682
1694
|
|
|
1683
|
-
|
|
1684
|
-
}
|
|
1685
|
-
|
|
1686
|
-
this._occlusionTester.drawMarkers(frameCtx);
|
|
1687
|
-
this._occlusionTester.doOcclusionTest(); // Updates Marker "visible" properties
|
|
1688
|
-
this._occlusionTester.unbindRenderBuf();
|
|
1689
|
-
}
|
|
1690
|
-
};
|
|
1695
|
+
this._occlusionTester.drawMarkers();
|
|
1691
1696
|
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
* @private
|
|
1699
|
-
*/
|
|
1700
|
-
this.readPixels = function (pixels, colors, len, opaqueOnly) {
|
|
1701
|
-
const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
|
|
1702
|
-
snapshotBuffer.bind();
|
|
1703
|
-
snapshotBuffer.clear();
|
|
1704
|
-
this.render({force: true, opaqueOnly: opaqueOnly});
|
|
1705
|
-
let color;
|
|
1706
|
-
let i;
|
|
1707
|
-
let j;
|
|
1708
|
-
let k;
|
|
1709
|
-
for (i = 0; i < len; i++) {
|
|
1710
|
-
j = i * 2;
|
|
1711
|
-
k = i * 4;
|
|
1712
|
-
color = snapshotBuffer.read(pixels[j], pixels[j + 1]);
|
|
1713
|
-
colors[k] = color[0];
|
|
1714
|
-
colors[k + 1] = color[1];
|
|
1715
|
-
colors[k + 2] = color[2];
|
|
1716
|
-
colors[k + 3] = color[3];
|
|
1717
|
-
}
|
|
1718
|
-
snapshotBuffer.unbind();
|
|
1719
|
-
imageDirty = true;
|
|
1720
|
-
};
|
|
1721
|
-
|
|
1722
|
-
/**
|
|
1723
|
-
* Enter snapshot mode.
|
|
1724
|
-
*
|
|
1725
|
-
* Switches rendering to a hidden snapshot canvas.
|
|
1726
|
-
*
|
|
1727
|
-
* Exit snapshot mode using endSnapshot().
|
|
1728
|
-
*/
|
|
1729
|
-
this.beginSnapshot = function (params = {}) {
|
|
1730
|
-
const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
|
|
1731
|
-
if (params.width && params.height) {
|
|
1732
|
-
snapshotBuffer.setSize([params.width, params.height]);
|
|
1733
|
-
}
|
|
1734
|
-
snapshotBuffer.bind();
|
|
1735
|
-
snapshotBuffer.clear();
|
|
1736
|
-
snapshotBound = true;
|
|
1737
|
-
};
|
|
1738
|
-
|
|
1739
|
-
/**
|
|
1740
|
-
* When in snapshot mode, renders a frame of the current Scene state to the snapshot canvas.
|
|
1741
|
-
*/
|
|
1742
|
-
this.renderSnapshot = function () {
|
|
1743
|
-
if (!snapshotBound) {
|
|
1744
|
-
return;
|
|
1697
|
+
if (readPixelBuf) {
|
|
1698
|
+
const resolutionScale = scene.canvas.resolutionScale;
|
|
1699
|
+
this._occlusionTester.doOcclusionTest( // Updates Marker "visible" properties
|
|
1700
|
+
(x, y) => readPixelBuf.read(Math.round(resolutionScale * x), Math.round(resolutionScale * y)));
|
|
1701
|
+
readPixelBuf.unbind();
|
|
1702
|
+
}
|
|
1745
1703
|
}
|
|
1746
|
-
const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
|
|
1747
|
-
snapshotBuffer.clear();
|
|
1748
|
-
this.render({force: true, opaqueOnly: false});
|
|
1749
|
-
imageDirty = true;
|
|
1750
1704
|
};
|
|
1751
1705
|
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1706
|
+
this.snapshot = (() => {
|
|
1707
|
+
let snapshotBound = false;
|
|
1708
|
+
const snapshotBuffer = new RenderBuffer(gl);
|
|
1709
|
+
let snapshotCanvas = null;
|
|
1710
|
+
|
|
1711
|
+
return {
|
|
1712
|
+
/**
|
|
1713
|
+
* Read pixels from the renderer's current output. Performs a force-render first.
|
|
1714
|
+
* @param pixels
|
|
1715
|
+
* @param colors
|
|
1716
|
+
* @param len
|
|
1717
|
+
* @private
|
|
1718
|
+
*/
|
|
1719
|
+
readPixels: (pixels, colors, len) => {
|
|
1720
|
+
snapshotBuffer.bind();
|
|
1721
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1722
|
+
imageDirty = true;
|
|
1723
|
+
this.render();
|
|
1724
|
+
for (let i = 0; i < len; i++) {
|
|
1725
|
+
const j = i * 2;
|
|
1726
|
+
const k = i * 4;
|
|
1727
|
+
const color = snapshotBuffer.read(pixels[j], pixels[j + 1]);
|
|
1728
|
+
colors[k] = color[0];
|
|
1729
|
+
colors[k + 1] = color[1];
|
|
1730
|
+
colors[k + 2] = color[2];
|
|
1731
|
+
colors[k + 3] = color[3];
|
|
1732
|
+
}
|
|
1733
|
+
snapshotBuffer.unbind();
|
|
1734
|
+
imageDirty = true;
|
|
1735
|
+
},
|
|
1736
|
+
|
|
1737
|
+
/**
|
|
1738
|
+
* Enter snapshot mode.
|
|
1739
|
+
*
|
|
1740
|
+
* Switches rendering to a hidden snapshot canvas.
|
|
1741
|
+
*
|
|
1742
|
+
* Exit snapshot mode using endSnapshot().
|
|
1743
|
+
*/
|
|
1744
|
+
beginSnapshot: () => {
|
|
1745
|
+
snapshotBuffer.setSize([gl.drawingBufferWidth, gl.drawingBufferHeight]);
|
|
1746
|
+
snapshotBuffer.bind();
|
|
1747
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1748
|
+
snapshotBound = true;
|
|
1749
|
+
},
|
|
1750
|
+
|
|
1751
|
+
/**
|
|
1752
|
+
* Returns an HTMLCanvas containing an image of the snapshot canvas.
|
|
1753
|
+
*
|
|
1754
|
+
* - The HTMLCanvas has a CanvasRenderingContext2D.
|
|
1755
|
+
* - Expects the caller to draw more things on the HTMLCanvas (annotations etc).
|
|
1756
|
+
*
|
|
1757
|
+
* @returns {HTMLCanvasElement}
|
|
1758
|
+
*/
|
|
1759
|
+
renderSnapshotToCanvas: () => {
|
|
1760
|
+
const width = snapshotBuffer.buffer.width;
|
|
1761
|
+
const height = snapshotBuffer.buffer.height;
|
|
1762
|
+
|
|
1763
|
+
if ((! snapshotCanvas) || (snapshotCanvas.width !== width) || (snapshotCanvas.height !== height)) {
|
|
1764
|
+
snapshotCanvas = (function() {
|
|
1765
|
+
const canvas = document.createElement('canvas');
|
|
1766
|
+
const context = canvas.getContext('2d');
|
|
1767
|
+
canvas.width = width;
|
|
1768
|
+
canvas.height = height;
|
|
1769
|
+
const pixelData = new Uint8Array(width * height * 4);
|
|
1770
|
+
const imageData = context.createImageData(width, height);
|
|
1771
|
+
|
|
1772
|
+
return {
|
|
1773
|
+
width: width,
|
|
1774
|
+
height: height,
|
|
1775
|
+
getUpdatedCanvas: () => {
|
|
1776
|
+
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixelData);
|
|
1777
|
+
|
|
1778
|
+
// flip verically
|
|
1779
|
+
const halfHeight = Math.floor(height / 2);
|
|
1780
|
+
const bytesPerRow = width * 4;
|
|
1781
|
+
const temp = new Uint8Array(bytesPerRow);
|
|
1782
|
+
for (let y = 0; y < halfHeight; ++y) {
|
|
1783
|
+
const topOffset = y * bytesPerRow;
|
|
1784
|
+
const bottomOffset = (height - y - 1) * bytesPerRow;
|
|
1785
|
+
temp.set(pixelData.subarray(topOffset, topOffset + bytesPerRow));
|
|
1786
|
+
pixelData.copyWithin(topOffset, bottomOffset, bottomOffset + bytesPerRow);
|
|
1787
|
+
pixelData.set(temp, bottomOffset);
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
imageData.data.set(pixelData);
|
|
1791
|
+
|
|
1792
|
+
context.resetTransform(); // Prevents strange scale-accumulation effect with html2canvas
|
|
1793
|
+
context.putImageData(imageData, 0, 0);
|
|
1794
|
+
|
|
1795
|
+
return canvas;
|
|
1796
|
+
}
|
|
1797
|
+
};
|
|
1798
|
+
})();
|
|
1799
|
+
}
|
|
1762
1800
|
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
* @returns {HTMLCanvasElement}
|
|
1770
|
-
*/
|
|
1771
|
-
this.readSnapshotAsCanvas = function () {
|
|
1772
|
-
const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
|
|
1773
|
-
return snapshotBuffer.readImageAsCanvas();
|
|
1774
|
-
};
|
|
1801
|
+
if (snapshotBound) {
|
|
1802
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1803
|
+
imageDirty = true;
|
|
1804
|
+
this.render();
|
|
1805
|
+
imageDirty = true;
|
|
1806
|
+
}
|
|
1775
1807
|
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1808
|
+
return snapshotCanvas.getUpdatedCanvas();
|
|
1809
|
+
},
|
|
1810
|
+
|
|
1811
|
+
/**
|
|
1812
|
+
* Exists snapshot mode.
|
|
1813
|
+
*
|
|
1814
|
+
* Switches rendering back to the main canvas.
|
|
1815
|
+
*/
|
|
1816
|
+
endSnapshot: () => {
|
|
1817
|
+
if (snapshotBound) {
|
|
1818
|
+
snapshotBuffer.unbind();
|
|
1819
|
+
snapshotBound = false;
|
|
1820
|
+
}
|
|
1821
|
+
imageDirty = true;
|
|
1822
|
+
this.render();
|
|
1823
|
+
}
|
|
1824
|
+
};
|
|
1825
|
+
})();
|
|
1789
1826
|
|
|
1790
1827
|
/**
|
|
1791
1828
|
* Destroys this renderer.
|