@cesium/engine 21.0.1 → 22.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Build/Workers/{chunk-LPKJSIMD.js → chunk-2D3GLFZD.js} +12 -12
- package/Build/Workers/chunk-34YXP222.js +352 -0
- package/Build/Workers/{chunk-UKA7OISV.js → chunk-3GL53OCU.js} +17 -18
- package/Build/Workers/{chunk-WQZL6CA2.js → chunk-5B7VZQZY.js} +6 -6
- package/Build/Workers/{chunk-FE565QHX.js → chunk-5T5SY63I.js} +2 -2
- package/Build/Workers/{chunk-RR3NCT4R.js → chunk-5ZF53EY6.js} +4 -4
- package/Build/Workers/{chunk-PZUZCAX3.js → chunk-6HBKE43B.js} +7 -7
- package/Build/Workers/{chunk-5YXA47QD.js → chunk-726NINF5.js} +16 -16
- package/Build/Workers/{chunk-3RKX3UFI.js → chunk-75HAJIDT.js} +1 -1
- package/Build/Workers/{chunk-CBPNIEGH.js → chunk-7KAXDKRU.js} +10 -10
- package/Build/Workers/chunk-7XEJGXX2.js +2759 -0
- package/Build/Workers/{chunk-U2GR5FDL.js → chunk-A4DPJIWS.js} +18 -10
- package/Build/Workers/{chunk-G3CKZ34K.js → chunk-A6JAFSZT.js} +5 -5
- package/Build/Workers/{chunk-2SI7DEW5.js → chunk-AARZSH4V.js} +5 -5
- package/Build/Workers/{chunk-W6KMV4F5.js → chunk-AOM3FHBN.js} +6 -6
- package/Build/Workers/{chunk-VVALNLSH.js → chunk-BJSNGGBM.js} +4 -4
- package/Build/Workers/{chunk-3YNW5K6O.js → chunk-ECHAJNQJ.js} +12 -12
- package/Build/Workers/{chunk-KZ7GDSAJ.js → chunk-EJO3NKMS.js} +1 -1
- package/Build/Workers/{chunk-UFSYRVC5.js → chunk-EZ7NJXQN.js} +4 -4
- package/Build/Workers/{chunk-P2UKEFCK.js → chunk-FA3SCJDX.js} +2 -2
- package/Build/Workers/{chunk-MXOGBWMP.js → chunk-GYRDA3XK.js} +14 -14
- package/Build/Workers/{chunk-KVB73ECP.js → chunk-H7B7FU2U.js} +7 -7
- package/Build/Workers/{chunk-XJVRYJVZ.js → chunk-IGX772ZQ.js} +1 -1
- package/Build/Workers/{chunk-MQPDOWGH.js → chunk-JDJAPBZP.js} +1 -1
- package/Build/Workers/{chunk-DDXI6UYW.js → chunk-JZFU2LEM.js} +4 -4
- package/Build/Workers/{chunk-DAJKOQW6.js → chunk-KGLDJRSO.js} +9 -9
- package/Build/Workers/{chunk-CSDYSXBI.js → chunk-KUB64XW6.js} +11 -11
- package/Build/Workers/{chunk-X3ZV3XNO.js → chunk-L7U26FFD.js} +16 -16
- package/Build/Workers/{chunk-YZ3RCE45.js → chunk-LEFQBK6H.js} +11 -11
- package/Build/Workers/{chunk-KEPPNSBL.js → chunk-LWJXCI3F.js} +5 -5
- package/Build/Workers/{chunk-YNOVMSUX.js → chunk-M7HRE4QR.js} +8 -8
- package/Build/Workers/{chunk-ASVODZNK.js → chunk-MXHRZHDF.js} +6 -6
- package/Build/Workers/{chunk-PJAA7QSC.js → chunk-N52ZRKUE.js} +6 -6
- package/Build/Workers/{chunk-W6I3LNPF.js → chunk-NE5JTQJP.js} +7 -7
- package/Build/Workers/{chunk-XG54SG4O.js → chunk-NGKF5NTR.js} +5 -5
- package/Build/Workers/{chunk-42EJCSIV.js → chunk-NHZNMTIR.js} +5 -5
- package/Build/Workers/{chunk-LU7DLY2L.js → chunk-OE22564R.js} +3 -3
- package/Build/Workers/{chunk-A2SP2EJZ.js → chunk-OUBBMEWX.js} +6 -6
- package/Build/Workers/{chunk-J2XQVKVH.js → chunk-P2H75UV5.js} +67 -33
- package/Build/Workers/{chunk-J3KPR6DJ.js → chunk-QCMRUVVF.js} +12 -12
- package/Build/Workers/{chunk-RVRN4KDB.js → chunk-QSMIHPUM.js} +2 -2
- package/Build/Workers/{chunk-EBDZDBJN.js → chunk-RCCYW6E7.js} +12 -12
- package/Build/Workers/{chunk-LV3G32QE.js → chunk-RQRODXVN.js} +4 -4
- package/Build/Workers/{chunk-OBS5EMZ6.js → chunk-SZN34LQ5.js} +10 -10
- package/Build/Workers/{chunk-IKUOV6DO.js → chunk-U4XMLGSR.js} +7 -7
- package/Build/Workers/{chunk-NYYQZ3LH.js → chunk-U7CX3HHE.js} +8 -8
- package/Build/Workers/{chunk-QNOIRRJK.js → chunk-VCVA7BMD.js} +4 -4
- package/Build/Workers/{chunk-TGJQMEL4.js → chunk-VVZ667H6.js} +2 -2
- package/Build/Workers/{chunk-DBHL2UVG.js → chunk-W4PIP5PG.js} +2 -2
- package/Build/Workers/{chunk-2QPH5QDK.js → chunk-XPVZWY4A.js} +8 -8
- package/Build/Workers/{chunk-4CORGH7N.js → chunk-XQ347YWU.js} +13 -13
- package/Build/Workers/{chunk-T7HU6E7G.js → chunk-XZO6F23E.js} +1 -1
- package/Build/Workers/{chunk-DTKSVIH5.js → chunk-YLILBDWK.js} +2 -2
- package/Build/Workers/{chunk-JG3C3LPY.js → chunk-YLXWC7OW.js} +4 -4
- package/Build/Workers/combineGeometry.js +21 -21
- package/Build/Workers/createBoxGeometry.js +15 -15
- package/Build/Workers/createBoxOutlineGeometry.js +13 -13
- package/Build/Workers/createCircleGeometry.js +23 -23
- package/Build/Workers/createCircleOutlineGeometry.js +16 -16
- package/Build/Workers/createCoplanarPolygonGeometry.js +30 -30
- package/Build/Workers/createCoplanarPolygonOutlineGeometry.js +28 -28
- package/Build/Workers/createCorridorGeometry.js +26 -26
- package/Build/Workers/createCorridorOutlineGeometry.js +25 -25
- package/Build/Workers/createCylinderGeometry.js +17 -17
- package/Build/Workers/createCylinderOutlineGeometry.js +15 -15
- package/Build/Workers/createEllipseGeometry.js +23 -23
- package/Build/Workers/createEllipseOutlineGeometry.js +16 -16
- package/Build/Workers/createEllipsoidGeometry.js +16 -16
- package/Build/Workers/createEllipsoidOutlineGeometry.js +15 -15
- package/Build/Workers/createFrustumGeometry.js +15 -15
- package/Build/Workers/createFrustumOutlineGeometry.js +15 -15
- package/Build/Workers/createGeometry.js +24 -22
- package/Build/Workers/createGroundPolylineGeometry.js +19 -19
- package/Build/Workers/createPlaneGeometry.js +13 -13
- package/Build/Workers/createPlaneOutlineGeometry.js +12 -12
- package/Build/Workers/createPolygonGeometry.js +29 -29
- package/Build/Workers/createPolygonOutlineGeometry.js +27 -27
- package/Build/Workers/createPolylineGeometry.js +22 -22
- package/Build/Workers/createPolylineVolumeGeometry.js +28 -28
- package/Build/Workers/createPolylineVolumeOutlineGeometry.js +24 -24
- package/Build/Workers/createRectangleGeometry.js +24 -24
- package/Build/Workers/createRectangleOutlineGeometry.js +17 -17
- package/Build/Workers/createSimplePolylineGeometry.js +20 -20
- package/Build/Workers/createSphereGeometry.js +16 -16
- package/Build/Workers/createSphereOutlineGeometry.js +15 -15
- package/Build/Workers/createTaskProcessorWorker.js +3 -3
- package/Build/Workers/createVectorTileClampedPolylines.js +12 -12
- package/Build/Workers/createVectorTileGeometries.js +21 -21
- package/Build/Workers/createVectorTilePoints.js +11 -11
- package/Build/Workers/createVectorTilePolygons.js +19 -19
- package/Build/Workers/createVectorTilePolylines.js +12 -12
- package/Build/Workers/createVerticesFromCesium3DTilesTerrain.js +88 -0
- package/Build/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +21 -21
- package/Build/Workers/createVerticesFromHeightmap.js +21 -21
- package/Build/Workers/createVerticesFromQuantizedTerrainMesh.js +19 -277
- package/Build/Workers/createWallGeometry.js +21 -21
- package/Build/Workers/createWallOutlineGeometry.js +20 -20
- package/Build/Workers/decodeDraco.js +10 -10
- package/Build/Workers/decodeGoogleEarthEnterprisePacket.js +5 -5
- package/Build/Workers/decodeI3S.js +9 -9
- package/Build/Workers/gaussianSplatSorter.js +4 -4
- package/Build/Workers/gaussianSplatTextureGenerator.js +4 -4
- package/Build/Workers/transcodeKTX2.js +6 -6
- package/Build/Workers/transferTypedArrayTest.js +1 -1
- package/Build/Workers/upsampleQuantizedTerrainMesh.js +19 -19
- package/Build/Workers/upsampleVerticesFromCesium3DTilesTerrain.js +92 -0
- package/Source/Core/ArcGISTiledElevationTerrainProvider.js +2 -2
- package/Source/Core/Cesium3DTilesTerrainData.js +930 -0
- package/Source/Core/Cesium3DTilesTerrainGeometryProcessor.js +1866 -0
- package/Source/Core/Cesium3DTilesTerrainProvider.js +1052 -0
- package/Source/Core/CesiumTerrainProvider.js +2 -2
- package/Source/Core/Color.js +23 -6
- package/Source/Core/EllipsoidalOccluder.js +2 -2
- package/Source/Core/FeatureDetection.js +0 -2
- package/Source/Core/GoogleEarthEnterpriseMetadata.js +1 -1
- package/Source/Core/GoogleEarthEnterpriseTerrainData.js +1 -1
- package/Source/Core/GoogleEarthEnterpriseTerrainProvider.js +1 -1
- package/Source/Core/HeightmapTerrainData.js +10 -22
- package/Source/Core/HilbertOrder.js +0 -6
- package/Source/Core/ITwinPlatform.js +6 -6
- package/Source/Core/Ion.js +1 -1
- package/Source/Core/IonResource.js +35 -27
- package/Source/Core/PixelFormat.js +2 -2
- package/Source/Core/QuantizedMeshTerrainData.js +23 -57
- package/Source/Core/Resource.js +15 -11
- package/Source/Core/S2Cell.js +6 -18
- package/Source/Core/TaskProcessor.js +1 -1
- package/Source/Core/TerrainData.js +2 -1
- package/Source/Core/TerrainEncoding.js +215 -38
- package/Source/Core/TerrainMesh.js +8 -8
- package/Source/Core/TerrainProvider.js +151 -0
- package/Source/Core/VRTheWorldTerrainProvider.js +2 -2
- package/Source/Core/binarySearch.js +1 -1
- package/Source/Core/createWorldBathymetryAsync.js +2 -2
- package/Source/Core/createWorldTerrainAsync.js +3 -3
- package/Source/Core/loadImageFromTypedArray.js +9 -3
- package/Source/Core/mergeSort.js +1 -1
- package/Source/DataSources/PropertyArray.js +2 -2
- package/Source/Renderer/AutomaticUniforms.js +61 -0
- package/Source/Renderer/Context.js +13 -7
- package/Source/Renderer/Pass.js +10 -9
- package/Source/Renderer/UniformState.js +12 -0
- package/Source/Renderer/VertexArray.js +1 -1
- package/Source/Scene/ArcGisMapServerImageryProvider.js +1 -1
- package/Source/Scene/ArcGisMapService.js +1 -1
- package/Source/Scene/Azure2DImageryProvider.js +7 -5
- package/Source/Scene/BatchTable.js +2 -2
- package/Source/Scene/BillboardCollection.js +25 -21
- package/Source/Scene/BingMapsImageryProvider.js +1 -1
- package/Source/Scene/BoundingVolumeSemantics.js +54 -62
- package/Source/Scene/Cesium3DTile.js +3 -3
- package/Source/Scene/Cesium3DTilesVoxelProvider.js +1 -1
- package/Source/Scene/Cesium3DTileset.js +1 -1
- package/Source/Scene/EdgeFramebuffer.js +245 -0
- package/Source/Scene/FrameState.js +12 -0
- package/Source/Scene/GaussianSplat3DTileContent.js +12 -16
- package/Source/Scene/GaussianSplatPrimitive.js +12 -8
- package/Source/Scene/GaussianSplatSorter.js +2 -2
- package/Source/Scene/Globe.js +1 -1
- package/Source/Scene/GlobeSurfaceTile.js +10 -4
- package/Source/Scene/GltfBufferViewLoader.js +18 -0
- package/Source/Scene/GltfLoader.js +46 -8
- package/Source/Scene/Google2DImageryProvider.js +39 -27
- package/Source/Scene/GoogleEarthEnterpriseMapsProvider.js +1 -1
- package/Source/Scene/I3SDataProvider.js +1 -1
- package/Source/Scene/I3SDecoder.js +3 -3
- package/Source/Scene/ITwinData.js +4 -4
- package/Source/Scene/ImageryLayer.js +1 -1
- package/Source/Scene/Implicit3DTileContent.js +18 -7
- package/Source/Scene/ImplicitSubtree.js +3 -3
- package/Source/Scene/ImplicitTileset.js +2 -2
- package/Source/Scene/IonImageryProvider.js +15 -84
- package/Source/Scene/IonImageryProviderFactory.js +194 -0
- package/Source/Scene/LabelCollection.js +54 -36
- package/Source/Scene/MetadataComponentType.js +5 -5
- package/Source/Scene/MetadataTableProperty.js +3 -9
- package/Source/Scene/Model/EdgeDetectionPipelineStage.js +42 -0
- package/Source/Scene/Model/EdgeVisibilityPipelineStage.js +800 -0
- package/Source/Scene/Model/MetadataPipelineStage.js +7 -7
- package/Source/Scene/Model/ModelDrawCommand.js +69 -0
- package/Source/Scene/Model/ModelImagery.js +4 -0
- package/Source/Scene/Model/ModelRuntimeNode.js +2 -2
- package/Source/Scene/Model/ModelRuntimePrimitive.js +13 -2
- package/Source/Scene/Model/ModelSceneGraph.js +15 -3
- package/Source/Scene/Model/ModelUtility.js +0 -1
- package/Source/Scene/Model/NodeRenderResources.js +1 -1
- package/Source/Scene/Model/PrimitiveRenderResources.js +1 -1
- package/Source/Scene/OIT.js +11 -1
- package/Source/Scene/PickFramebuffer.js +13 -17
- package/Source/Scene/Picking.js +104 -80
- package/Source/Scene/QuadtreePrimitive.js +34 -26
- package/Source/Scene/QuadtreeTile.js +66 -46
- package/Source/Scene/ResourceLoaderState.js +1 -1
- package/Source/Scene/Scene.js +124 -12
- package/Source/Scene/ScreenSpaceCameraController.js +1 -1
- package/Source/Scene/SensorVolumePortionToDisplay.js +6 -6
- package/Source/Scene/SingleTileImageryProvider.js +3 -3
- package/Source/Scene/Terrain.js +5 -5
- package/Source/Scene/TileMapServiceImageryProvider.js +2 -2
- package/Source/Scene/UrlTemplateImageryProvider.js +1 -1
- package/Source/Scene/View.js +3 -0
- package/Source/Scene/VoxelPrimitive.js +196 -189
- package/Source/Scene/VoxelShape.js +2 -0
- package/Source/Scene/createWorldImageryAsync.js +1 -1
- package/Source/Shaders/BillboardCollectionFS.glsl +102 -62
- package/Source/Shaders/BillboardCollectionFS.js +102 -63
- package/Source/Shaders/BillboardCollectionVS.glsl +44 -37
- package/Source/Shaders/BillboardCollectionVS.js +45 -38
- package/Source/Shaders/Builtin/Constants/passCesium3DTile.glsl +1 -1
- package/Source/Shaders/Builtin/Constants/passCesium3DTile.js +1 -1
- package/Source/Shaders/Builtin/Constants/passCesium3DTileClassification.glsl +1 -1
- package/Source/Shaders/Builtin/Constants/passCesium3DTileClassification.js +1 -1
- package/Source/Shaders/Builtin/Constants/passCesium3DTileClassificationIgnoreShow.glsl +1 -1
- package/Source/Shaders/Builtin/Constants/passCesium3DTileClassificationIgnoreShow.js +1 -1
- package/Source/Shaders/Builtin/Constants/passCesium3DTileEdges.glsl +10 -0
- package/Source/Shaders/Builtin/Constants/passCesium3DTileEdges.js +12 -0
- package/Source/Shaders/Builtin/Constants/passGaussianSplats.glsl +1 -1
- package/Source/Shaders/Builtin/Constants/passGaussianSplats.js +1 -1
- package/Source/Shaders/Builtin/Constants/passOpaque.glsl +1 -1
- package/Source/Shaders/Builtin/Constants/passOpaque.js +1 -1
- package/Source/Shaders/Builtin/Constants/passOverlay.glsl +1 -1
- package/Source/Shaders/Builtin/Constants/passOverlay.js +1 -1
- package/Source/Shaders/Builtin/Constants/passTranslucent.glsl +1 -1
- package/Source/Shaders/Builtin/Constants/passTranslucent.js +1 -1
- package/Source/Shaders/Builtin/Constants/passVoxels.glsl +1 -1
- package/Source/Shaders/Builtin/Constants/passVoxels.js +1 -1
- package/Source/Shaders/Builtin/CzmBuiltins.js +2 -0
- package/Source/Shaders/GlobeVS.glsl +1 -1
- package/Source/Shaders/GlobeVS.js +1 -1
- package/Source/Shaders/Model/EdgeDetectionStageFS.glsl +58 -0
- package/Source/Shaders/Model/EdgeDetectionStageFS.js +60 -0
- package/Source/Shaders/Model/EdgeVisibilityStageFS.glsl +83 -0
- package/Source/Shaders/Model/EdgeVisibilityStageFS.js +85 -0
- package/Source/Shaders/Model/ModelFS.glsl +5 -0
- package/Source/Shaders/Model/ModelFS.js +5 -0
- package/Source/Shaders/Model/PrimitiveOutlineStageFS.glsl +0 -1
- package/Source/Shaders/Model/PrimitiveOutlineStageFS.js +0 -1
- package/Source/Shaders/ShadowVolumeAppearanceFS.glsl +7 -15
- package/Source/Shaders/ShadowVolumeAppearanceFS.js +7 -15
- package/Source/Workers/createVerticesFromCesium3DTilesTerrain.js +46 -0
- package/Source/Workers/upsampleVerticesFromCesium3DTilesTerrain.js +55 -0
- package/index.d.ts +281 -27
- package/index.js +200 -190
- package/package.json +2 -1
|
@@ -0,0 +1,800 @@
|
|
|
1
|
+
import Buffer from "../../Renderer/Buffer.js";
|
|
2
|
+
import BufferUsage from "../../Renderer/BufferUsage.js";
|
|
3
|
+
import VertexArray from "../../Renderer/VertexArray.js";
|
|
4
|
+
import defined from "../../Core/defined.js";
|
|
5
|
+
import IndexDatatype from "../../Core/IndexDatatype.js";
|
|
6
|
+
import ComponentDatatype from "../../Core/ComponentDatatype.js";
|
|
7
|
+
import PrimitiveType from "../../Core/PrimitiveType.js";
|
|
8
|
+
import Cartesian3 from "../../Core/Cartesian3.js";
|
|
9
|
+
import Pass from "../../Renderer/Pass.js";
|
|
10
|
+
import ShaderDestination from "../../Renderer/ShaderDestination.js";
|
|
11
|
+
import EdgeVisibilityStageFS from "../../Shaders/Model/EdgeVisibilityStageFS.js";
|
|
12
|
+
import ModelUtility from "./ModelUtility.js";
|
|
13
|
+
import ModelReader from "./ModelReader.js";
|
|
14
|
+
import VertexAttributeSemantic from "../VertexAttributeSemantic.js";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Builds derived line geometry for model edges using EXT_mesh_primitive_edge_visibility data.
|
|
18
|
+
* It parses the encoded edge visibility bits, creates a separate edge-domain vertex array with
|
|
19
|
+
* per-edge attributes (edge type, optional feature ID, silhouette normal, adjacent face normals),
|
|
20
|
+
* sets up the required shader defines / varyings, and stores the resulting line list geometry on
|
|
21
|
+
* the render resources for a later edge rendering pass.
|
|
22
|
+
*
|
|
23
|
+
* @namespace EdgeVisibilityPipelineStage
|
|
24
|
+
* @private
|
|
25
|
+
*/
|
|
26
|
+
const EdgeVisibilityPipelineStage = {
|
|
27
|
+
name: "EdgeVisibilityPipelineStage",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Process a primitive to derive edge geometry and shader bindings. This modifies the render resources by:
|
|
32
|
+
* <ul>
|
|
33
|
+
* <li>Adding shader defines (<code>HAS_EDGE_VISIBILITY</code>, <code>HAS_EDGE_VISIBILITY_MRT</code>)</li>
|
|
34
|
+
* <li>Injecting the fragment shader logic that outputs edge color / feature information</li>
|
|
35
|
+
* <li>Adding per-vertex attributes: edge type, optional feature ID, silhouette normal, and adjacent face normals</li>
|
|
36
|
+
* <li>Adding varyings to pass these attributes to the fragment stage</li>
|
|
37
|
+
* <li>Creating and storing a derived line list vertex array in <code>renderResources.edgeGeometry</code></li>
|
|
38
|
+
* </ul>
|
|
39
|
+
* If the primitive does not contain edge visibility data, the function returns early.
|
|
40
|
+
*
|
|
41
|
+
* @param {PrimitiveRenderResources} renderResources The render resources for the primitive
|
|
42
|
+
* @param {ModelComponents.Primitive} primitive The primitive to be rendered
|
|
43
|
+
* @param {FrameState} frameState The frame state
|
|
44
|
+
* @private
|
|
45
|
+
*/
|
|
46
|
+
EdgeVisibilityPipelineStage.process = function (
|
|
47
|
+
renderResources,
|
|
48
|
+
primitive,
|
|
49
|
+
frameState,
|
|
50
|
+
) {
|
|
51
|
+
if (!defined(primitive.edgeVisibility)) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Fallback request: mark that edge visibility is needed this frame.
|
|
56
|
+
frameState.edgeVisibilityRequested = true;
|
|
57
|
+
|
|
58
|
+
const shaderBuilder = renderResources.shaderBuilder;
|
|
59
|
+
|
|
60
|
+
// Add shader defines and fragment code
|
|
61
|
+
shaderBuilder.addDefine(
|
|
62
|
+
"HAS_EDGE_VISIBILITY",
|
|
63
|
+
undefined,
|
|
64
|
+
ShaderDestination.BOTH,
|
|
65
|
+
);
|
|
66
|
+
shaderBuilder.addDefine(
|
|
67
|
+
"HAS_EDGE_VISIBILITY_MRT",
|
|
68
|
+
undefined,
|
|
69
|
+
ShaderDestination.FRAGMENT,
|
|
70
|
+
);
|
|
71
|
+
shaderBuilder.addFragmentLines(EdgeVisibilityStageFS);
|
|
72
|
+
|
|
73
|
+
// Add a uniform to distinguish between original geometry pass and edge pass
|
|
74
|
+
shaderBuilder.addUniform("bool", "u_isEdgePass", ShaderDestination.BOTH);
|
|
75
|
+
|
|
76
|
+
// Add edge type attribute and varying
|
|
77
|
+
const edgeTypeLocation = shaderBuilder.addAttribute("float", "a_edgeType");
|
|
78
|
+
shaderBuilder.addVarying("float", "v_edgeType", "flat");
|
|
79
|
+
|
|
80
|
+
// Add edge feature ID attribute and varying
|
|
81
|
+
const edgeFeatureIdLocation = shaderBuilder.addAttribute(
|
|
82
|
+
"float",
|
|
83
|
+
"a_edgeFeatureId",
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// Add silhouette normal attribute and varying for silhouette edges
|
|
87
|
+
const silhouetteNormalLocation = shaderBuilder.addAttribute(
|
|
88
|
+
"vec3",
|
|
89
|
+
"a_silhouetteNormal",
|
|
90
|
+
);
|
|
91
|
+
shaderBuilder.addVarying("vec3", "v_silhouetteNormalView", "flat");
|
|
92
|
+
|
|
93
|
+
// Add face normal attributes for silhouette detection
|
|
94
|
+
const faceNormalALocation = shaderBuilder.addAttribute(
|
|
95
|
+
"vec3",
|
|
96
|
+
"a_faceNormalA",
|
|
97
|
+
);
|
|
98
|
+
const faceNormalBLocation = shaderBuilder.addAttribute(
|
|
99
|
+
"vec3",
|
|
100
|
+
"a_faceNormalB",
|
|
101
|
+
);
|
|
102
|
+
shaderBuilder.addVarying("vec3", "v_faceNormalAView", "flat");
|
|
103
|
+
shaderBuilder.addVarying("vec3", "v_faceNormalBView", "flat");
|
|
104
|
+
|
|
105
|
+
// Add varying for view space position for perspective-correct silhouette detection
|
|
106
|
+
|
|
107
|
+
// Pass edge type, silhouette normal, and face normals from vertex to fragment shader
|
|
108
|
+
shaderBuilder.addFunctionLines("setDynamicVaryingsVS", [
|
|
109
|
+
"#ifdef HAS_EDGE_VISIBILITY",
|
|
110
|
+
" if (u_isEdgePass) {",
|
|
111
|
+
" v_edgeType = a_edgeType;",
|
|
112
|
+
"#ifdef HAS_EDGE_FEATURE_ID",
|
|
113
|
+
" v_featureId_0 = a_edgeFeatureId;",
|
|
114
|
+
"#endif",
|
|
115
|
+
" // Transform normals from model space to view space",
|
|
116
|
+
" v_silhouetteNormalView = czm_normal * a_silhouetteNormal;",
|
|
117
|
+
" v_faceNormalAView = czm_normal * a_faceNormalA;",
|
|
118
|
+
" v_faceNormalBView = czm_normal * a_faceNormalB;",
|
|
119
|
+
" }",
|
|
120
|
+
"#endif",
|
|
121
|
+
]);
|
|
122
|
+
|
|
123
|
+
// Build triangle adjacency (mapping edges to adjacent triangles) and compute per-triangle face normals.
|
|
124
|
+
const adjacencyData = buildTriangleAdjacency(primitive);
|
|
125
|
+
|
|
126
|
+
const edgeResult = extractVisibleEdges(primitive);
|
|
127
|
+
|
|
128
|
+
if (
|
|
129
|
+
!defined(edgeResult) ||
|
|
130
|
+
!defined(edgeResult.edgeIndices) ||
|
|
131
|
+
edgeResult.edgeIndices.length === 0
|
|
132
|
+
) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Generate paired face normals for each unique edge (used to classify silhouette edges in the shader).
|
|
137
|
+
const edgeFaceNormals = generateEdgeFaceNormals(
|
|
138
|
+
adjacencyData,
|
|
139
|
+
edgeResult.edgeIndices,
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
// Create edge-domain line list geometry (2 vertices per edge) with all required attributes.
|
|
143
|
+
const edgeGeometry = createCPULineEdgeGeometry(
|
|
144
|
+
edgeResult.edgeIndices,
|
|
145
|
+
edgeResult.edgeData,
|
|
146
|
+
renderResources,
|
|
147
|
+
frameState.context,
|
|
148
|
+
edgeTypeLocation,
|
|
149
|
+
silhouetteNormalLocation,
|
|
150
|
+
faceNormalALocation,
|
|
151
|
+
faceNormalBLocation,
|
|
152
|
+
edgeFeatureIdLocation,
|
|
153
|
+
primitive.edgeVisibility,
|
|
154
|
+
edgeFaceNormals,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
if (!defined(edgeGeometry)) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (edgeGeometry.hasEdgeFeatureIds) {
|
|
162
|
+
shaderBuilder.addDefine(
|
|
163
|
+
"HAS_EDGE_FEATURE_ID",
|
|
164
|
+
undefined,
|
|
165
|
+
ShaderDestination.BOTH,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Set default value for u_isEdgePass uniform (false for original geometry pass). A later pass overrides this.
|
|
170
|
+
renderResources.uniformMap.u_isEdgePass = function () {
|
|
171
|
+
return false;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// Store edge geometry metadata so the renderer can issue a separate edges pass.
|
|
175
|
+
renderResources.edgeGeometry = {
|
|
176
|
+
vertexArray: edgeGeometry.vertexArray,
|
|
177
|
+
indexCount: edgeGeometry.indexCount,
|
|
178
|
+
primitiveType: PrimitiveType.LINES,
|
|
179
|
+
pass: Pass.CESIUM_3D_TILE_EDGES,
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Build triangle adjacency information and per-triangle face normals in model space.
|
|
185
|
+
* The adjacency map associates an undirected edge (minIndex,maxIndex) with the indices
|
|
186
|
+
* of up to two adjacent triangles. Face normals are normalized and stored sequentially.
|
|
187
|
+
*
|
|
188
|
+
* @param {ModelComponents.Primitive} primitive The primitive containing triangle index + position data
|
|
189
|
+
* @returns {{edgeMap:Map<string, number[]>, faceNormals:Float32Array, triangleCount:number}}
|
|
190
|
+
* @private
|
|
191
|
+
*/
|
|
192
|
+
function buildTriangleAdjacency(primitive) {
|
|
193
|
+
const indices = primitive.indices;
|
|
194
|
+
if (!defined(indices)) {
|
|
195
|
+
return {
|
|
196
|
+
edgeMap: new Map(),
|
|
197
|
+
faceNormals: new Float32Array(0),
|
|
198
|
+
triangleCount: 0,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const triangleIndexArray = indices.typedArray;
|
|
203
|
+
const triangleCount = Math.floor(triangleIndexArray.length / 3);
|
|
204
|
+
|
|
205
|
+
// Get vertex positions for face normal calculation
|
|
206
|
+
const positionAttribute = ModelUtility.getAttributeBySemantic(
|
|
207
|
+
primitive,
|
|
208
|
+
VertexAttributeSemantic.POSITION,
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
// Retrieve raw (possibly quantized) position data. If the attribute is quantized
|
|
212
|
+
// we must dequantize on the CPU here because we compute face normals and silhouette
|
|
213
|
+
// classification data before the vertex shader's dequantization stage runs.
|
|
214
|
+
let positions = defined(positionAttribute.typedArray)
|
|
215
|
+
? positionAttribute.typedArray
|
|
216
|
+
: ModelReader.readAttributeAsTypedArray(positionAttribute);
|
|
217
|
+
|
|
218
|
+
const quantization = positionAttribute.quantization;
|
|
219
|
+
if (defined(quantization) && !quantization.octEncoded) {
|
|
220
|
+
const count = positions.length; // length is 3 * vertexCount
|
|
221
|
+
const dequantized = new Float32Array(count);
|
|
222
|
+
const offset = quantization.quantizedVolumeOffset;
|
|
223
|
+
const step = quantization.quantizedVolumeStepSize;
|
|
224
|
+
for (let i = 0; i < count; i += 3) {
|
|
225
|
+
dequantized[i] = offset.x + positions[i] * step.x;
|
|
226
|
+
dequantized[i + 1] = offset.y + positions[i + 1] * step.y;
|
|
227
|
+
dequantized[i + 2] = offset.z + positions[i + 2] * step.z;
|
|
228
|
+
}
|
|
229
|
+
positions = dequantized;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Build edge map: key = "min,max", value = [triangleA, triangleB?]
|
|
233
|
+
const edgeMap = new Map();
|
|
234
|
+
|
|
235
|
+
// Calculate face normals for each triangle (model space)
|
|
236
|
+
const faceNormals = new Float32Array(triangleCount * 3);
|
|
237
|
+
|
|
238
|
+
// Scratch vectors to avoid heap allocations per triangle
|
|
239
|
+
const scratchP0 = new Cartesian3();
|
|
240
|
+
const scratchP1 = new Cartesian3();
|
|
241
|
+
const scratchP2 = new Cartesian3();
|
|
242
|
+
const scratchE1 = new Cartesian3();
|
|
243
|
+
const scratchE2 = new Cartesian3();
|
|
244
|
+
const scratchCross = new Cartesian3();
|
|
245
|
+
|
|
246
|
+
function processEdge(a, b, triIndex) {
|
|
247
|
+
const edgeKey = `${a < b ? a : b},${a < b ? b : a}`;
|
|
248
|
+
let list = edgeMap.get(edgeKey);
|
|
249
|
+
if (!defined(list)) {
|
|
250
|
+
list = [];
|
|
251
|
+
edgeMap.set(edgeKey, list);
|
|
252
|
+
}
|
|
253
|
+
if (list.length < 2) {
|
|
254
|
+
list.push(triIndex);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
for (let t = 0; t < triangleCount; t++) {
|
|
259
|
+
const base = t * 3;
|
|
260
|
+
const i0 = triangleIndexArray[base];
|
|
261
|
+
const i1 = triangleIndexArray[base + 1];
|
|
262
|
+
const i2 = triangleIndexArray[base + 2];
|
|
263
|
+
|
|
264
|
+
const i0o = i0 * 3;
|
|
265
|
+
const i1o = i1 * 3;
|
|
266
|
+
const i2o = i2 * 3;
|
|
267
|
+
|
|
268
|
+
scratchP0.x = positions[i0o];
|
|
269
|
+
scratchP0.y = positions[i0o + 1];
|
|
270
|
+
scratchP0.z = positions[i0o + 2];
|
|
271
|
+
scratchP1.x = positions[i1o];
|
|
272
|
+
scratchP1.y = positions[i1o + 1];
|
|
273
|
+
scratchP1.z = positions[i1o + 2];
|
|
274
|
+
scratchP2.x = positions[i2o];
|
|
275
|
+
scratchP2.y = positions[i2o + 1];
|
|
276
|
+
scratchP2.z = positions[i2o + 2];
|
|
277
|
+
|
|
278
|
+
Cartesian3.subtract(scratchP1, scratchP0, scratchE1);
|
|
279
|
+
Cartesian3.subtract(scratchP2, scratchP0, scratchE2);
|
|
280
|
+
Cartesian3.cross(scratchE1, scratchE2, scratchCross);
|
|
281
|
+
Cartesian3.normalize(scratchCross, scratchCross);
|
|
282
|
+
|
|
283
|
+
faceNormals[base] = scratchCross.x;
|
|
284
|
+
faceNormals[base + 1] = scratchCross.y;
|
|
285
|
+
faceNormals[base + 2] = scratchCross.z;
|
|
286
|
+
|
|
287
|
+
// Edges
|
|
288
|
+
processEdge(i0, i1, t);
|
|
289
|
+
processEdge(i1, i2, t);
|
|
290
|
+
processEdge(i2, i0, t);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return { edgeMap, faceNormals, triangleCount };
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* For each unique edge produce a pair of face normals (A,B). For boundary edges where only a single
|
|
298
|
+
* adjacent triangle exists, the second normal is synthesized as the negation of the first to allow
|
|
299
|
+
* the shader to reason about front/back facing transitions uniformly.
|
|
300
|
+
*
|
|
301
|
+
* @param {{edgeMap:Map<string,number[]>, faceNormals:Float32Array}} adjacencyData The adjacency data from buildTriangleAdjacency
|
|
302
|
+
* @param {number[]} edgeIndices Packed array of 2 vertex indices per edge
|
|
303
|
+
* @returns {Float32Array} Packed array: 6 floats per edge (normalA.xyz, normalB.xyz)
|
|
304
|
+
* @private
|
|
305
|
+
*/
|
|
306
|
+
function generateEdgeFaceNormals(adjacencyData, edgeIndices) {
|
|
307
|
+
const { edgeMap, faceNormals } = adjacencyData;
|
|
308
|
+
const numEdges = edgeIndices.length / 2;
|
|
309
|
+
|
|
310
|
+
// Each edge needs 2 face normals (left and right side)
|
|
311
|
+
const edgeFaceNormals = new Float32Array(numEdges * 6); // 2 normals * 3 components each
|
|
312
|
+
|
|
313
|
+
for (let i = 0; i < numEdges; i++) {
|
|
314
|
+
const a = edgeIndices[i * 2];
|
|
315
|
+
const b = edgeIndices[i * 2 + 1];
|
|
316
|
+
const edgeKey = `${a < b ? a : b},${a < b ? b : a}`;
|
|
317
|
+
const triangleList = edgeMap.get(edgeKey);
|
|
318
|
+
|
|
319
|
+
// Expect at least one triangle; silently skip if not found (defensive)
|
|
320
|
+
if (!defined(triangleList) || triangleList.length === 0) {
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const tA = triangleList[0];
|
|
325
|
+
const aBase = tA * 3;
|
|
326
|
+
const nAx = faceNormals[aBase];
|
|
327
|
+
const nAy = faceNormals[aBase + 1];
|
|
328
|
+
const nAz = faceNormals[aBase + 2];
|
|
329
|
+
|
|
330
|
+
let nBx;
|
|
331
|
+
let nBy;
|
|
332
|
+
let nBz;
|
|
333
|
+
if (triangleList.length > 1) {
|
|
334
|
+
const tB = triangleList[1];
|
|
335
|
+
const bBase = tB * 3;
|
|
336
|
+
nBx = faceNormals[bBase];
|
|
337
|
+
nBy = faceNormals[bBase + 1];
|
|
338
|
+
nBz = faceNormals[bBase + 2];
|
|
339
|
+
} else {
|
|
340
|
+
// Boundary edge – synthesize opposite normal
|
|
341
|
+
nBx = -nAx;
|
|
342
|
+
nBy = -nAy;
|
|
343
|
+
nBz = -nAz;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const baseIdx = i * 6;
|
|
347
|
+
edgeFaceNormals[baseIdx] = nAx;
|
|
348
|
+
edgeFaceNormals[baseIdx + 1] = nAy;
|
|
349
|
+
edgeFaceNormals[baseIdx + 2] = nAz;
|
|
350
|
+
edgeFaceNormals[baseIdx + 3] = nBx;
|
|
351
|
+
edgeFaceNormals[baseIdx + 4] = nBy;
|
|
352
|
+
edgeFaceNormals[baseIdx + 5] = nBz;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return edgeFaceNormals;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Parse the EXT_mesh_primitive_edge_visibility 2-bit edge encoding and extract
|
|
360
|
+
* a unique set of edges that should be considered for rendering. Edge types:
|
|
361
|
+
* <ul>
|
|
362
|
+
* <li>0 HIDDEN - skipped</li>
|
|
363
|
+
* <li>1 SILHOUETTE - candidates for conditional display based on facing</li>
|
|
364
|
+
* <li>2 HARD - always displayed</li>
|
|
365
|
+
* <li>3 REPEATED - secondary encoding for a hard edge (treated same as 2)</li>
|
|
366
|
+
* </ul>
|
|
367
|
+
* Deduplicates edges shared by adjacent triangles and records per-edge metadata.
|
|
368
|
+
*
|
|
369
|
+
* @param {ModelComponents.Primitive} primitive The primitive with EXT_mesh_primitive_edge_visibility data
|
|
370
|
+
* @returns {{edgeIndices:number[], edgeData:Object[], silhouetteEdgeCount:number}} Edge extraction result
|
|
371
|
+
* @private
|
|
372
|
+
*/
|
|
373
|
+
function extractVisibleEdges(primitive) {
|
|
374
|
+
const edgeVisibility = primitive.edgeVisibility;
|
|
375
|
+
const visibility = edgeVisibility.visibility;
|
|
376
|
+
const indices = primitive.indices;
|
|
377
|
+
|
|
378
|
+
if (!defined(visibility) || !defined(indices)) {
|
|
379
|
+
return [];
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const triangleIndexArray = indices.typedArray;
|
|
383
|
+
const vertexCount = primitive.attributes[0].count;
|
|
384
|
+
const edgeIndices = [];
|
|
385
|
+
const edgeData = [];
|
|
386
|
+
const seenEdgeHashes = new Set();
|
|
387
|
+
let silhouetteEdgeCount = 0;
|
|
388
|
+
|
|
389
|
+
// Process triangles and extract edges (2 bits per edge)
|
|
390
|
+
let edgeIndex = 0;
|
|
391
|
+
const totalIndices = triangleIndexArray.length;
|
|
392
|
+
|
|
393
|
+
for (let i = 0; i + 2 < totalIndices; i += 3) {
|
|
394
|
+
const v0 = triangleIndexArray[i];
|
|
395
|
+
const v1 = triangleIndexArray[i + 1];
|
|
396
|
+
const v2 = triangleIndexArray[i + 2];
|
|
397
|
+
for (let e = 0; e < 3; e++) {
|
|
398
|
+
let a, b;
|
|
399
|
+
if (e === 0) {
|
|
400
|
+
a = v0;
|
|
401
|
+
b = v1;
|
|
402
|
+
} else if (e === 1) {
|
|
403
|
+
a = v1;
|
|
404
|
+
b = v2;
|
|
405
|
+
} else if (e === 2) {
|
|
406
|
+
a = v2;
|
|
407
|
+
b = v0;
|
|
408
|
+
}
|
|
409
|
+
const byteIndex = Math.floor(edgeIndex / 4);
|
|
410
|
+
const bitPairOffset = (edgeIndex % 4) * 2;
|
|
411
|
+
edgeIndex++;
|
|
412
|
+
|
|
413
|
+
if (byteIndex >= visibility.length) {
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const byte = visibility[byteIndex];
|
|
418
|
+
const visibility2Bit = (byte >> bitPairOffset) & 0x3;
|
|
419
|
+
|
|
420
|
+
// Only include visible edge types according to EXT_mesh_primitive_edge_visibility spec
|
|
421
|
+
let shouldIncludeEdge = false;
|
|
422
|
+
switch (visibility2Bit) {
|
|
423
|
+
case 0: // HIDDEN - never draw
|
|
424
|
+
shouldIncludeEdge = false;
|
|
425
|
+
break;
|
|
426
|
+
case 1: // SILHOUETTE - conditionally visible (front-facing vs back-facing)
|
|
427
|
+
shouldIncludeEdge = true;
|
|
428
|
+
break;
|
|
429
|
+
case 2: // HARD - always draw (primary encoding)
|
|
430
|
+
shouldIncludeEdge = true;
|
|
431
|
+
break;
|
|
432
|
+
case 3: // REPEATED - always draw (secondary encoding of a hard edge already encoded as 2)
|
|
433
|
+
shouldIncludeEdge = true;
|
|
434
|
+
break;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (shouldIncludeEdge) {
|
|
438
|
+
const small = Math.min(a, b);
|
|
439
|
+
const big = Math.max(a, b);
|
|
440
|
+
const hash = small * vertexCount + big;
|
|
441
|
+
|
|
442
|
+
if (!seenEdgeHashes.has(hash)) {
|
|
443
|
+
seenEdgeHashes.add(hash);
|
|
444
|
+
edgeIndices.push(a, b);
|
|
445
|
+
|
|
446
|
+
let mateVertexIndex = -1;
|
|
447
|
+
if (visibility2Bit === 1) {
|
|
448
|
+
mateVertexIndex = silhouetteEdgeCount;
|
|
449
|
+
silhouetteEdgeCount++;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
edgeData.push({
|
|
453
|
+
edgeType: visibility2Bit,
|
|
454
|
+
triangleIndex: Math.floor(i / 3),
|
|
455
|
+
edgeIndex: e,
|
|
456
|
+
mateVertexIndex: mateVertexIndex,
|
|
457
|
+
currentTriangleVertices: [v0, v1, v2],
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return { edgeIndices, edgeData, silhouetteEdgeCount };
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Create a derived line list geometry representing edges. A new vertex domain is used so we can pack
|
|
469
|
+
* per-edge attributes (silhouette normal, face normal pair, edge type, optional feature ID) without
|
|
470
|
+
* modifying or duplicating the original triangle mesh. Two vertices are generated per unique edge.
|
|
471
|
+
*
|
|
472
|
+
* @param {number[]} edgeIndices Packed array [a0,b0, a1,b1, ...] of vertex indices into the source mesh
|
|
473
|
+
* @param {Object[]} edgeData Array of edge metadata including edge type and silhouette normal lookup index
|
|
474
|
+
* @param {PrimitiveRenderResources} renderResources The render resources for the primitive
|
|
475
|
+
* @param {Context} context The WebGL rendering context
|
|
476
|
+
* @param {number} edgeTypeLocation Shader attribute location for the edge type
|
|
477
|
+
* @param {number} silhouetteNormalLocation Shader attribute location for input silhouette normal
|
|
478
|
+
* @param {number} faceNormalALocation Shader attribute location for face normal A
|
|
479
|
+
* @param {number} faceNormalBLocation Shader attribute location for face normal B
|
|
480
|
+
* @param {number} edgeFeatureIdLocation Shader attribute location for optional edge feature ID
|
|
481
|
+
* @param {Object} edgeVisibility Edge visibility extension object (may contain silhouetteNormals[])
|
|
482
|
+
* @param {Float32Array} edgeFaceNormals Packed face normals (6 floats per edge)
|
|
483
|
+
* @returns {Object|undefined} Object with {vertexArray, indexBuffer, indexCount} or undefined on failure
|
|
484
|
+
* @private
|
|
485
|
+
*/
|
|
486
|
+
function createCPULineEdgeGeometry(
|
|
487
|
+
edgeIndices,
|
|
488
|
+
edgeData,
|
|
489
|
+
renderResources,
|
|
490
|
+
context,
|
|
491
|
+
edgeTypeLocation,
|
|
492
|
+
silhouetteNormalLocation,
|
|
493
|
+
faceNormalALocation,
|
|
494
|
+
faceNormalBLocation,
|
|
495
|
+
edgeFeatureIdLocation,
|
|
496
|
+
edgeVisibility,
|
|
497
|
+
edgeFaceNormals,
|
|
498
|
+
) {
|
|
499
|
+
if (!defined(edgeIndices) || edgeIndices.length === 0) {
|
|
500
|
+
return undefined;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const numEdges = edgeData.length;
|
|
504
|
+
const vertsPerEdge = 2;
|
|
505
|
+
const totalVerts = numEdges * vertsPerEdge;
|
|
506
|
+
|
|
507
|
+
// Always use location 0 for position to avoid conflicts
|
|
508
|
+
const positionLocation = 0;
|
|
509
|
+
|
|
510
|
+
// Get original vertex positions
|
|
511
|
+
const positionAttribute = ModelUtility.getAttributeBySemantic(
|
|
512
|
+
renderResources.runtimePrimitive.primitive,
|
|
513
|
+
VertexAttributeSemantic.POSITION,
|
|
514
|
+
);
|
|
515
|
+
const srcPos = defined(positionAttribute.typedArray)
|
|
516
|
+
? positionAttribute.typedArray
|
|
517
|
+
: ModelReader.readAttributeAsTypedArray(positionAttribute);
|
|
518
|
+
|
|
519
|
+
// Create edge-domain vertices (2 per edge)
|
|
520
|
+
const edgePosArray = new Float32Array(totalVerts * 3);
|
|
521
|
+
const edgeTypeArray = new Float32Array(totalVerts);
|
|
522
|
+
const silhouetteNormalArray = new Float32Array(totalVerts * 3);
|
|
523
|
+
const faceNormalAArray = new Float32Array(totalVerts * 3);
|
|
524
|
+
const faceNormalBArray = new Float32Array(totalVerts * 3);
|
|
525
|
+
let p = 0;
|
|
526
|
+
|
|
527
|
+
const maxSrcVertex = srcPos.length / 3 - 1;
|
|
528
|
+
|
|
529
|
+
for (let i = 0; i < numEdges; i++) {
|
|
530
|
+
const a = edgeIndices[i * 2];
|
|
531
|
+
const b = edgeIndices[i * 2 + 1];
|
|
532
|
+
|
|
533
|
+
// Validate vertex indices
|
|
534
|
+
if (a < 0 || b < 0 || a > maxSrcVertex || b > maxSrcVertex) {
|
|
535
|
+
// Fill with zeros to maintain indexing
|
|
536
|
+
edgePosArray[p++] = 0;
|
|
537
|
+
edgePosArray[p++] = 0;
|
|
538
|
+
edgePosArray[p++] = 0;
|
|
539
|
+
edgePosArray[p++] = 0;
|
|
540
|
+
edgePosArray[p++] = 0;
|
|
541
|
+
edgePosArray[p++] = 0;
|
|
542
|
+
edgeTypeArray[i * 2] = 0;
|
|
543
|
+
edgeTypeArray[i * 2 + 1] = 0;
|
|
544
|
+
// Fill with default values
|
|
545
|
+
const normalIdx = i * 2;
|
|
546
|
+
silhouetteNormalArray[normalIdx * 3] = 0;
|
|
547
|
+
silhouetteNormalArray[normalIdx * 3 + 1] = 0;
|
|
548
|
+
silhouetteNormalArray[normalIdx * 3 + 2] = 1;
|
|
549
|
+
silhouetteNormalArray[(normalIdx + 1) * 3] = 0;
|
|
550
|
+
silhouetteNormalArray[(normalIdx + 1) * 3 + 1] = 0;
|
|
551
|
+
silhouetteNormalArray[(normalIdx + 1) * 3 + 2] = 1;
|
|
552
|
+
|
|
553
|
+
// Fill face normals with default values
|
|
554
|
+
faceNormalAArray[normalIdx * 3] = 0;
|
|
555
|
+
faceNormalAArray[normalIdx * 3 + 1] = 0;
|
|
556
|
+
faceNormalAArray[normalIdx * 3 + 2] = 1;
|
|
557
|
+
faceNormalAArray[(normalIdx + 1) * 3] = 0;
|
|
558
|
+
faceNormalAArray[(normalIdx + 1) * 3 + 1] = 0;
|
|
559
|
+
faceNormalAArray[(normalIdx + 1) * 3 + 2] = 1;
|
|
560
|
+
|
|
561
|
+
faceNormalBArray[normalIdx * 3] = 0;
|
|
562
|
+
faceNormalBArray[normalIdx * 3 + 1] = 0;
|
|
563
|
+
faceNormalBArray[normalIdx * 3 + 2] = 1;
|
|
564
|
+
faceNormalBArray[(normalIdx + 1) * 3] = 0;
|
|
565
|
+
faceNormalBArray[(normalIdx + 1) * 3 + 1] = 0;
|
|
566
|
+
faceNormalBArray[(normalIdx + 1) * 3 + 2] = 1;
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
const ax = srcPos[a * 3];
|
|
571
|
+
const ay = srcPos[a * 3 + 1];
|
|
572
|
+
const az = srcPos[a * 3 + 2];
|
|
573
|
+
const bx = srcPos[b * 3];
|
|
574
|
+
const by = srcPos[b * 3 + 1];
|
|
575
|
+
const bz = srcPos[b * 3 + 2];
|
|
576
|
+
|
|
577
|
+
// Add edge endpoints
|
|
578
|
+
edgePosArray[p++] = ax;
|
|
579
|
+
edgePosArray[p++] = ay;
|
|
580
|
+
edgePosArray[p++] = az;
|
|
581
|
+
edgePosArray[p++] = bx;
|
|
582
|
+
edgePosArray[p++] = by;
|
|
583
|
+
edgePosArray[p++] = bz;
|
|
584
|
+
|
|
585
|
+
const rawType = edgeData[i].edgeType;
|
|
586
|
+
const t = rawType / 255.0;
|
|
587
|
+
|
|
588
|
+
edgeTypeArray[i * 2] = t;
|
|
589
|
+
edgeTypeArray[i * 2 + 1] = t;
|
|
590
|
+
|
|
591
|
+
// Add silhouette normal for silhouette edges (type 1)
|
|
592
|
+
let normalX = 0,
|
|
593
|
+
normalY = 0,
|
|
594
|
+
normalZ = 1; // Default normal pointing up
|
|
595
|
+
|
|
596
|
+
if (rawType === 1 && defined(edgeVisibility.silhouetteNormals)) {
|
|
597
|
+
const mateVertexIndex = edgeData[i].mateVertexIndex;
|
|
598
|
+
if (
|
|
599
|
+
mateVertexIndex >= 0 &&
|
|
600
|
+
mateVertexIndex < edgeVisibility.silhouetteNormals.length
|
|
601
|
+
) {
|
|
602
|
+
const silhouetteNormals = edgeVisibility.silhouetteNormals;
|
|
603
|
+
const normal = silhouetteNormals[mateVertexIndex];
|
|
604
|
+
|
|
605
|
+
if (defined(normal)) {
|
|
606
|
+
normalX = normal.x;
|
|
607
|
+
normalY = normal.y;
|
|
608
|
+
normalZ = normal.z;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Set silhouette normal for both edge endpoints
|
|
614
|
+
const normalIdx = i * 2;
|
|
615
|
+
silhouetteNormalArray[normalIdx * 3] = normalX;
|
|
616
|
+
silhouetteNormalArray[normalIdx * 3 + 1] = normalY;
|
|
617
|
+
silhouetteNormalArray[normalIdx * 3 + 2] = normalZ;
|
|
618
|
+
silhouetteNormalArray[(normalIdx + 1) * 3] = normalX;
|
|
619
|
+
silhouetteNormalArray[(normalIdx + 1) * 3 + 1] = normalY;
|
|
620
|
+
silhouetteNormalArray[(normalIdx + 1) * 3 + 2] = normalZ;
|
|
621
|
+
|
|
622
|
+
// Set face normals for both edge endpoints
|
|
623
|
+
const faceNormalIdx = i * 6; // 6 floats per edge (2 normals * 3 components)
|
|
624
|
+
const normalAX = edgeFaceNormals[faceNormalIdx];
|
|
625
|
+
const normalAY = edgeFaceNormals[faceNormalIdx + 1];
|
|
626
|
+
const normalAZ = edgeFaceNormals[faceNormalIdx + 2];
|
|
627
|
+
const normalBX = edgeFaceNormals[faceNormalIdx + 3];
|
|
628
|
+
const normalBY = edgeFaceNormals[faceNormalIdx + 4];
|
|
629
|
+
const normalBZ = edgeFaceNormals[faceNormalIdx + 5];
|
|
630
|
+
|
|
631
|
+
// Face normal A for both endpoints
|
|
632
|
+
faceNormalAArray[normalIdx * 3] = normalAX;
|
|
633
|
+
faceNormalAArray[normalIdx * 3 + 1] = normalAY;
|
|
634
|
+
faceNormalAArray[normalIdx * 3 + 2] = normalAZ;
|
|
635
|
+
faceNormalAArray[(normalIdx + 1) * 3] = normalAX;
|
|
636
|
+
faceNormalAArray[(normalIdx + 1) * 3 + 1] = normalAY;
|
|
637
|
+
faceNormalAArray[(normalIdx + 1) * 3 + 2] = normalAZ;
|
|
638
|
+
|
|
639
|
+
// Face normal B for both endpoints
|
|
640
|
+
faceNormalBArray[normalIdx * 3] = normalBX;
|
|
641
|
+
faceNormalBArray[normalIdx * 3 + 1] = normalBY;
|
|
642
|
+
faceNormalBArray[normalIdx * 3 + 2] = normalBZ;
|
|
643
|
+
faceNormalBArray[(normalIdx + 1) * 3] = normalBX;
|
|
644
|
+
faceNormalBArray[(normalIdx + 1) * 3 + 1] = normalBY;
|
|
645
|
+
faceNormalBArray[(normalIdx + 1) * 3 + 2] = normalBZ;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Create vertex buffers
|
|
649
|
+
const edgePosBuffer = Buffer.createVertexBuffer({
|
|
650
|
+
context,
|
|
651
|
+
typedArray: edgePosArray,
|
|
652
|
+
usage: BufferUsage.STATIC_DRAW,
|
|
653
|
+
});
|
|
654
|
+
const edgeTypeBuffer = Buffer.createVertexBuffer({
|
|
655
|
+
context,
|
|
656
|
+
typedArray: edgeTypeArray,
|
|
657
|
+
usage: BufferUsage.STATIC_DRAW,
|
|
658
|
+
});
|
|
659
|
+
const silhouetteNormalBuffer = Buffer.createVertexBuffer({
|
|
660
|
+
context,
|
|
661
|
+
typedArray: silhouetteNormalArray,
|
|
662
|
+
usage: BufferUsage.STATIC_DRAW,
|
|
663
|
+
});
|
|
664
|
+
const faceNormalABuffer = Buffer.createVertexBuffer({
|
|
665
|
+
context,
|
|
666
|
+
typedArray: faceNormalAArray,
|
|
667
|
+
usage: BufferUsage.STATIC_DRAW,
|
|
668
|
+
});
|
|
669
|
+
const faceNormalBBuffer = Buffer.createVertexBuffer({
|
|
670
|
+
context,
|
|
671
|
+
typedArray: faceNormalBArray,
|
|
672
|
+
usage: BufferUsage.STATIC_DRAW,
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
// Create sequential indices for line pairs
|
|
676
|
+
const useU32 = totalVerts > 65534;
|
|
677
|
+
const idx = new Array(totalVerts);
|
|
678
|
+
for (let i = 0; i < totalVerts; i++) {
|
|
679
|
+
idx[i] = i;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const indexBuffer = Buffer.createIndexBuffer({
|
|
683
|
+
context,
|
|
684
|
+
typedArray: useU32 ? new Uint32Array(idx) : new Uint16Array(idx),
|
|
685
|
+
usage: BufferUsage.STATIC_DRAW,
|
|
686
|
+
indexDatatype: useU32
|
|
687
|
+
? IndexDatatype.UNSIGNED_INT
|
|
688
|
+
: IndexDatatype.UNSIGNED_SHORT,
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
// Create vertex array with position, edge type, silhouette normal, and face normal attributes
|
|
692
|
+
const attributes = [
|
|
693
|
+
{
|
|
694
|
+
index: positionLocation,
|
|
695
|
+
vertexBuffer: edgePosBuffer,
|
|
696
|
+
componentsPerAttribute: 3,
|
|
697
|
+
componentDatatype: ComponentDatatype.FLOAT,
|
|
698
|
+
normalize: false,
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
index: edgeTypeLocation,
|
|
702
|
+
vertexBuffer: edgeTypeBuffer,
|
|
703
|
+
componentsPerAttribute: 1,
|
|
704
|
+
componentDatatype: ComponentDatatype.FLOAT,
|
|
705
|
+
normalize: false,
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
index: silhouetteNormalLocation,
|
|
709
|
+
vertexBuffer: silhouetteNormalBuffer,
|
|
710
|
+
componentsPerAttribute: 3,
|
|
711
|
+
componentDatatype: ComponentDatatype.FLOAT,
|
|
712
|
+
normalize: false,
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
index: faceNormalALocation,
|
|
716
|
+
vertexBuffer: faceNormalABuffer,
|
|
717
|
+
componentsPerAttribute: 3,
|
|
718
|
+
componentDatatype: ComponentDatatype.FLOAT,
|
|
719
|
+
normalize: false,
|
|
720
|
+
},
|
|
721
|
+
{
|
|
722
|
+
index: faceNormalBLocation,
|
|
723
|
+
vertexBuffer: faceNormalBBuffer,
|
|
724
|
+
componentsPerAttribute: 3,
|
|
725
|
+
componentDatatype: ComponentDatatype.FLOAT,
|
|
726
|
+
normalize: false,
|
|
727
|
+
},
|
|
728
|
+
];
|
|
729
|
+
|
|
730
|
+
// Get feature ID from original geometry
|
|
731
|
+
const primitive = renderResources.runtimePrimitive.primitive;
|
|
732
|
+
const getFeatureIdForEdge = function () {
|
|
733
|
+
// Try to get the first feature ID from the original primitive
|
|
734
|
+
if (defined(primitive.featureIds) && primitive.featureIds.length > 0) {
|
|
735
|
+
const firstFeatureIdSet = primitive.featureIds[0];
|
|
736
|
+
|
|
737
|
+
// Handle FeatureIdAttribute objects directly using setIndex
|
|
738
|
+
if (defined(firstFeatureIdSet.setIndex)) {
|
|
739
|
+
const featureIdAttribute = primitive.attributes.find(
|
|
740
|
+
(attr) =>
|
|
741
|
+
attr.semantic === VertexAttributeSemantic.FEATURE_ID &&
|
|
742
|
+
attr.setIndex === firstFeatureIdSet.setIndex,
|
|
743
|
+
);
|
|
744
|
+
|
|
745
|
+
if (defined(featureIdAttribute)) {
|
|
746
|
+
const featureIds = defined(featureIdAttribute.typedArray)
|
|
747
|
+
? featureIdAttribute.typedArray
|
|
748
|
+
: ModelReader.readAttributeAsTypedArray(featureIdAttribute);
|
|
749
|
+
|
|
750
|
+
// Create edge feature ID buffer based on edge indices
|
|
751
|
+
const edgeFeatureIds = new Float32Array(totalVerts);
|
|
752
|
+
for (let i = 0; i < numEdges; i++) {
|
|
753
|
+
const a = edgeIndices[i * 2];
|
|
754
|
+
const featureId = a < featureIds.length ? featureIds[a] : 0;
|
|
755
|
+
edgeFeatureIds[i * 2] = featureId;
|
|
756
|
+
edgeFeatureIds[i * 2 + 1] = featureId;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
return edgeFeatureIds;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
return undefined;
|
|
765
|
+
};
|
|
766
|
+
|
|
767
|
+
const edgeFeatureIds = getFeatureIdForEdge();
|
|
768
|
+
const hasEdgeFeatureIds = defined(edgeFeatureIds);
|
|
769
|
+
|
|
770
|
+
if (hasEdgeFeatureIds) {
|
|
771
|
+
const edgeFeatureIdBuffer = Buffer.createVertexBuffer({
|
|
772
|
+
context,
|
|
773
|
+
typedArray: edgeFeatureIds,
|
|
774
|
+
usage: BufferUsage.STATIC_DRAW,
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
attributes.push({
|
|
778
|
+
index: edgeFeatureIdLocation,
|
|
779
|
+
vertexBuffer: edgeFeatureIdBuffer,
|
|
780
|
+
componentsPerAttribute: 1,
|
|
781
|
+
componentDatatype: ComponentDatatype.FLOAT,
|
|
782
|
+
normalize: false,
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
const vertexArray = new VertexArray({ context, indexBuffer, attributes });
|
|
787
|
+
|
|
788
|
+
if (!vertexArray || totalVerts === 0 || totalVerts % 2 !== 0) {
|
|
789
|
+
return undefined;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
return {
|
|
793
|
+
vertexArray,
|
|
794
|
+
indexBuffer,
|
|
795
|
+
indexCount: totalVerts,
|
|
796
|
+
hasEdgeFeatureIds,
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
export default EdgeVisibilityPipelineStage;
|