UNPKG

@itwin/core-frontend

Version:
282 lines (260 loc) • 12.2 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module WebGL */ Object.defineProperty(exports, "__esModule", { value: true }); exports.addEdgeContrast = addEdgeContrast; exports.createEdgeBuilder = createEdgeBuilder; const core_bentley_1 = require("@itwin/core-bentley"); const AttributeMap_1 = require("../AttributeMap"); const ShaderBuilder_1 = require("../ShaderBuilder"); const RenderFlags_1 = require("../RenderFlags"); const Animation_1 = require("./Animation"); const Color_1 = require("./Color"); const Common_1 = require("./Common"); const Fragment_1 = require("./Fragment"); const Polyline_1 = require("./Polyline"); const Surface_1 = require("./Surface"); const Vertex_1 = require("./Vertex"); const Viewport_1 = require("./Viewport"); const LookupTable_1 = require("./LookupTable"); const FeatureSymbology_1 = require("./FeatureSymbology"); const computeOtherPos = ` g_otherPos = samplePosition(g_otherIndex); `; const decodeEndPointAndQuadIndices = ` g_otherIndex = decodeUInt24(a_endPointAndQuadIndices.xyz); ${computeOtherPos} g_quadIndex = a_endPointAndQuadIndices.w; `; const animateEndPoint = `g_otherPos.xyz += computeAnimationDisplacement(g_otherIndex, u_animDispParams.x, u_animDispParams.y, u_animDispParams.z, u_qAnimDispOrigin, u_qAnimDispScale);`; // a_pos is a 24-bit index into edge lookup table. // First six bytes of lookup table entry are the pair of 24-bit indices identifying the endpoints of the edge in the vertex table. // Return the 24-bit index of "this" vertex in the vertex table encoded in a vec3. const computeIndexedQuantizedPosition = ` g_vertexId = gl_VertexID % 6; if (g_vertexId == 0) g_quadIndex = 0.0; else if (g_vertexId == 2 || g_vertexId == 3) g_quadIndex = 1.0; else if (g_vertexId == 1 || g_vertexId == 4) g_quadIndex = 2.0; else g_quadIndex = 3.0; // The following formula computes the texel index, but suffers from precision issues for large edge indices, so we must compute using integers instead. // float edgeBaseIndex = u_edgeParams.z * 1.5 + u_edgeParams.w * 0.25 + (edgeIndex - u_edgeParams.z) * 2.5); float fEdgeIndex = decodeUInt24(a_pos); g_isSilhouette = fEdgeIndex >= u_edgeParams.z; int edgeIndex = int(fEdgeIndex); bool isEven = 0 == (edgeIndex & 1); float edgeBaseIndex; if (!g_isSilhouette) { edgeBaseIndex = float(edgeIndex + (edgeIndex / 2)); } else { // If both pad and edgeIndex produce a remainder (0.5 for each - pad is a multiple of 2), we must add one to the index to account for it. int shift = isEven ? 0 : 1; int pad = int(u_edgeParams.w); if (0 != (pad % 4)) { isEven = !isEven; shift = shift + 1; } // s = num segments p = num padding bytes i = edge index // texel index = 1.5s + .25p + 2.5(i - s) = 1.5s + .25p + 2.5i - 2.5s = 2.5i + .25p - s = i + i + i/2 + p/4 - s edgeBaseIndex = float(edgeIndex + edgeIndex + edgeIndex / 2 + pad / 4 - int(u_edgeParams.z) + shift / 2); } vec2 tc = compute_edge_coords(floor(edgeBaseIndex)); vec4 s0 = floor(TEXTURE(u_edgeLUT, tc) * 255.0 + 0.5); tc.x += g_edge_stepX; vec4 s1 = floor(TEXTURE(u_edgeLUT, tc) * 255.0 + 0.5); tc.x += g_edge_stepX; vec4 s2 = floor(TEXTURE(u_edgeLUT, tc) * 255.0 + 0.5); vec3 i0 = isEven ? s0.xyz : vec3(s0.zw, s1.x); vec3 i1 = isEven ? vec3(s0.w, s1.xy) : s1.yzw; g_otherIndexIndex = g_quadIndex < 2.0 ? i1 : i0; g_normals = isEven ? vec4(s1.zw, s2.xy) : s2; return g_quadIndex < 2.0 ? i0 : i1; `; const initializeIndexed = ` g_otherIndex = decodeUInt24(g_otherIndexIndex); ${computeOtherPos} `; // IndexedEdgeGeometry.renderOrder returns Edge or PlanarEdge. Adjust if silhouette for output to pick buffers. const computeIndexedRenderOrder = ` if (g_isSilhouette) v_renderOrder = kRenderOrder_Edge == u_renderOrder ? kRenderOrder_Silhouette : kRenderOrder_PlanarSilhouette; else v_renderOrder = u_renderOrder; `; const checkForSilhouetteDiscard = ` if (kFrustumType_Perspective != u_frustum.z) { float perpTol = 4.75e-6; return (n0.z * n1.z > perpTol); // orthographic. } else { float perpTol = 2.5e-4; vec4 viewPos = MAT_MV * rawPos; // perspective vec3 toEye = normalize(viewPos.xyz); float dot0 = dot(n0, toEye); float dot1 = dot(n1, toEye); if (dot0 * dot1 > perpTol) return true; // Need to discard if either is non-silhouette. vec4 otherPosition = g_otherPos; viewPos = MAT_MV * otherPosition; toEye = normalize(viewPos.xyz); dot0 = dot(n0, toEye); dot1 = dot(n1, toEye); return dot0 * dot1 > perpTol; } `; const checkForSilhouetteDiscardNonIndexed = ` vec3 n0 = MAT_NORM * octDecodeNormal(a_normals.xy); vec3 n1 = MAT_NORM * octDecodeNormal(a_normals.zw); ${checkForSilhouetteDiscard} `; const checkForSilhouetteDiscardIndexed = ` if (!g_isSilhouette) return false; vec3 n0 = MAT_NORM * octDecodeNormal(g_normals.xy); vec3 n1 = MAT_NORM * octDecodeNormal(g_normals.zw); ${checkForSilhouetteDiscard} `; const computePosition = ` v_lnInfo = vec4(0.0, 0.0, 0.0, 0.0); // init and set flag to false vec4 other = g_otherPos; float miterAdjust = 0.0; float weight = computeLineWeight(); vec4 pos; g_windowPos = modelToWindowCoordinates(rawPos, other, pos, v_eyeSpace); if (g_windowPos.w == 0.0) // Clipped out. return g_windowPos; vec4 otherPos; vec3 otherMvPos; vec4 projOther = modelToWindowCoordinates(other, rawPos, otherPos, otherMvPos); g_windowDir = projOther.xy - g_windowPos.xy; adjustWidth(weight, g_windowDir, g_windowPos.xy); g_windowDir = normalize(g_windowDir); vec2 perp = vec2(-g_windowDir.y, g_windowDir.x); float perpDist = weight / 2.0; float alongDist = 0.0; perpDist *= sign(0.5 - float(g_quadIndex == 0.0 || g_quadIndex == 3.0)); // negate for index 0 and 3 alongDist += distance(rawPos, other) * float(g_quadIndex >= 2.0); // index 2 and 3 correspond to 'far' endpoint of segment pos.x += perp.x * perpDist * 2.0 * pos.w / u_viewport.x; pos.y += perp.y * perpDist * 2.0 * pos.w / u_viewport.y; lineCodeEyePos = .5 * (rawPos + other); lineCodeDist = alongDist; return pos; `; const lineCodeArgs = "g_windowDir, g_windowPos, 0.0"; const adjustContrast = ` float bgi = u_bgIntensity; if (bgi < 0.0) return baseColor; float s; float rgbi = baseColor.r * 0.3 + baseColor.g * 0.59 + baseColor.b * 0.11; if (rgbi > 0.81) s = bgi > 0.57 ? 0.0 : 0.699; else if (rgbi > 0.57) s = bgi > 0.57 ? 0.0 : 1.0; else s = bgi < 0.81 ? 1.0 : 0.699; return vec4(vec3(s), baseColor.a); `; /** @internal */ function addEdgeContrast(vert) { vert.addUniform("u_bgIntensity", 2 /* VariableType.Float */, (prog) => { prog.addGraphicUniform("u_bgIntensity", (uniform, params) => { let bgi = -1; if (params.geometry.isEdge && params.target.currentEdgeSettings.wantContrastingColor(params.target.currentViewFlags.renderMode)) bgi = params.target.uniforms.style.backgroundIntensity; uniform.setUniform1f(bgi); }); }); vert.set(8 /* VertexShaderComponent.AdjustContrast */, adjustContrast); } const edgeLutParams = new Float32Array(4); function createBase(type, instanced, isAnimated, positionType) { const isInstanced = 1 /* IsInstanced.Yes */ === instanced; const isSilhouette = "Silhouette" === type; const isIndexed = "IndexedEdge" === type; const techId = isSilhouette ? 5 /* TechniqueId.SilhouetteEdge */ : (isIndexed ? 6 /* TechniqueId.IndexedEdge */ : 4 /* TechniqueId.Edge */); const attrMap = AttributeMap_1.AttributeMap.findAttributeMap(techId, isInstanced); const builder = new ShaderBuilder_1.ProgramBuilder(attrMap, { positionType, instanced: isInstanced }); const vert = builder.vert; vert.addGlobal("g_otherPos", 5 /* VariableType.Vec4 */); vert.addGlobal("g_quadIndex", 2 /* VariableType.Float */); vert.addGlobal("g_windowPos", 5 /* VariableType.Vec4 */); vert.addGlobal("g_windowDir", 3 /* VariableType.Vec2 */); vert.addGlobal("g_otherIndex", 2 /* VariableType.Float */); (0, Vertex_1.addSamplePosition)(vert); if (isIndexed) { vert.addGlobal("g_vertexId", 1 /* VariableType.Int */); vert.addGlobal("g_otherIndexIndex", 4 /* VariableType.Vec3 */); vert.addGlobal("g_isSilhouette", 0 /* VariableType.Boolean */, "false"); vert.addGlobal("g_normals", 5 /* VariableType.Vec4 */); const initLut = (0, LookupTable_1.addLookupTable)(vert, "edge", "1.0"); vert.addUniform("u_edgeLUT", 8 /* VariableType.Sampler2D */, (prog) => { prog.addGraphicUniform("u_edgeLUT", (uniform, params) => { const edge = params.geometry.asIndexedEdge; (0, core_bentley_1.assert)(undefined !== edge); edge.edgeLut.texture.bindSampler(uniform, RenderFlags_1.TextureUnit.EdgeLUT); }); }); vert.addUniform("u_edgeParams", 5 /* VariableType.Vec4 */, (prog) => { prog.addGraphicUniform("u_edgeParams", (uniform, params) => { const edge = params.geometry.asIndexedEdge; (0, core_bentley_1.assert)(undefined !== edge); edgeLutParams[0] = edge.edgeLut.texture.width; edgeLutParams[1] = edge.edgeLut.texture.height; edgeLutParams[2] = edge.edgeLut.numSegments; edgeLutParams[3] = edge.edgeLut.silhouettePadding; uniform.setUniform4fv(edgeLutParams); }); }); vert.set(0 /* VertexShaderComponent.ComputeQuantizedPosition */, `${initLut}\n\n${computeIndexedQuantizedPosition}`); vert.addInitializer(initializeIndexed); (0, FeatureSymbology_1.addRenderOrder)(vert); (0, FeatureSymbology_1.addRenderOrderConstants)(vert); builder.addInlineComputedVarying("v_renderOrder", 2 /* VariableType.Float */, computeIndexedRenderOrder); builder.frag.set(22 /* FragmentShaderComponent.OverrideRenderOrder */, "return v_renderOrder;"); } else { vert.addInitializer(decodeEndPointAndQuadIndices); } if (isAnimated) { (0, Animation_1.addAnimation)(vert, false); vert.addInitializer(animateEndPoint); } vert.addGlobal("lineCodeEyePos", 5 /* VariableType.Vec4 */); vert.addGlobal("lineCodeDist", 2 /* VariableType.Float */, "0.0"); (0, Viewport_1.addModelToWindowCoordinates)(vert); // adds u_mvp, u_viewportTransformation, and sets g_eyeSpace (0, Vertex_1.addProjectionMatrix)(vert); (0, Polyline_1.addLineCode)(builder, lineCodeArgs); builder.addVarying("v_eyeSpace", 4 /* VariableType.Vec3 */); vert.set(10 /* VertexShaderComponent.ComputePosition */, computePosition); builder.addVarying("v_lnInfo", 5 /* VariableType.Vec4 */); (0, Polyline_1.addAdjustWidth)(vert); (0, Viewport_1.addViewport)(vert); (0, Vertex_1.addModelViewMatrix)(vert); (0, Vertex_1.addLineWeight)(vert); if (isSilhouette || isIndexed) { (0, Vertex_1.addNormalMatrix)(vert); (0, Common_1.addFrustum)(builder); vert.addFunction(Surface_1.octDecodeNormal); vert.set(2 /* VertexShaderComponent.CheckForEarlyDiscard */, isSilhouette ? checkForSilhouetteDiscardNonIndexed : checkForSilhouetteDiscardIndexed); } return builder; } /** @internal */ function createEdgeBuilder(type, instanced, isAnimated, posType) { const builder = createBase(type, instanced, isAnimated, posType); (0, Common_1.addShaderFlags)(builder); (0, Color_1.addColor)(builder); addEdgeContrast(builder.vert); (0, Fragment_1.addWhiteOnWhiteReversal)(builder.frag); return builder; } //# sourceMappingURL=Edge.js.map