@xeokit/xeokit-sdk 2.6.91-renderers-refactor-v9 → 2.6.92

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