@xeokit/xeokit-sdk 2.6.84 → 2.6.85-renderers-refactor-v2
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 +13077 -44659
- package/dist/xeokit-sdk.es.js +13078 -44658
- package/dist/xeokit-sdk.es5.js +1402 -3502
- 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/lib/ui/index.js +12 -0
- 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 -1502
- 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 -157
- package/src/viewer/scene/mesh/pick/PickMeshShaderSource.js +21 -150
- 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 +245 -861
- 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 +786 -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 +28 -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 -996
- package/src/viewer/scene/mesh/emphasis/EmphasisEdgesRenderer.js +0 -259
- package/src/viewer/scene/mesh/emphasis/EmphasisEdgesShaderSource.js +0 -159
- package/src/viewer/scene/mesh/emphasis/EmphasisFillRenderer.js +0 -286
- package/src/viewer/scene/mesh/emphasis/EmphasisFillShaderSource.js +0 -262
- 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
|
const byDist = normalFillTransparentBin.map(d => ({ drawable: d, distSq: math.distVec3(d.origin || vec3_0, eye) }));
|
|
728
971
|
byDist.sort((a, b) => b.distSq - a.distSq);
|
|
729
972
|
for (i = 0; i < normalFillTransparentBinLen; i++) {
|
|
@@ -900,12 +1143,30 @@ const Renderer = function (scene, options) {
|
|
|
900
1143
|
for (let ii = 0; ii < numVertexAttribs; ii++) {
|
|
901
1144
|
gl.disableVertexAttribArray(ii);
|
|
902
1145
|
}
|
|
903
|
-
|
|
904
|
-
if (unbindOutputFrameBuffer) {
|
|
905
|
-
unbindOutputFrameBuffer(params.pass);
|
|
906
|
-
}
|
|
907
1146
|
}
|
|
908
1147
|
|
|
1148
|
+
const resetPickFrameCtx = (canvasPos, clipTransformDiv, camera, eye, projMatrix, viewMatrix, frameCtx) => {
|
|
1149
|
+
frameCtx.reset();
|
|
1150
|
+
frameCtx.backfaces = true;
|
|
1151
|
+
frameCtx.frontface = true; // "ccw"
|
|
1152
|
+
|
|
1153
|
+
frameCtx.viewParams.eye = eye;
|
|
1154
|
+
frameCtx.viewParams.projMatrix = projMatrix;
|
|
1155
|
+
frameCtx.viewParams.viewMatrix = viewMatrix;
|
|
1156
|
+
frameCtx.nearPlaneHeight = getNearPlaneHeight(camera, gl.drawingBufferHeight);
|
|
1157
|
+
|
|
1158
|
+
const resolutionScale = scene.canvas.resolutionScale;
|
|
1159
|
+
frameCtx.pickClipPos = [
|
|
1160
|
+
canvasPos ? ( 2 * canvasPos[0] * resolutionScale / gl.drawingBufferWidth - 1) : 0,
|
|
1161
|
+
canvasPos ? (1 - 2 * canvasPos[1] * resolutionScale / gl.drawingBufferHeight) : 0
|
|
1162
|
+
];
|
|
1163
|
+
|
|
1164
|
+
frameCtx.pickClipPosInv = [
|
|
1165
|
+
gl.drawingBufferWidth / clipTransformDiv,
|
|
1166
|
+
gl.drawingBufferHeight / clipTransformDiv
|
|
1167
|
+
];
|
|
1168
|
+
};
|
|
1169
|
+
|
|
909
1170
|
/**
|
|
910
1171
|
* Picks an Entity.
|
|
911
1172
|
* @private
|
|
@@ -913,11 +1174,18 @@ const Renderer = function (scene, options) {
|
|
|
913
1174
|
this.pick = (function () {
|
|
914
1175
|
|
|
915
1176
|
const tempVec3a = math.vec3();
|
|
1177
|
+
const tempVec3b = math.vec3();
|
|
1178
|
+
const tempVec4a = math.vec4();
|
|
1179
|
+
const tempVec4b = math.vec4();
|
|
1180
|
+
const tempVec4c = math.vec4();
|
|
1181
|
+
const tempVec4d = math.vec4();
|
|
1182
|
+
const tempVec4e = math.vec4();
|
|
916
1183
|
const tempMat4a = math.mat4();
|
|
917
1184
|
const tempMat4b = math.mat4();
|
|
1185
|
+
const tempMat4c = math.mat4();
|
|
1186
|
+
const tempMat4d = math.mat4();
|
|
918
1187
|
|
|
919
|
-
const
|
|
920
|
-
const up = math.vec3([0, 1, 0]);
|
|
1188
|
+
const upVec = math.vec3([0, 1, 0]);
|
|
921
1189
|
const _pickResult = new PickResult();
|
|
922
1190
|
|
|
923
1191
|
const nearAndFar = math.vec2();
|
|
@@ -929,16 +1197,22 @@ const Renderer = function (scene, options) {
|
|
|
929
1197
|
const worldSurfacePos = math.vec3();
|
|
930
1198
|
const worldSurfaceNormal = math.vec3();
|
|
931
1199
|
|
|
1200
|
+
const pickBuffer = new RenderBuffer(gl);
|
|
1201
|
+
pickBuffer.setSize([1, 1]);
|
|
1202
|
+
|
|
1203
|
+
const pickNormalBuffer = new RenderBuffer(gl, [gl.RGBA32I]);
|
|
1204
|
+
pickNormalBuffer.setSize([3, 3]);
|
|
1205
|
+
|
|
932
1206
|
return function (params, pickResult = _pickResult) {
|
|
933
1207
|
|
|
934
1208
|
pickResult.reset();
|
|
935
1209
|
|
|
936
1210
|
updateDrawlist();
|
|
937
1211
|
|
|
938
|
-
let look;
|
|
939
1212
|
let pickViewMatrix = null;
|
|
940
1213
|
let pickProjMatrix = null;
|
|
941
1214
|
let projection = null;
|
|
1215
|
+
const camera = scene.camera;
|
|
942
1216
|
|
|
943
1217
|
pickResult.pickSurface = params.pickSurface;
|
|
944
1218
|
|
|
@@ -947,12 +1221,12 @@ const Renderer = function (scene, options) {
|
|
|
947
1221
|
canvasPos[0] = params.canvasPos[0];
|
|
948
1222
|
canvasPos[1] = params.canvasPos[1];
|
|
949
1223
|
|
|
950
|
-
pickViewMatrix =
|
|
951
|
-
pickProjMatrix =
|
|
952
|
-
projection =
|
|
1224
|
+
pickViewMatrix = camera.viewMatrix;
|
|
1225
|
+
pickProjMatrix = camera.projMatrix;
|
|
1226
|
+
projection = camera.projection;
|
|
953
1227
|
|
|
954
|
-
nearAndFar[0] =
|
|
955
|
-
nearAndFar[1] =
|
|
1228
|
+
nearAndFar[0] = camera.project.near;
|
|
1229
|
+
nearAndFar[1] = camera.project.far;
|
|
956
1230
|
|
|
957
1231
|
pickResult.canvasPos = params.canvasPos;
|
|
958
1232
|
|
|
@@ -964,33 +1238,37 @@ const Renderer = function (scene, options) {
|
|
|
964
1238
|
if (params.matrix) {
|
|
965
1239
|
|
|
966
1240
|
pickViewMatrix = params.matrix;
|
|
967
|
-
pickProjMatrix =
|
|
968
|
-
projection =
|
|
1241
|
+
pickProjMatrix = camera.projMatrix;
|
|
1242
|
+
projection = camera.projection;
|
|
969
1243
|
|
|
970
|
-
nearAndFar[0] =
|
|
971
|
-
nearAndFar[1] =
|
|
1244
|
+
nearAndFar[0] = camera.project.near;
|
|
1245
|
+
nearAndFar[1] = camera.project.far;
|
|
972
1246
|
|
|
973
1247
|
} else {
|
|
974
1248
|
|
|
975
1249
|
worldRayOrigin.set(params.origin || [0, 0, 0]);
|
|
976
1250
|
worldRayDir.set(params.direction || [0, 0, 1]);
|
|
977
1251
|
|
|
978
|
-
look = math.addVec3(worldRayOrigin, worldRayDir, tempVec3a);
|
|
979
|
-
|
|
980
|
-
randomVec3[0] = Math.random();
|
|
981
|
-
randomVec3[1] = Math.random();
|
|
982
|
-
randomVec3[2] = Math.random();
|
|
1252
|
+
const look = math.addVec3(worldRayOrigin, worldRayDir, tempVec3a);
|
|
1253
|
+
const up = tempVec3b;
|
|
983
1254
|
|
|
984
|
-
math.
|
|
985
|
-
|
|
1255
|
+
if (Math.abs(math.dotVec3(worldRayDir, upVec)) > (1 - 1e-6)) { // worldRayDir aligned with Y axis
|
|
1256
|
+
up[0] = 0;
|
|
1257
|
+
up[1] = 0;
|
|
1258
|
+
up[2] = Math.sign(worldRayDir[1]);
|
|
1259
|
+
} else {
|
|
1260
|
+
math.cross3Vec3(worldRayDir, upVec, up);
|
|
1261
|
+
math.cross3Vec3(up, worldRayDir, up);
|
|
1262
|
+
math.normalizeVec3(up, up);
|
|
1263
|
+
}
|
|
986
1264
|
|
|
987
1265
|
pickViewMatrix = math.lookAtMat4v(worldRayOrigin, look, up, tempMat4b);
|
|
988
|
-
// pickProjMatrix =
|
|
989
|
-
pickProjMatrix =
|
|
1266
|
+
// pickProjMatrix = camera.projMatrix;
|
|
1267
|
+
pickProjMatrix = camera.ortho.matrix;
|
|
990
1268
|
projection = "ortho";
|
|
991
1269
|
|
|
992
|
-
nearAndFar[0] =
|
|
993
|
-
nearAndFar[1] =
|
|
1270
|
+
nearAndFar[0] = camera.ortho.near;
|
|
1271
|
+
nearAndFar[1] = camera.ortho.far;
|
|
994
1272
|
|
|
995
1273
|
pickResult.origin = worldRayOrigin;
|
|
996
1274
|
pickResult.direction = worldRayDir;
|
|
@@ -1000,23 +1278,42 @@ const Renderer = function (scene, options) {
|
|
|
1000
1278
|
canvasPos[1] = canvas.clientHeight * 0.5;
|
|
1001
1279
|
}
|
|
1002
1280
|
|
|
1003
|
-
|
|
1004
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
1005
|
-
const drawableList = drawableTypeInfo[type].drawableList;
|
|
1006
|
-
for (let i = 0, len = drawableList.length; i < len; i++) {
|
|
1007
|
-
const drawable = drawableList[i];
|
|
1008
|
-
if (drawable.setPickMatrices) { // Eg. SceneModel, which needs pre-loading into texture
|
|
1009
|
-
drawable.setPickMatrices(pickViewMatrix, pickProjMatrix);
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1281
|
+
pickBuffer.bind();
|
|
1014
1282
|
|
|
1015
|
-
const
|
|
1283
|
+
const resetFrameCtx = (clipTransformDiv) => resetPickFrameCtx(canvasPos, clipTransformDiv, camera, pickResult.origin || camera.eye, pickProjMatrix || camera.projMatrix, pickViewMatrix || camera.viewMatrix, frameCtx);
|
|
1016
1284
|
|
|
1017
|
-
|
|
1285
|
+
// gpuPickPickable
|
|
1286
|
+
resetFrameCtx(1);
|
|
1287
|
+
frameCtx.pickInvisible = !!params.pickInvisible;
|
|
1288
|
+
|
|
1289
|
+
gl.viewport(0, 0, 1, 1);
|
|
1290
|
+
gl.depthMask(true);
|
|
1291
|
+
gl.enable(gl.DEPTH_TEST);
|
|
1292
|
+
gl.disable(gl.CULL_FACE);
|
|
1293
|
+
gl.disable(gl.BLEND);
|
|
1294
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1295
|
+
|
|
1296
|
+
const includeEntityIds = params.includeEntityIds;
|
|
1297
|
+
const excludeEntityIds = params.excludeEntityIds;
|
|
1298
|
+
|
|
1299
|
+
const renderDrawables = function(drawables) {
|
|
1300
|
+
drawables.forEach(drawable => {
|
|
1301
|
+
if (!drawable.culled && drawable.visible && drawable.pickable && drawable.drawPickMesh // TODO: push this logic into drawable
|
|
1302
|
+
&& ((! includeEntityIds) || includeEntityIds[drawable.id])
|
|
1303
|
+
&& ((! excludeEntityIds) || (! excludeEntityIds[drawable.id]))) {
|
|
1304
|
+
drawable.drawPickMesh(frameCtx);
|
|
1305
|
+
}
|
|
1306
|
+
});
|
|
1307
|
+
};
|
|
1308
|
+
|
|
1309
|
+
renderDrawables(postCullDrawableList);
|
|
1310
|
+
if (uiDrawableList.length > 0) {
|
|
1311
|
+
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
1312
|
+
renderDrawables(uiDrawableList);
|
|
1313
|
+
}
|
|
1018
1314
|
|
|
1019
|
-
const
|
|
1315
|
+
const pickID = pixelToInt(pickBuffer.read(0, 0));
|
|
1316
|
+
const pickable = (pickID >= 0) && pickIDs.items[pickID];
|
|
1020
1317
|
|
|
1021
1318
|
if (!pickable) {
|
|
1022
1319
|
pickBuffer.unbind();
|
|
@@ -1036,265 +1333,108 @@ const Renderer = function (scene, options) {
|
|
|
1036
1333
|
|
|
1037
1334
|
if (pickable.canPickTriangle && pickable.canPickTriangle()) {
|
|
1038
1335
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1336
|
+
if (pickable.drawPickTriangles) {
|
|
1337
|
+
resetFrameCtx(1);
|
|
1338
|
+
// frameCtx.pickInvisible = !!params.pickInvisible;
|
|
1042
1339
|
|
|
1043
|
-
|
|
1340
|
+
gl.viewport(0, 0, 1, 1);
|
|
1341
|
+
gl.clearColor(0, 0, 0, 0);
|
|
1342
|
+
gl.enable(gl.DEPTH_TEST);
|
|
1343
|
+
gl.disable(gl.CULL_FACE);
|
|
1344
|
+
gl.disable(gl.BLEND);
|
|
1345
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1044
1346
|
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
if (pickable.canPickWorldPos && pickable.canPickWorldPos()) {
|
|
1048
|
-
|
|
1049
|
-
gpuPickWorldPos(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, nearAndFar, pickResult);
|
|
1050
|
-
|
|
1051
|
-
if (params.pickSurfaceNormal !== false) {
|
|
1052
|
-
gpuPickWorldNormal(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, pickResult);
|
|
1053
|
-
}
|
|
1347
|
+
pickable.drawPickTriangles(frameCtx);
|
|
1054
1348
|
|
|
1055
|
-
pickResult.
|
|
1349
|
+
pickResult.primIndex = 3 * pixelToInt(pickBuffer.read(0, 0)); // Convert from triangle number to first vertex in indices
|
|
1056
1350
|
}
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
pickBuffer.unbind();
|
|
1060
|
-
pickResult.entity = pickedEntity;
|
|
1061
|
-
return pickResult;
|
|
1062
|
-
};
|
|
1063
|
-
})();
|
|
1064
|
-
|
|
1065
|
-
function gpuPickPickable(pickBuffer, canvasPos, pickViewMatrix, pickProjMatrix, params, pickResult) {
|
|
1066
|
-
|
|
1067
|
-
const resolutionScale = scene.canvas.resolutionScale;
|
|
1068
|
-
|
|
1069
|
-
frameCtx.reset();
|
|
1070
|
-
frameCtx.backfaces = true;
|
|
1071
|
-
frameCtx.frontface = true; // "ccw"
|
|
1072
|
-
frameCtx.pickOrigin = pickResult.origin;
|
|
1073
|
-
frameCtx.pickViewMatrix = pickViewMatrix;
|
|
1074
|
-
frameCtx.pickProjMatrix = pickProjMatrix;
|
|
1075
|
-
frameCtx.pickInvisible = !!params.pickInvisible;
|
|
1076
|
-
frameCtx.pickClipPos = [
|
|
1077
|
-
getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
|
|
1078
|
-
getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight)
|
|
1079
|
-
];
|
|
1080
|
-
|
|
1081
|
-
gl.viewport(0, 0, 1, 1);
|
|
1082
|
-
gl.depthMask(true);
|
|
1083
|
-
gl.enable(gl.DEPTH_TEST);
|
|
1084
|
-
gl.disable(gl.CULL_FACE);
|
|
1085
|
-
gl.disable(gl.BLEND);
|
|
1086
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1087
|
-
|
|
1088
|
-
const includeEntityIds = params.includeEntityIds;
|
|
1089
|
-
const excludeEntityIds = params.excludeEntityIds;
|
|
1090
|
-
|
|
1091
|
-
const renderDrawables = function(drawables) {
|
|
1092
|
-
for (let i = 0, len = drawables.length; i < len; i++) {
|
|
1093
|
-
const drawable = drawables[i];
|
|
1094
|
-
if (drawable.culled === true || drawable.visible === false) {
|
|
1095
|
-
continue;
|
|
1096
|
-
}
|
|
1097
|
-
if (!drawable.drawPickMesh || (params.pickInvisible !== true && drawable.visible === false) || drawable.pickable === false) {
|
|
1098
|
-
continue;
|
|
1099
|
-
}
|
|
1100
|
-
if (includeEntityIds && !includeEntityIds[drawable.id]) { // TODO: push this logic into drawable
|
|
1101
|
-
continue;
|
|
1102
|
-
}
|
|
1103
|
-
if (excludeEntityIds && excludeEntityIds[drawable.id]) {
|
|
1104
|
-
continue;
|
|
1105
|
-
}
|
|
1106
|
-
drawable.drawPickMesh(frameCtx);
|
|
1107
|
-
}
|
|
1108
|
-
};
|
|
1109
|
-
|
|
1110
|
-
renderDrawables(postCullDrawableList);
|
|
1111
|
-
if (uiDrawableList.length > 0) {
|
|
1112
|
-
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
1113
|
-
renderDrawables(uiDrawableList);
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
const pix = pickBuffer.read(0, 0);
|
|
1117
|
-
const pickID = pix[0] + (pix[1] << 8) + (pix[2] << 16) + (pix[3] << 24);
|
|
1118
|
-
|
|
1119
|
-
if (pickID < 0) {
|
|
1120
|
-
return;
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
const pickable = pickIDs.items[pickID];
|
|
1124
|
-
|
|
1125
|
-
return pickable;
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
function gpuPickTriangle(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, pickResult) {
|
|
1129
|
-
|
|
1130
|
-
if (!pickable.drawPickTriangles) {
|
|
1131
|
-
return;
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
const resolutionScale = scene.canvas.resolutionScale;
|
|
1135
|
-
|
|
1136
|
-
frameCtx.reset();
|
|
1137
|
-
frameCtx.backfaces = true;
|
|
1138
|
-
frameCtx.frontface = true; // "ccw"
|
|
1139
|
-
frameCtx.pickOrigin = pickResult.origin;
|
|
1140
|
-
frameCtx.pickViewMatrix = pickViewMatrix; // Can be null
|
|
1141
|
-
frameCtx.pickProjMatrix = pickProjMatrix; // Can be null
|
|
1142
|
-
// frameCtx.pickInvisible = !!params.pickInvisible;
|
|
1143
|
-
frameCtx.pickClipPos = [
|
|
1144
|
-
getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
|
|
1145
|
-
getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight)
|
|
1146
|
-
];
|
|
1147
1351
|
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
gl.clearColor(0, 0, 0, 0);
|
|
1151
|
-
gl.enable(gl.DEPTH_TEST);
|
|
1152
|
-
gl.disable(gl.CULL_FACE);
|
|
1153
|
-
gl.disable(gl.BLEND);
|
|
1154
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1155
|
-
|
|
1156
|
-
pickable.drawPickTriangles(frameCtx);
|
|
1157
|
-
|
|
1158
|
-
const pix = pickBuffer.read(0, 0);
|
|
1159
|
-
|
|
1160
|
-
let primIndex = pix[0] + (pix[1] * 256) + (pix[2] * 256 * 256) + (pix[3] * 256 * 256 * 256);
|
|
1161
|
-
|
|
1162
|
-
primIndex *= 3; // Convert from triangle number to first vertex in indices
|
|
1163
|
-
|
|
1164
|
-
pickResult.primIndex = primIndex;
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
const gpuPickWorldPos = (function () {
|
|
1168
|
-
|
|
1169
|
-
const tempVec4a = math.vec4();
|
|
1170
|
-
const tempVec4b = math.vec4();
|
|
1171
|
-
const tempVec4c = math.vec4();
|
|
1172
|
-
const tempVec4d = math.vec4();
|
|
1173
|
-
const tempVec4e = math.vec4();
|
|
1174
|
-
const tempMat4a = math.mat4();
|
|
1175
|
-
const tempMat4b = math.mat4();
|
|
1176
|
-
const tempMat4c = math.mat4();
|
|
1177
|
-
|
|
1178
|
-
return function (pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, nearAndFar, pickResult) {
|
|
1179
|
-
|
|
1180
|
-
const resolutionScale = scene.canvas.resolutionScale;
|
|
1181
|
-
|
|
1182
|
-
frameCtx.reset();
|
|
1183
|
-
frameCtx.backfaces = true;
|
|
1184
|
-
frameCtx.frontface = true; // "ccw"
|
|
1185
|
-
frameCtx.pickOrigin = pickResult.origin;
|
|
1186
|
-
frameCtx.pickViewMatrix = pickViewMatrix;
|
|
1187
|
-
frameCtx.pickProjMatrix = pickProjMatrix;
|
|
1188
|
-
frameCtx.pickZNear = nearAndFar[0];
|
|
1189
|
-
frameCtx.pickZFar = nearAndFar[1];
|
|
1190
|
-
frameCtx.pickElementsCount = pickable.pickElementsCount;
|
|
1191
|
-
frameCtx.pickElementsOffset = pickable.pickElementsOffset;
|
|
1192
|
-
frameCtx.pickClipPos = [
|
|
1193
|
-
getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
|
|
1194
|
-
getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight)
|
|
1195
|
-
];
|
|
1352
|
+
pickable.pickTriangleSurface(pickViewMatrix, pickProjMatrix, projection, pickResult);
|
|
1196
1353
|
|
|
1197
|
-
|
|
1354
|
+
pickResult.pickSurfacePrecision = false;
|
|
1198
1355
|
|
|
1199
|
-
|
|
1200
|
-
gl.depthMask(true);
|
|
1201
|
-
gl.enable(gl.DEPTH_TEST);
|
|
1202
|
-
gl.disable(gl.CULL_FACE);
|
|
1203
|
-
gl.disable(gl.BLEND);
|
|
1204
|
-
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1356
|
+
} else {
|
|
1205
1357
|
|
|
1206
|
-
|
|
1358
|
+
if (pickable.canPickWorldPos && pickable.canPickWorldPos()) {
|
|
1207
1359
|
|
|
1208
|
-
|
|
1360
|
+
// pickWorldPos
|
|
1361
|
+
resetFrameCtx(1);
|
|
1362
|
+
frameCtx.viewParams.near = nearAndFar[0];
|
|
1363
|
+
frameCtx.viewParams.far = nearAndFar[1];
|
|
1209
1364
|
|
|
1210
|
-
|
|
1365
|
+
gl.viewport(0, 0, 1, 1);
|
|
1211
1366
|
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1367
|
+
gl.clearColor(0, 0, 0, 0);
|
|
1368
|
+
gl.depthMask(true);
|
|
1369
|
+
gl.enable(gl.DEPTH_TEST);
|
|
1370
|
+
gl.disable(gl.CULL_FACE);
|
|
1371
|
+
gl.disable(gl.BLEND);
|
|
1372
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1215
1373
|
|
|
1216
|
-
|
|
1217
|
-
let pvMat;
|
|
1374
|
+
pickable.drawPickDepths(frameCtx); // Draw color-encoded fragment screen-space depths
|
|
1218
1375
|
|
|
1219
|
-
|
|
1220
|
-
const rtcPickViewMat = createRTCViewMat(pickViewMatrix, origin, tempMat4a);
|
|
1221
|
-
pvMat = math.mulMat4(pickProjMatrix, rtcPickViewMat, tempMat4b);
|
|
1376
|
+
const screenZ = math.dotVec4(pickBuffer.read(0, 0), bitShiftScreenZ);
|
|
1222
1377
|
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1378
|
+
// Calculate clip space coordinates, which will be in range of x=[-1..1] and y=[-1..1], with y=(+1) at top
|
|
1379
|
+
const x = (canvasPos[0] - canvas.clientWidth / 2) / (canvas.clientWidth / 2);
|
|
1380
|
+
const y = -(canvasPos[1] - canvas.clientHeight / 2) / (canvas.clientHeight / 2);
|
|
1226
1381
|
|
|
1227
|
-
|
|
1382
|
+
const origin = pickable.origin;
|
|
1228
1383
|
|
|
1229
|
-
|
|
1230
|
-
tempVec4a[1] = y;
|
|
1231
|
-
tempVec4a[2] = -1;
|
|
1232
|
-
tempVec4a[3] = 1;
|
|
1384
|
+
const pvMatInverse = math.inverseMat4(math.mulMat4(pickProjMatrix, (origin ? createRTCViewMat(pickViewMatrix, origin, tempMat4a) : pickViewMatrix), tempMat4c), tempMat4d);
|
|
1233
1385
|
|
|
1234
|
-
|
|
1235
|
-
|
|
1386
|
+
const toWorld = (z, dst) => {
|
|
1387
|
+
dst[0] = x;
|
|
1388
|
+
dst[1] = y;
|
|
1389
|
+
dst[2] = z;
|
|
1390
|
+
dst[3] = 1;
|
|
1391
|
+
math.transformVec4(pvMatInverse, dst, dst);
|
|
1392
|
+
return math.mulVec4Scalar(dst, 1 / dst[3]);
|
|
1393
|
+
};
|
|
1236
1394
|
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
tempVec4b[2] = 1;
|
|
1240
|
-
tempVec4b[3] = 1;
|
|
1395
|
+
const world1 = toWorld(-1, tempVec4a);
|
|
1396
|
+
const world2 = toWorld( 1, tempVec4b);
|
|
1241
1397
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1398
|
+
const dir = math.subVec3(world2, world1, tempVec4c);
|
|
1399
|
+
const worldPos = math.addVec3(world1, math.mulVec4Scalar(dir, screenZ, tempVec4d), tempVec4e);
|
|
1244
1400
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1401
|
+
if (origin) {
|
|
1402
|
+
math.addVec3(worldPos, origin);
|
|
1403
|
+
}
|
|
1247
1404
|
|
|
1248
|
-
|
|
1249
|
-
math.addVec3(worldPos, origin);
|
|
1250
|
-
}
|
|
1405
|
+
pickResult.worldPos = worldPos;
|
|
1251
1406
|
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1407
|
+
if (params.pickSurfaceNormal !== false) {
|
|
1408
|
+
// gpuPickWorldNormal
|
|
1409
|
+
resetFrameCtx(3);
|
|
1255
1410
|
|
|
1256
|
-
|
|
1257
|
-
frameCtx.snapPickLayerParams = [];
|
|
1258
|
-
frameCtx.snapPickLayerNumber = 0;
|
|
1411
|
+
pickNormalBuffer.bind();
|
|
1259
1412
|
|
|
1260
|
-
|
|
1413
|
+
gl.viewport(0, 0, pickNormalBuffer.size[0], pickNormalBuffer.size[1]);
|
|
1414
|
+
gl.enable(gl.DEPTH_TEST);
|
|
1415
|
+
gl.disable(gl.CULL_FACE);
|
|
1416
|
+
gl.disable(gl.BLEND);
|
|
1417
|
+
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
1418
|
+
gl.clearBufferiv(gl.COLOR, 0, new Int32Array([0, 0, 0, 0]));
|
|
1261
1419
|
|
|
1262
|
-
|
|
1420
|
+
pickable.drawPickNormals(frameCtx); // Draw color-encoded fragment World-space normals
|
|
1263
1421
|
|
|
1264
|
-
|
|
1265
|
-
if (!drawable.culled && drawable.visible && drawable.pickable) {
|
|
1266
|
-
drawable.drawSnapInit(frameCtx);
|
|
1267
|
-
}
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
|
-
return frameCtx.snapPickLayerParams;
|
|
1271
|
-
}
|
|
1422
|
+
const pix = pickNormalBuffer.read(1, 1, gl.RGBA_INTEGER, gl.INT, Int32Array, 4);
|
|
1272
1423
|
|
|
1273
|
-
|
|
1274
|
-
frameCtx.snapPickLayerParams = frameCtx.snapPickLayerParams || [];
|
|
1275
|
-
frameCtx.snapPickLayerNumber = frameCtx.snapPickLayerParams.length;
|
|
1276
|
-
for (let i = 0, len = postCullDrawableList.length; i < len; i++) {
|
|
1424
|
+
pickNormalBuffer.unbind();
|
|
1277
1425
|
|
|
1278
|
-
|
|
1426
|
+
pickResult.worldNormal = toWorldNormal(pix);
|
|
1427
|
+
}
|
|
1279
1428
|
|
|
1280
|
-
|
|
1281
|
-
if (drawable.drawSnap) {
|
|
1282
|
-
if (!drawable.culled && drawable.visible && drawable.pickable) {
|
|
1283
|
-
drawable.drawSnap(frameCtx);
|
|
1429
|
+
pickResult.pickSurfacePrecision = false;
|
|
1284
1430
|
}
|
|
1285
1431
|
}
|
|
1286
1432
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
return 2 * (pos / size) - 1;
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
function getClipPosY(pos, size) {
|
|
1296
|
-
return 1 - 2 * (pos / size);
|
|
1297
|
-
}
|
|
1433
|
+
pickBuffer.unbind();
|
|
1434
|
+
pickResult.entity = pickedEntity;
|
|
1435
|
+
return pickResult;
|
|
1436
|
+
};
|
|
1437
|
+
})();
|
|
1298
1438
|
|
|
1299
1439
|
/**
|
|
1300
1440
|
* @param {[number, number]} canvasPos
|
|
@@ -1308,6 +1448,18 @@ const Renderer = function (scene, options) {
|
|
|
1308
1448
|
|
|
1309
1449
|
const _pickResult = new PickResult();
|
|
1310
1450
|
|
|
1451
|
+
const getVertexPickBuffer = (function() {
|
|
1452
|
+
const cache = { };
|
|
1453
|
+
return (snapRadiusInPixels) => {
|
|
1454
|
+
if (! (snapRadiusInPixels in cache)) {
|
|
1455
|
+
const buf = new RenderBuffer(gl, [gl.RGBA32I, gl.RGBA32I, gl.RGBA8UI], true);
|
|
1456
|
+
buf.setSize([2 * snapRadiusInPixels + 1, 2 * snapRadiusInPixels + 1]);
|
|
1457
|
+
cache[snapRadiusInPixels] = buf;
|
|
1458
|
+
}
|
|
1459
|
+
return cache[snapRadiusInPixels];
|
|
1460
|
+
};
|
|
1461
|
+
})();
|
|
1462
|
+
|
|
1311
1463
|
return function (params, pickResult = _pickResult) {
|
|
1312
1464
|
|
|
1313
1465
|
const {canvasPos, origin, direction, snapRadius, snapToVertex, snapToEdge} = params;
|
|
@@ -1316,40 +1468,21 @@ const Renderer = function (scene, options) {
|
|
|
1316
1468
|
return this.pick({canvasPos, pickSurface: true});
|
|
1317
1469
|
}
|
|
1318
1470
|
|
|
1319
|
-
const
|
|
1320
|
-
|
|
1321
|
-
frameCtx.reset();
|
|
1322
|
-
frameCtx.backfaces = true;
|
|
1323
|
-
frameCtx.frontface = true; // "ccw"
|
|
1324
|
-
frameCtx.pickZNear = scene.camera.project.near;
|
|
1325
|
-
frameCtx.pickZFar = scene.camera.project.far;
|
|
1326
|
-
|
|
1471
|
+
const camera = scene.camera;
|
|
1327
1472
|
const snapRadiusInPixels = snapRadius || 30;
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
]
|
|
1337
|
-
}
|
|
1338
|
-
);
|
|
1339
|
-
|
|
1340
|
-
frameCtx.snapVectorA = [
|
|
1341
|
-
canvasPos ? getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth) : 0,
|
|
1342
|
-
canvasPos ? getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight) : 0,
|
|
1343
|
-
];
|
|
1344
|
-
|
|
1345
|
-
frameCtx.snapInvVectorAB = [
|
|
1346
|
-
gl.drawingBufferWidth / (2 * snapRadiusInPixels),
|
|
1347
|
-
gl.drawingBufferHeight / (2 * snapRadiusInPixels),
|
|
1348
|
-
];
|
|
1473
|
+
const viewMatrix = (canvasPos
|
|
1474
|
+
? camera.viewMatrix
|
|
1475
|
+
: math.lookAtMat4v(
|
|
1476
|
+
origin,
|
|
1477
|
+
math.addVec3(origin, direction, math.vec3()),
|
|
1478
|
+
math.vec3([0, 1, 0]),
|
|
1479
|
+
math.mat4()));
|
|
1480
|
+
resetPickFrameCtx(canvasPos, 2 * snapRadiusInPixels, camera, camera.eye, camera.projMatrix, viewMatrix, frameCtx);
|
|
1349
1481
|
|
|
1350
1482
|
// Bind and clear the snap render target
|
|
1351
1483
|
|
|
1352
|
-
vertexPickBuffer
|
|
1484
|
+
const vertexPickBuffer = getVertexPickBuffer(snapRadiusInPixels);
|
|
1485
|
+
vertexPickBuffer.bind();
|
|
1353
1486
|
gl.viewport(0, 0, vertexPickBuffer.size[0], vertexPickBuffer.size[1]);
|
|
1354
1487
|
gl.enable(gl.DEPTH_TEST);
|
|
1355
1488
|
gl.frontFace(gl.CCW);
|
|
@@ -1362,64 +1495,59 @@ const Renderer = function (scene, options) {
|
|
|
1362
1495
|
gl.clearBufferiv(gl.COLOR, 1, new Int32Array([0, 0, 0, 0]));
|
|
1363
1496
|
gl.clearBufferuiv(gl.COLOR, 2, new Uint32Array([0, 0, 0, 0]));
|
|
1364
1497
|
|
|
1365
|
-
//////////////////////////////////
|
|
1366
|
-
// Set view and proj mats for VBO renderers
|
|
1367
|
-
///////////////////////////////////////
|
|
1368
|
-
|
|
1369
|
-
frameCtx.pickViewMatrix = (canvasPos
|
|
1370
|
-
? scene.camera.viewMatrix
|
|
1371
|
-
: math.lookAtMat4v(
|
|
1372
|
-
origin,
|
|
1373
|
-
math.addVec3(origin, direction, math.vec3()),
|
|
1374
|
-
math.vec3([0, 1, 0]),
|
|
1375
|
-
math.mat4()));
|
|
1376
|
-
|
|
1377
|
-
const pickProjMatrix = scene.camera.projMatrix;
|
|
1378
|
-
|
|
1379
|
-
for (let type in drawableTypeInfo) {
|
|
1380
|
-
if (drawableTypeInfo.hasOwnProperty(type)) {
|
|
1381
|
-
const drawableList = drawableTypeInfo[type].drawableList;
|
|
1382
|
-
for (let i = 0, len = drawableList.length; i < len; i++) {
|
|
1383
|
-
const drawable = drawableList[i];
|
|
1384
|
-
if (drawable.setPickMatrices) { // Eg. SceneModel, which needs pre-loading into texture
|
|
1385
|
-
drawable.setPickMatrices(frameCtx.pickViewMatrix, pickProjMatrix);
|
|
1386
|
-
}
|
|
1387
|
-
}
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
1390
|
-
|
|
1391
1498
|
// a) init z-buffer
|
|
1392
1499
|
gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2]);
|
|
1393
|
-
|
|
1500
|
+
|
|
1501
|
+
frameCtx.snapPickLayerParams = [];
|
|
1502
|
+
frameCtx.snapPickLayerParams.push(null); // This recreates previous situation, which relied on snapPickLayerNumber
|
|
1503
|
+
postCullDrawableList.forEach(drawable => {
|
|
1504
|
+
if (!drawable.culled && drawable.visible && drawable.pickable && drawable.drawSnapInit) {
|
|
1505
|
+
drawable.drawSnapInit(frameCtx);
|
|
1506
|
+
}
|
|
1507
|
+
});
|
|
1508
|
+
|
|
1509
|
+
const layerParamsSurface = frameCtx.snapPickLayerParams;
|
|
1394
1510
|
|
|
1395
1511
|
// b) snap-pick
|
|
1396
|
-
|
|
1397
|
-
frameCtx.snapPickLayerParams = layerParamsSnap;
|
|
1512
|
+
frameCtx.snapPickLayerParams = [];
|
|
1398
1513
|
|
|
1399
1514
|
gl.depthMask(false);
|
|
1400
1515
|
gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
|
|
1401
1516
|
|
|
1402
|
-
|
|
1403
|
-
frameCtx.snapMode =
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
}
|
|
1411
|
-
frameCtx.snapMode = snapToVertex ? "vertex" : "edge";
|
|
1517
|
+
const drawSnap = (snapMode) => {
|
|
1518
|
+
frameCtx.snapMode = snapMode;
|
|
1519
|
+
frameCtx.snapPickLayerParams.push(null); // This recreates previous situation, which relied on snapPickLayerNumber
|
|
1520
|
+
postCullDrawableList.forEach(drawable => {
|
|
1521
|
+
if (!drawable.culled && drawable.visible && drawable.pickable && drawable.drawSnap) {
|
|
1522
|
+
drawable.drawSnap(frameCtx);
|
|
1523
|
+
}
|
|
1524
|
+
});
|
|
1525
|
+
};
|
|
1412
1526
|
|
|
1413
|
-
|
|
1527
|
+
if (snapToEdge) {
|
|
1528
|
+
drawSnap("edge");
|
|
1529
|
+
}
|
|
1530
|
+
if (snapToVertex) {
|
|
1531
|
+
drawSnap("vertex");
|
|
1414
1532
|
}
|
|
1415
1533
|
|
|
1416
1534
|
gl.depthMask(true);
|
|
1417
1535
|
|
|
1536
|
+
const layerParamsSnap = frameCtx.snapPickLayerParams;
|
|
1537
|
+
|
|
1418
1538
|
// Read and decode the snapped coordinates
|
|
1539
|
+
const readSnapPickBuffer = (source, arrayType, glType) => {
|
|
1540
|
+
const w = vertexPickBuffer.buffer.width;
|
|
1541
|
+
const h = vertexPickBuffer.buffer.height;
|
|
1542
|
+
const pix = new arrayType(4 * w * h);
|
|
1543
|
+
gl.readBuffer(source);
|
|
1544
|
+
gl.readPixels(0, 0, w, h, gl.RGBA_INTEGER, glType, pix, 0);
|
|
1545
|
+
return pix;
|
|
1546
|
+
};
|
|
1419
1547
|
|
|
1420
|
-
const snapPickResultArray
|
|
1421
|
-
const snapPickNormalResultArray =
|
|
1422
|
-
const snapPickIdResultArray
|
|
1548
|
+
const snapPickResultArray = readSnapPickBuffer(gl.COLOR_ATTACHMENT0, Int32Array, gl.INT);
|
|
1549
|
+
const snapPickNormalResultArray = readSnapPickBuffer(gl.COLOR_ATTACHMENT1, Int32Array, gl.INT);
|
|
1550
|
+
const snapPickIdResultArray = readSnapPickBuffer(gl.COLOR_ATTACHMENT2, Uint32Array, gl.UNSIGNED_INT);
|
|
1423
1551
|
|
|
1424
1552
|
vertexPickBuffer.unbind();
|
|
1425
1553
|
|
|
@@ -1438,195 +1566,76 @@ const Renderer = function (scene, options) {
|
|
|
1438
1566
|
|
|
1439
1567
|
if (pickResultMiddleXY[3] !== 0) {
|
|
1440
1568
|
const pickedLayerParmasSurface = layerParamsSurface[Math.abs(pickResultMiddleXY[3]) % layerParamsSurface.length];
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
pickResultMiddleXY[1] * scale[1] + origin[1],
|
|
1446
|
-
pickResultMiddleXY[2] * scale[2] + origin[2],
|
|
1447
|
-
];
|
|
1448
|
-
worldNormal = math.normalizeVec3([
|
|
1449
|
-
pickNormalResultMiddleXY[0] / math.MAX_INT,
|
|
1450
|
-
pickNormalResultMiddleXY[1] / math.MAX_INT,
|
|
1451
|
-
pickNormalResultMiddleXY[2] / math.MAX_INT,
|
|
1452
|
-
]);
|
|
1453
|
-
|
|
1454
|
-
const pickID =
|
|
1455
|
-
pickPickableResultMiddleXY[0]
|
|
1456
|
-
+ (pickPickableResultMiddleXY[1] << 8)
|
|
1457
|
-
+ (pickPickableResultMiddleXY[2] << 16)
|
|
1458
|
-
+ (pickPickableResultMiddleXY[3] << 24);
|
|
1459
|
-
|
|
1460
|
-
pickable = pickIDs.items[pickID];
|
|
1569
|
+
worldPos = toWorldPos(pickResultMiddleXY, pickedLayerParmasSurface.origin, pickedLayerParmasSurface.coordinateScale);
|
|
1570
|
+
worldNormal = toWorldNormal(pickNormalResultMiddleXY);
|
|
1571
|
+
|
|
1572
|
+
pickable = pickIDs.items[pixelToInt(pickPickableResultMiddleXY)];
|
|
1461
1573
|
}
|
|
1462
1574
|
|
|
1463
1575
|
// result 2) hi-precision snapped (to vertex/edge) world position
|
|
1464
1576
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1577
|
+
const snapPickResult = [ ];
|
|
1467
1578
|
for (let i = 0; i < snapPickResultArray.length; i += 4) {
|
|
1468
|
-
|
|
1579
|
+
const layerNumber = snapPickResultArray[i + 3];
|
|
1580
|
+
if (layerNumber > 0) {
|
|
1469
1581
|
const pixelNumber = Math.floor(i / 4);
|
|
1470
1582
|
const w = vertexPickBuffer.size[0];
|
|
1471
1583
|
const x = pixelNumber % w - Math.floor(w / 2);
|
|
1472
1584
|
const y = Math.floor(pixelNumber / w) - Math.floor(w / 2);
|
|
1473
|
-
const dist = (Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));
|
|
1474
1585
|
snapPickResult.push({
|
|
1475
|
-
x,
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
snapPickResultArray[i + 0],
|
|
1481
|
-
snapPickResultArray[i + 1],
|
|
1482
|
-
snapPickResultArray[i + 2],
|
|
1483
|
-
snapPickResultArray[i + 3],
|
|
1484
|
-
],
|
|
1485
|
-
normal: [
|
|
1486
|
-
snapPickNormalResultArray[i + 0],
|
|
1487
|
-
snapPickNormalResultArray[i + 1],
|
|
1488
|
-
snapPickNormalResultArray[i + 2],
|
|
1489
|
-
snapPickNormalResultArray[i + 3],
|
|
1490
|
-
],
|
|
1491
|
-
id: [
|
|
1492
|
-
snapPickIdResultArray[i + 0],
|
|
1493
|
-
snapPickIdResultArray[i + 1],
|
|
1494
|
-
snapPickIdResultArray[i + 2],
|
|
1495
|
-
snapPickIdResultArray[i + 3],
|
|
1496
|
-
]
|
|
1586
|
+
dist: math.lenVec2([ x, y ]),
|
|
1587
|
+
isVertex: (snapToVertex && snapToEdge) ? (layerNumber > layerParamsSnap.length / 2) : snapToVertex,
|
|
1588
|
+
result: snapPickResultArray.subarray(i, i+4),
|
|
1589
|
+
normal: snapPickNormalResultArray.subarray(i, i+4),
|
|
1590
|
+
id: snapPickIdResultArray.subarray(i, i+4)
|
|
1497
1591
|
});
|
|
1498
1592
|
}
|
|
1499
1593
|
}
|
|
1500
1594
|
|
|
1501
|
-
|
|
1502
|
-
let snappedWorldNormal = null;
|
|
1503
|
-
let snappedPickable = null;
|
|
1504
|
-
let snapType = null;
|
|
1595
|
+
const getPickedEntity = pickable => (pickable && pickable.delegatePickedEntity) ? pickable.delegatePickedEntity() : pickable;
|
|
1505
1596
|
|
|
1506
1597
|
if (snapPickResult.length > 0) {
|
|
1507
|
-
// vertex snap first, then edge snap
|
|
1508
|
-
snapPickResult.
|
|
1509
|
-
|
|
1510
|
-
return a.isVertex ? -1 : 1;
|
|
1511
|
-
} else {
|
|
1512
|
-
return a.dist - b.dist;
|
|
1513
|
-
}
|
|
1514
|
-
});
|
|
1515
|
-
|
|
1516
|
-
snapType = snapPickResult[0].isVertex ? "vertex" : "edge";
|
|
1517
|
-
const snapPick = snapPickResult[0].result;
|
|
1518
|
-
const snapPickNormal = snapPickResult[0].normal;
|
|
1519
|
-
const snapPickId = snapPickResult[0].id;
|
|
1520
|
-
|
|
1598
|
+
// closest vertex snap first, then closest edge snap
|
|
1599
|
+
const res = snapPickResult.reduce((a,b) => ((((a.isVertex-b.isVertex) || (b.dist-a.dist)) > 0) ? a : b));
|
|
1600
|
+
const snapPick = res.result;
|
|
1521
1601
|
const pickedLayerParmas = layerParamsSnap[snapPick[3]];
|
|
1602
|
+
const snappedWorldPos = toWorldPos(snapPick, pickedLayerParmas.origin, pickedLayerParmas.coordinateScale);
|
|
1603
|
+
const snappedCanvasPos = camera.projectWorldPos(snappedWorldPos);
|
|
1604
|
+
|
|
1605
|
+
pickResult.reset();
|
|
1606
|
+
pickResult.snappedToEdge = !res.isVertex;
|
|
1607
|
+
pickResult.snappedToVertex = res.isVertex;
|
|
1608
|
+
pickResult.worldPos = snappedWorldPos;
|
|
1609
|
+
pickResult.worldNormal = toWorldNormal(res.normal);
|
|
1610
|
+
pickResult.entity = getPickedEntity(pickIDs.items[pixelToInt(res.id)]);
|
|
1611
|
+
pickResult.canvasPos = canvasPos || (worldPos && camera.projectWorldPos(worldPos)) || snappedCanvasPos;
|
|
1612
|
+
pickResult.snappedCanvasPos = snappedCanvasPos;
|
|
1613
|
+
return pickResult;
|
|
1614
|
+
|
|
1615
|
+
} else if (worldPos) {
|
|
1616
|
+
|
|
1617
|
+
pickResult.reset();
|
|
1618
|
+
pickResult.snappedToEdge = false;
|
|
1619
|
+
pickResult.snappedToVertex = false;
|
|
1620
|
+
pickResult.worldPos = worldPos;
|
|
1621
|
+
pickResult.worldNormal = worldNormal;
|
|
1622
|
+
pickResult.entity = getPickedEntity(pickable);
|
|
1623
|
+
pickResult.canvasPos = canvasPos || camera.projectWorldPos(worldPos);
|
|
1624
|
+
pickResult.snappedCanvasPos = canvasPos;
|
|
1625
|
+
return pickResult;
|
|
1522
1626
|
|
|
1523
|
-
|
|
1524
|
-
const scale = pickedLayerParmas.coordinateScale;
|
|
1525
|
-
|
|
1526
|
-
snappedWorldNormal = math.normalizeVec3([
|
|
1527
|
-
snapPickNormal[0] / math.MAX_INT,
|
|
1528
|
-
snapPickNormal[1] / math.MAX_INT,
|
|
1529
|
-
snapPickNormal[2] / math.MAX_INT,
|
|
1530
|
-
]);
|
|
1531
|
-
|
|
1532
|
-
snappedWorldPos = [
|
|
1533
|
-
snapPick[0] * scale[0] + origin[0],
|
|
1534
|
-
snapPick[1] * scale[1] + origin[1],
|
|
1535
|
-
snapPick[2] * scale[2] + origin[2],
|
|
1536
|
-
];
|
|
1537
|
-
|
|
1538
|
-
snappedPickable = pickIDs.items[
|
|
1539
|
-
snapPickId[0]
|
|
1540
|
-
+ (snapPickId[1] << 8)
|
|
1541
|
-
+ (snapPickId[2] << 16)
|
|
1542
|
-
+ (snapPickId[3] << 24)
|
|
1543
|
-
];
|
|
1544
|
-
}
|
|
1545
|
-
|
|
1546
|
-
if (null === worldPos && null == snappedWorldPos) { // If neither regular pick or snap pick, return null
|
|
1627
|
+
} else {
|
|
1547
1628
|
return null;
|
|
1548
1629
|
}
|
|
1549
|
-
|
|
1550
|
-
let snappedCanvasPos = null;
|
|
1551
|
-
|
|
1552
|
-
if (null !== snappedWorldPos) {
|
|
1553
|
-
snappedCanvasPos = scene.camera.projectWorldPos(snappedWorldPos);
|
|
1554
|
-
}
|
|
1555
|
-
|
|
1556
|
-
const snappedEntity = (snappedPickable && snappedPickable.delegatePickedEntity) ? snappedPickable.delegatePickedEntity() : snappedPickable;
|
|
1557
|
-
if (!snappedEntity && pickable) {
|
|
1558
|
-
pickable = pickable.delegatePickedEntity ? pickable.delegatePickedEntity() : pickable;
|
|
1559
|
-
}
|
|
1560
|
-
|
|
1561
|
-
pickResult.reset();
|
|
1562
|
-
pickResult.snappedToEdge = (snapType === "edge");
|
|
1563
|
-
pickResult.snappedToVertex = (snapType === "vertex");
|
|
1564
|
-
pickResult.worldPos = snappedWorldPos || worldPos;
|
|
1565
|
-
pickResult.worldNormal = snappedWorldNormal || worldNormal;
|
|
1566
|
-
pickResult.entity = snappedEntity || pickable;
|
|
1567
|
-
pickResult.canvasPos = canvasPos || scene.camera.projectWorldPos(worldPos || snappedWorldPos);
|
|
1568
|
-
pickResult.snappedCanvasPos = snappedCanvasPos || canvasPos;
|
|
1569
|
-
|
|
1570
|
-
return pickResult;
|
|
1571
1630
|
};
|
|
1572
1631
|
})();
|
|
1573
1632
|
|
|
1574
|
-
function unpackDepth(depthZ) {
|
|
1575
|
-
const vec = [depthZ[0] / 256.0, depthZ[1] / 256.0, depthZ[2] / 256.0, depthZ[3] / 256.0];
|
|
1576
|
-
const bitShift = [1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0];
|
|
1577
|
-
return math.dotVec4(vec, bitShift);
|
|
1578
|
-
}
|
|
1579
|
-
|
|
1580
|
-
function gpuPickWorldNormal(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, pickResult) {
|
|
1581
|
-
|
|
1582
|
-
const resolutionScale = scene.canvas.resolutionScale;
|
|
1583
|
-
|
|
1584
|
-
frameCtx.reset();
|
|
1585
|
-
frameCtx.backfaces = true;
|
|
1586
|
-
frameCtx.frontface = true; // "ccw"
|
|
1587
|
-
frameCtx.pickOrigin = pickResult.origin;
|
|
1588
|
-
frameCtx.pickViewMatrix = pickViewMatrix;
|
|
1589
|
-
frameCtx.pickProjMatrix = pickProjMatrix;
|
|
1590
|
-
frameCtx.pickClipPos = [
|
|
1591
|
-
getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
|
|
1592
|
-
getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight),
|
|
1593
|
-
];
|
|
1594
|
-
|
|
1595
|
-
const pickNormalBuffer = renderBufferManager.getRenderBuffer("pick-normal", {size: [3, 3]});
|
|
1596
|
-
|
|
1597
|
-
pickNormalBuffer.bind(gl.RGBA32I);
|
|
1598
|
-
|
|
1599
|
-
gl.viewport(0, 0, pickNormalBuffer.size[0], pickNormalBuffer.size[1]);
|
|
1600
|
-
|
|
1601
|
-
gl.enable(gl.DEPTH_TEST);
|
|
1602
|
-
gl.disable(gl.CULL_FACE);
|
|
1603
|
-
gl.disable(gl.BLEND);
|
|
1604
|
-
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
1605
|
-
gl.clearBufferiv(gl.COLOR, 0, new Int32Array([0, 0, 0, 0]));
|
|
1606
|
-
|
|
1607
|
-
pickable.drawPickNormals(frameCtx); // Draw color-encoded fragment World-space normals
|
|
1608
|
-
|
|
1609
|
-
const pix = pickNormalBuffer.read(1, 1, gl.RGBA_INTEGER, gl.INT, Int32Array, 4);
|
|
1610
|
-
|
|
1611
|
-
pickNormalBuffer.unbind();
|
|
1612
|
-
|
|
1613
|
-
const worldNormal = [
|
|
1614
|
-
pix[0] / math.MAX_INT,
|
|
1615
|
-
pix[1] / math.MAX_INT,
|
|
1616
|
-
pix[2] / math.MAX_INT,
|
|
1617
|
-
];
|
|
1618
|
-
|
|
1619
|
-
math.normalizeVec3(worldNormal);
|
|
1620
|
-
|
|
1621
|
-
pickResult.worldNormal = worldNormal;
|
|
1622
|
-
}
|
|
1623
|
-
|
|
1624
1633
|
/**
|
|
1625
1634
|
* Adds a {@link Marker} for occlusion testing.
|
|
1626
1635
|
* @param marker
|
|
1627
1636
|
*/
|
|
1628
1637
|
this.addMarker = function (marker) {
|
|
1629
|
-
this._occlusionTester = this._occlusionTester || new OcclusionTester(scene
|
|
1638
|
+
this._occlusionTester = this._occlusionTester || new OcclusionTester(scene);
|
|
1630
1639
|
this._occlusionTester.addMarker(marker);
|
|
1631
1640
|
scene.occlusionTestCountdown = 0;
|
|
1632
1641
|
};
|
|
@@ -1657,11 +1666,17 @@ const Renderer = function (scene, options) {
|
|
|
1657
1666
|
|
|
1658
1667
|
updateDrawlist();
|
|
1659
1668
|
|
|
1660
|
-
|
|
1669
|
+
const readPixelBuf = (! OCCLUSION_TEST_MODE) && renderBufferManager.getRenderBuffer("occlusionReadPix");
|
|
1670
|
+
if (readPixelBuf) {
|
|
1671
|
+
readPixelBuf.setSize([gl.drawingBufferWidth, gl.drawingBufferHeight]);
|
|
1672
|
+
readPixelBuf.bind();
|
|
1673
|
+
}
|
|
1661
1674
|
|
|
1662
1675
|
frameCtx.reset();
|
|
1663
1676
|
frameCtx.backfaces = true;
|
|
1664
1677
|
frameCtx.frontface = true; // "ccw"
|
|
1678
|
+
frameCtx.viewParams = getSceneCameraViewParams();
|
|
1679
|
+
frameCtx.nearPlaneHeight = getNearPlaneHeight(scene.camera, gl.drawingBufferHeight);
|
|
1665
1680
|
|
|
1666
1681
|
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
1667
1682
|
gl.clearColor(0, 0, 0, 0);
|
|
@@ -1670,121 +1685,143 @@ const Renderer = function (scene, options) {
|
|
|
1670
1685
|
gl.disable(gl.BLEND);
|
|
1671
1686
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1672
1687
|
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
const drawable = postCullDrawableList[i];
|
|
1677
|
-
|
|
1678
|
-
if (!drawable.drawOcclusion || drawable.culled === true || drawable.visible === false || drawable.pickable === false) { // TODO: Option to exclude transparent?
|
|
1679
|
-
continue;
|
|
1688
|
+
postCullDrawableList.forEach(drawable => {
|
|
1689
|
+
if (!drawable.culled && drawable.visible && drawable.pickable && drawable.drawOcclusion) { // TODO: Option to exclude transparent?
|
|
1690
|
+
drawable.drawOcclusion(frameCtx);
|
|
1680
1691
|
}
|
|
1692
|
+
});
|
|
1681
1693
|
|
|
1682
|
-
|
|
1683
|
-
}
|
|
1684
|
-
|
|
1685
|
-
this._occlusionTester.drawMarkers(frameCtx);
|
|
1686
|
-
this._occlusionTester.doOcclusionTest(); // Updates Marker "visible" properties
|
|
1687
|
-
this._occlusionTester.unbindRenderBuf();
|
|
1688
|
-
}
|
|
1689
|
-
};
|
|
1694
|
+
this._occlusionTester.drawMarkers();
|
|
1690
1695
|
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
* @private
|
|
1698
|
-
*/
|
|
1699
|
-
this.readPixels = function (pixels, colors, len, opaqueOnly) {
|
|
1700
|
-
const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
|
|
1701
|
-
snapshotBuffer.bind();
|
|
1702
|
-
snapshotBuffer.clear();
|
|
1703
|
-
this.render({force: true, opaqueOnly: opaqueOnly});
|
|
1704
|
-
let color;
|
|
1705
|
-
let i;
|
|
1706
|
-
let j;
|
|
1707
|
-
let k;
|
|
1708
|
-
for (i = 0; i < len; i++) {
|
|
1709
|
-
j = i * 2;
|
|
1710
|
-
k = i * 4;
|
|
1711
|
-
color = snapshotBuffer.read(pixels[j], pixels[j + 1]);
|
|
1712
|
-
colors[k] = color[0];
|
|
1713
|
-
colors[k + 1] = color[1];
|
|
1714
|
-
colors[k + 2] = color[2];
|
|
1715
|
-
colors[k + 3] = color[3];
|
|
1716
|
-
}
|
|
1717
|
-
snapshotBuffer.unbind();
|
|
1718
|
-
imageDirty = true;
|
|
1719
|
-
};
|
|
1720
|
-
|
|
1721
|
-
/**
|
|
1722
|
-
* Enter snapshot mode.
|
|
1723
|
-
*
|
|
1724
|
-
* Switches rendering to a hidden snapshot canvas.
|
|
1725
|
-
*
|
|
1726
|
-
* Exit snapshot mode using endSnapshot().
|
|
1727
|
-
*/
|
|
1728
|
-
this.beginSnapshot = function (params = {}) {
|
|
1729
|
-
const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
|
|
1730
|
-
if (params.width && params.height) {
|
|
1731
|
-
snapshotBuffer.setSize([params.width, params.height]);
|
|
1732
|
-
}
|
|
1733
|
-
snapshotBuffer.bind();
|
|
1734
|
-
snapshotBuffer.clear();
|
|
1735
|
-
snapshotBound = true;
|
|
1736
|
-
};
|
|
1737
|
-
|
|
1738
|
-
/**
|
|
1739
|
-
* When in snapshot mode, renders a frame of the current Scene state to the snapshot canvas.
|
|
1740
|
-
*/
|
|
1741
|
-
this.renderSnapshot = function () {
|
|
1742
|
-
if (!snapshotBound) {
|
|
1743
|
-
return;
|
|
1696
|
+
if (readPixelBuf) {
|
|
1697
|
+
const resolutionScale = scene.canvas.resolutionScale;
|
|
1698
|
+
this._occlusionTester.doOcclusionTest( // Updates Marker "visible" properties
|
|
1699
|
+
(x, y) => readPixelBuf.read(Math.round(resolutionScale * x), Math.round(resolutionScale * y)));
|
|
1700
|
+
readPixelBuf.unbind();
|
|
1701
|
+
}
|
|
1744
1702
|
}
|
|
1745
|
-
const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
|
|
1746
|
-
snapshotBuffer.clear();
|
|
1747
|
-
this.render({force: true, opaqueOnly: false});
|
|
1748
|
-
imageDirty = true;
|
|
1749
1703
|
};
|
|
1750
1704
|
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1705
|
+
this.snapshot = (() => {
|
|
1706
|
+
let snapshotBound = false;
|
|
1707
|
+
const snapshotBuffer = new RenderBuffer(gl);
|
|
1708
|
+
let snapshotCanvas = null;
|
|
1709
|
+
|
|
1710
|
+
return {
|
|
1711
|
+
/**
|
|
1712
|
+
* Read pixels from the renderer's current output. Performs a force-render first.
|
|
1713
|
+
* @param pixels
|
|
1714
|
+
* @param colors
|
|
1715
|
+
* @param len
|
|
1716
|
+
* @private
|
|
1717
|
+
*/
|
|
1718
|
+
readPixels: (pixels, colors, len) => {
|
|
1719
|
+
snapshotBuffer.bind();
|
|
1720
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1721
|
+
imageDirty = true;
|
|
1722
|
+
this.render();
|
|
1723
|
+
for (let i = 0; i < len; i++) {
|
|
1724
|
+
const j = i * 2;
|
|
1725
|
+
const k = i * 4;
|
|
1726
|
+
const color = snapshotBuffer.read(pixels[j], pixels[j + 1]);
|
|
1727
|
+
colors[k] = color[0];
|
|
1728
|
+
colors[k + 1] = color[1];
|
|
1729
|
+
colors[k + 2] = color[2];
|
|
1730
|
+
colors[k + 3] = color[3];
|
|
1731
|
+
}
|
|
1732
|
+
snapshotBuffer.unbind();
|
|
1733
|
+
imageDirty = true;
|
|
1734
|
+
},
|
|
1735
|
+
|
|
1736
|
+
/**
|
|
1737
|
+
* Enter snapshot mode.
|
|
1738
|
+
*
|
|
1739
|
+
* Switches rendering to a hidden snapshot canvas.
|
|
1740
|
+
*
|
|
1741
|
+
* Exit snapshot mode using endSnapshot().
|
|
1742
|
+
*/
|
|
1743
|
+
beginSnapshot: () => {
|
|
1744
|
+
snapshotBuffer.setSize([gl.drawingBufferWidth, gl.drawingBufferHeight]);
|
|
1745
|
+
snapshotBuffer.bind();
|
|
1746
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1747
|
+
snapshotBound = true;
|
|
1748
|
+
},
|
|
1749
|
+
|
|
1750
|
+
/**
|
|
1751
|
+
* Returns an HTMLCanvas containing an image of the snapshot canvas.
|
|
1752
|
+
*
|
|
1753
|
+
* - The HTMLCanvas has a CanvasRenderingContext2D.
|
|
1754
|
+
* - Expects the caller to draw more things on the HTMLCanvas (annotations etc).
|
|
1755
|
+
*
|
|
1756
|
+
* @returns {HTMLCanvasElement}
|
|
1757
|
+
*/
|
|
1758
|
+
renderSnapshotToCanvas: () => {
|
|
1759
|
+
const width = snapshotBuffer.buffer.width;
|
|
1760
|
+
const height = snapshotBuffer.buffer.height;
|
|
1761
|
+
|
|
1762
|
+
if ((! snapshotCanvas) || (snapshotCanvas.width !== width) || (snapshotCanvas.height !== height)) {
|
|
1763
|
+
snapshotCanvas = (function() {
|
|
1764
|
+
const canvas = document.createElement('canvas');
|
|
1765
|
+
const context = canvas.getContext('2d');
|
|
1766
|
+
canvas.width = width;
|
|
1767
|
+
canvas.height = height;
|
|
1768
|
+
const pixelData = new Uint8Array(width * height * 4);
|
|
1769
|
+
const imageData = context.createImageData(width, height);
|
|
1770
|
+
|
|
1771
|
+
return {
|
|
1772
|
+
width: width,
|
|
1773
|
+
height: height,
|
|
1774
|
+
getUpdatedCanvas: () => {
|
|
1775
|
+
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixelData);
|
|
1776
|
+
|
|
1777
|
+
// flip verically
|
|
1778
|
+
const halfHeight = Math.floor(height / 2);
|
|
1779
|
+
const bytesPerRow = width * 4;
|
|
1780
|
+
const temp = new Uint8Array(bytesPerRow);
|
|
1781
|
+
for (let y = 0; y < halfHeight; ++y) {
|
|
1782
|
+
const topOffset = y * bytesPerRow;
|
|
1783
|
+
const bottomOffset = (height - y - 1) * bytesPerRow;
|
|
1784
|
+
temp.set(pixelData.subarray(topOffset, topOffset + bytesPerRow));
|
|
1785
|
+
pixelData.copyWithin(topOffset, bottomOffset, bottomOffset + bytesPerRow);
|
|
1786
|
+
pixelData.set(temp, bottomOffset);
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
imageData.data.set(pixelData);
|
|
1790
|
+
|
|
1791
|
+
context.resetTransform(); // Prevents strange scale-accumulation effect with html2canvas
|
|
1792
|
+
context.putImageData(imageData, 0, 0);
|
|
1793
|
+
|
|
1794
|
+
return canvas;
|
|
1795
|
+
}
|
|
1796
|
+
};
|
|
1797
|
+
})();
|
|
1798
|
+
}
|
|
1761
1799
|
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
* @returns {HTMLCanvasElement}
|
|
1769
|
-
*/
|
|
1770
|
-
this.readSnapshotAsCanvas = function () {
|
|
1771
|
-
const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
|
|
1772
|
-
return snapshotBuffer.readImageAsCanvas();
|
|
1773
|
-
};
|
|
1800
|
+
if (snapshotBound) {
|
|
1801
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
1802
|
+
imageDirty = true;
|
|
1803
|
+
this.render();
|
|
1804
|
+
imageDirty = true;
|
|
1805
|
+
}
|
|
1774
1806
|
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1807
|
+
return snapshotCanvas.getUpdatedCanvas();
|
|
1808
|
+
},
|
|
1809
|
+
|
|
1810
|
+
/**
|
|
1811
|
+
* Exists snapshot mode.
|
|
1812
|
+
*
|
|
1813
|
+
* Switches rendering back to the main canvas.
|
|
1814
|
+
*/
|
|
1815
|
+
endSnapshot: () => {
|
|
1816
|
+
if (snapshotBound) {
|
|
1817
|
+
snapshotBuffer.unbind();
|
|
1818
|
+
snapshotBound = false;
|
|
1819
|
+
}
|
|
1820
|
+
imageDirty = true;
|
|
1821
|
+
this.render();
|
|
1822
|
+
}
|
|
1823
|
+
};
|
|
1824
|
+
})();
|
|
1788
1825
|
|
|
1789
1826
|
/**
|
|
1790
1827
|
* Destroys this renderer.
|