Reference Source

src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsSnapRenderer.js

  1.  
  2. import {createRTCViewMat} from "../../../../../math/rtcCoords.js";
  3. import {math} from "../../../../../math/math.js";
  4. import {VBORenderer} from "../../../VBORenderer.js";
  5.  
  6. const tempVec3a = math.vec3();
  7. const tempVec3b = math.vec3();
  8. const tempVec3c = math.vec3();
  9. const tempVec3d = math.vec3();
  10. const tempMat4a = math.mat4();
  11.  
  12. const SNAPPING_LOG_DEPTH_BUF_ENABLED = true; // Improves occlusion accuracy at distance
  13.  
  14. /**
  15. * @private
  16. */
  17. export class VBOBatchingPointsSnapRenderer extends VBORenderer{
  18. _getHash() {
  19. return this._scene._sectionPlanesState.getHash() + (this._scene.pointsMaterial.hash);
  20. }
  21.  
  22. drawLayer(frameCtx, batchingLayer, renderPass) {
  23.  
  24. if (!this._program) {
  25. this._allocate();
  26. if (this.errors) {
  27. return;
  28. }
  29. }
  30.  
  31. if (frameCtx.lastProgramId !== this._program.id) {
  32. frameCtx.lastProgramId = this._program.id;
  33. this._bindProgram();
  34. }
  35.  
  36. const model = batchingLayer.model;
  37. const scene = model.scene;
  38. const camera = scene.camera;
  39. const gl = scene.canvas.gl;
  40. const state = batchingLayer._state;
  41. const origin = batchingLayer._state.origin;
  42. const {position, rotationMatrix} = model;
  43. const aabb = batchingLayer.aabb; // Per-layer AABB for best RTC accuracy
  44. const viewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix;
  45.  
  46. if (this._vaoCache.has(batchingLayer)) {
  47. gl.bindVertexArray(this._vaoCache.get(batchingLayer));
  48. } else {
  49. this._vaoCache.set(batchingLayer, this._makeVAO(state))
  50. }
  51.  
  52. const coordinateScaler = tempVec3a;
  53. coordinateScaler[0] = math.safeInv(aabb[3] - aabb[0]) * math.MAX_INT;
  54. coordinateScaler[1] = math.safeInv(aabb[4] - aabb[1]) * math.MAX_INT;
  55. coordinateScaler[2] = math.safeInv(aabb[5] - aabb[2]) * math.MAX_INT;
  56.  
  57. frameCtx.snapPickCoordinateScale[0] = math.safeInv(coordinateScaler[0]);
  58. frameCtx.snapPickCoordinateScale[1] = math.safeInv(coordinateScaler[1]);
  59. frameCtx.snapPickCoordinateScale[2] = math.safeInv(coordinateScaler[2]);
  60.  
  61. let rtcViewMatrix;
  62. let rtcCameraEye;
  63.  
  64. if (origin || position[0] !== 0 || position[1] !== 0 || position[2] !== 0) {
  65. const rtcOrigin = tempVec3b;
  66. if (origin) {
  67. const rotatedOrigin = tempVec3c;
  68. math.transformPoint3(rotationMatrix, origin, rotatedOrigin);
  69. rtcOrigin[0] = rotatedOrigin[0];
  70. rtcOrigin[1] = rotatedOrigin[1];
  71. rtcOrigin[2] = rotatedOrigin[2];
  72. } else {
  73. rtcOrigin[0] = 0;
  74. rtcOrigin[1] = 0;
  75. rtcOrigin[2] = 0;
  76. }
  77. rtcOrigin[0] += position[0];
  78. rtcOrigin[1] += position[1];
  79. rtcOrigin[2] += position[2];
  80. rtcViewMatrix = createRTCViewMat(viewMatrix, rtcOrigin, tempMat4a);
  81. rtcCameraEye = tempVec3d;
  82. rtcCameraEye[0] = camera.eye[0] - rtcOrigin[0];
  83. rtcCameraEye[1] = camera.eye[1] - rtcOrigin[1];
  84. rtcCameraEye[2] = camera.eye[2] - rtcOrigin[2];
  85. frameCtx.snapPickOrigin[0] = rtcOrigin[0];
  86. frameCtx.snapPickOrigin[1] = rtcOrigin[1];
  87. frameCtx.snapPickOrigin[2] = rtcOrigin[2];
  88. } else {
  89. rtcViewMatrix = viewMatrix;
  90. rtcCameraEye = camera.eye;
  91. frameCtx.snapPickOrigin[0] = 0;
  92. frameCtx.snapPickOrigin[1] = 0;
  93. frameCtx.snapPickOrigin[2] = 0;
  94. }
  95.  
  96. gl.uniform3fv(this._uCameraEyeRtc, rtcCameraEye);
  97. gl.uniform2fv(this.uVectorA, frameCtx.snapVectorA);
  98. gl.uniform2fv(this.uInverseVectorAB, frameCtx.snapInvVectorAB);
  99. gl.uniform1i(this._uLayerNumber, frameCtx.snapPickLayerNumber);
  100. gl.uniform3fv(this._uCoordinateScaler, coordinateScaler);
  101. gl.uniform1i(this._uRenderPass, renderPass);
  102. gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible);
  103.  
  104. let offset = 0;
  105. const mat4Size = 4 * 4;
  106.  
  107. this._matricesUniformBlockBufferData.set(rotationMatrix, 0);
  108. this._matricesUniformBlockBufferData.set(rtcViewMatrix, offset += mat4Size);
  109. this._matricesUniformBlockBufferData.set(camera.projMatrix, offset += mat4Size);
  110. this._matricesUniformBlockBufferData.set(state.positionsDecodeMatrix, offset += mat4Size);
  111.  
  112. gl.bindBuffer(gl.UNIFORM_BUFFER, this._matricesUniformBlockBuffer);
  113. gl.bufferData(gl.UNIFORM_BUFFER, this._matricesUniformBlockBufferData, gl.DYNAMIC_DRAW);
  114.  
  115. gl.bindBufferBase(
  116. gl.UNIFORM_BUFFER,
  117. this._matricesUniformBlockBufferBindingPoint,
  118. this._matricesUniformBlockBuffer);
  119.  
  120. if (SNAPPING_LOG_DEPTH_BUF_ENABLED) {
  121. const logDepthBufFC = 2.0 / (Math.log(frameCtx.pickZFar + 1.0) / Math.LN2); // TODO: Far from pick project matrix?
  122. gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC);
  123. }
  124.  
  125. this.setSectionPlanesStateUniforms(batchingLayer);
  126.  
  127. //=============================================================
  128. // TODO: Use drawElements count and offset to draw only one entity
  129. //=============================================================
  130.  
  131. gl.drawArrays(gl.POINTS, 0, state.positionsBuf.numItems);
  132. }
  133.  
  134. _allocate() {
  135. super._allocate();
  136.  
  137. const program = this._program;
  138.  
  139. if (SNAPPING_LOG_DEPTH_BUF_ENABLED) {
  140. this._uLogDepthBufFC = program.getLocation("logDepthBufFC");
  141. }
  142.  
  143. this._uCameraEyeRtc = program.getLocation("uCameraEyeRtc");
  144. this.uVectorA = program.getLocation("snapVectorA");
  145. this.uInverseVectorAB = program.getLocation("snapInvVectorAB");
  146. this._uLayerNumber = program.getLocation("layerNumber");
  147. this._uCoordinateScaler = program.getLocation("coordinateScaler");
  148. }
  149.  
  150. _bindProgram() {
  151. this._program.bind();
  152. }
  153.  
  154. _buildVertexShader() {
  155. const scene = this._scene;
  156. const clipping = scene._sectionPlanesState.getNumAllocatedSectionPlanes() > 0;
  157. const pointsMaterial = scene.pointsMaterial._state;
  158. const src = [];
  159. src.push ('#version 300 es');
  160. src.push("// VBOBatchingPointsSnapRenderer vertex shader");
  161. src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH");
  162. src.push("precision highp float;");
  163. src.push("precision highp int;");
  164. src.push("precision highp usampler2D;");
  165. src.push("precision highp isampler2D;");
  166. src.push("precision highp sampler2D;");
  167. src.push("#else");
  168. src.push("precision mediump float;");
  169. src.push("precision mediump int;");
  170. src.push("precision mediump usampler2D;");
  171. src.push("precision mediump isampler2D;");
  172. src.push("precision mediump sampler2D;");
  173. src.push("#endif");
  174. src.push("uniform int renderPass;");
  175. src.push("in vec3 position;");
  176. if (scene.entityOffsetsEnabled) {
  177. src.push("in vec3 offset;");
  178. }
  179. src.push("in float flags;");
  180. src.push("uniform bool pickInvisible;");
  181.  
  182. this._addMatricesUniformBlockLines(src);
  183.  
  184. src.push("uniform vec3 uCameraEyeRtc;");
  185. src.push("uniform vec2 snapVectorA;");
  186. src.push("uniform vec2 snapInvVectorAB;");
  187. if (SNAPPING_LOG_DEPTH_BUF_ENABLED) {
  188. src.push("uniform float logDepthBufFC;");
  189. src.push("out float vFragDepth;");
  190. src.push("bool isPerspectiveMatrix(mat4 m) {");
  191. src.push(" return (m[2][3] == - 1.0);");
  192. src.push("}");
  193. src.push("out float isPerspective;");
  194. }
  195. src.push("vec2 remapClipPos(vec2 clipPos) {");
  196. src.push(" float x = (clipPos.x - snapVectorA.x) * snapInvVectorAB.x;");
  197. src.push(" float y = (clipPos.y - snapVectorA.y) * snapInvVectorAB.y;");
  198. src.push(" return vec2(x, y);")
  199. src.push("}");
  200. if (clipping) {
  201. src.push("out vec4 vWorldPosition;");
  202. src.push("out float vFlags;");
  203. }
  204. src.push("out highp vec3 relativeToOriginPosition;");
  205. src.push("void main(void) {");
  206.  
  207. // pickFlag = NOT_RENDERED | PICK
  208. // renderPass = PICK
  209.  
  210. src.push(`int pickFlag = int(flags) >> 12 & 0xF;`);
  211. src.push(`if (pickFlag != renderPass) {`);
  212. src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex
  213. src.push(" } else {");
  214. src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); ");
  215. if (scene.entityOffsetsEnabled) {
  216. src.push(" worldPosition.xyz = worldPosition.xyz + offset;");
  217. }
  218. src.push("relativeToOriginPosition = worldPosition.xyz;")
  219. src.push(" vec4 viewPosition = viewMatrix * worldPosition; ");
  220. if (clipping) {
  221. src.push(" vWorldPosition = worldPosition;");
  222. src.push(" vFlags = flags;");
  223. }
  224. src.push("vec4 clipPos = projMatrix * viewPosition;");
  225. src.push("float tmp = clipPos.w;")
  226. src.push("clipPos.xyzw /= tmp;")
  227. src.push("clipPos.xy = remapClipPos(clipPos.xy);");
  228. src.push("clipPos.xyzw *= tmp;");
  229. if (SNAPPING_LOG_DEPTH_BUF_ENABLED) {
  230. src.push("vFragDepth = 1.0 + clipPos.w;");
  231. src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));");
  232. }
  233. src.push("gl_Position = clipPos;");
  234. src.push("gl_PointSize = 1.0;"); // Windows needs this?
  235. src.push(" }");
  236. src.push("}");
  237. return src;
  238. }
  239.  
  240. _buildFragmentShader() {
  241. const scene = this._scene;
  242. const sectionPlanesState = scene._sectionPlanesState;
  243. const clipping = sectionPlanesState.getNumAllocatedSectionPlanes() > 0;
  244. const src = [];
  245. src.push ('#version 300 es');
  246. src.push("// VBOBatchingPointsSnapRenderer fragment shader");
  247. src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH");
  248. src.push("precision highp float;");
  249. src.push("precision highp int;");
  250. src.push("#else");
  251. src.push("precision mediump float;");
  252. src.push("precision mediump int;");
  253. src.push("#endif");
  254. if (SNAPPING_LOG_DEPTH_BUF_ENABLED) {
  255. src.push("in float isPerspective;");
  256. src.push("uniform float logDepthBufFC;");
  257. src.push("in float vFragDepth;");
  258. }
  259. src.push("uniform int layerNumber;");
  260. src.push("uniform vec3 coordinateScaler;");
  261. if (clipping) {
  262. src.push("in vec4 vWorldPosition;");
  263. src.push("in float vFlags;");
  264. for (let i = 0; i < sectionPlanesState.getNumAllocatedSectionPlanes(); i++) {
  265. src.push("uniform bool sectionPlaneActive" + i + ";");
  266. src.push("uniform vec3 sectionPlanePos" + i + ";");
  267. src.push("uniform vec3 sectionPlaneDir" + i + ";");
  268. }
  269. }
  270. src.push("in highp vec3 relativeToOriginPosition;");
  271. src.push("out highp ivec4 outCoords;");
  272. src.push("void main(void) {");
  273. if (clipping) {
  274. src.push(" bool clippable = (int(vFlags) >> 16 & 0xF) == 1;");
  275. src.push(" if (clippable) {");
  276. src.push(" float dist = 0.0;");
  277. for (var i = 0; i < sectionPlanesState.getNumAllocatedSectionPlanes(); i++) {
  278. src.push(" if (sectionPlaneActive" + i + ") {");
  279. src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);");
  280. src.push(" }");
  281. }
  282. src.push(" if (dist > 0.0) { discard; }");
  283. src.push(" }");
  284. }
  285. if (SNAPPING_LOG_DEPTH_BUF_ENABLED) {
  286. src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;");
  287. }
  288. src.push("outCoords = ivec4(relativeToOriginPosition.xyz*coordinateScaler.xyz, layerNumber);")
  289. src.push("}");
  290. return src;
  291. }
  292.  
  293. webglContextRestored() {
  294. this._program = null;
  295. }
  296.  
  297. destroy() {
  298. if (this._program) {
  299. this._program.destroy();
  300. }
  301. this._program = null;
  302. }
  303. }