UNPKG

@itwin/core-frontend

Version:
167 lines (155 loc) • 8.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.addApplyContours = addApplyContours; /*--------------------------------------------------------------------------------------------- * 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 */ const core_common_1 = require("@itwin/core-common"); const RenderFlags_1 = require("../RenderFlags"); const FeatureSymbology_1 = require("./FeatureSymbology"); const Vertex_1 = require("./Vertex"); const Decode_1 = require("./Decode"); const computeContourNdx = ` if (u_contourLUTWidth == 0u) return 15.0; uint lutIndex = uint(getFeatureIndex()); bool odd = bool(lutIndex & 1u); lutIndex /= 2u; uint byteSel = lutIndex & 0x3u; lutIndex /= 4u; ivec2 coords = ivec2(lutIndex % u_contourLUTWidth, lutIndex / u_contourLUTWidth); uvec4 contourNdx4 = uvec4(texelFetch(u_contourLUT, coords, 0) * 255.0 + 0.5); uvec2 contourNdx2 = bool(byteSel & 2u) ? contourNdx4.ba : contourNdx4.rg; uint contourNdx = bool(byteSel & 1u) ? contourNdx2.g : contourNdx2.r; return float(odd ? contourNdx >> 4u : contourNdx & 0xFu); `; const unpack2BytesVec4 = ` vec4 unpack2BytesVec4(vec4 f, bool upper) { f = floor(f + 0.5); vec4 outUpper = floor(f / 256.0); vec4 outLower = floor(f - outUpper * 256.0); return upper ? outUpper : outLower; } `; const unpackAndNormalize2BytesVec4 = ` vec4 unpackAndNormalize2BytesVec4(vec4 f, bool upper) { return unpack2BytesVec4(f, upper) / 255.0; } `; const encodeContourLineInfo = ` void encodeContourLineInfo(int groupIndex, bool isMajor, float interval) { // ContourDisplay.maxContourGroups is currently 5. Must change this code if that changes. float groupIndexAndType = float(groupIndex + (isMajor ? 16 : 8)); // Find nearest multiple of interval to pixel world height. float elevation = (v_height >= 0.0 ? floor((v_height + interval / 2.0) / interval) : ceil((v_height - interval / 2.0) / interval)) * interval; // Convert elevation to a fraction of the frustum's world Z extents elevation = clamp((elevation - u_worldFrustumZRange.x) / (u_worldFrustumZRange.y - u_worldFrustumZRange.x), 0.0, 1.0); // Encode elevation in RGB and the rest of the info in A g_contourLineInfo = vec4(groupIndexAndType * 0.03125, encodeDepthRgb(elevation)); } `; const applyContours = ` int contourNdx = int(v_contourNdx + 0.5); if (contourNdx > 14) // 15 => no contours return baseColor; const int maxDefs = ${core_common_1.ContourDisplay.maxContourGroups}; // max number of contour definitions allowed, have to change index arrays if this changes int contourNdxC = clamp(contourNdx, 0, maxDefs - 1); bool even = (contourNdxC & 1) == 0; vec4 rgbfp = u_contourDefs[even ? contourNdxC * 3 / 2 : (contourNdxC - 1) * 3 / 2 + 2]; vec4 intervalsPair = u_contourDefs[(contourNdxC / 2) * 3 + 1]; // intervals.r => minor interval distance, intervals.g => major index count vec2 intervals = even ? intervalsPair.rg : intervalsPair.ba; float coord = v_height / intervals.r; // determine if this is in the vicinity of a major contour line (1/2 an interval either way, which is one limit of drawing width) bool maj = (fract((abs(coord) + 0.5) / intervals.g) < (1.0 / intervals.g)); vec4 rgbf = unpackAndNormalize2BytesVec4(rgbfp, maj); // rgbf.a => (4-bit linecode / 4-bit weight) maj/min, where the 4-bit weight is a 3-bit weight value with one fraction bit and a 1.5 offset. // This gives a weight range of 1.5 to 9 in 0.5 increments. // NB: the showGeometry bit flag is stuck in at bit 16 of this, so the major line code has an extra bit in it that needs to be masked out int lineCodeWt = int((rgbf.a * 255.0) + 0.5); // first * 0.5 is for fractional part of width, then have to add 1.0 for offset, then another 1.0 for actual width bias float lineRadius = (float(lineCodeWt & 0xf) * 0.5 + 2.0) * 0.5; // abs(fract(coord - 0.5) - 0.5) will produce 0.0 at the contour line, and 0.5 at the mid-point between contour lines // fwidth(coord) is sum of absolute diffs in coord in adjacent pixels float line = abs(fract(coord - 0.5) - 0.5) / fwidth(coord); // If line is 0 (like at contour line), contourAlpha = lineRadius, so will use draw in contour color // If line >= lineRadius, contourAlpha = 0, so won't show contour float contourAlpha = lineRadius - min(line, lineRadius); // figure out which direction line is going, to know which screen pattern offset to use float dx = dFdx(contourAlpha); float dy = dFdy(contourAlpha); const float patLength = 32.0; uint patterns[10] = uint[](0xffffffffu, 0x80808080u, 0xf8f8f8f8u, 0xffe0ffe0u, 0xfe10fe10u, 0xe0e0e0e0u, 0xf888f888u, 0xff18ff18u, 0xccccccccu, 0x00000001u); float offset = trunc((abs(dx) > abs(dy)) ? gl_FragCoord.y : gl_FragCoord.x); offset = mod(offset, patLength); uint msk = 1u << uint(offset); contourAlpha *= (patterns[(lineCodeWt / 16) & 0xf] & msk) > 0u ? 1.0 : 0.0; contourAlpha = min(contourAlpha, 1.0); bool isContourLine = contourAlpha >= 0.5; if (isContourLine) encodeContourLineInfo(contourNdxC, maj, intervals.r); if (rgbfp.a / 65536.0 < 0.5) { // showGeometry == 0 if (!isContourLine) discard; return vec4(rgbf.rgb, 1.0); } // set contour opaque even if base color is transparent float alpha = contourAlpha >= 0.5 ? 1.0 : baseColor.a; return vec4(mix(baseColor.rgb, rgbf.rgb, contourAlpha), alpha); `; /** @internal */ function addApplyContours(builder) { const modelPos = builder.vert.usesInstancedGeometry ? "(g_instancedRtcMatrix * rawPosition)" : "rawPosition"; const computeWorldHeight = ` float computeWorldHeight(vec4 rawPosition) { float height = (u_modelToWorldC * ${modelPos}).z; // TODO: apply ECEF correction to height return height; } `; (0, FeatureSymbology_1.addFeatureIndex)(builder.vert); builder.addFunctionComputedVarying("v_contourNdx", 2 /* VariableType.Float */, "computeContourNdx", computeContourNdx); builder.addFunctionComputedVaryingWithArgs("v_height", 2 /* VariableType.Float */, "computeWorldHeight(rawPosition)", computeWorldHeight); if (builder.vert.usesInstancedGeometry) (0, Vertex_1.addInstancedRtcMatrix)(builder.vert); builder.vert.addUniform("u_contourLUT", 8 /* VariableType.Sampler2D */, (prog) => { prog.addGraphicUniform("u_contourLUT", (uniform, params) => { // set this uniform here so that it won't cause problems (e.g.: loopback) if it does not end up being set by bindContourLUT call uniform.setUniform1i(RenderFlags_1.TextureUnit.Contours - RenderFlags_1.TextureUnit.Zero); params.target.uniforms.batch.bindContourLUT(uniform); }); }); builder.vert.addUniform("u_contourLUTWidth", 10 /* VariableType.Uint */, (prog) => { prog.addGraphicUniform("u_contourLUTWidth", (uniform, params) => { params.target.uniforms.batch.bindContourLUTWidth(uniform); }); }); builder.vert.addUniform("u_modelToWorldC", 7 /* VariableType.Mat4 */, (prog) => { prog.addGraphicUniform("u_modelToWorldC", (uniform, params) => { params.target.uniforms.branch.bindModelToWorldTransform(uniform, params.geometry, false); }); }); builder.frag.addUniform("u_worldFrustumZRange", 3 /* VariableType.Vec2 */, (prog) => { prog.addProgramUniform("u_worldFrustumZRange", (uniform, params) => { uniform.setUniform2fv(params.target.uniforms.frustum.worldFrustumZRange); }); }); const contourDefsSize = 8; builder.frag.addUniformArray("u_contourDefs", 5 /* VariableType.Vec4 */, contourDefsSize, (prog) => { prog.addGraphicUniform("u_contourDefs", (uniform, params) => { params.target.uniforms.contours.bindcontourDefs(uniform); }); }); builder.frag.addGlobal("g_contourLineInfo", 5 /* VariableType.Vec4 */, "vec4(0.0)"); builder.frag.addFunction(Decode_1.encodeDepthRgb); builder.frag.addFunction(encodeContourLineInfo); builder.frag.addFunction(unpack2BytesVec4); builder.frag.addFunction(unpackAndNormalize2BytesVec4); builder.frag.set(11 /* FragmentShaderComponent.ApplyContours */, applyContours); builder.frag.set(23 /* FragmentShaderComponent.ComputeContourLineInfo */, "return g_contourLineInfo;"); } //# sourceMappingURL=Contours.js.map