Reference Source

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