@xeokit/xeokit-sdk 2.6.85-renderers-refactor-v2 → 2.6.86

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 +44618 -13007
  2. package/dist/xeokit-sdk.es.js +44617 -13008
  3. package/dist/xeokit-sdk.es5.js +3488 -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/lib/html/MenuEvent.js +2 -2
  9. package/src/viewer/Viewer.js +103 -55
  10. package/src/viewer/scene/canvas/Canvas.js +43 -3
  11. package/src/viewer/scene/geometry/ReadableGeometry.js +25 -0
  12. package/src/viewer/scene/lights/CubeTexture.js +13 -0
  13. package/src/viewer/scene/lights/DirLight.js +1 -2
  14. package/src/viewer/scene/lights/PointLight.js +1 -2
  15. package/src/viewer/scene/materials/Texture.js +9 -0
  16. package/src/viewer/scene/math/rtcCoords.js +38 -1
  17. package/src/viewer/scene/mesh/Mesh.js +212 -454
  18. package/src/viewer/scene/mesh/draw/DrawRenderer.js +998 -0
  19. package/src/viewer/scene/mesh/draw/DrawShaderSource.js +1504 -305
  20. package/src/viewer/scene/mesh/emphasis/EmphasisEdgesRenderer.js +259 -0
  21. package/src/viewer/scene/mesh/emphasis/EmphasisEdgesShaderSource.js +160 -0
  22. package/src/viewer/scene/mesh/emphasis/EmphasisFillRenderer.js +286 -0
  23. package/src/viewer/scene/mesh/emphasis/EmphasisFillShaderSource.js +263 -0
  24. package/src/viewer/scene/mesh/occlusion/OcclusionRenderer.js +221 -0
  25. package/src/viewer/scene/mesh/occlusion/OcclusionShaderSource.js +158 -9
  26. package/src/viewer/scene/mesh/pick/PickMeshRenderer.js +223 -0
  27. package/src/viewer/scene/mesh/pick/PickMeshShaderSource.js +151 -21
  28. package/src/viewer/scene/mesh/pick/PickTriangleRenderer.js +200 -0
  29. package/src/viewer/scene/mesh/pick/PickTriangleShaderSource.js +124 -12
  30. package/src/viewer/scene/mesh/shadow/ShadowRenderer.js +214 -0
  31. package/src/viewer/scene/mesh/shadow/ShadowShaderSource.js +97 -22
  32. package/src/viewer/scene/model/RENDER_PASSES.js +34 -0
  33. package/src/viewer/scene/model/SceneModel.js +861 -245
  34. package/src/viewer/scene/model/SceneModelEntity.js +4 -4
  35. package/src/viewer/scene/model/SceneModelMesh.js +3 -3
  36. package/src/viewer/scene/model/dtx/BindableDataTexture.js +31 -0
  37. package/src/viewer/scene/model/dtx/lines/DTXLinesBuffer.js +27 -0
  38. package/src/viewer/scene/model/dtx/lines/DTXLinesLayer.js +897 -0
  39. package/src/viewer/scene/model/dtx/lines/DTXLinesState.js +46 -0
  40. package/src/viewer/scene/model/dtx/lines/DTXLinesTextureFactory.js +411 -0
  41. package/src/viewer/scene/model/dtx/lines/dataTextureRamStats.js +49 -0
  42. package/src/viewer/scene/model/dtx/lines/rebucketPositions.js +208 -0
  43. package/src/viewer/scene/model/dtx/lines/renderers/DTXLinesColorRenderer.js +389 -0
  44. package/src/viewer/scene/model/dtx/lines/renderers/DTXLinesRenderers.js +65 -0
  45. package/src/viewer/scene/model/dtx/triangles/DTXTrianglesLayer.js +1399 -0
  46. package/src/viewer/scene/model/dtx/triangles/lib/DTXTrianglesBuffer.js +46 -0
  47. package/src/viewer/scene/model/dtx/triangles/lib/DTXTrianglesState.js +250 -0
  48. package/src/viewer/scene/model/dtx/triangles/lib/DTXTrianglesTextureFactory.js +518 -0
  49. package/src/viewer/scene/model/dtx/triangles/lib/dataTextureRamStats.js +54 -0
  50. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesColorRenderer.js +639 -0
  51. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesDepthRenderer.js +464 -0
  52. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesEdgesColorRenderer.js +423 -0
  53. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesEdgesRenderer.js +431 -0
  54. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesNormalsRenderer.js +345 -0
  55. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesOcclusionRenderer.js +436 -0
  56. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesPickDepthRenderer.js +466 -0
  57. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesPickMeshRenderer.js +437 -0
  58. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesPickNormalsFlatRenderer.js +460 -0
  59. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesPickNormalsRenderer.js +437 -0
  60. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesRenderers.js +307 -0
  61. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesSilhouetteRenderer.js +472 -0
  62. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesSnapInitRenderer.js +474 -0
  63. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesSnapRenderer.js +435 -0
  64. package/src/viewer/scene/model/vbo/ScratchMemory.js +63 -0
  65. package/src/viewer/scene/model/vbo/VBORenderer.js +664 -0
  66. package/src/viewer/scene/model/vbo/batching/lines/VBOBatchingLinesLayer.js +704 -0
  67. package/src/viewer/scene/model/vbo/batching/lines/lib/VBOBatchingLinesBuffer.js +19 -0
  68. package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLineSnapInitRenderer.js +318 -0
  69. package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLinesColorRenderer.js +114 -0
  70. package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLinesRenderers.js +99 -0
  71. package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLinesSilhouetteRenderer.js +124 -0
  72. package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLinesSnapInitRenderer.js +313 -0
  73. package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLinesSnapRenderer.js +311 -0
  74. package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOSceneModelLineBatchingRenderer.js +24 -0
  75. package/src/viewer/scene/model/vbo/batching/points/VBOBatchingPointsLayer.js +688 -0
  76. package/src/viewer/scene/model/vbo/batching/points/VBOBatchingPointsRenderer.js +24 -0
  77. package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsColorRenderer.js +168 -0
  78. package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsOcclusionRenderer.js +136 -0
  79. package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsPickDepthRenderer.js +156 -0
  80. package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsPickMeshRenderer.js +148 -0
  81. package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsRenderers.js +144 -0
  82. package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsShadowRenderer.js +107 -0
  83. package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsSilhouetteRenderer.js +146 -0
  84. package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsSnapInitRenderer.js +315 -0
  85. package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsSnapRenderer.js +305 -0
  86. package/src/viewer/scene/model/vbo/batching/triangles/VBOBatchingTrianglesBuffer.js +24 -0
  87. package/src/viewer/scene/model/vbo/batching/triangles/VBOBatchingTrianglesLayer.js +1346 -0
  88. package/src/viewer/scene/model/vbo/batching/triangles/renderers/EdgesColorRenderer.js +131 -0
  89. package/src/viewer/scene/model/vbo/batching/triangles/renderers/EdgesEmphasisRenderer.js +135 -0
  90. package/src/viewer/scene/model/vbo/batching/triangles/renderers/EdgesRenderer.js +12 -0
  91. package/src/viewer/scene/model/vbo/batching/triangles/renderers/Renderers.js +403 -0
  92. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesBatchingRenderer.js +35 -0
  93. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesColorRenderer.js +252 -0
  94. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesColorTextureRenderer.js +294 -0
  95. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesDepthRenderer.js +115 -0
  96. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesFlatColorRenderer.js +246 -0
  97. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesNormalsRenderer.js +139 -0
  98. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesOcclusionRenderer.js +125 -0
  99. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesPBRRenderer.js +561 -0
  100. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesPickDepthRenderer.js +144 -0
  101. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesPickMeshRenderer.js +130 -0
  102. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesPickNormalsFlatRenderer.js +121 -0
  103. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesPickNormalsRenderer.js +131 -0
  104. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesShadowRenderer.js +107 -0
  105. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesSilhouetteRenderer.js +144 -0
  106. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesSnapInitRenderer.js +313 -0
  107. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesSnapRenderer.js +312 -0
  108. package/src/viewer/scene/model/vbo/float16.js +760 -0
  109. package/src/viewer/scene/model/vbo/instancing/lines/VBOInstancingLinesLayer.js +711 -0
  110. package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesColorRenderer.js +148 -0
  111. package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesRenderer.js +26 -0
  112. package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesRenderers.js +139 -0
  113. package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesSilhouetteRenderer.js +127 -0
  114. package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesSnapInitRenderer.js +308 -0
  115. package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesSnapRenderer.js +299 -0
  116. package/src/viewer/scene/model/vbo/instancing/points/VBOInstancingPointsLayer.js +733 -0
  117. package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsColorRenderer.js +174 -0
  118. package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsDepthRenderer.js +156 -0
  119. package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsOcclusionRenderer.js +149 -0
  120. package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsPickDepthRenderer.js +170 -0
  121. package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsPickMeshRenderer.js +152 -0
  122. package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsRenderer.js +26 -0
  123. package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsRenderers.js +174 -0
  124. package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsShadowRenderer.js +119 -0
  125. package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsSilhouetteRenderer.js +154 -0
  126. package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsSnapInitRenderer.js +307 -0
  127. package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsSnapRenderer.js +293 -0
  128. package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingTrianglesRenderer.js +150 -0
  129. package/src/viewer/scene/model/vbo/instancing/triangles/VBOInstancingTrianglesLayer.js +1289 -0
  130. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/EdgesColorRenderer.js +135 -0
  131. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/EdgesEmphasisRenderer.js +137 -0
  132. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/EdgesRenderer.js +12 -0
  133. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/Renderers.js +403 -0
  134. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesColorRenderer.js +267 -0
  135. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesColorTextureRenderer.js +299 -0
  136. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesDepthRenderer.js +126 -0
  137. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesFlatColorRenderer.js +255 -0
  138. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesFlatNormalsRenderer.js +130 -0
  139. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesInstancingRenderer.js +32 -0
  140. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesNormalsRenderer.js +138 -0
  141. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesOcclusionRenderer.js +128 -0
  142. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesPBRRenderer.js +561 -0
  143. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesPickDepthRenderer.js +149 -0
  144. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesPickMeshRenderer.js +136 -0
  145. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesPickNormalsFlatRenderer.js +130 -0
  146. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesPickNormalsRenderer.js +145 -0
  147. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesShadowRenderer.js +113 -0
  148. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesSilhouetteRenderer.js +148 -0
  149. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesSnapInitRenderer.js +319 -0
  150. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesSnapRenderer.js +310 -0
  151. package/src/viewer/scene/scene/Scene.js +38 -21
  152. package/src/viewer/scene/webgl/ArrayBuf.js +20 -5
  153. package/src/viewer/scene/webgl/Attribute.js +23 -0
  154. package/src/viewer/scene/webgl/FrameContext.js +86 -14
  155. package/src/viewer/scene/webgl/Program.js +181 -0
  156. package/src/viewer/scene/webgl/RenderBuffer.js +262 -62
  157. package/src/viewer/scene/webgl/RenderBufferManager.js +34 -0
  158. package/src/viewer/scene/webgl/Renderer.js +843 -880
  159. package/src/viewer/scene/webgl/Sampler.js +18 -0
  160. package/src/viewer/scene/webgl/Shader.js +49 -0
  161. package/src/viewer/scene/webgl/occlusion/OcclusionLayer.js +132 -60
  162. package/src/viewer/scene/webgl/occlusion/OcclusionTester.js +328 -167
  163. package/src/viewer/scene/webgl/sao/SAODepthLimitedBlurRenderer.js +324 -0
  164. package/src/viewer/scene/webgl/sao/SAOOcclusionRenderer.js +384 -0
  165. package/src/viewer/utils/os.js +9 -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 -786
  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 -28
  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
  const byDist = normalFillTransparentBin.map(d => ({ drawable: d, distSq: math.distVec3(d.origin || vec3_0, eye) }));
971
728
  byDist.sort((a, b) => b.distSq - a.distSq);
972
729
  for (i = 0; i < normalFillTransparentBinLen; i++) {
@@ -1143,29 +900,11 @@ const Renderer = function (scene, options) {
1143
900
  for (let ii = 0; ii < numVertexAttribs; ii++) {
1144
901
  gl.disableVertexAttribArray(ii);
1145
902
  }
1146
- }
1147
-
1148
- const resetPickFrameCtx = (canvasPos, clipTransformDiv, camera, eye, projMatrix, viewMatrix, frameCtx) => {
1149
- frameCtx.reset();
1150
- frameCtx.backfaces = true;
1151
- frameCtx.frontface = true; // "ccw"
1152
-
1153
- frameCtx.viewParams.eye = eye;
1154
- frameCtx.viewParams.projMatrix = projMatrix;
1155
- frameCtx.viewParams.viewMatrix = viewMatrix;
1156
- frameCtx.nearPlaneHeight = getNearPlaneHeight(camera, gl.drawingBufferHeight);
1157
-
1158
- const resolutionScale = scene.canvas.resolutionScale;
1159
- frameCtx.pickClipPos = [
1160
- canvasPos ? ( 2 * canvasPos[0] * resolutionScale / gl.drawingBufferWidth - 1) : 0,
1161
- canvasPos ? (1 - 2 * canvasPos[1] * resolutionScale / gl.drawingBufferHeight) : 0
1162
- ];
1163
903
 
1164
- frameCtx.pickClipPosInv = [
1165
- gl.drawingBufferWidth / clipTransformDiv,
1166
- gl.drawingBufferHeight / clipTransformDiv
1167
- ];
1168
- };
904
+ if (unbindOutputFrameBuffer) {
905
+ unbindOutputFrameBuffer(params.pass);
906
+ }
907
+ }
1169
908
 
1170
909
  /**
1171
910
  * Picks an Entity.
@@ -1174,18 +913,11 @@ const Renderer = function (scene, options) {
1174
913
  this.pick = (function () {
1175
914
 
1176
915
  const tempVec3a = math.vec3();
1177
- const tempVec3b = math.vec3();
1178
- const tempVec4a = math.vec4();
1179
- const tempVec4b = math.vec4();
1180
- const tempVec4c = math.vec4();
1181
- const tempVec4d = math.vec4();
1182
- const tempVec4e = math.vec4();
1183
916
  const tempMat4a = math.mat4();
1184
917
  const tempMat4b = math.mat4();
1185
- const tempMat4c = math.mat4();
1186
- const tempMat4d = math.mat4();
1187
918
 
1188
- const upVec = math.vec3([0, 1, 0]);
919
+ const randomVec3 = math.vec3();
920
+ const up = math.vec3([0, 1, 0]);
1189
921
  const _pickResult = new PickResult();
1190
922
 
1191
923
  const nearAndFar = math.vec2();
@@ -1197,22 +929,16 @@ const Renderer = function (scene, options) {
1197
929
  const worldSurfacePos = math.vec3();
1198
930
  const worldSurfaceNormal = math.vec3();
1199
931
 
1200
- const pickBuffer = new RenderBuffer(gl);
1201
- pickBuffer.setSize([1, 1]);
1202
-
1203
- const pickNormalBuffer = new RenderBuffer(gl, [gl.RGBA32I]);
1204
- pickNormalBuffer.setSize([3, 3]);
1205
-
1206
932
  return function (params, pickResult = _pickResult) {
1207
933
 
1208
934
  pickResult.reset();
1209
935
 
1210
936
  updateDrawlist();
1211
937
 
938
+ let look;
1212
939
  let pickViewMatrix = null;
1213
940
  let pickProjMatrix = null;
1214
941
  let projection = null;
1215
- const camera = scene.camera;
1216
942
 
1217
943
  pickResult.pickSurface = params.pickSurface;
1218
944
 
@@ -1221,12 +947,12 @@ const Renderer = function (scene, options) {
1221
947
  canvasPos[0] = params.canvasPos[0];
1222
948
  canvasPos[1] = params.canvasPos[1];
1223
949
 
1224
- pickViewMatrix = camera.viewMatrix;
1225
- pickProjMatrix = camera.projMatrix;
1226
- projection = camera.projection;
950
+ pickViewMatrix = scene.camera.viewMatrix;
951
+ pickProjMatrix = scene.camera.projMatrix;
952
+ projection = scene.camera.projection;
1227
953
 
1228
- nearAndFar[0] = camera.project.near;
1229
- nearAndFar[1] = camera.project.far;
954
+ nearAndFar[0] = scene.camera.project.near;
955
+ nearAndFar[1] = scene.camera.project.far;
1230
956
 
1231
957
  pickResult.canvasPos = params.canvasPos;
1232
958
 
@@ -1238,37 +964,33 @@ const Renderer = function (scene, options) {
1238
964
  if (params.matrix) {
1239
965
 
1240
966
  pickViewMatrix = params.matrix;
1241
- pickProjMatrix = camera.projMatrix;
1242
- projection = camera.projection;
967
+ pickProjMatrix = scene.camera.projMatrix;
968
+ projection = scene.camera.projection;
1243
969
 
1244
- nearAndFar[0] = camera.project.near;
1245
- nearAndFar[1] = camera.project.far;
970
+ nearAndFar[0] = scene.camera.project.near;
971
+ nearAndFar[1] = scene.camera.project.far;
1246
972
 
1247
973
  } else {
1248
974
 
1249
975
  worldRayOrigin.set(params.origin || [0, 0, 0]);
1250
976
  worldRayDir.set(params.direction || [0, 0, 1]);
1251
977
 
1252
- const look = math.addVec3(worldRayOrigin, worldRayDir, tempVec3a);
1253
- const up = tempVec3b;
978
+ look = math.addVec3(worldRayOrigin, worldRayDir, tempVec3a);
1254
979
 
1255
- if (Math.abs(math.dotVec3(worldRayDir, upVec)) > (1 - 1e-6)) { // worldRayDir aligned with Y axis
1256
- up[0] = 0;
1257
- up[1] = 0;
1258
- up[2] = Math.sign(worldRayDir[1]);
1259
- } else {
1260
- math.cross3Vec3(worldRayDir, upVec, up);
1261
- math.cross3Vec3(up, worldRayDir, up);
1262
- math.normalizeVec3(up, up);
1263
- }
980
+ randomVec3[0] = Math.random();
981
+ randomVec3[1] = Math.random();
982
+ randomVec3[2] = Math.random();
983
+
984
+ math.normalizeVec3(randomVec3);
985
+ math.cross3Vec3(worldRayDir, randomVec3, up);
1264
986
 
1265
987
  pickViewMatrix = math.lookAtMat4v(worldRayOrigin, look, up, tempMat4b);
1266
- // pickProjMatrix = camera.projMatrix;
1267
- pickProjMatrix = camera.ortho.matrix;
988
+ // pickProjMatrix = scene.camera.projMatrix;
989
+ pickProjMatrix = scene.camera.ortho.matrix;
1268
990
  projection = "ortho";
1269
991
 
1270
- nearAndFar[0] = camera.ortho.near;
1271
- nearAndFar[1] = camera.ortho.far;
992
+ nearAndFar[0] = scene.camera.ortho.near;
993
+ nearAndFar[1] = scene.camera.ortho.far;
1272
994
 
1273
995
  pickResult.origin = worldRayOrigin;
1274
996
  pickResult.direction = worldRayDir;
@@ -1278,42 +1000,23 @@ const Renderer = function (scene, options) {
1278
1000
  canvasPos[1] = canvas.clientHeight * 0.5;
1279
1001
  }
1280
1002
 
1281
- pickBuffer.bind();
1282
-
1283
- const resetFrameCtx = (clipTransformDiv) => resetPickFrameCtx(canvasPos, clipTransformDiv, camera, pickResult.origin || camera.eye, pickProjMatrix || camera.projMatrix, pickViewMatrix || camera.viewMatrix, frameCtx);
1284
-
1285
- // gpuPickPickable
1286
- resetFrameCtx(1);
1287
- frameCtx.pickInvisible = !!params.pickInvisible;
1288
-
1289
- gl.viewport(0, 0, 1, 1);
1290
- gl.depthMask(true);
1291
- gl.enable(gl.DEPTH_TEST);
1292
- gl.disable(gl.CULL_FACE);
1293
- gl.disable(gl.BLEND);
1294
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
1295
-
1296
- const includeEntityIds = params.includeEntityIds;
1297
- const excludeEntityIds = params.excludeEntityIds;
1298
-
1299
- const renderDrawables = function(drawables) {
1300
- drawables.forEach(drawable => {
1301
- if (!drawable.culled && drawable.visible && drawable.pickable && drawable.drawPickMesh // TODO: push this logic into drawable
1302
- && ((! includeEntityIds) || includeEntityIds[drawable.id])
1303
- && ((! excludeEntityIds) || (! excludeEntityIds[drawable.id]))) {
1304
- drawable.drawPickMesh(frameCtx);
1003
+ for (let type in drawableTypeInfo) {
1004
+ if (drawableTypeInfo.hasOwnProperty(type)) {
1005
+ const drawableList = drawableTypeInfo[type].drawableList;
1006
+ for (let i = 0, len = drawableList.length; i < len; i++) {
1007
+ const drawable = drawableList[i];
1008
+ if (drawable.setPickMatrices) { // Eg. SceneModel, which needs pre-loading into texture
1009
+ drawable.setPickMatrices(pickViewMatrix, pickProjMatrix);
1010
+ }
1305
1011
  }
1306
- });
1307
- };
1308
-
1309
- renderDrawables(postCullDrawableList);
1310
- if (uiDrawableList.length > 0) {
1311
- gl.clear(gl.DEPTH_BUFFER_BIT);
1312
- renderDrawables(uiDrawableList);
1012
+ }
1313
1013
  }
1314
1014
 
1315
- const pickID = pixelToInt(pickBuffer.read(0, 0));
1316
- const pickable = (pickID >= 0) && pickIDs.items[pickID];
1015
+ const pickBuffer = renderBufferManager.getRenderBuffer("pick", {size: [1, 1]});
1016
+
1017
+ pickBuffer.bind();
1018
+
1019
+ const pickable = gpuPickPickable(pickBuffer, canvasPos, pickViewMatrix, pickProjMatrix, params, pickResult);
1317
1020
 
1318
1021
  if (!pickable) {
1319
1022
  pickBuffer.unbind();
@@ -1333,21 +1036,7 @@ const Renderer = function (scene, options) {
1333
1036
 
1334
1037
  if (pickable.canPickTriangle && pickable.canPickTriangle()) {
1335
1038
 
1336
- if (pickable.drawPickTriangles) {
1337
- resetFrameCtx(1);
1338
- // frameCtx.pickInvisible = !!params.pickInvisible;
1339
-
1340
- gl.viewport(0, 0, 1, 1);
1341
- gl.clearColor(0, 0, 0, 0);
1342
- gl.enable(gl.DEPTH_TEST);
1343
- gl.disable(gl.CULL_FACE);
1344
- gl.disable(gl.BLEND);
1345
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
1346
-
1347
- pickable.drawPickTriangles(frameCtx);
1348
-
1349
- pickResult.primIndex = 3 * pixelToInt(pickBuffer.read(0, 0)); // Convert from triangle number to first vertex in indices
1350
- }
1039
+ gpuPickTriangle(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, pickResult);
1351
1040
 
1352
1041
  pickable.pickTriangleSurface(pickViewMatrix, pickProjMatrix, projection, pickResult);
1353
1042
 
@@ -1357,84 +1046,255 @@ const Renderer = function (scene, options) {
1357
1046
 
1358
1047
  if (pickable.canPickWorldPos && pickable.canPickWorldPos()) {
1359
1048
 
1360
- // pickWorldPos
1361
- resetFrameCtx(1);
1362
- frameCtx.viewParams.near = nearAndFar[0];
1363
- frameCtx.viewParams.far = nearAndFar[1];
1049
+ gpuPickWorldPos(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, nearAndFar, pickResult);
1364
1050
 
1365
- gl.viewport(0, 0, 1, 1);
1051
+ if (params.pickSurfaceNormal !== false) {
1052
+ gpuPickWorldNormal(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, pickResult);
1053
+ }
1366
1054
 
1367
- gl.clearColor(0, 0, 0, 0);
1368
- gl.depthMask(true);
1369
- gl.enable(gl.DEPTH_TEST);
1370
- gl.disable(gl.CULL_FACE);
1371
- gl.disable(gl.BLEND);
1372
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
1055
+ pickResult.pickSurfacePrecision = false;
1056
+ }
1057
+ }
1058
+ }
1059
+ pickBuffer.unbind();
1060
+ pickResult.entity = pickedEntity;
1061
+ return pickResult;
1062
+ };
1063
+ })();
1064
+
1065
+ function gpuPickPickable(pickBuffer, canvasPos, pickViewMatrix, pickProjMatrix, params, pickResult) {
1066
+
1067
+ const resolutionScale = scene.canvas.resolutionScale;
1068
+
1069
+ frameCtx.reset();
1070
+ frameCtx.backfaces = true;
1071
+ frameCtx.frontface = true; // "ccw"
1072
+ frameCtx.pickOrigin = pickResult.origin;
1073
+ frameCtx.pickViewMatrix = pickViewMatrix;
1074
+ frameCtx.pickProjMatrix = pickProjMatrix;
1075
+ frameCtx.pickInvisible = !!params.pickInvisible;
1076
+ frameCtx.pickClipPos = [
1077
+ getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
1078
+ getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight)
1079
+ ];
1080
+
1081
+ gl.viewport(0, 0, 1, 1);
1082
+ gl.depthMask(true);
1083
+ gl.enable(gl.DEPTH_TEST);
1084
+ gl.disable(gl.CULL_FACE);
1085
+ gl.disable(gl.BLEND);
1086
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
1087
+
1088
+ const includeEntityIds = params.includeEntityIds;
1089
+ const excludeEntityIds = params.excludeEntityIds;
1090
+
1091
+ const renderDrawables = function(drawables) {
1092
+ for (let i = 0, len = drawables.length; i < len; i++) {
1093
+ const drawable = drawables[i];
1094
+ if (drawable.culled === true || drawable.visible === false) {
1095
+ continue;
1096
+ }
1097
+ if (!drawable.drawPickMesh || (params.pickInvisible !== true && drawable.visible === false) || drawable.pickable === false) {
1098
+ continue;
1099
+ }
1100
+ if (includeEntityIds && !includeEntityIds[drawable.id]) { // TODO: push this logic into drawable
1101
+ continue;
1102
+ }
1103
+ if (excludeEntityIds && excludeEntityIds[drawable.id]) {
1104
+ continue;
1105
+ }
1106
+ drawable.drawPickMesh(frameCtx);
1107
+ }
1108
+ };
1373
1109
 
1374
- pickable.drawPickDepths(frameCtx); // Draw color-encoded fragment screen-space depths
1110
+ renderDrawables(postCullDrawableList);
1111
+ if (uiDrawableList.length > 0) {
1112
+ gl.clear(gl.DEPTH_BUFFER_BIT);
1113
+ renderDrawables(uiDrawableList);
1114
+ }
1375
1115
 
1376
- const screenZ = math.dotVec4(pickBuffer.read(0, 0), bitShiftScreenZ);
1116
+ const pix = pickBuffer.read(0, 0);
1117
+ const pickID = pix[0] + (pix[1] << 8) + (pix[2] << 16) + (pix[3] << 24);
1377
1118
 
1378
- // Calculate clip space coordinates, which will be in range of x=[-1..1] and y=[-1..1], with y=(+1) at top
1379
- const x = (canvasPos[0] - canvas.clientWidth / 2) / (canvas.clientWidth / 2);
1380
- const y = -(canvasPos[1] - canvas.clientHeight / 2) / (canvas.clientHeight / 2);
1119
+ if (pickID < 0) {
1120
+ return;
1121
+ }
1381
1122
 
1382
- const origin = pickable.origin;
1123
+ const pickable = pickIDs.items[pickID];
1383
1124
 
1384
- const pvMatInverse = math.inverseMat4(math.mulMat4(pickProjMatrix, (origin ? createRTCViewMat(pickViewMatrix, origin, tempMat4a) : pickViewMatrix), tempMat4c), tempMat4d);
1125
+ return pickable;
1126
+ }
1385
1127
 
1386
- const toWorld = (z, dst) => {
1387
- dst[0] = x;
1388
- dst[1] = y;
1389
- dst[2] = z;
1390
- dst[3] = 1;
1391
- math.transformVec4(pvMatInverse, dst, dst);
1392
- return math.mulVec4Scalar(dst, 1 / dst[3]);
1393
- };
1128
+ function gpuPickTriangle(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, pickResult) {
1394
1129
 
1395
- const world1 = toWorld(-1, tempVec4a);
1396
- const world2 = toWorld( 1, tempVec4b);
1130
+ if (!pickable.drawPickTriangles) {
1131
+ return;
1132
+ }
1397
1133
 
1398
- const dir = math.subVec3(world2, world1, tempVec4c);
1399
- const worldPos = math.addVec3(world1, math.mulVec4Scalar(dir, screenZ, tempVec4d), tempVec4e);
1134
+ const resolutionScale = scene.canvas.resolutionScale;
1400
1135
 
1401
- if (origin) {
1402
- math.addVec3(worldPos, origin);
1403
- }
1136
+ frameCtx.reset();
1137
+ frameCtx.backfaces = true;
1138
+ frameCtx.frontface = true; // "ccw"
1139
+ frameCtx.pickOrigin = pickResult.origin;
1140
+ frameCtx.pickViewMatrix = pickViewMatrix; // Can be null
1141
+ frameCtx.pickProjMatrix = pickProjMatrix; // Can be null
1142
+ // frameCtx.pickInvisible = !!params.pickInvisible;
1143
+ frameCtx.pickClipPos = [
1144
+ getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
1145
+ getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight)
1146
+ ];
1404
1147
 
1405
- pickResult.worldPos = worldPos;
1148
+ gl.viewport(0, 0, 1, 1);
1406
1149
 
1407
- if (params.pickSurfaceNormal !== false) {
1408
- // gpuPickWorldNormal
1409
- resetFrameCtx(3);
1150
+ gl.clearColor(0, 0, 0, 0);
1151
+ gl.enable(gl.DEPTH_TEST);
1152
+ gl.disable(gl.CULL_FACE);
1153
+ gl.disable(gl.BLEND);
1154
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
1410
1155
 
1411
- pickNormalBuffer.bind();
1156
+ pickable.drawPickTriangles(frameCtx);
1412
1157
 
1413
- gl.viewport(0, 0, pickNormalBuffer.size[0], pickNormalBuffer.size[1]);
1414
- gl.enable(gl.DEPTH_TEST);
1415
- gl.disable(gl.CULL_FACE);
1416
- gl.disable(gl.BLEND);
1417
- gl.clear(gl.DEPTH_BUFFER_BIT);
1418
- gl.clearBufferiv(gl.COLOR, 0, new Int32Array([0, 0, 0, 0]));
1158
+ const pix = pickBuffer.read(0, 0);
1419
1159
 
1420
- pickable.drawPickNormals(frameCtx); // Draw color-encoded fragment World-space normals
1160
+ let primIndex = pix[0] + (pix[1] * 256) + (pix[2] * 256 * 256) + (pix[3] * 256 * 256 * 256);
1421
1161
 
1422
- const pix = pickNormalBuffer.read(1, 1, gl.RGBA_INTEGER, gl.INT, Int32Array, 4);
1162
+ primIndex *= 3; // Convert from triangle number to first vertex in indices
1423
1163
 
1424
- pickNormalBuffer.unbind();
1164
+ pickResult.primIndex = primIndex;
1165
+ }
1425
1166
 
1426
- pickResult.worldNormal = toWorldNormal(pix);
1427
- }
1167
+ const gpuPickWorldPos = (function () {
1428
1168
 
1429
- pickResult.pickSurfacePrecision = false;
1169
+ const tempVec4a = math.vec4();
1170
+ const tempVec4b = math.vec4();
1171
+ const tempVec4c = math.vec4();
1172
+ const tempVec4d = math.vec4();
1173
+ const tempVec4e = math.vec4();
1174
+ const tempMat4a = math.mat4();
1175
+ const tempMat4b = math.mat4();
1176
+ const tempMat4c = math.mat4();
1177
+
1178
+ return function (pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, nearAndFar, pickResult) {
1179
+
1180
+ const resolutionScale = scene.canvas.resolutionScale;
1181
+
1182
+ frameCtx.reset();
1183
+ frameCtx.backfaces = true;
1184
+ frameCtx.frontface = true; // "ccw"
1185
+ frameCtx.pickOrigin = pickResult.origin;
1186
+ frameCtx.pickViewMatrix = pickViewMatrix;
1187
+ frameCtx.pickProjMatrix = pickProjMatrix;
1188
+ frameCtx.pickZNear = nearAndFar[0];
1189
+ frameCtx.pickZFar = nearAndFar[1];
1190
+ frameCtx.pickElementsCount = pickable.pickElementsCount;
1191
+ frameCtx.pickElementsOffset = pickable.pickElementsOffset;
1192
+ frameCtx.pickClipPos = [
1193
+ getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
1194
+ getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight)
1195
+ ];
1196
+
1197
+ gl.viewport(0, 0, 1, 1);
1198
+
1199
+ gl.clearColor(0, 0, 0, 0);
1200
+ gl.depthMask(true);
1201
+ gl.enable(gl.DEPTH_TEST);
1202
+ gl.disable(gl.CULL_FACE);
1203
+ gl.disable(gl.BLEND);
1204
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
1205
+
1206
+ pickable.drawPickDepths(frameCtx); // Draw color-encoded fragment screen-space depths
1207
+
1208
+ const pix = pickBuffer.read(0, 0);
1209
+
1210
+ const screenZ = unpackDepth(pix); // Get screen-space Z at the given canvas coords
1211
+
1212
+ // Calculate clip space coordinates, which will be in range of x=[-1..1] and y=[-1..1], with y=(+1) at top
1213
+ const x = (canvasPos[0] - canvas.clientWidth / 2) / (canvas.clientWidth / 2);
1214
+ const y = -(canvasPos[1] - canvas.clientHeight / 2) / (canvas.clientHeight / 2);
1215
+
1216
+ const origin = pickable.origin;
1217
+ let pvMat;
1218
+
1219
+ if (origin) {
1220
+ const rtcPickViewMat = createRTCViewMat(pickViewMatrix, origin, tempMat4a);
1221
+ pvMat = math.mulMat4(pickProjMatrix, rtcPickViewMat, tempMat4b);
1222
+
1223
+ } else {
1224
+ pvMat = math.mulMat4(pickProjMatrix, pickViewMatrix, tempMat4b);
1225
+ }
1226
+
1227
+ const pvMatInverse = math.inverseMat4(pvMat, tempMat4c);
1228
+
1229
+ tempVec4a[0] = x;
1230
+ tempVec4a[1] = y;
1231
+ tempVec4a[2] = -1;
1232
+ tempVec4a[3] = 1;
1233
+
1234
+ let world1 = math.transformVec4(pvMatInverse, tempVec4a);
1235
+ world1 = math.mulVec4Scalar(world1, 1 / world1[3]);
1236
+
1237
+ tempVec4b[0] = x;
1238
+ tempVec4b[1] = y;
1239
+ tempVec4b[2] = 1;
1240
+ tempVec4b[3] = 1;
1241
+
1242
+ let world2 = math.transformVec4(pvMatInverse, tempVec4b);
1243
+ world2 = math.mulVec4Scalar(world2, 1 / world2[3]);
1244
+
1245
+ const dir = math.subVec3(world2, world1, tempVec4c);
1246
+ const worldPos = math.addVec3(world1, math.mulVec4Scalar(dir, screenZ, tempVec4d), tempVec4e);
1247
+
1248
+ if (origin) {
1249
+ math.addVec3(worldPos, origin);
1250
+ }
1251
+
1252
+ pickResult.worldPos = worldPos;
1253
+ }
1254
+ })();
1255
+
1256
+ function drawSnapInit(frameCtx) {
1257
+ frameCtx.snapPickLayerParams = [];
1258
+ frameCtx.snapPickLayerNumber = 0;
1259
+
1260
+ for (let i = 0, len = postCullDrawableList.length; i < len; i++) {
1261
+
1262
+ const drawable = postCullDrawableList[i];
1263
+
1264
+ if (drawable.drawSnapInit) {
1265
+ if (!drawable.culled && drawable.visible && drawable.pickable) {
1266
+ drawable.drawSnapInit(frameCtx);
1267
+ }
1268
+ }
1269
+ }
1270
+ return frameCtx.snapPickLayerParams;
1271
+ }
1272
+
1273
+ function drawSnap(frameCtx) {
1274
+ frameCtx.snapPickLayerParams = frameCtx.snapPickLayerParams || [];
1275
+ frameCtx.snapPickLayerNumber = frameCtx.snapPickLayerParams.length;
1276
+ for (let i = 0, len = postCullDrawableList.length; i < len; i++) {
1277
+
1278
+ const drawable = postCullDrawableList[i];
1279
+
1280
+ if (drawable.drawSnapInit) {
1281
+ if (drawable.drawSnap) {
1282
+ if (!drawable.culled && drawable.visible && drawable.pickable) {
1283
+ drawable.drawSnap(frameCtx);
1430
1284
  }
1431
1285
  }
1432
1286
  }
1433
- pickBuffer.unbind();
1434
- pickResult.entity = pickedEntity;
1435
- return pickResult;
1436
- };
1437
- })();
1287
+ }
1288
+ return frameCtx.snapPickLayerParams;
1289
+ }
1290
+
1291
+ function getClipPosX(pos, size) {
1292
+ return 2 * (pos / size) - 1;
1293
+ }
1294
+
1295
+ function getClipPosY(pos, size) {
1296
+ return 1 - 2 * (pos / size);
1297
+ }
1438
1298
 
1439
1299
  /**
1440
1300
  * @param {[number, number]} canvasPos
@@ -1448,18 +1308,6 @@ const Renderer = function (scene, options) {
1448
1308
 
1449
1309
  const _pickResult = new PickResult();
1450
1310
 
1451
- const getVertexPickBuffer = (function() {
1452
- const cache = { };
1453
- return (snapRadiusInPixels) => {
1454
- if (! (snapRadiusInPixels in cache)) {
1455
- const buf = new RenderBuffer(gl, [gl.RGBA32I, gl.RGBA32I, gl.RGBA8UI], true);
1456
- buf.setSize([2 * snapRadiusInPixels + 1, 2 * snapRadiusInPixels + 1]);
1457
- cache[snapRadiusInPixels] = buf;
1458
- }
1459
- return cache[snapRadiusInPixels];
1460
- };
1461
- })();
1462
-
1463
1311
  return function (params, pickResult = _pickResult) {
1464
1312
 
1465
1313
  const {canvasPos, origin, direction, snapRadius, snapToVertex, snapToEdge} = params;
@@ -1468,21 +1316,40 @@ const Renderer = function (scene, options) {
1468
1316
  return this.pick({canvasPos, pickSurface: true});
1469
1317
  }
1470
1318
 
1471
- const camera = scene.camera;
1319
+ const resolutionScale = scene.canvas.resolutionScale;
1320
+
1321
+ frameCtx.reset();
1322
+ frameCtx.backfaces = true;
1323
+ frameCtx.frontface = true; // "ccw"
1324
+ frameCtx.pickZNear = scene.camera.project.near;
1325
+ frameCtx.pickZFar = scene.camera.project.far;
1326
+
1472
1327
  const snapRadiusInPixels = snapRadius || 30;
1473
- const viewMatrix = (canvasPos
1474
- ? camera.viewMatrix
1475
- : math.lookAtMat4v(
1476
- origin,
1477
- math.addVec3(origin, direction, math.vec3()),
1478
- math.vec3([0, 1, 0]),
1479
- math.mat4()));
1480
- resetPickFrameCtx(canvasPos, 2 * snapRadiusInPixels, camera, camera.eye, camera.projMatrix, viewMatrix, frameCtx);
1328
+
1329
+ const vertexPickBuffer = renderBufferManager.getRenderBuffer(
1330
+ `uniquePickColors-aabs-${snapRadiusInPixels}`,
1331
+ {
1332
+ depthTexture: true,
1333
+ size: [
1334
+ 2 * snapRadiusInPixels + 1,
1335
+ 2 * snapRadiusInPixels + 1,
1336
+ ]
1337
+ }
1338
+ );
1339
+
1340
+ frameCtx.snapVectorA = [
1341
+ canvasPos ? getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth) : 0,
1342
+ canvasPos ? getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight) : 0,
1343
+ ];
1344
+
1345
+ frameCtx.snapInvVectorAB = [
1346
+ gl.drawingBufferWidth / (2 * snapRadiusInPixels),
1347
+ gl.drawingBufferHeight / (2 * snapRadiusInPixels),
1348
+ ];
1481
1349
 
1482
1350
  // Bind and clear the snap render target
1483
1351
 
1484
- const vertexPickBuffer = getVertexPickBuffer(snapRadiusInPixels);
1485
- vertexPickBuffer.bind();
1352
+ vertexPickBuffer.bind(gl.RGBA32I, gl.RGBA32I, gl.RGBA8UI);
1486
1353
  gl.viewport(0, 0, vertexPickBuffer.size[0], vertexPickBuffer.size[1]);
1487
1354
  gl.enable(gl.DEPTH_TEST);
1488
1355
  gl.frontFace(gl.CCW);
@@ -1495,59 +1362,64 @@ const Renderer = function (scene, options) {
1495
1362
  gl.clearBufferiv(gl.COLOR, 1, new Int32Array([0, 0, 0, 0]));
1496
1363
  gl.clearBufferuiv(gl.COLOR, 2, new Uint32Array([0, 0, 0, 0]));
1497
1364
 
1498
- // a) init z-buffer
1499
- gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2]);
1500
-
1501
- frameCtx.snapPickLayerParams = [];
1502
- frameCtx.snapPickLayerParams.push(null); // This recreates previous situation, which relied on snapPickLayerNumber
1503
- postCullDrawableList.forEach(drawable => {
1504
- if (!drawable.culled && drawable.visible && drawable.pickable && drawable.drawSnapInit) {
1505
- drawable.drawSnapInit(frameCtx);
1365
+ //////////////////////////////////
1366
+ // Set view and proj mats for VBO renderers
1367
+ ///////////////////////////////////////
1368
+
1369
+ frameCtx.pickViewMatrix = (canvasPos
1370
+ ? scene.camera.viewMatrix
1371
+ : math.lookAtMat4v(
1372
+ origin,
1373
+ math.addVec3(origin, direction, math.vec3()),
1374
+ math.vec3([0, 1, 0]),
1375
+ math.mat4()));
1376
+
1377
+ const pickProjMatrix = scene.camera.projMatrix;
1378
+
1379
+ for (let type in drawableTypeInfo) {
1380
+ if (drawableTypeInfo.hasOwnProperty(type)) {
1381
+ const drawableList = drawableTypeInfo[type].drawableList;
1382
+ for (let i = 0, len = drawableList.length; i < len; i++) {
1383
+ const drawable = drawableList[i];
1384
+ if (drawable.setPickMatrices) { // Eg. SceneModel, which needs pre-loading into texture
1385
+ drawable.setPickMatrices(frameCtx.pickViewMatrix, pickProjMatrix);
1386
+ }
1387
+ }
1506
1388
  }
1507
- });
1389
+ }
1508
1390
 
1509
- const layerParamsSurface = frameCtx.snapPickLayerParams;
1391
+ // a) init z-buffer
1392
+ gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2]);
1393
+ const layerParamsSurface = drawSnapInit(frameCtx);
1510
1394
 
1511
1395
  // b) snap-pick
1512
- frameCtx.snapPickLayerParams = [];
1396
+ const layerParamsSnap = []
1397
+ frameCtx.snapPickLayerParams = layerParamsSnap;
1513
1398
 
1514
1399
  gl.depthMask(false);
1515
1400
  gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
1516
1401
 
1517
- const drawSnap = (snapMode) => {
1518
- frameCtx.snapMode = snapMode;
1519
- frameCtx.snapPickLayerParams.push(null); // This recreates previous situation, which relied on snapPickLayerNumber
1520
- postCullDrawableList.forEach(drawable => {
1521
- if (!drawable.culled && drawable.visible && drawable.pickable && drawable.drawSnap) {
1522
- drawable.drawSnap(frameCtx);
1523
- }
1524
- });
1525
- };
1402
+ if (snapToVertex && snapToEdge) {
1403
+ frameCtx.snapMode = "edge";
1404
+ drawSnap(frameCtx);
1526
1405
 
1527
- if (snapToEdge) {
1528
- drawSnap("edge");
1529
- }
1530
- if (snapToVertex) {
1531
- drawSnap("vertex");
1406
+ frameCtx.snapMode = "vertex";
1407
+ frameCtx.snapPickLayerNumber++;
1408
+
1409
+ drawSnap(frameCtx);
1410
+ } else {
1411
+ frameCtx.snapMode = snapToVertex ? "vertex" : "edge";
1412
+
1413
+ drawSnap(frameCtx);
1532
1414
  }
1533
1415
 
1534
1416
  gl.depthMask(true);
1535
1417
 
1536
- const layerParamsSnap = frameCtx.snapPickLayerParams;
1537
-
1538
1418
  // Read and decode the snapped coordinates
1539
- const readSnapPickBuffer = (source, arrayType, glType) => {
1540
- const w = vertexPickBuffer.buffer.width;
1541
- const h = vertexPickBuffer.buffer.height;
1542
- const pix = new arrayType(4 * w * h);
1543
- gl.readBuffer(source);
1544
- gl.readPixels(0, 0, w, h, gl.RGBA_INTEGER, glType, pix, 0);
1545
- return pix;
1546
- };
1547
1419
 
1548
- const snapPickResultArray = readSnapPickBuffer(gl.COLOR_ATTACHMENT0, Int32Array, gl.INT);
1549
- const snapPickNormalResultArray = readSnapPickBuffer(gl.COLOR_ATTACHMENT1, Int32Array, gl.INT);
1550
- const snapPickIdResultArray = readSnapPickBuffer(gl.COLOR_ATTACHMENT2, Uint32Array, gl.UNSIGNED_INT);
1420
+ const snapPickResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.INT, Int32Array, 4);
1421
+ const snapPickNormalResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.INT, Int32Array, 4, 1);
1422
+ const snapPickIdResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.UNSIGNED_INT, Uint32Array, 4, 2);
1551
1423
 
1552
1424
  vertexPickBuffer.unbind();
1553
1425
 
@@ -1566,76 +1438,195 @@ const Renderer = function (scene, options) {
1566
1438
 
1567
1439
  if (pickResultMiddleXY[3] !== 0) {
1568
1440
  const pickedLayerParmasSurface = layerParamsSurface[Math.abs(pickResultMiddleXY[3]) % layerParamsSurface.length];
1569
- worldPos = toWorldPos(pickResultMiddleXY, pickedLayerParmasSurface.origin, pickedLayerParmasSurface.coordinateScale);
1570
- worldNormal = toWorldNormal(pickNormalResultMiddleXY);
1571
-
1572
- pickable = pickIDs.items[pixelToInt(pickPickableResultMiddleXY)];
1441
+ const origin = pickedLayerParmasSurface.origin;
1442
+ const scale = pickedLayerParmasSurface.coordinateScale;
1443
+ worldPos = [
1444
+ pickResultMiddleXY[0] * scale[0] + origin[0],
1445
+ pickResultMiddleXY[1] * scale[1] + origin[1],
1446
+ pickResultMiddleXY[2] * scale[2] + origin[2],
1447
+ ];
1448
+ worldNormal = math.normalizeVec3([
1449
+ pickNormalResultMiddleXY[0] / math.MAX_INT,
1450
+ pickNormalResultMiddleXY[1] / math.MAX_INT,
1451
+ pickNormalResultMiddleXY[2] / math.MAX_INT,
1452
+ ]);
1453
+
1454
+ const pickID =
1455
+ pickPickableResultMiddleXY[0]
1456
+ + (pickPickableResultMiddleXY[1] << 8)
1457
+ + (pickPickableResultMiddleXY[2] << 16)
1458
+ + (pickPickableResultMiddleXY[3] << 24);
1459
+
1460
+ pickable = pickIDs.items[pickID];
1573
1461
  }
1574
1462
 
1575
1463
  // result 2) hi-precision snapped (to vertex/edge) world position
1576
1464
 
1577
- const snapPickResult = [ ];
1465
+ let snapPickResult = [];
1466
+
1578
1467
  for (let i = 0; i < snapPickResultArray.length; i += 4) {
1579
- const layerNumber = snapPickResultArray[i + 3];
1580
- if (layerNumber > 0) {
1468
+ if (snapPickResultArray[i + 3] > 0) {
1581
1469
  const pixelNumber = Math.floor(i / 4);
1582
1470
  const w = vertexPickBuffer.size[0];
1583
1471
  const x = pixelNumber % w - Math.floor(w / 2);
1584
1472
  const y = Math.floor(pixelNumber / w) - Math.floor(w / 2);
1473
+ const dist = (Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));
1585
1474
  snapPickResult.push({
1586
- dist: math.lenVec2([ x, y ]),
1587
- isVertex: (snapToVertex && snapToEdge) ? (layerNumber > layerParamsSnap.length / 2) : snapToVertex,
1588
- result: snapPickResultArray.subarray(i, i+4),
1589
- normal: snapPickNormalResultArray.subarray(i, i+4),
1590
- id: snapPickIdResultArray.subarray(i, i+4)
1475
+ x,
1476
+ y,
1477
+ dist,
1478
+ isVertex: snapToVertex && snapToEdge ? snapPickResultArray[i + 3] > layerParamsSnap.length / 2 : snapToVertex,
1479
+ result: [
1480
+ snapPickResultArray[i + 0],
1481
+ snapPickResultArray[i + 1],
1482
+ snapPickResultArray[i + 2],
1483
+ snapPickResultArray[i + 3],
1484
+ ],
1485
+ normal: [
1486
+ snapPickNormalResultArray[i + 0],
1487
+ snapPickNormalResultArray[i + 1],
1488
+ snapPickNormalResultArray[i + 2],
1489
+ snapPickNormalResultArray[i + 3],
1490
+ ],
1491
+ id: [
1492
+ snapPickIdResultArray[i + 0],
1493
+ snapPickIdResultArray[i + 1],
1494
+ snapPickIdResultArray[i + 2],
1495
+ snapPickIdResultArray[i + 3],
1496
+ ]
1591
1497
  });
1592
1498
  }
1593
1499
  }
1594
1500
 
1595
- const getPickedEntity = pickable => (pickable && pickable.delegatePickedEntity) ? pickable.delegatePickedEntity() : pickable;
1501
+ let snappedWorldPos = null;
1502
+ let snappedWorldNormal = null;
1503
+ let snappedPickable = null;
1504
+ let snapType = null;
1596
1505
 
1597
1506
  if (snapPickResult.length > 0) {
1598
- // closest vertex snap first, then closest edge snap
1599
- const res = snapPickResult.reduce((a,b) => ((((a.isVertex-b.isVertex) || (b.dist-a.dist)) > 0) ? a : b));
1600
- const snapPick = res.result;
1507
+ // vertex snap first, then edge snap
1508
+ snapPickResult.sort((a, b) => {
1509
+ if (a.isVertex !== b.isVertex) {
1510
+ return a.isVertex ? -1 : 1;
1511
+ } else {
1512
+ return a.dist - b.dist;
1513
+ }
1514
+ });
1515
+
1516
+ snapType = snapPickResult[0].isVertex ? "vertex" : "edge";
1517
+ const snapPick = snapPickResult[0].result;
1518
+ const snapPickNormal = snapPickResult[0].normal;
1519
+ const snapPickId = snapPickResult[0].id;
1520
+
1601
1521
  const pickedLayerParmas = layerParamsSnap[snapPick[3]];
1602
- const snappedWorldPos = toWorldPos(snapPick, pickedLayerParmas.origin, pickedLayerParmas.coordinateScale);
1603
- const snappedCanvasPos = camera.projectWorldPos(snappedWorldPos);
1604
-
1605
- pickResult.reset();
1606
- pickResult.snappedToEdge = !res.isVertex;
1607
- pickResult.snappedToVertex = res.isVertex;
1608
- pickResult.worldPos = snappedWorldPos;
1609
- pickResult.worldNormal = toWorldNormal(res.normal);
1610
- pickResult.entity = getPickedEntity(pickIDs.items[pixelToInt(res.id)]);
1611
- pickResult.canvasPos = canvasPos || (worldPos && camera.projectWorldPos(worldPos)) || snappedCanvasPos;
1612
- pickResult.snappedCanvasPos = snappedCanvasPos;
1613
- return pickResult;
1614
-
1615
- } else if (worldPos) {
1616
-
1617
- pickResult.reset();
1618
- pickResult.snappedToEdge = false;
1619
- pickResult.snappedToVertex = false;
1620
- pickResult.worldPos = worldPos;
1621
- pickResult.worldNormal = worldNormal;
1622
- pickResult.entity = getPickedEntity(pickable);
1623
- pickResult.canvasPos = canvasPos || camera.projectWorldPos(worldPos);
1624
- pickResult.snappedCanvasPos = canvasPos;
1625
- return pickResult;
1626
1522
 
1627
- } else {
1523
+ const origin = pickedLayerParmas.origin;
1524
+ const scale = pickedLayerParmas.coordinateScale;
1525
+
1526
+ snappedWorldNormal = math.normalizeVec3([
1527
+ snapPickNormal[0] / math.MAX_INT,
1528
+ snapPickNormal[1] / math.MAX_INT,
1529
+ snapPickNormal[2] / math.MAX_INT,
1530
+ ]);
1531
+
1532
+ snappedWorldPos = [
1533
+ snapPick[0] * scale[0] + origin[0],
1534
+ snapPick[1] * scale[1] + origin[1],
1535
+ snapPick[2] * scale[2] + origin[2],
1536
+ ];
1537
+
1538
+ snappedPickable = pickIDs.items[
1539
+ snapPickId[0]
1540
+ + (snapPickId[1] << 8)
1541
+ + (snapPickId[2] << 16)
1542
+ + (snapPickId[3] << 24)
1543
+ ];
1544
+ }
1545
+
1546
+ if (null === worldPos && null == snappedWorldPos) { // If neither regular pick or snap pick, return null
1628
1547
  return null;
1629
1548
  }
1549
+
1550
+ let snappedCanvasPos = null;
1551
+
1552
+ if (null !== snappedWorldPos) {
1553
+ snappedCanvasPos = scene.camera.projectWorldPos(snappedWorldPos);
1554
+ }
1555
+
1556
+ const snappedEntity = (snappedPickable && snappedPickable.delegatePickedEntity) ? snappedPickable.delegatePickedEntity() : snappedPickable;
1557
+ if (!snappedEntity && pickable) {
1558
+ pickable = pickable.delegatePickedEntity ? pickable.delegatePickedEntity() : pickable;
1559
+ }
1560
+
1561
+ pickResult.reset();
1562
+ pickResult.snappedToEdge = (snapType === "edge");
1563
+ pickResult.snappedToVertex = (snapType === "vertex");
1564
+ pickResult.worldPos = snappedWorldPos || worldPos;
1565
+ pickResult.worldNormal = snappedWorldNormal || worldNormal;
1566
+ pickResult.entity = snappedEntity || pickable;
1567
+ pickResult.canvasPos = canvasPos || scene.camera.projectWorldPos(worldPos || snappedWorldPos);
1568
+ pickResult.snappedCanvasPos = snappedCanvasPos || canvasPos;
1569
+
1570
+ return pickResult;
1630
1571
  };
1631
1572
  })();
1632
1573
 
1574
+ function unpackDepth(depthZ) {
1575
+ const vec = [depthZ[0] / 256.0, depthZ[1] / 256.0, depthZ[2] / 256.0, depthZ[3] / 256.0];
1576
+ const bitShift = [1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0];
1577
+ return math.dotVec4(vec, bitShift);
1578
+ }
1579
+
1580
+ function gpuPickWorldNormal(pickBuffer, pickable, canvasPos, pickViewMatrix, pickProjMatrix, pickResult) {
1581
+
1582
+ const resolutionScale = scene.canvas.resolutionScale;
1583
+
1584
+ frameCtx.reset();
1585
+ frameCtx.backfaces = true;
1586
+ frameCtx.frontface = true; // "ccw"
1587
+ frameCtx.pickOrigin = pickResult.origin;
1588
+ frameCtx.pickViewMatrix = pickViewMatrix;
1589
+ frameCtx.pickProjMatrix = pickProjMatrix;
1590
+ frameCtx.pickClipPos = [
1591
+ getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
1592
+ getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight),
1593
+ ];
1594
+
1595
+ const pickNormalBuffer = renderBufferManager.getRenderBuffer("pick-normal", {size: [3, 3]});
1596
+
1597
+ pickNormalBuffer.bind(gl.RGBA32I);
1598
+
1599
+ gl.viewport(0, 0, pickNormalBuffer.size[0], pickNormalBuffer.size[1]);
1600
+
1601
+ gl.enable(gl.DEPTH_TEST);
1602
+ gl.disable(gl.CULL_FACE);
1603
+ gl.disable(gl.BLEND);
1604
+ gl.clear(gl.DEPTH_BUFFER_BIT);
1605
+ gl.clearBufferiv(gl.COLOR, 0, new Int32Array([0, 0, 0, 0]));
1606
+
1607
+ pickable.drawPickNormals(frameCtx); // Draw color-encoded fragment World-space normals
1608
+
1609
+ const pix = pickNormalBuffer.read(1, 1, gl.RGBA_INTEGER, gl.INT, Int32Array, 4);
1610
+
1611
+ pickNormalBuffer.unbind();
1612
+
1613
+ const worldNormal = [
1614
+ pix[0] / math.MAX_INT,
1615
+ pix[1] / math.MAX_INT,
1616
+ pix[2] / math.MAX_INT,
1617
+ ];
1618
+
1619
+ math.normalizeVec3(worldNormal);
1620
+
1621
+ pickResult.worldNormal = worldNormal;
1622
+ }
1623
+
1633
1624
  /**
1634
1625
  * Adds a {@link Marker} for occlusion testing.
1635
1626
  * @param marker
1636
1627
  */
1637
1628
  this.addMarker = function (marker) {
1638
- this._occlusionTester = this._occlusionTester || new OcclusionTester(scene);
1629
+ this._occlusionTester = this._occlusionTester || new OcclusionTester(scene, renderBufferManager);
1639
1630
  this._occlusionTester.addMarker(marker);
1640
1631
  scene.occlusionTestCountdown = 0;
1641
1632
  };
@@ -1666,17 +1657,11 @@ const Renderer = function (scene, options) {
1666
1657
 
1667
1658
  updateDrawlist();
1668
1659
 
1669
- const readPixelBuf = (! OCCLUSION_TEST_MODE) && renderBufferManager.getRenderBuffer("occlusionReadPix");
1670
- if (readPixelBuf) {
1671
- readPixelBuf.setSize([gl.drawingBufferWidth, gl.drawingBufferHeight]);
1672
- readPixelBuf.bind();
1673
- }
1660
+ this._occlusionTester.bindRenderBuf();
1674
1661
 
1675
1662
  frameCtx.reset();
1676
1663
  frameCtx.backfaces = true;
1677
1664
  frameCtx.frontface = true; // "ccw"
1678
- frameCtx.viewParams = getSceneCameraViewParams();
1679
- frameCtx.nearPlaneHeight = getNearPlaneHeight(scene.camera, gl.drawingBufferHeight);
1680
1665
 
1681
1666
  gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
1682
1667
  gl.clearColor(0, 0, 0, 0);
@@ -1685,143 +1670,121 @@ const Renderer = function (scene, options) {
1685
1670
  gl.disable(gl.BLEND);
1686
1671
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
1687
1672
 
1688
- postCullDrawableList.forEach(drawable => {
1689
- if (!drawable.culled && drawable.visible && drawable.pickable && drawable.drawOcclusion) { // TODO: Option to exclude transparent?
1690
- drawable.drawOcclusion(frameCtx);
1691
- }
1692
- });
1693
1673
 
1694
- this._occlusionTester.drawMarkers();
1674
+ for (let i = 0, len = postCullDrawableList.length; i < len; i++) {
1675
+
1676
+ const drawable = postCullDrawableList[i];
1677
+
1678
+ if (!drawable.drawOcclusion || drawable.culled === true || drawable.visible === false || drawable.pickable === false) { // TODO: Option to exclude transparent?
1679
+ continue;
1680
+ }
1695
1681
 
1696
- if (readPixelBuf) {
1697
- const resolutionScale = scene.canvas.resolutionScale;
1698
- this._occlusionTester.doOcclusionTest( // Updates Marker "visible" properties
1699
- (x, y) => readPixelBuf.read(Math.round(resolutionScale * x), Math.round(resolutionScale * y)));
1700
- readPixelBuf.unbind();
1682
+ drawable.drawOcclusion(frameCtx);
1701
1683
  }
1684
+
1685
+ this._occlusionTester.drawMarkers(frameCtx);
1686
+ this._occlusionTester.doOcclusionTest(); // Updates Marker "visible" properties
1687
+ this._occlusionTester.unbindRenderBuf();
1702
1688
  }
1703
1689
  };
1704
1690
 
1705
- this.snapshot = (() => {
1706
- let snapshotBound = false;
1707
- const snapshotBuffer = new RenderBuffer(gl);
1708
- let snapshotCanvas = null;
1709
-
1710
- return {
1711
- /**
1712
- * Read pixels from the renderer's current output. Performs a force-render first.
1713
- * @param pixels
1714
- * @param colors
1715
- * @param len
1716
- * @private
1717
- */
1718
- readPixels: (pixels, colors, len) => {
1719
- snapshotBuffer.bind();
1720
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
1721
- imageDirty = true;
1722
- this.render();
1723
- for (let i = 0; i < len; i++) {
1724
- const j = i * 2;
1725
- const k = i * 4;
1726
- const color = snapshotBuffer.read(pixels[j], pixels[j + 1]);
1727
- colors[k] = color[0];
1728
- colors[k + 1] = color[1];
1729
- colors[k + 2] = color[2];
1730
- colors[k + 3] = color[3];
1731
- }
1732
- snapshotBuffer.unbind();
1733
- imageDirty = true;
1734
- },
1735
-
1736
- /**
1737
- * Enter snapshot mode.
1738
- *
1739
- * Switches rendering to a hidden snapshot canvas.
1740
- *
1741
- * Exit snapshot mode using endSnapshot().
1742
- */
1743
- beginSnapshot: () => {
1744
- snapshotBuffer.setSize([gl.drawingBufferWidth, gl.drawingBufferHeight]);
1745
- snapshotBuffer.bind();
1746
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
1747
- snapshotBound = true;
1748
- },
1749
-
1750
- /**
1751
- * Returns an HTMLCanvas containing an image of the snapshot canvas.
1752
- *
1753
- * - The HTMLCanvas has a CanvasRenderingContext2D.
1754
- * - Expects the caller to draw more things on the HTMLCanvas (annotations etc).
1755
- *
1756
- * @returns {HTMLCanvasElement}
1757
- */
1758
- renderSnapshotToCanvas: () => {
1759
- const width = snapshotBuffer.buffer.width;
1760
- const height = snapshotBuffer.buffer.height;
1761
-
1762
- if ((! snapshotCanvas) || (snapshotCanvas.width !== width) || (snapshotCanvas.height !== height)) {
1763
- snapshotCanvas = (function() {
1764
- const canvas = document.createElement('canvas');
1765
- const context = canvas.getContext('2d');
1766
- canvas.width = width;
1767
- canvas.height = height;
1768
- const pixelData = new Uint8Array(width * height * 4);
1769
- const imageData = context.createImageData(width, height);
1770
-
1771
- return {
1772
- width: width,
1773
- height: height,
1774
- getUpdatedCanvas: () => {
1775
- gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixelData);
1776
-
1777
- // flip verically
1778
- const halfHeight = Math.floor(height / 2);
1779
- const bytesPerRow = width * 4;
1780
- const temp = new Uint8Array(bytesPerRow);
1781
- for (let y = 0; y < halfHeight; ++y) {
1782
- const topOffset = y * bytesPerRow;
1783
- const bottomOffset = (height - y - 1) * bytesPerRow;
1784
- temp.set(pixelData.subarray(topOffset, topOffset + bytesPerRow));
1785
- pixelData.copyWithin(topOffset, bottomOffset, bottomOffset + bytesPerRow);
1786
- pixelData.set(temp, bottomOffset);
1787
- }
1788
-
1789
- imageData.data.set(pixelData);
1790
-
1791
- context.resetTransform(); // Prevents strange scale-accumulation effect with html2canvas
1792
- context.putImageData(imageData, 0, 0);
1793
-
1794
- return canvas;
1795
- }
1796
- };
1797
- })();
1798
- }
1691
+ /**
1692
+ * Read pixels from the renderer's current output. Performs a force-render first.
1693
+ * @param pixels
1694
+ * @param colors
1695
+ * @param len
1696
+ * @param opaqueOnly
1697
+ * @private
1698
+ */
1699
+ this.readPixels = function (pixels, colors, len, opaqueOnly) {
1700
+ const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
1701
+ snapshotBuffer.bind();
1702
+ snapshotBuffer.clear();
1703
+ this.render({force: true, opaqueOnly: opaqueOnly});
1704
+ let color;
1705
+ let i;
1706
+ let j;
1707
+ let k;
1708
+ for (i = 0; i < len; i++) {
1709
+ j = i * 2;
1710
+ k = i * 4;
1711
+ color = snapshotBuffer.read(pixels[j], pixels[j + 1]);
1712
+ colors[k] = color[0];
1713
+ colors[k + 1] = color[1];
1714
+ colors[k + 2] = color[2];
1715
+ colors[k + 3] = color[3];
1716
+ }
1717
+ snapshotBuffer.unbind();
1718
+ imageDirty = true;
1719
+ };
1799
1720
 
1800
- if (snapshotBound) {
1801
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
1802
- imageDirty = true;
1803
- this.render();
1804
- imageDirty = true;
1805
- }
1721
+ /**
1722
+ * Enter snapshot mode.
1723
+ *
1724
+ * Switches rendering to a hidden snapshot canvas.
1725
+ *
1726
+ * Exit snapshot mode using endSnapshot().
1727
+ */
1728
+ this.beginSnapshot = function (params = {}) {
1729
+ const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
1730
+ if (params.width && params.height) {
1731
+ snapshotBuffer.setSize([params.width, params.height]);
1732
+ }
1733
+ snapshotBuffer.bind();
1734
+ snapshotBuffer.clear();
1735
+ snapshotBound = true;
1736
+ };
1806
1737
 
1807
- return snapshotCanvas.getUpdatedCanvas();
1808
- },
1809
-
1810
- /**
1811
- * Exists snapshot mode.
1812
- *
1813
- * Switches rendering back to the main canvas.
1814
- */
1815
- endSnapshot: () => {
1816
- if (snapshotBound) {
1817
- snapshotBuffer.unbind();
1818
- snapshotBound = false;
1819
- }
1820
- imageDirty = true;
1821
- this.render();
1822
- }
1823
- };
1824
- })();
1738
+ /**
1739
+ * When in snapshot mode, renders a frame of the current Scene state to the snapshot canvas.
1740
+ */
1741
+ this.renderSnapshot = function () {
1742
+ if (!snapshotBound) {
1743
+ return;
1744
+ }
1745
+ const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
1746
+ snapshotBuffer.clear();
1747
+ this.render({force: true, opaqueOnly: false});
1748
+ imageDirty = true;
1749
+ };
1750
+
1751
+ /**
1752
+ * When in snapshot mode, gets an image of the snapshot canvas.
1753
+ *
1754
+ * @private
1755
+ * @returns {String} The image data URI.
1756
+ */
1757
+ this.readSnapshot = function (params) {
1758
+ const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
1759
+ return snapshotBuffer.readImage(params);
1760
+ };
1761
+
1762
+ /**
1763
+ * Returns an HTMLCanvas containing an image of the snapshot canvas.
1764
+ *
1765
+ * - The HTMLCanvas has a CanvasRenderingContext2D.
1766
+ * - Expects the caller to draw more things on the HTMLCanvas (annotations etc).
1767
+ *
1768
+ * @returns {HTMLCanvasElement}
1769
+ */
1770
+ this.readSnapshotAsCanvas = function () {
1771
+ const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
1772
+ return snapshotBuffer.readImageAsCanvas();
1773
+ };
1774
+
1775
+ /**
1776
+ * Exists snapshot mode.
1777
+ *
1778
+ * Switches rendering back to the main canvas.
1779
+ */
1780
+ this.endSnapshot = function () {
1781
+ if (!snapshotBound) {
1782
+ return;
1783
+ }
1784
+ const snapshotBuffer = renderBufferManager.getRenderBuffer("snapshot");
1785
+ snapshotBuffer.unbind();
1786
+ snapshotBound = false;
1787
+ };
1825
1788
 
1826
1789
  /**
1827
1790
  * Destroys this renderer.