Reference Source

src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesSnapRenderer.js

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