import Cartesian2 from "../Core/Cartesian2.js"; import Check from "../Core/Check.js"; import ClippingPlaneCollection from "./ClippingPlaneCollection.js"; var textureResolutionScratch = new Cartesian2(); /** * Gets the GLSL functions needed to retrieve clipping planes from a ClippingPlaneCollection's texture. * * @param {ClippingPlaneCollection} clippingPlaneCollection ClippingPlaneCollection with a defined texture. * @param {Context} context The current rendering context. * @returns {String} A string containing GLSL functions for retrieving clipping planes. * @private */ function getClippingFunction(clippingPlaneCollection, context) { //>>includeStart('debug', pragmas.debug); Check.typeOf.object("clippingPlaneCollection", clippingPlaneCollection); Check.typeOf.object("context", context); //>>includeEnd('debug'); var unionClippingRegions = clippingPlaneCollection.unionClippingRegions; var clippingPlanesLength = clippingPlaneCollection.length; var usingFloatTexture = ClippingPlaneCollection.useFloatTexture(context); var textureResolution = ClippingPlaneCollection.getTextureResolution( clippingPlaneCollection, context, textureResolutionScratch ); var width = textureResolution.x; var height = textureResolution.y; var functions = usingFloatTexture ? getClippingPlaneFloat(width, height) : getClippingPlaneUint8(width, height); functions += "\n"; functions += unionClippingRegions ? clippingFunctionUnion(clippingPlanesLength) : clippingFunctionIntersect(clippingPlanesLength); return functions; } function clippingFunctionUnion(clippingPlanesLength) { var functionString = "float clip(vec4 fragCoord, sampler2D clippingPlanes, mat4 clippingPlanesMatrix)\n" + "{\n" + " vec4 position = czm_windowToEyeCoordinates(fragCoord);\n" + " vec3 clipNormal = vec3(0.0);\n" + " vec3 clipPosition = vec3(0.0);\n" + " float clipAmount;\n" + // For union planes, we want to get the min distance. So we set the initial value to the first plane distance in the loop below. " float pixelWidth = czm_metersPerPixel(position);\n" + " bool breakAndDiscard = false;\n" + " for (int i = 0; i < " + clippingPlanesLength + "; ++i)\n" + " {\n" + " vec4 clippingPlane = getClippingPlane(clippingPlanes, i, clippingPlanesMatrix);\n" + " clipNormal = clippingPlane.xyz;\n" + " clipPosition = -clippingPlane.w * clipNormal;\n" + " float amount = dot(clipNormal, (position.xyz - clipPosition)) / pixelWidth;\n" + " clipAmount = czm_branchFreeTernary(i == 0, amount, min(amount, clipAmount));\n" + " if (amount <= 0.0)\n" + " {\n" + " breakAndDiscard = true;\n" + " break;\n" + // HLSL compiler bug if we discard here: https://bugs.chromium.org/p/angleproject/issues/detail?id=1945#c6 " }\n" + " }\n" + " if (breakAndDiscard) {\n" + " discard;\n" + " }\n" + " return clipAmount;\n" + "}\n"; return functionString; } function clippingFunctionIntersect(clippingPlanesLength) { var functionString = "float clip(vec4 fragCoord, sampler2D clippingPlanes, mat4 clippingPlanesMatrix)\n" + "{\n" + " bool clipped = true;\n" + " vec4 position = czm_windowToEyeCoordinates(fragCoord);\n" + " vec3 clipNormal = vec3(0.0);\n" + " vec3 clipPosition = vec3(0.0);\n" + " float clipAmount = 0.0;\n" + " float pixelWidth = czm_metersPerPixel(position);\n" + " for (int i = 0; i < " + clippingPlanesLength + "; ++i)\n" + " {\n" + " vec4 clippingPlane = getClippingPlane(clippingPlanes, i, clippingPlanesMatrix);\n" + " clipNormal = clippingPlane.xyz;\n" + " clipPosition = -clippingPlane.w * clipNormal;\n" + " float amount = dot(clipNormal, (position.xyz - clipPosition)) / pixelWidth;\n" + " clipAmount = max(amount, clipAmount);\n" + " clipped = clipped && (amount <= 0.0);\n" + " }\n" + " if (clipped)\n" + " {\n" + " discard;\n" + " }\n" + " return clipAmount;\n" + "}\n"; return functionString; } function getClippingPlaneFloat(width, height) { var pixelWidth = 1.0 / width; var pixelHeight = 1.0 / height; var pixelWidthString = pixelWidth + ""; if (pixelWidthString.indexOf(".") === -1) { pixelWidthString += ".0"; } var pixelHeightString = pixelHeight + ""; if (pixelHeightString.indexOf(".") === -1) { pixelHeightString += ".0"; } var functionString = "vec4 getClippingPlane(highp sampler2D packedClippingPlanes, int clippingPlaneNumber, mat4 transform)\n" + "{\n" + " int pixY = clippingPlaneNumber / " + width + ";\n" + " int pixX = clippingPlaneNumber - (pixY * " + width + ");\n" + " float u = (float(pixX) + 0.5) * " + pixelWidthString + ";\n" + // sample from center of pixel " float v = (float(pixY) + 0.5) * " + pixelHeightString + ";\n" + " vec4 plane = texture2D(packedClippingPlanes, vec2(u, v));\n" + " return czm_transformPlane(plane, transform);\n" + "}\n"; return functionString; } function getClippingPlaneUint8(width, height) { var pixelWidth = 1.0 / width; var pixelHeight = 1.0 / height; var pixelWidthString = pixelWidth + ""; if (pixelWidthString.indexOf(".") === -1) { pixelWidthString += ".0"; } var pixelHeightString = pixelHeight + ""; if (pixelHeightString.indexOf(".") === -1) { pixelHeightString += ".0"; } var functionString = "vec4 getClippingPlane(highp sampler2D packedClippingPlanes, int clippingPlaneNumber, mat4 transform)\n" + "{\n" + " int clippingPlaneStartIndex = clippingPlaneNumber * 2;\n" + // clipping planes are two pixels each " int pixY = clippingPlaneStartIndex / " + width + ";\n" + " int pixX = clippingPlaneStartIndex - (pixY * " + width + ");\n" + " float u = (float(pixX) + 0.5) * " + pixelWidthString + ";\n" + // sample from center of pixel " float v = (float(pixY) + 0.5) * " + pixelHeightString + ";\n" + " vec4 oct32 = texture2D(packedClippingPlanes, vec2(u, v)) * 255.0;\n" + " vec2 oct = vec2(oct32.x * 256.0 + oct32.y, oct32.z * 256.0 + oct32.w);\n" + " vec4 plane;\n" + " plane.xyz = czm_octDecode(oct, 65535.0);\n" + " plane.w = czm_unpackFloat(texture2D(packedClippingPlanes, vec2(u + " + pixelWidthString + ", v)));\n" + " return czm_transformPlane(plane, transform);\n" + "}\n"; return functionString; } export default getClippingFunction;