@3driseai/3drise-viewer 0.1.42 → 0.1.43
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/dist/animationsV2/ClipsRuntime.d.ts +16 -1
- package/dist/animationsV2/ClipsRuntime.d.ts.map +1 -1
- package/dist/animationsV2/ClipsRuntime.js +144 -25
- package/dist/animationsV2/appliers.d.ts +9 -0
- package/dist/animationsV2/appliers.d.ts.map +1 -1
- package/dist/animationsV2/appliers.js +62 -2
- package/dist/animationsV2/clipUtils.d.ts +30 -0
- package/dist/animationsV2/clipUtils.d.ts.map +1 -1
- package/dist/animationsV2/clipUtils.js +163 -17
- package/dist/animationsV2/elementSettings.d.ts +5 -0
- package/dist/animationsV2/elementSettings.d.ts.map +1 -1
- package/dist/animationsV2/elementSettings.js +6 -3
- package/dist/animationsV2/sequenceUtils.js +4 -4
- package/dist/animationsV2/types.d.ts +23 -0
- package/dist/animationsV2/types.d.ts.map +1 -1
- package/dist/api/sceneHandle.js +2 -2
- package/dist/components/CreatedObject.d.ts +3 -0
- package/dist/components/CreatedObject.d.ts.map +1 -1
- package/dist/components/CreatedObject.js +6 -2
- package/dist/components/CustomPrimitive.d.ts.map +1 -1
- package/dist/components/CustomPrimitive.js +1 -10
- package/dist/components/EnvironmentManager.d.ts.map +1 -1
- package/dist/components/EnvironmentManager.js +11 -5
- package/dist/components/GeometryShape.d.ts +5 -2
- package/dist/components/GeometryShape.d.ts.map +1 -1
- package/dist/components/GeometryShape.js +71 -10
- package/dist/components/LandObject.d.ts.map +1 -1
- package/dist/components/LandObject.js +1 -1
- package/dist/components/LayoutInstances.d.ts +2 -1
- package/dist/components/LayoutInstances.d.ts.map +1 -1
- package/dist/components/LayoutInstances.js +39 -6
- package/dist/components/LightObject.d.ts.map +1 -1
- package/dist/components/LightObject.js +3 -0
- package/dist/components/ObjectNode.d.ts.map +1 -1
- package/dist/components/ObjectNode.js +62 -13
- package/dist/components/OceanBuilder.d.ts +2 -0
- package/dist/components/OceanBuilder.d.ts.map +1 -1
- package/dist/components/OceanBuilder.js +2 -1
- package/dist/components/RenderEffects.d.ts +8 -0
- package/dist/components/RenderEffects.d.ts.map +1 -0
- package/dist/components/RenderEffects.js +120 -0
- package/dist/components/SceneBuilder.d.ts.map +1 -1
- package/dist/components/SceneBuilder.js +18 -9
- package/dist/components/SportsObject.d.ts +9 -0
- package/dist/components/SportsObject.d.ts.map +1 -0
- package/dist/components/SportsObject.js +20 -0
- package/dist/components/UrbanObject.d.ts +9 -0
- package/dist/components/UrbanObject.d.ts.map +1 -0
- package/dist/components/UrbanObject.js +28 -0
- package/dist/components/VegetationObject.d.ts +9 -0
- package/dist/components/VegetationObject.d.ts.map +1 -0
- package/dist/components/VegetationObject.js +26 -0
- package/dist/components/WaterObject.d.ts +15 -0
- package/dist/components/WaterObject.d.ts.map +1 -0
- package/dist/components/WaterObject.js +29 -0
- package/dist/components/index.d.ts +7 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +6 -1
- package/dist/components/land/LandPatch.d.ts +3 -1
- package/dist/components/land/LandPatch.d.ts.map +1 -1
- package/dist/components/land/LandPatch.js +80 -7
- package/dist/components/layout/InstancedLayout.d.ts +19 -0
- package/dist/components/layout/InstancedLayout.d.ts.map +1 -0
- package/dist/components/layout/InstancedLayout.js +154 -0
- package/dist/components/layout/LayoutGrounds.d.ts +19 -0
- package/dist/components/layout/LayoutGrounds.d.ts.map +1 -0
- package/dist/components/layout/LayoutGrounds.js +104 -0
- package/dist/components/layout/LinkProxies.d.ts +5 -0
- package/dist/components/layout/LinkProxies.d.ts.map +1 -0
- package/dist/components/layout/LinkProxies.js +51 -0
- package/dist/components/layout/LinkedSource.d.ts +14 -0
- package/dist/components/layout/LinkedSource.d.ts.map +1 -0
- package/dist/components/layout/LinkedSource.js +129 -0
- package/dist/components/projector/Projector.d.ts +14 -0
- package/dist/components/projector/Projector.d.ts.map +1 -0
- package/dist/components/projector/Projector.js +44 -0
- package/dist/components/projector/index.d.ts +4 -0
- package/dist/components/projector/index.d.ts.map +1 -0
- package/dist/components/projector/index.js +2 -0
- package/dist/components/projector/projectorCore.d.ts +19 -0
- package/dist/components/projector/projectorCore.d.ts.map +1 -0
- package/dist/components/projector/projectorCore.js +545 -0
- package/dist/components/sports/SportsBall.d.ts +9 -0
- package/dist/components/sports/SportsBall.d.ts.map +1 -0
- package/dist/components/sports/SportsBall.js +23 -0
- package/dist/components/sports/SportsCourt.d.ts +9 -0
- package/dist/components/sports/SportsCourt.d.ts.map +1 -0
- package/dist/components/sports/SportsCourt.js +23 -0
- package/dist/components/sports/SportsEquipment.d.ts +9 -0
- package/dist/components/sports/SportsEquipment.d.ts.map +1 -0
- package/dist/components/sports/SportsEquipment.js +23 -0
- package/dist/components/sports/SportsGoal.d.ts +9 -0
- package/dist/components/sports/SportsGoal.d.ts.map +1 -0
- package/dist/components/sports/SportsGoal.js +23 -0
- package/dist/components/sports/core/ball.d.ts +166 -0
- package/dist/components/sports/core/ball.d.ts.map +1 -0
- package/dist/components/sports/core/ball.js +402 -0
- package/dist/components/sports/core/court.d.ts +442 -0
- package/dist/components/sports/core/court.d.ts.map +1 -0
- package/dist/components/sports/core/court.js +658 -0
- package/dist/components/sports/core/equipment.d.ts +103 -0
- package/dist/components/sports/core/equipment.d.ts.map +1 -0
- package/dist/components/sports/core/equipment.js +403 -0
- package/dist/components/sports/core/goal.d.ts +98 -0
- package/dist/components/sports/core/goal.d.ts.map +1 -0
- package/dist/components/sports/core/goal.js +44 -0
- package/dist/components/sports/index.d.ts +11 -0
- package/dist/components/sports/index.d.ts.map +1 -0
- package/dist/components/sports/index.js +8 -0
- package/dist/components/sports/sportsCore.d.ts +195 -0
- package/dist/components/sports/sportsCore.d.ts.map +1 -0
- package/dist/components/sports/sportsCore.js +758 -0
- package/dist/components/sports/useSportsInstance.d.ts +35 -0
- package/dist/components/sports/useSportsInstance.d.ts.map +1 -0
- package/dist/components/sports/useSportsInstance.js +47 -0
- package/dist/components/terrain/TerrainSurface.d.ts.map +1 -1
- package/dist/components/terrain/TerrainSurface.js +14 -0
- package/dist/components/urban/UrbanBlock.d.ts +9 -0
- package/dist/components/urban/UrbanBlock.d.ts.map +1 -0
- package/dist/components/urban/UrbanBlock.js +23 -0
- package/dist/components/urban/UrbanBuilding.d.ts +9 -0
- package/dist/components/urban/UrbanBuilding.d.ts.map +1 -0
- package/dist/components/urban/UrbanBuilding.js +23 -0
- package/dist/components/urban/UrbanJunction.d.ts +9 -0
- package/dist/components/urban/UrbanJunction.d.ts.map +1 -0
- package/dist/components/urban/UrbanJunction.js +23 -0
- package/dist/components/urban/UrbanPark.d.ts +9 -0
- package/dist/components/urban/UrbanPark.d.ts.map +1 -0
- package/dist/components/urban/UrbanPark.js +23 -0
- package/dist/components/urban/UrbanParkingLot.d.ts +9 -0
- package/dist/components/urban/UrbanParkingLot.d.ts.map +1 -0
- package/dist/components/urban/UrbanParkingLot.js +23 -0
- package/dist/components/urban/UrbanPlaza.d.ts +9 -0
- package/dist/components/urban/UrbanPlaza.d.ts.map +1 -0
- package/dist/components/urban/UrbanPlaza.js +23 -0
- package/dist/components/urban/UrbanRoad.d.ts +9 -0
- package/dist/components/urban/UrbanRoad.d.ts.map +1 -0
- package/dist/components/urban/UrbanRoad.js +23 -0
- package/dist/components/urban/UrbanSignage.d.ts +9 -0
- package/dist/components/urban/UrbanSignage.d.ts.map +1 -0
- package/dist/components/urban/UrbanSignage.js +23 -0
- package/dist/components/urban/UrbanSkyline.d.ts +9 -0
- package/dist/components/urban/UrbanSkyline.d.ts.map +1 -0
- package/dist/components/urban/UrbanSkyline.js +23 -0
- package/dist/components/urban/UrbanStreetFurniture.d.ts +9 -0
- package/dist/components/urban/UrbanStreetFurniture.d.ts.map +1 -0
- package/dist/components/urban/UrbanStreetFurniture.js +23 -0
- package/dist/components/urban/UrbanStreetGrid.d.ts +9 -0
- package/dist/components/urban/UrbanStreetGrid.d.ts.map +1 -0
- package/dist/components/urban/UrbanStreetGrid.js +34 -0
- package/dist/components/urban/UrbanTraffic.d.ts +9 -0
- package/dist/components/urban/UrbanTraffic.d.ts.map +1 -0
- package/dist/components/urban/UrbanTraffic.js +23 -0
- package/dist/components/urban/core/block.d.ts +119 -0
- package/dist/components/urban/core/block.d.ts.map +1 -0
- package/dist/components/urban/core/block.js +266 -0
- package/dist/components/urban/core/building.d.ts +128 -0
- package/dist/components/urban/core/building.d.ts.map +1 -0
- package/dist/components/urban/core/building.js +741 -0
- package/dist/components/urban/core/junction.d.ts +152 -0
- package/dist/components/urban/core/junction.d.ts.map +1 -0
- package/dist/components/urban/core/junction.js +617 -0
- package/dist/components/urban/core/park.d.ts +67 -0
- package/dist/components/urban/core/park.d.ts.map +1 -0
- package/dist/components/urban/core/park.js +176 -0
- package/dist/components/urban/core/parkingLot.d.ts +82 -0
- package/dist/components/urban/core/parkingLot.d.ts.map +1 -0
- package/dist/components/urban/core/parkingLot.js +284 -0
- package/dist/components/urban/core/plaza.d.ts +24 -0
- package/dist/components/urban/core/plaza.d.ts.map +1 -0
- package/dist/components/urban/core/plaza.js +243 -0
- package/dist/components/urban/core/road.d.ts +113 -0
- package/dist/components/urban/core/road.d.ts.map +1 -0
- package/dist/components/urban/core/road.js +347 -0
- package/dist/components/urban/core/signage.d.ts +83 -0
- package/dist/components/urban/core/signage.d.ts.map +1 -0
- package/dist/components/urban/core/signage.js +209 -0
- package/dist/components/urban/core/skyline.d.ts +100 -0
- package/dist/components/urban/core/skyline.d.ts.map +1 -0
- package/dist/components/urban/core/skyline.js +89 -0
- package/dist/components/urban/core/streetFurniture.d.ts +75 -0
- package/dist/components/urban/core/streetFurniture.d.ts.map +1 -0
- package/dist/components/urban/core/streetFurniture.js +193 -0
- package/dist/components/urban/core/streetGrid.d.ts +134 -0
- package/dist/components/urban/core/streetGrid.d.ts.map +1 -0
- package/dist/components/urban/core/streetGrid.js +422 -0
- package/dist/components/urban/core/traffic.d.ts +125 -0
- package/dist/components/urban/core/traffic.d.ts.map +1 -0
- package/dist/components/urban/core/traffic.js +305 -0
- package/dist/components/urban/index.d.ts +29 -0
- package/dist/components/urban/index.d.ts.map +1 -0
- package/dist/components/urban/index.js +16 -0
- package/dist/components/urban/textureSetResolver.d.ts +8 -0
- package/dist/components/urban/textureSetResolver.d.ts.map +1 -0
- package/dist/components/urban/textureSetResolver.js +16 -0
- package/dist/components/urban/urbanCore.d.ts +262 -0
- package/dist/components/urban/urbanCore.d.ts.map +1 -0
- package/dist/components/urban/urbanCore.js +928 -0
- package/dist/components/urban/useUrbanInstance.d.ts +53 -0
- package/dist/components/urban/useUrbanInstance.d.ts.map +1 -0
- package/dist/components/urban/useUrbanInstance.js +100 -0
- package/dist/components/vegetation/VegetationBush.d.ts +9 -0
- package/dist/components/vegetation/VegetationBush.d.ts.map +1 -0
- package/dist/components/vegetation/VegetationBush.js +23 -0
- package/dist/components/vegetation/VegetationCrops.d.ts +9 -0
- package/dist/components/vegetation/VegetationCrops.d.ts.map +1 -0
- package/dist/components/vegetation/VegetationCrops.js +23 -0
- package/dist/components/vegetation/VegetationFlowers.d.ts +9 -0
- package/dist/components/vegetation/VegetationFlowers.d.ts.map +1 -0
- package/dist/components/vegetation/VegetationFlowers.js +23 -0
- package/dist/components/vegetation/VegetationForest.d.ts +9 -0
- package/dist/components/vegetation/VegetationForest.d.ts.map +1 -0
- package/dist/components/vegetation/VegetationForest.js +23 -0
- package/dist/components/vegetation/VegetationFruit.d.ts +9 -0
- package/dist/components/vegetation/VegetationFruit.d.ts.map +1 -0
- package/dist/components/vegetation/VegetationFruit.js +23 -0
- package/dist/components/vegetation/VegetationGrass.d.ts +9 -0
- package/dist/components/vegetation/VegetationGrass.d.ts.map +1 -0
- package/dist/components/vegetation/VegetationGrass.js +23 -0
- package/dist/components/vegetation/VegetationHedge.d.ts +9 -0
- package/dist/components/vegetation/VegetationHedge.d.ts.map +1 -0
- package/dist/components/vegetation/VegetationHedge.js +23 -0
- package/dist/components/vegetation/VegetationIvy.d.ts +9 -0
- package/dist/components/vegetation/VegetationIvy.d.ts.map +1 -0
- package/dist/components/vegetation/VegetationIvy.js +23 -0
- package/dist/components/vegetation/VegetationTree.d.ts +9 -0
- package/dist/components/vegetation/VegetationTree.d.ts.map +1 -0
- package/dist/components/vegetation/VegetationTree.js +23 -0
- package/dist/components/vegetation/VegetationVegetable.d.ts +9 -0
- package/dist/components/vegetation/VegetationVegetable.d.ts.map +1 -0
- package/dist/components/vegetation/VegetationVegetable.js +23 -0
- package/dist/components/vegetation/core/bush.d.ts +1256 -0
- package/dist/components/vegetation/core/bush.d.ts.map +1 -0
- package/dist/components/vegetation/core/bush.js +376 -0
- package/dist/components/vegetation/core/crops.d.ts +1033 -0
- package/dist/components/vegetation/core/crops.d.ts.map +1 -0
- package/dist/components/vegetation/core/crops.js +378 -0
- package/dist/components/vegetation/core/flowers.d.ts +648 -0
- package/dist/components/vegetation/core/flowers.d.ts.map +1 -0
- package/dist/components/vegetation/core/flowers.js +225 -0
- package/dist/components/vegetation/core/forest.d.ts +138 -0
- package/dist/components/vegetation/core/forest.d.ts.map +1 -0
- package/dist/components/vegetation/core/forest.js +310 -0
- package/dist/components/vegetation/core/fruit.d.ts +99 -0
- package/dist/components/vegetation/core/fruit.d.ts.map +1 -0
- package/dist/components/vegetation/core/fruit.js +77 -0
- package/dist/components/vegetation/core/grass.d.ts +103 -0
- package/dist/components/vegetation/core/grass.d.ts.map +1 -0
- package/dist/components/vegetation/core/grass.js +102 -0
- package/dist/components/vegetation/core/hedge.d.ts +193 -0
- package/dist/components/vegetation/core/hedge.d.ts.map +1 -0
- package/dist/components/vegetation/core/hedge.js +243 -0
- package/dist/components/vegetation/core/ivy.d.ts +213 -0
- package/dist/components/vegetation/core/ivy.d.ts.map +1 -0
- package/dist/components/vegetation/core/ivy.js +173 -0
- package/dist/components/vegetation/core/tree.d.ts +1117 -0
- package/dist/components/vegetation/core/tree.d.ts.map +1 -0
- package/dist/components/vegetation/core/tree.js +408 -0
- package/dist/components/vegetation/core/vegetable.d.ts +99 -0
- package/dist/components/vegetation/core/vegetable.d.ts.map +1 -0
- package/dist/components/vegetation/core/vegetable.js +76 -0
- package/dist/components/vegetation/index.d.ts +23 -0
- package/dist/components/vegetation/index.d.ts.map +1 -0
- package/dist/components/vegetation/index.js +14 -0
- package/dist/components/vegetation/produceCore.d.ts +929 -0
- package/dist/components/vegetation/produceCore.d.ts.map +1 -0
- package/dist/components/vegetation/produceCore.js +723 -0
- package/dist/components/vegetation/useVegetationInstance.d.ts +39 -0
- package/dist/components/vegetation/useVegetationInstance.d.ts.map +1 -0
- package/dist/components/vegetation/useVegetationInstance.js +45 -0
- package/dist/components/vegetation/vegetationCore.d.ts +412 -0
- package/dist/components/vegetation/vegetationCore.d.ts.map +1 -0
- package/dist/components/vegetation/vegetationCore.js +1728 -0
- package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts +5 -0
- package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts.map +1 -1
- package/dist/components/volumetricClouds/VolumetricCloudsPass.js +39 -13
- package/dist/components/water/OceanSurface.d.ts.map +1 -1
- package/dist/components/water/OceanSurface.js +3 -2
- package/dist/components/water/WaterBody.d.ts.map +1 -1
- package/dist/components/water/WaterBody.js +31 -10
- package/dist/components/water/WaterFountain.d.ts +9 -0
- package/dist/components/water/WaterFountain.d.ts.map +1 -0
- package/dist/components/water/WaterFountain.js +24 -0
- package/dist/components/water/WaterStream.d.ts +9 -0
- package/dist/components/water/WaterStream.d.ts.map +1 -0
- package/dist/components/water/WaterStream.js +24 -0
- package/dist/components/water/WaterWaterfall.d.ts +9 -0
- package/dist/components/water/WaterWaterfall.d.ts.map +1 -0
- package/dist/components/water/WaterWaterfall.js +24 -0
- package/dist/components/water/core/fountain.d.ts +70 -0
- package/dist/components/water/core/fountain.d.ts.map +1 -0
- package/dist/components/water/core/fountain.js +619 -0
- package/dist/components/water/core/stream.d.ts +72 -0
- package/dist/components/water/core/stream.d.ts.map +1 -0
- package/dist/components/water/core/stream.js +167 -0
- package/dist/components/water/core/waterfall.d.ts +78 -0
- package/dist/components/water/core/waterfall.d.ts.map +1 -0
- package/dist/components/water/core/waterfall.js +325 -0
- package/dist/components/water/index.d.ts +8 -0
- package/dist/components/water/index.d.ts.map +1 -1
- package/dist/components/water/index.js +7 -0
- package/dist/components/water/types.d.ts +3 -0
- package/dist/components/water/types.d.ts.map +1 -1
- package/dist/components/water/useWaterInstance.d.ts +43 -0
- package/dist/components/water/useWaterInstance.d.ts.map +1 -0
- package/dist/components/water/useWaterInstance.js +89 -0
- package/dist/components/water/waterCore.d.ts +179 -0
- package/dist/components/water/waterCore.d.ts.map +1 -0
- package/dist/components/water/waterCore.js +516 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +9 -1
- package/dist/hooks/index.d.ts +7 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +5 -2
- package/dist/hooks/useActionPatch.d.ts +23 -0
- package/dist/hooks/useActionPatch.d.ts.map +1 -0
- package/dist/hooks/useActionPatch.js +38 -0
- package/dist/hooks/useCloudSun.d.ts.map +1 -1
- package/dist/hooks/useCloudSun.js +3 -2
- package/dist/hooks/useCommittedInstance.d.ts +6 -0
- package/dist/hooks/useCommittedInstance.d.ts.map +1 -0
- package/dist/hooks/useCommittedInstance.js +42 -0
- package/dist/hooks/useConfigLive.d.ts +1 -1
- package/dist/hooks/useConfigLive.d.ts.map +1 -1
- package/dist/hooks/useContinuousEffects.d.ts.map +1 -1
- package/dist/hooks/useContinuousEffects.js +36 -20
- package/dist/hooks/useGridLayout.d.ts +7 -0
- package/dist/hooks/useGridLayout.d.ts.map +1 -0
- package/dist/hooks/useGridLayout.js +10 -0
- package/dist/hooks/useInteractionEffects.d.ts.map +1 -1
- package/dist/hooks/useInteractionEffects.js +48 -9
- package/dist/hooks/useLightLive.d.ts.map +1 -1
- package/dist/hooks/useLightLive.js +2 -0
- package/dist/hooks/useLinkStatus.d.ts +7 -0
- package/dist/hooks/useLinkStatus.d.ts.map +1 -0
- package/dist/hooks/useLinkStatus.js +20 -0
- package/dist/hooks/useMaterialApplication.d.ts +6 -1
- package/dist/hooks/useMaterialApplication.d.ts.map +1 -1
- package/dist/hooks/useMaterialApplication.js +7 -2
- package/dist/hooks/useOceanMaterial.d.ts +11 -1
- package/dist/hooks/useOceanMaterial.d.ts.map +1 -1
- package/dist/hooks/useOceanMaterial.js +185 -27
- package/dist/hooks/usePathAnimation.d.ts +8 -0
- package/dist/hooks/usePathAnimation.d.ts.map +1 -1
- package/dist/hooks/usePathAnimation.js +140 -59
- package/dist/hooks/useResolvedLayout.d.ts +10 -0
- package/dist/hooks/useResolvedLayout.d.ts.map +1 -0
- package/dist/hooks/useResolvedLayout.js +17 -0
- package/dist/hooks/useTimeLighting.d.ts +36 -0
- package/dist/hooks/useTimeLighting.d.ts.map +1 -0
- package/dist/hooks/useTimeLighting.js +67 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/operations/catalogue/shaderLayers.d.ts.map +1 -1
- package/dist/operations/catalogue/shaderLayers.js +26 -3
- package/dist/render/renderLive.d.ts +11 -0
- package/dist/render/renderLive.d.ts.map +1 -0
- package/dist/render/renderLive.js +57 -0
- package/dist/shaders/glsl/oceanCore.glsl.d.ts +2 -2
- package/dist/shaders/glsl/oceanCore.glsl.d.ts.map +1 -1
- package/dist/shaders/glsl/oceanCore.glsl.js +35 -5
- package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts +12 -0
- package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts.map +1 -1
- package/dist/shaders/ocean/OceanSurfaceMaterial.js +55 -7
- package/dist/shaders/terrain/TerrainMaterial.d.ts.map +1 -1
- package/dist/shaders/terrain/TerrainMaterial.js +28 -0
- package/dist/triggers/kinds/change.js +1 -1
- package/dist/utils/composerHostedPass.d.ts +74 -0
- package/dist/utils/composerHostedPass.d.ts.map +1 -0
- package/dist/utils/composerHostedPass.js +63 -0
- package/dist/utils/geometryScript.d.ts +17 -0
- package/dist/utils/geometryScript.d.ts.map +1 -0
- package/dist/utils/geometryScript.js +92 -0
- package/dist/utils/geometryScript.worker.d.ts +2 -0
- package/dist/utils/geometryScript.worker.d.ts.map +1 -0
- package/dist/utils/geometryScript.worker.js +42 -0
- package/dist/utils/groundRegistry.d.ts +11 -0
- package/dist/utils/groundRegistry.d.ts.map +1 -0
- package/dist/utils/groundRegistry.js +39 -0
- package/dist/utils/instancingSupport.d.ts +9 -0
- package/dist/utils/instancingSupport.d.ts.map +1 -0
- package/dist/utils/instancingSupport.js +13 -0
- package/dist/utils/landPatch.d.ts +26 -5
- package/dist/utils/landPatch.d.ts.map +1 -1
- package/dist/utils/landPatch.js +124 -9
- package/dist/utils/layoutPlacement.d.ts +30 -0
- package/dist/utils/layoutPlacement.d.ts.map +1 -0
- package/dist/utils/layoutPlacement.js +113 -0
- package/dist/utils/linkRegistry.d.ts +15 -0
- package/dist/utils/linkRegistry.d.ts.map +1 -0
- package/dist/utils/linkRegistry.js +11 -0
- package/dist/utils/shapes.d.ts +28 -2
- package/dist/utils/shapes.d.ts.map +1 -1
- package/dist/utils/shapes.js +32 -3
- package/dist/utils/sharedParts.d.ts +61 -0
- package/dist/utils/sharedParts.d.ts.map +1 -0
- package/dist/utils/sharedParts.js +268 -0
- package/dist/utils/svgAsset.d.ts +6 -0
- package/dist/utils/svgAsset.d.ts.map +1 -0
- package/dist/utils/svgAsset.js +46 -0
- package/dist/utils/waterLight.d.ts +29 -0
- package/dist/utils/waterLight.d.ts.map +1 -0
- package/dist/utils/waterLight.js +67 -0
- package/dist/utils/waterReflection.d.ts +185 -0
- package/dist/utils/waterReflection.d.ts.map +1 -0
- package/dist/utils/waterReflection.js +616 -0
- package/package.json +4 -3
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
// Emitted from Claude outputs/sports-lab/court.mjs by gen_family.mjs — edit the lab module and re-emit.
|
|
2
|
+
// sports/core/court — Court (type 'sports', config.type 'court'). Shared core: ../sportsCore.
|
|
3
|
+
// Construction: a playing surface at regulation size with its markings drawn as anti-aliased signed
|
|
4
|
+
// distances in the fragment (every line of the rulebook, metres, sharp at any zoom), on a procedural
|
|
5
|
+
// surface (acrylic, clay, grass, parquet, ice, tartan, turf, sand, concrete, paint) with wear where
|
|
6
|
+
// the play is and puddles when wet; the sport's fixtures (nets, goals, hoops) built from the shared
|
|
7
|
+
// goal builders. Lines are drawn on the mesh itself — no decals, no textures. Size: real metres;
|
|
8
|
+
// the transform places it.
|
|
9
|
+
// Night: the court is lit the urban way, with no real lights — its surface gathers the lamps of the
|
|
10
|
+
// one lamp list (street lamps, other courts' floodlights) and adds their pools, scaled by the night
|
|
11
|
+
// factor from the scene sun; its own floodlight masts register their heads in the same list, so
|
|
12
|
+
// they light the court evenly and spill onto the paving around it.
|
|
13
|
+
import * as THREE from 'three';
|
|
14
|
+
import { setColor, createCommonUniforms, applyCommonConfig, updateCommon, QUALITY_S, litMaterial, propMesh, partMaterial, mergeGeos, box, bar, buildGoal, GOAL_COLORS, disposePair, registerLamp, unregisterLamp, touchLamps, setLamps, placeLamps, createLampUniforms, createSunUniforms, GLSL_COMMON } from '../sportsCore.js';
|
|
15
|
+
/**
|
|
16
|
+
* The sports: regulation size (length × width, metres), line width, the run-off the venue adds around
|
|
17
|
+
* the lines [ends, sides], the natural surface, the three colour slots when the config leaves them
|
|
18
|
+
* white (surface, lines, accent), the fixtures and where they stand (x along the length).
|
|
19
|
+
*/
|
|
20
|
+
export const SPORTS = {
|
|
21
|
+
tennis: { L: 23.77, W: 10.97, line: 0.05, mow: 1.32, runoff: [6.4, 3.66], surface: 'hardcourt', colors: ['#2a62a8', '#ffffff', '#3b7f44'], fixtures: [{ kind: 'tennisNet', x: 0, rot: 1 }] },
|
|
22
|
+
basketball: { L: 28, W: 15, line: 0.05, runoff: [2, 2], surface: 'wood', colors: ['#c89659', '#ffffff', '#a2372f'], fixtures: [{ kind: 'basketballHoop', x: 12.425, rot: -1 }, { kind: 'basketballHoop', x: -12.425, rot: 1 }] },
|
|
23
|
+
soccer: { L: 105, W: 68, line: 0.12, mow: 5.25, runoff: [6, 4], surface: 'grass', colors: ['#3d8a39', '#ffffff', '#3d8a39'], fixtures: [{ kind: 'footballGoal', x: 52.5, rot: -1 }, { kind: 'footballGoal', x: -52.5, rot: 1 }] },
|
|
24
|
+
futsal: { L: 40, W: 20, line: 0.08, runoff: [2, 1.5], surface: 'wood', colors: ['#c89659', '#ffffff', '#2a62a8'], fixtures: [{ kind: 'futsalGoal', x: 20, rot: -1 }, { kind: 'futsalGoal', x: -20, rot: 1 }] },
|
|
25
|
+
handball: { L: 40, W: 20, line: 0.05, runoff: [2, 1], surface: 'wood', colors: ['#c89659', '#ffffff', '#2f6cb5'], fixtures: [{ kind: 'handballGoal', x: 20, rot: -1 }, { kind: 'handballGoal', x: -20, rot: 1 }] },
|
|
26
|
+
volleyball: { L: 18, W: 9, line: 0.05, runoff: [5, 3], surface: 'hardcourt', colors: ['#d4823a', '#ffffff', '#2a62a8'], fixtures: [{ kind: 'volleyballNet', x: 0, rot: 1 }] },
|
|
27
|
+
badminton: { L: 13.4, W: 6.1, line: 0.04, runoff: [2, 1.5], surface: 'hardcourt', colors: ['#3b8a4a', '#ffffff', '#2d6d3a'], fixtures: [{ kind: 'badmintonNet', x: 0, rot: 1 }] },
|
|
28
|
+
padel: { L: 20, W: 10, line: 0.05, runoff: [0.5, 0.5], surface: 'turf', colors: ['#2a62a8', '#ffffff', '#1f4f8a'], fixtures: [{ kind: 'padelNet', x: 0, rot: 1 }] },
|
|
29
|
+
pickleball: { L: 13.41, W: 6.1, line: 0.05, runoff: [3, 2], surface: 'hardcourt', colors: ['#2a62a8', '#ffffff', '#3b8a4a'], fixtures: [{ kind: 'pickleballNet', x: 0, rot: 1 }] },
|
|
30
|
+
iceHockey: { L: 60.96, W: 25.91, line: 0.05, runoff: [0, 0], corner: 8.53, surface: 'ice', colors: ['#e9f1f6', '#d8322d', '#2f6cd0'], fixtures: [{ kind: 'hockeyNet', x: 27.13, rot: -1 }, { kind: 'hockeyNet', x: -27.13, rot: 1 }] },
|
|
31
|
+
athleticsTrack: { L: 176.9, W: 92.5, line: 0.05, runoff: [3, 3], surface: 'tartan', colors: ['#b8453a', '#ffffff', '#3d8a39'], fixtures: [] },
|
|
32
|
+
tableTennis: { L: 2.74, W: 1.525, line: 0.02, runoff: [0, 0], table: 0.76, surface: 'painted', colors: ['#1d3f86', '#ffffff', '#1d3f86'], fixtures: [{ kind: 'tableTennisNet', x: 0, rot: 1 }] },
|
|
33
|
+
// NFL: 120 × 53⅓ yd with the end zones; the uprights' crossbar stands over each end line
|
|
34
|
+
americanFootball: { L: 109.728, W: 48.768, line: 0.1016, mow: 4.572, runoff: [6, 8], surface: 'grass', colors: ['#3d8a39', '#ffffff', '#1f3f7a'], fixtures: [{ kind: 'americanUprights', x: 54.864, rot: -1 }, { kind: 'americanUprights', x: -54.864, rot: 1 }] },
|
|
35
|
+
};
|
|
36
|
+
export const SPORT_LIST = Object.keys(SPORTS);
|
|
37
|
+
/** Earlier names of a sport (saved scenes keep working): 'football' was the soccer pitch. */
|
|
38
|
+
export const SPORT_ALIASES = { football: 'soccer' };
|
|
39
|
+
/** The sport key a config means (an alias resolved; unknown -> tennis). */
|
|
40
|
+
export function sportKey(k) { const a = SPORT_ALIASES[k] || k; return SPORTS[a] ? a : 'tennis'; }
|
|
41
|
+
/**
|
|
42
|
+
* Floodlights per sport. sides: n masts along each long side, heads on an arm over the slab edge,
|
|
43
|
+
* tilted toward the court (street-lamp pools); towers: four stadium towers outside the corners, each a
|
|
44
|
+
* bank of rows × cols projectors aimed into the field, registered as PROJECTOR lamps (aimed long-throw
|
|
45
|
+
* beams: lamp.aim + lamp.spread) — every tower throws one beam at each quarter of the field, so the
|
|
46
|
+
* whole surface is lit evenly. h = head height (m), set = how far outside the corner the tower stands,
|
|
47
|
+
* radius = reach, I = lamp intensity (urban units), spread = cos of a beam's outer half-angle.
|
|
48
|
+
*/
|
|
49
|
+
export const FLOOD = {
|
|
50
|
+
tennis: { mode: 'sides', n: 3, h: 9, radius: 26, I: 0.9 },
|
|
51
|
+
basketball: { mode: 'sides', n: 3, h: 10, radius: 26, I: 0.9 },
|
|
52
|
+
soccer: { mode: 'towers', h: 32, rows: 4, cols: 5, set: 6, radius: 170, I: 0.2, spread: 0.74 },
|
|
53
|
+
futsal: { mode: 'sides', n: 3, h: 10, radius: 28, I: 0.95 },
|
|
54
|
+
handball: { mode: 'sides', n: 3, h: 10, radius: 28, I: 0.95 },
|
|
55
|
+
volleyball: { mode: 'sides', n: 2, h: 9, radius: 24, I: 0.9 },
|
|
56
|
+
badminton: { mode: 'sides', n: 2, h: 7, radius: 18, I: 0.8 },
|
|
57
|
+
padel: { mode: 'sides', n: 2, h: 7, radius: 18, I: 0.8 },
|
|
58
|
+
pickleball: { mode: 'sides', n: 2, h: 7, radius: 18, I: 0.8 },
|
|
59
|
+
iceHockey: { mode: 'sides', n: 4, h: 12, radius: 30, I: 1.0 },
|
|
60
|
+
athleticsTrack: { mode: 'towers', h: 38, rows: 5, cols: 6, set: 8, radius: 240, I: 0.2, spread: 0.74 },
|
|
61
|
+
tableTennis: null,
|
|
62
|
+
americanFootball: { mode: 'towers', h: 34, rows: 4, cols: 5, set: 7, radius: 175, I: 0.2, spread: 0.74 },
|
|
63
|
+
};
|
|
64
|
+
export const LIGHTING = ['auto', 'day', 'night'];
|
|
65
|
+
export const SURFACES = ['auto', 'hardcourt', 'clay', 'grass', 'wood', 'ice', 'tartan', 'turf', 'sand', 'concrete', 'painted'];
|
|
66
|
+
export function createUniforms() {
|
|
67
|
+
return Object.assign(createCommonUniforms(), {
|
|
68
|
+
// the fixtures (nets, goals, hoops) keep their own natural colours: the court's colour slots are surface / lines / zone
|
|
69
|
+
fixtureU: createCommonUniforms(),
|
|
70
|
+
uSport: { value: 0 }, uSurface: { value: 0 }, uMow: { value: 5 }, uLineW: { value: 0.05 }, uWet: { value: 0 }, uTableY: { value: -1 },
|
|
71
|
+
uSurfCol: { value: new THREE.Color('#2a62a8') }, uLineCol: { value: new THREE.Color('#ffffff') }, uZoneCol: { value: new THREE.Color('#3b7f44') },
|
|
72
|
+
uFloodColor: { value: new THREE.Color('#fff1dc') }, uFloodGlow: { value: 1 },
|
|
73
|
+
}, createSunUniforms(), createLampUniforms());
|
|
74
|
+
}
|
|
75
|
+
export function applyConfig(u, c, inst = undefined) {
|
|
76
|
+
applyCommonConfig(u, c, inst && inst.mats);
|
|
77
|
+
const S = SPORTS[sportKey(c.sport)];
|
|
78
|
+
// the three colour slots (surface, lines, surround / zone): the sport's own while naturalColors is on
|
|
79
|
+
const nat = c.naturalColors !== false;
|
|
80
|
+
setColor(u.uSurfCol, nat ? S.colors[0] : c.color);
|
|
81
|
+
setColor(u.uLineCol, nat ? S.colors[1] : c.secondaryColor);
|
|
82
|
+
setColor(u.uZoneCol, nat ? S.colors[2] : c.accentColor);
|
|
83
|
+
if (c.sport !== undefined) {
|
|
84
|
+
u.uSport.value = SPORT_LIST.indexOf(sportKey(c.sport));
|
|
85
|
+
u.uMow.value = S.mow || 5;
|
|
86
|
+
}
|
|
87
|
+
if (c.surface !== undefined)
|
|
88
|
+
u.uSurface.value = Math.max(0, SURFACES.indexOf(c.surface === 'auto' ? S.surface : c.surface) - 1);
|
|
89
|
+
if (c.lineScale !== undefined)
|
|
90
|
+
u.uLineW.value = S.line * c.lineScale;
|
|
91
|
+
if (c.wetness !== undefined)
|
|
92
|
+
u.uWet.value = c.wetness;
|
|
93
|
+
// fixtures: the court's wear / gloss / seed / opacity, their own colours (set at build from GOAL_COLORS)
|
|
94
|
+
const fu = u.fixtureU;
|
|
95
|
+
applyCommonConfig(fu, { wear: c.wear, gloss: c.gloss, seed: c.seed, opacity: c.opacity }, inst && inst.fixtureMats);
|
|
96
|
+
if (inst)
|
|
97
|
+
for (const f of inst.fixtures)
|
|
98
|
+
f.apply({ netTension: 0.75 });
|
|
99
|
+
// floodlights: the heads' glow and their entries in the lamp list
|
|
100
|
+
if (c.floodColor !== undefined)
|
|
101
|
+
setColor(u.uFloodColor, c.floodColor);
|
|
102
|
+
if (c.floodIntensity !== undefined)
|
|
103
|
+
u.uFloodGlow.value = c.floodIntensity;
|
|
104
|
+
// setLamps bumps the shared lamp list only on a real change: apply runs every frame while any
|
|
105
|
+
// knob animates, and a bump per frame re-gathers / re-bakes every lamp-lit surface in the scene
|
|
106
|
+
if (inst && inst.lamps.length)
|
|
107
|
+
setLamps(inst.lamps, c.floodColor, c.floodIntensity !== undefined ? inst.lamps[0].base * c.floodIntensity : undefined);
|
|
108
|
+
}
|
|
109
|
+
// ---------------------------------------------------------------------------- GLSL: the markings
|
|
110
|
+
// p = (x along the length, z across), metres from the centre. Every sport writes:
|
|
111
|
+
// dL distance to the nearest line (drawn in the line colour, width uLineW)
|
|
112
|
+
// dA distance to the nearest accent-coloured line (hockey blue lines), width wA
|
|
113
|
+
// zone 1 inside the accent-filled area (a key, a crease, the surround, the infield)
|
|
114
|
+
// field 1 inside the playing area (for the surface's own wear focus)
|
|
115
|
+
const MARKINGS_GLSL = /* glsl */ `
|
|
116
|
+
uniform float uSport, uSurface, uLineW, uWet, uTableY, uMow;
|
|
117
|
+
uniform vec3 uSurfCol, uLineCol, uZoneCol;
|
|
118
|
+
// a stadium (two straights + two semicircles): distance to its outline
|
|
119
|
+
float lnStadium(vec2 p, float a, float r) { return abs(length(vec2(max(abs(p.x) - a, 0.0), p.y)) - r); }
|
|
120
|
+
float inBox(vec2 p, vec2 hb) { return step(abs(p.x), hb.x) * step(abs(p.y), hb.y); }
|
|
121
|
+
// dashes are a coverage mask (dOn), never a jump in the distance field — a discontinuous distance
|
|
122
|
+
// blows up fwidth and smears the line across a whole band
|
|
123
|
+
float dashOn(float s, float len) { return step(0.5, fract(s / (2.0 * len))); }
|
|
124
|
+
|
|
125
|
+
// a seven-segment digit (0–9), centred, 1.2 × 1.83 m (the field numbers' 4 × 6 ft), distance to its strokes' centre lines
|
|
126
|
+
float segD(vec2 uv, vec2 a, vec2 b) { return sdSeg(uv, a, b); }
|
|
127
|
+
float digit7(vec2 uv, int n) {
|
|
128
|
+
float w = 0.49, h = 0.805, d = 1e9;
|
|
129
|
+
bool A = n != 1 && n != 4, B = n != 5 && n != 6, C = n != 2, D = n != 1 && n != 4 && n != 7;
|
|
130
|
+
bool E = n == 0 || n == 2 || n == 6 || n == 8, F = n != 1 && n != 2 && n != 3 && n != 7, G = n != 0 && n != 1 && n != 7;
|
|
131
|
+
if (A) d = min(d, segD(uv, vec2(-w, h), vec2(w, h)));
|
|
132
|
+
if (B) d = min(d, segD(uv, vec2(w, h), vec2(w, 0.0)));
|
|
133
|
+
if (C) d = min(d, segD(uv, vec2(w, 0.0), vec2(w, -h)));
|
|
134
|
+
if (D) d = min(d, segD(uv, vec2(-w, -h), vec2(w, -h)));
|
|
135
|
+
if (E) d = min(d, segD(uv, vec2(-w, 0.0), vec2(-w, -h)));
|
|
136
|
+
if (F) d = min(d, segD(uv, vec2(-w, h), vec2(-w, 0.0)));
|
|
137
|
+
if (G) d = min(d, segD(uv, vec2(-w, 0.0), vec2(w, 0.0)));
|
|
138
|
+
return d;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
void markings(vec2 p, out float dL, out float dA, out float wA, out float dD, out float dOn, out float zone, out float field) {
|
|
142
|
+
dL = 1e9; dA = 1e9; wA = uLineW; dD = 1e9; dOn = 0.0; zone = 0.0; field = 0.0;
|
|
143
|
+
vec2 q = abs(p); // every court is symmetric about both axes
|
|
144
|
+
int s = int(uSport + 0.5);
|
|
145
|
+
if (s == 0) { // tennis 23.77 × 10.97
|
|
146
|
+
vec2 H = vec2(11.885, 5.485);
|
|
147
|
+
dL = lnBox(p, vec2(0.0), H);
|
|
148
|
+
dL = min(dL, sdSeg(q, vec2(0.0, 4.115), vec2(11.885, 4.115))); // singles sideline
|
|
149
|
+
dL = min(dL, sdSeg(q, vec2(6.4, 0.0), vec2(6.4, 4.115))); // service line
|
|
150
|
+
dL = min(dL, sdSeg(q, vec2(0.0, 0.0), vec2(6.4, 0.0))); // centre service line
|
|
151
|
+
dL = min(dL, sdSeg(q, vec2(11.885, 0.0), vec2(11.785, 0.0))); // centre mark
|
|
152
|
+
field = inBox(p, H); zone = 1.0 - field;
|
|
153
|
+
} else if (s == 1) { // basketball FIBA 28 × 15
|
|
154
|
+
vec2 H = vec2(14.0, 7.5);
|
|
155
|
+
dL = lnBox(p, vec2(0.0), H);
|
|
156
|
+
dL = min(dL, sdSeg(q, vec2(0.0, 0.0), vec2(0.0, 7.5))); // halfway
|
|
157
|
+
dL = min(dL, lnCircle(p, vec2(0.0), 1.8)); // centre circle
|
|
158
|
+
dL = min(dL, lnBox(q, vec2(11.1, 0.0), vec2(2.9, 2.45))); // the key 5.8 × 4.9
|
|
159
|
+
dL = min(dL, lnCircle(q, vec2(8.2, 0.0), 1.8)); // free-throw circle
|
|
160
|
+
vec2 bk = vec2(12.425, 0.0); // basket
|
|
161
|
+
dL = min(dL, lnArc(q, bk, 6.75, 3.14159 - 1.3598, 3.14159 + 1.3598)); // 3-pt arc (meets the straights at |z| = 6.6)
|
|
162
|
+
dL = min(dL, sdSeg(q, vec2(14.0, 6.6), vec2(11.01, 6.6))); // 3-pt straight
|
|
163
|
+
dL = min(dL, lnArc(q, bk, 1.25, 1.5708, 4.7124)); // no-charge semicircle
|
|
164
|
+
field = inBox(p, H); zone = inBox(q - vec2(11.1, 0.0), vec2(2.9, 2.45));
|
|
165
|
+
} else if (s == 2) { // soccer 105 × 68
|
|
166
|
+
vec2 H = vec2(52.5, 34.0);
|
|
167
|
+
dL = lnBox(p, vec2(0.0), H);
|
|
168
|
+
dL = min(dL, sdSeg(q, vec2(0.0, 0.0), vec2(0.0, 34.0))); // halfway
|
|
169
|
+
dL = min(dL, lnCircle(p, vec2(0.0), 9.15));
|
|
170
|
+
dL = min(dL, length(p) - 0.2); // centre spot
|
|
171
|
+
dL = min(dL, lnBox(q, vec2(44.25, 0.0), vec2(8.25, 20.16))); // penalty area 16.5 × 40.32
|
|
172
|
+
dL = min(dL, lnBox(q, vec2(49.75, 0.0), vec2(2.75, 9.16))); // goal area 5.5 × 18.32
|
|
173
|
+
dL = min(dL, length(q - vec2(41.5, 0.0)) - 0.2); // penalty mark
|
|
174
|
+
dL = min(dL, lnArc(q, vec2(41.5, 0.0), 9.15, 3.14159 - 0.9273, 3.14159 + 0.9273)); // penalty arc, outside the area
|
|
175
|
+
dL = min(dL, lnArc(q, vec2(52.5, 34.0), 1.0, 3.14159, 4.7124)); // corner arc
|
|
176
|
+
field = inBox(p, H);
|
|
177
|
+
} else if (s == 3 || s == 4) { // futsal / handball 40 × 20
|
|
178
|
+
vec2 H = vec2(20.0, 10.0);
|
|
179
|
+
dL = lnBox(p, vec2(0.0), H);
|
|
180
|
+
dL = min(dL, sdSeg(q, vec2(0.0, 0.0), vec2(0.0, 10.0)));
|
|
181
|
+
float r = s == 3 ? 6.0 : 6.0;
|
|
182
|
+
// the D: quarter circles around the posts (±1.5) joined by a straight
|
|
183
|
+
float dD = min(lnArc(q, vec2(20.0, 1.5), r, 1.5708, 3.14159), sdSeg(q, vec2(20.0 - r, 0.0), vec2(20.0 - r, 1.5)));
|
|
184
|
+
dL = min(dL, dD);
|
|
185
|
+
if (s == 3) {
|
|
186
|
+
dL = min(dL, lnCircle(p, vec2(0.0), 3.0));
|
|
187
|
+
dL = min(dL, length(q - vec2(14.0, 0.0)) - 0.15); // penalty mark 6 m
|
|
188
|
+
dL = min(dL, length(q - vec2(10.0, 0.0)) - 0.15); // second mark 10 m
|
|
189
|
+
} else {
|
|
190
|
+
// 9 m dashed line, 7 m mark, 4 m goalkeeper line
|
|
191
|
+
vec2 c = vec2(20.0, 1.5);
|
|
192
|
+
float a = atan(q.y - 1.5, q.x - 20.0);
|
|
193
|
+
float d9 = min(lnArc(q, c, 9.0, 1.5708, 3.14159), sdSeg(q, vec2(11.0, 0.0), vec2(11.0, 1.5)));
|
|
194
|
+
float along = q.y < 1.5 && q.x < 11.5 ? q.y : (a - 1.5708) * 9.0 + 1.5;
|
|
195
|
+
dD = d9; dOn = dashOn(along, 0.15);
|
|
196
|
+
dL = min(dL, sdSeg(q, vec2(13.0, 0.0), vec2(13.0, 0.5))); // 7 m mark (1 m long)
|
|
197
|
+
dL = min(dL, sdSeg(q, vec2(16.0, 0.0), vec2(16.0, 0.075))); // 4 m line
|
|
198
|
+
zone = step(sdSeg(q, vec2(20.0, 0.0), vec2(20.0, 1.5)), r); // the goal area, filled
|
|
199
|
+
}
|
|
200
|
+
field = inBox(p, H);
|
|
201
|
+
} else if (s == 5) { // volleyball 18 × 9
|
|
202
|
+
vec2 H = vec2(9.0, 4.5);
|
|
203
|
+
dL = lnBox(p, vec2(0.0), H);
|
|
204
|
+
dL = min(dL, sdSeg(q, vec2(0.0, 0.0), vec2(0.0, 4.5)));
|
|
205
|
+
dL = min(dL, sdSeg(q, vec2(3.0, 0.0), vec2(3.0, 4.5))); // attack line
|
|
206
|
+
field = inBox(p, H); zone = 1.0 - field;
|
|
207
|
+
} else if (s == 6) { // badminton 13.4 × 6.1
|
|
208
|
+
vec2 H = vec2(6.7, 3.05);
|
|
209
|
+
dL = lnBox(p, vec2(0.0), H);
|
|
210
|
+
dL = min(dL, sdSeg(q, vec2(0.0, 2.59), vec2(6.7, 2.59))); // singles sideline
|
|
211
|
+
dL = min(dL, sdSeg(q, vec2(1.98, 0.0), vec2(1.98, 3.05))); // short service line
|
|
212
|
+
dL = min(dL, sdSeg(q, vec2(5.94, 0.0), vec2(5.94, 3.05))); // doubles long service line
|
|
213
|
+
dL = min(dL, sdSeg(q, vec2(1.98, 0.0), vec2(6.7, 0.0))); // centre line
|
|
214
|
+
field = inBox(p, H); zone = 1.0 - field;
|
|
215
|
+
} else if (s == 7) { // padel 20 × 10
|
|
216
|
+
vec2 H = vec2(10.0, 5.0);
|
|
217
|
+
dL = lnBox(p, vec2(0.0), H);
|
|
218
|
+
dL = min(dL, sdSeg(q, vec2(6.95, 0.0), vec2(6.95, 5.0))); // service line
|
|
219
|
+
dL = min(dL, sdSeg(q, vec2(0.0, 0.0), vec2(6.95, 0.0))); // centre service line
|
|
220
|
+
field = inBox(p, H); zone = 1.0 - field;
|
|
221
|
+
} else if (s == 8) { // pickleball 13.41 × 6.1
|
|
222
|
+
vec2 H = vec2(6.705, 3.05);
|
|
223
|
+
dL = lnBox(p, vec2(0.0), H);
|
|
224
|
+
dL = min(dL, sdSeg(q, vec2(2.13, 0.0), vec2(2.13, 3.05))); // non-volley line
|
|
225
|
+
dL = min(dL, sdSeg(q, vec2(2.13, 0.0), vec2(6.705, 0.0))); // centre line
|
|
226
|
+
field = inBox(p, H); zone = step(q.x, 2.13) * field;
|
|
227
|
+
} else if (s == 9) { // ice hockey NHL 60.96 × 25.91
|
|
228
|
+
float gl = 27.13;
|
|
229
|
+
dL = sdSeg(q, vec2(gl, 0.0), vec2(gl, 13.0)); // goal line (red)
|
|
230
|
+
dA = sdSeg(q, vec2(7.62, 0.0), vec2(7.62, 13.0)); wA = 0.3; // blue lines
|
|
231
|
+
dD = sdSeg(q, vec2(0.0, 0.0), vec2(0.0, 13.0)); dOn = dashOn(q.y, 0.2); // centre red line (dashed look)
|
|
232
|
+
dL = min(dL, lnCircle(p, vec2(0.0), 4.57) + 0.0); // centre faceoff circle
|
|
233
|
+
vec2 fo = vec2(gl - 6.1, 6.71);
|
|
234
|
+
dL = min(dL, lnCircle(q, fo, 4.57)); // end-zone circles
|
|
235
|
+
dL = min(dL, length(q - fo) - 0.3); // faceoff dots
|
|
236
|
+
dL = min(dL, length(q - vec2(6.1, 6.71)) - 0.3); // neutral-zone dots
|
|
237
|
+
dL = min(dL, length(p) - 0.15);
|
|
238
|
+
dL = min(dL, sdSeg(q, vec2(fo.x - 0.6, fo.y - 0.9), vec2(fo.x - 0.6, fo.y + 0.9))); // hash marks (simplified)
|
|
239
|
+
dL = min(dL, sdSeg(q, vec2(fo.x + 0.6, fo.y - 0.9), vec2(fo.x + 0.6, fo.y + 0.9)));
|
|
240
|
+
dL = min(dL, lnArc(q, vec2(gl, 0.0), 1.83, 1.5708, 4.7124)); // crease outline (red)
|
|
241
|
+
zone = step(length(q - vec2(gl, 0.0)), 1.83) * step(q.x, gl); // crease fill (light blue)
|
|
242
|
+
field = 1.0;
|
|
243
|
+
} else if (s == 10) { // athletics track: 400 m, 8 lanes of 1.22 m, r 36.5, straights 84.39
|
|
244
|
+
float a = 42.195, r0 = 36.5;
|
|
245
|
+
for (int k = 0; k <= 8; k++) dL = min(dL, lnStadium(p, a, r0 + 1.22 * float(k)));
|
|
246
|
+
float rr = length(vec2(max(abs(p.x) - a, 0.0), p.y));
|
|
247
|
+
field = step(r0, rr) * step(rr, r0 + 9.76);
|
|
248
|
+
zone = 1.0 - field;
|
|
249
|
+
// finish line across the home straight at the start of the bend
|
|
250
|
+
dL = min(dL, sdSeg(vec2(p.x, p.y), vec2(a, r0), vec2(a, r0 + 9.76)));
|
|
251
|
+
} else if (s == 12) { // American football (NFL) 120 × 53⅓ yd, in metres
|
|
252
|
+
float Y = 0.9144, hx = 54.864, hz = 24.384, gl = 45.72;
|
|
253
|
+
// the 6 ft white border outside the sidelines and end lines
|
|
254
|
+
vec2 bq = q - vec2(hx, hz) - 0.915;
|
|
255
|
+
// (filled shapes: zero inside, so the line test |dL| < lw/2 paints them whole)
|
|
256
|
+
dL = max(abs(length(max(bq, 0.0)) + min(max(bq.x, bq.y), 0.0)) - 0.915 + uLineW * 0.5, 0.0);
|
|
257
|
+
dL = min(dL, max(sdSeg(q, vec2(gl, 0.0), vec2(gl, hz)) - 0.1016 + uLineW * 0.5, 0.0)); // goal lines, 8 in
|
|
258
|
+
// grids with the nearest index CLAMPED (never a branch per index): the distance stays continuous,
|
|
259
|
+
// so fwidth never spikes and paints a phantom line where the nearest mark changes
|
|
260
|
+
float n5 = clamp(floor(q.x / (5.0 * Y) + 0.5), 0.0, 10.0);
|
|
261
|
+
dL = min(dL, length(vec2(q.x - n5 * 5.0 * Y, max(q.y - hz, 0.0)))); // yard lines every 5 yd
|
|
262
|
+
float n1 = clamp(floor(q.x / Y + 0.5), 0.0, 50.0), dx = q.x - n1 * Y; // 1-yd hashes: inbounds (NFL) and sidelines
|
|
263
|
+
dL = min(dL, length(vec2(dx, max(abs(q.y - 3.124) - 0.305, 0.0))));
|
|
264
|
+
dL = min(dL, length(vec2(dx, max(abs(q.y - (hz - 0.407)) - 0.305, 0.0))));
|
|
265
|
+
dL = min(dL, sdSeg(q, vec2(gl - 1.8288, 0.0), vec2(gl - 1.8288, 0.457))); // try line at the 2
|
|
266
|
+
// field numbers every 10 yd, 6 ft tall, tops 12 yd in from the sideline, read from the near sideline
|
|
267
|
+
float k = clamp(floor(p.x / (10.0 * Y) + 0.5), -4.0, 4.0);
|
|
268
|
+
{
|
|
269
|
+
float sg = p.y < 0.0 ? -1.0 : 1.0;
|
|
270
|
+
vec2 uv = vec2(sg * (p.x - k * 10.0 * Y), -(q.y - (hz - 10.973 + 0.915)));
|
|
271
|
+
dL = min(dL, max(digit7(uv + vec2(0.95, 0.0), int(5.0 - abs(k) + 0.5)) - 0.1 + uLineW * 0.5, 0.0));
|
|
272
|
+
dL = min(dL, max(digit7(uv - vec2(0.95, 0.0), 0) - 0.1 + uLineW * 0.5, 0.0));
|
|
273
|
+
// direction arrows beside the numbers, pointing to the nearer goal (not at the 50)
|
|
274
|
+
if (abs(k) > 0.5) {
|
|
275
|
+
float dir = sign(k);
|
|
276
|
+
vec2 t = vec2((p.x - (k * 10.0 * Y + dir * 2.0)) * dir, q.y - (hz - 10.973 + 0.35));
|
|
277
|
+
float f = max(-0.15 - t.x, abs(t.y) - (0.3 - t.x) * 0.667);
|
|
278
|
+
dL = min(dL, max(f, 0.0));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
field = inBox(p, vec2(hx, hz));
|
|
282
|
+
zone = step(gl, q.x) * field; // the end zones
|
|
283
|
+
} else { // table tennis 2.74 × 1.525 (lines 2 cm along the edges, 3 mm centre line)
|
|
284
|
+
vec2 H = vec2(1.37 - 0.01, 0.7625 - 0.01);
|
|
285
|
+
dL = lnBox(p, vec2(0.0), H);
|
|
286
|
+
float dc = abs(p.y); // centre line along the length
|
|
287
|
+
dL = min(dL, dc + (uLineW - 0.003) * 0.5); // 3 mm line in the same width unit
|
|
288
|
+
field = 1.0;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
`;
|
|
292
|
+
// ---------------------------------------------------------------------------- GLSL: the surfaces
|
|
293
|
+
const SURFACE_GLSL = /* glsl */ `
|
|
294
|
+
// Returns albedo, roughness and a height (for the bump) of the bare surface at p (metres), given the
|
|
295
|
+
// in-play flag and the wear focus (0..1, higher where the play is).
|
|
296
|
+
vec3 surfAlb; float surfRough; float surfH; float lineSoft; float lineBump;
|
|
297
|
+
void surfaceAt(vec2 p, float focus, float worn) {
|
|
298
|
+
int k = int(uSurface + 0.5);
|
|
299
|
+
vec3 base = uSurfCol;
|
|
300
|
+
lineSoft = 1.0; lineBump = 0.0; surfH = 0.0;
|
|
301
|
+
if (k == 0) { // hardcourt: acrylic over asphalt — fine grit, ball marks and scuffs lighten it
|
|
302
|
+
float grit = snoise3(vec3(p * 900.0, 1.0));
|
|
303
|
+
surfAlb = base * (0.94 + 0.12 * grit) * (0.97 + 0.06 * sfbm2(p * 0.7));
|
|
304
|
+
surfAlb = mix(surfAlb, surfAlb * 1.35 + 0.05, worn * 0.7);
|
|
305
|
+
surfRough = 0.72 + 0.1 * grit - worn * 0.12;
|
|
306
|
+
surfH = grit * 0.00012;
|
|
307
|
+
} else if (k == 1) { // clay: crushed brick, brushed streaks along the length, damp patches
|
|
308
|
+
float gr = snoise3(vec3(p * 500.0, 2.0));
|
|
309
|
+
float streak = snoise2(vec2(p.x * 2.5, p.y * 90.0));
|
|
310
|
+
float damp = sfbm2(p * 0.35 + uSeed);
|
|
311
|
+
surfAlb = base * (0.9 + 0.18 * gr) * (0.92 + 0.12 * streak) * mix(1.0, 0.72, smoothstep(0.55, 0.8, damp) * 0.6);
|
|
312
|
+
surfAlb = mix(surfAlb, surfAlb * 0.8, worn * 0.6); // drag marks darken the clay
|
|
313
|
+
surfRough = 0.95;
|
|
314
|
+
surfH = gr * 0.0003 + streak * 0.0002;
|
|
315
|
+
lineSoft = 1.6; lineBump = 0.002; // tape lines, slightly raised, dusty edge
|
|
316
|
+
} else if (k == 2) { // grass: mowing stripes across the length (uMow metres: ~1.3 on a tennis lawn, ~5 on a pitch), blade noise, worn to earth where played
|
|
317
|
+
float tri = abs(fract(p.x / (2.0 * uMow)) - 0.5); // 0..0.5, one stripe each side of 0.25
|
|
318
|
+
float bw = fwidth(p.x) / (2.0 * uMow) + 1e-4;
|
|
319
|
+
float band = smoothstep(0.25 - bw, 0.25 + bw, tri);
|
|
320
|
+
float blades = snoise2(p * 60.0) * 0.5 + snoise2(p * 200.0 + 5.0) * 0.5;
|
|
321
|
+
float ptch = sfbm2(p * 0.15 + uSeed * 3.0);
|
|
322
|
+
surfAlb = base * mix(0.92, 1.08, band) * (0.85 + 0.3 * blades) * (0.9 + 0.2 * ptch);
|
|
323
|
+
vec3 earth = vec3(0.42, 0.33, 0.22);
|
|
324
|
+
surfAlb = mix(surfAlb, earth * (0.8 + 0.4 * blades), worn * 0.85);
|
|
325
|
+
surfRough = 0.95;
|
|
326
|
+
surfH = blades * 0.004 * (1.0 - worn);
|
|
327
|
+
lineSoft = 2.2; // chalk / paint on blades
|
|
328
|
+
} else if (k == 3) { // parquet: boards 5.7 cm wide along the length, staggered ends, varnish dulled where played
|
|
329
|
+
float bw = 0.057;
|
|
330
|
+
float row = floor(p.y / bw);
|
|
331
|
+
float h = shash12(vec2(row, uSeed));
|
|
332
|
+
float len = 1.8 + 0.8 * h;
|
|
333
|
+
float seg = floor((p.x + h * 7.0) / len);
|
|
334
|
+
float tone = shash12(vec2(row * 3.1, seg + uSeed));
|
|
335
|
+
float far = smoothstep(0.15, 0.5, fwidth(p.y) / bw); // boards thinner than a pixel: average them out
|
|
336
|
+
float grain = snoise2(vec2(p.x * 6.0 + seg, p.y * 260.0 + row * 7.0)) * (1.0 - far) + 0.5 * far;
|
|
337
|
+
vec3 wood = base * mix(0.86, 1.14, mix(tone, 0.5, far)) * (0.9 + 0.18 * grain);
|
|
338
|
+
float gap = min(abs(fract(p.y / bw) - 0.5) * bw, abs(fract((p.x + h * 7.0) / len) - 0.5) * len);
|
|
339
|
+
float gapL = (1.0 - smoothstep(0.0, 0.0015 + fwidth(p.x) * 0.5, gap - 0.0007)) * (1.0 - far);
|
|
340
|
+
surfAlb = mix(wood, wood * 0.55, gapL * 0.8);
|
|
341
|
+
surfAlb = mix(surfAlb, surfAlb * 0.9, worn * 0.4);
|
|
342
|
+
surfRough = mix(0.32, 0.6, worn) + 0.08 * grain;
|
|
343
|
+
surfH = -gapL * 0.0006 + grain * 0.00002;
|
|
344
|
+
} else if (k == 4) { // ice: pale blue-white, skate scratches in two directions, markings painted under it
|
|
345
|
+
float sc1 = snoise2(vec2(p.x * 1.5 + p.y * 0.3, p.y * 220.0));
|
|
346
|
+
float sc2 = snoise2(vec2(p.y * 1.2 - p.x * 0.2, p.x * 180.0 + 9.0));
|
|
347
|
+
float scr = max(sc1, sc2);
|
|
348
|
+
float frost = sfbm2(p * 0.4 + uSeed);
|
|
349
|
+
surfAlb = base * (0.96 + 0.04 * frost);
|
|
350
|
+
surfAlb = mix(surfAlb, vec3(1.0), worn * 0.5 * smoothstep(0.6, 0.95, scr)); // snow dust in the cuts
|
|
351
|
+
surfRough = mix(0.06, 0.3, worn * smoothstep(0.5, 0.95, scr)) + 0.02 * frost;
|
|
352
|
+
surfH = -worn * smoothstep(0.75, 0.95, scr) * 0.0004;
|
|
353
|
+
lineSoft = 2.5; // under the ice: soft-edged, slightly veiled
|
|
354
|
+
} else if (k == 5) { // tartan: rubber granules
|
|
355
|
+
float gr = snoise3(vec3(p * 420.0, 3.0));
|
|
356
|
+
surfAlb = base * (0.82 + 0.3 * gr) * (0.95 + 0.08 * sfbm2(p * 0.3));
|
|
357
|
+
surfAlb = mix(surfAlb, surfAlb * 1.2 + 0.03, worn * 0.5);
|
|
358
|
+
surfRough = 0.9;
|
|
359
|
+
surfH = gr * 0.0005;
|
|
360
|
+
} else if (k == 6) { // artificial turf: fibres with a nap direction, sand infill
|
|
361
|
+
float fib = snoise2(vec2(p.x * 300.0, p.y * 40.0));
|
|
362
|
+
float sand = step(0.93, snoise2(p * 700.0));
|
|
363
|
+
surfAlb = base * (0.85 + 0.3 * fib);
|
|
364
|
+
surfAlb = mix(surfAlb, vec3(0.75, 0.7, 0.6), sand * 0.5 + worn * 0.35);
|
|
365
|
+
surfRough = 0.9;
|
|
366
|
+
surfH = fib * 0.001;
|
|
367
|
+
} else if (k == 7) { // sand: ripples and footprints
|
|
368
|
+
float rip = sfbm2(p * vec2(2.5, 0.8));
|
|
369
|
+
float grain = snoise3(vec3(p * 600.0, 4.0));
|
|
370
|
+
surfAlb = base * (0.9 + 0.1 * rip) * (0.94 + 0.12 * grain);
|
|
371
|
+
surfAlb = mix(surfAlb, surfAlb * 0.85, worn * 0.4);
|
|
372
|
+
surfRough = 1.0;
|
|
373
|
+
surfH = rip * 0.012 + grain * 0.0006 - worn * 0.004 * smoothstep(0.4, 0.7, sfbm2(p * 3.0));
|
|
374
|
+
lineSoft = 3.0;
|
|
375
|
+
} else if (k == 8) { // concrete: panels, tone variation, cracks
|
|
376
|
+
float tone = sfbm2(p * 0.25 + uSeed);
|
|
377
|
+
float crack = 1.0 - abs(2.0 * sfbm2(p * 0.9 + 3.0) - 1.0);
|
|
378
|
+
float cr = smoothstep(0.93, 0.99, crack);
|
|
379
|
+
float joint = min(abs(fract(p.x / 4.0) - 0.5) * 4.0, abs(fract(p.y / 4.0) - 0.5) * 4.0);
|
|
380
|
+
float jl = 1.0 - smoothstep(0.004, 0.012, joint);
|
|
381
|
+
surfAlb = base * (0.85 + 0.3 * tone) * (1.0 - 0.5 * cr) * (1.0 - 0.4 * jl);
|
|
382
|
+
surfAlb = mix(surfAlb, surfAlb * 0.75, worn * 0.5);
|
|
383
|
+
surfRough = 0.9 - 0.1 * tone;
|
|
384
|
+
surfH = -cr * 0.0015 - jl * 0.002;
|
|
385
|
+
} else { // painted (a table top): matte paint, slight orange peel, scuffed edges
|
|
386
|
+
float peel = snoise2(p * 500.0);
|
|
387
|
+
surfAlb = base * (0.97 + 0.05 * peel);
|
|
388
|
+
surfAlb = mix(surfAlb, surfAlb * 1.3 + 0.05, worn * 0.5);
|
|
389
|
+
surfRough = 0.55 + 0.05 * peel + worn * 0.2;
|
|
390
|
+
surfH = peel * 0.00003;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
`;
|
|
394
|
+
export function courtMaterial(u) {
|
|
395
|
+
return litMaterial(u, {
|
|
396
|
+
name: 'court', roughness: 0.7, metalness: 0,
|
|
397
|
+
depthBias: [-4, -8], // beats urban paving (-2 / -4) it may be laid on
|
|
398
|
+
pars: 'float courtRough; float courtH;\n' + GLSL_COMMON + MARKINGS_GLSL + SURFACE_GLSL,
|
|
399
|
+
// the lamp list's pools (street lamps, floodlights), faded in by the night factor — urban's lampLight
|
|
400
|
+
emissive: /* glsl */ `totalEmissiveRadiance += diffuseColor.rgb * lampLight(vWorldPos, normalize(inverseTransformDirection(normal, viewMatrix)));`,
|
|
401
|
+
color: /* glsl */ `
|
|
402
|
+
vec2 p = vObj.xz;
|
|
403
|
+
float dL, dA, wA, dD, dOn, zone, field;
|
|
404
|
+
markings(p, dL, dA, wA, dD, dOn, zone, field);
|
|
405
|
+
// table top only (a flat court has uTableY < 0 → always true)
|
|
406
|
+
float top = step(uTableY - 0.002, vObj.y);
|
|
407
|
+
if (top < 0.5) { dL = 1e9; dA = 1e9; dD = 1e9; zone = 0.0; }
|
|
408
|
+
// wear concentrates where the lines are dense and inside the field
|
|
409
|
+
float focus = field * (0.2 + 0.8 * (1.0 - smoothstep(0.0, 1.2, min(dL, dA)))) + zone * 0.3;
|
|
410
|
+
if (int(uSport + 0.5) == 0) // tennis wears behind the baselines (centre), then around the service T
|
|
411
|
+
focus = field * 0.1 + exp(-pow((abs(p.x) - 11.6) / 1.4, 2.0) - pow(p.y / 2.6, 2.0)) + 0.45 * exp(-pow((abs(p.x) - 6.4) / 0.9, 2.0) - pow(p.y / 1.3, 2.0));
|
|
412
|
+
if (int(uSport + 0.5) == 12) // a gridiron wears between the hashes, most between the 20s
|
|
413
|
+
focus = field * (0.15 + 0.85 * exp(-pow(p.y / 6.0, 2.0)) * (0.5 + 0.5 * exp(-pow(p.x / 30.0, 2.0))));
|
|
414
|
+
if (int(uSport + 0.5) == 2) // a pitch wears in the goalmouths and around the centre spot
|
|
415
|
+
focus = field * (0.1 + 0.9 * exp(-pow((abs(p.x) - 52.5) / 7.0, 2.0) - pow(p.y / 9.0, 2.0)) + 0.5 * exp(-dot(p, p) / 60.0));
|
|
416
|
+
float worn = scuffs(vec3(p.x, 0.0, p.y), 1.6, focus) ;
|
|
417
|
+
surfaceAt(p, focus, worn);
|
|
418
|
+
vec3 alb = mix(surfAlb, surfAlb * (uZoneCol / max(uSurfCol, vec3(0.02))), zone);
|
|
419
|
+
// lines, anti-aliased, softened per surface; worn lines thin and fade
|
|
420
|
+
float lw = uLineW * mix(1.0, 0.85, worn);
|
|
421
|
+
float lineA = 1.0 - smoothstep(lw * 0.5 - fwidth(dL) * lineSoft * 0.7, lw * 0.5 + fwidth(dL) * lineSoft * 0.7, abs(dL));
|
|
422
|
+
float accA = 1.0 - smoothstep(wA * 0.5 - fwidth(dA) * lineSoft * 0.7, wA * 0.5 + fwidth(dA) * lineSoft * 0.7, abs(dA));
|
|
423
|
+
float dashA = (1.0 - smoothstep(lw * 0.5 - fwidth(dD) * lineSoft * 0.7, lw * 0.5 + fwidth(dD) * lineSoft * 0.7, abs(dD))) * dOn;
|
|
424
|
+
lineA = max(lineA, dashA);
|
|
425
|
+
lineA *= 1.0 - worn * 0.55;
|
|
426
|
+
alb = mix(alb, uZoneCol, accA * 0.95);
|
|
427
|
+
alb = mix(alb, uLineCol, lineA * 0.95);
|
|
428
|
+
float h = surfH + lineA * lineBump;
|
|
429
|
+
// wet: dark and glossy, puddles in the hollows
|
|
430
|
+
float puddle = smoothstep(1.0 - uWet * 0.6, 1.05 - uWet * 0.6, sfbm2(p * 0.22 + uSeed * 2.0 + 11.0)) * step(0.01, uWet);
|
|
431
|
+
float damp = clamp(uWet * 0.6 + puddle, 0.0, 1.0);
|
|
432
|
+
alb *= mix(1.0, 0.55, damp);
|
|
433
|
+
courtRough = clamp(mix(mix(surfRough, 0.35, lineA * 0.5), 0.06, damp) / max(uGloss, 0.05), 0.03, 1.0);
|
|
434
|
+
courtH = mix(h, 0.0, puddle);
|
|
435
|
+
diffuseColor.rgb *= alb;`,
|
|
436
|
+
rough: 'courtRough',
|
|
437
|
+
normal: /* glsl */ `normal = bumpNormal(normal, courtH);`,
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
export function build(u, c) {
|
|
441
|
+
const S = SPORTS[sportKey(c.sport)];
|
|
442
|
+
const q = QUALITY_S[c.quality] || 1;
|
|
443
|
+
const mx = S.runoff[0] * (c.margin ?? 1), mz = S.runoff[1] * (c.margin ?? 1);
|
|
444
|
+
const L = S.L + 2 * mx, W = S.W + 2 * mz;
|
|
445
|
+
const object = new THREE.Group();
|
|
446
|
+
object.name = 'court';
|
|
447
|
+
const geos = [], mats = [], fixtures = [];
|
|
448
|
+
const pair = courtMaterial(u);
|
|
449
|
+
mats.push(pair);
|
|
450
|
+
if (S.table) {
|
|
451
|
+
// a table: the top box (markings on its top face), an apron, four legs, a brace
|
|
452
|
+
const t = S.table, th = 0.025;
|
|
453
|
+
const top = new THREE.BoxGeometry(S.L, th, S.W);
|
|
454
|
+
top.translate(0, t - th / 2, 0);
|
|
455
|
+
geos.push(top);
|
|
456
|
+
object.add(propMesh(top, pair, 'top'));
|
|
457
|
+
u.uTableY.value = t - 0.001;
|
|
458
|
+
const legP = partMaterial(u, { kind: 'metal', slot: 3, tint: '#3a3a3a', roughness: 0.45, metalness: 1, axis: [0, 1, 0] });
|
|
459
|
+
mats.push(legP);
|
|
460
|
+
const legs = [];
|
|
461
|
+
for (const sx of [-1, 1])
|
|
462
|
+
for (const sz of [-1, 1])
|
|
463
|
+
legs.push(box(0.05, t - th, 0.05, [sx * (S.L / 2 - 0.25), (t - th) / 2, sz * (S.W / 2 - 0.2)]));
|
|
464
|
+
legs.push(box(S.L - 0.5, 0.04, 0.04, [0, 0.2, 0]), box(S.L - 0.1, 0.06, 0.02, [0, t - th - 0.03, S.W / 2 - 0.01]), box(S.L - 0.1, 0.06, 0.02, [0, t - th - 0.03, -S.W / 2 + 0.01]));
|
|
465
|
+
const lg = mergeGeos(legs);
|
|
466
|
+
geos.push(lg);
|
|
467
|
+
object.add(propMesh(lg, legP, 'legs'));
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
u.uTableY.value = -1;
|
|
471
|
+
// the slab: a rounded rectangle (hockey rink corners), flat on the ground
|
|
472
|
+
const rc = Math.min((S.corner || 0) + Math.min(mx, mz) * 0.0, L / 2, W / 2);
|
|
473
|
+
const shape = new THREE.Shape();
|
|
474
|
+
const hx = L / 2, hz = W / 2, r = Math.max(0, rc);
|
|
475
|
+
if (r > 0.01) {
|
|
476
|
+
shape.moveTo(-hx + r, -hz);
|
|
477
|
+
shape.lineTo(hx - r, -hz);
|
|
478
|
+
shape.absarc(hx - r, -hz + r, r, -Math.PI / 2, 0, false);
|
|
479
|
+
shape.lineTo(hx, hz - r);
|
|
480
|
+
shape.absarc(hx - r, hz - r, r, 0, Math.PI / 2, false);
|
|
481
|
+
shape.lineTo(-hx + r, hz);
|
|
482
|
+
shape.absarc(-hx + r, hz - r, r, Math.PI / 2, Math.PI, false);
|
|
483
|
+
shape.lineTo(-hx, -hz + r);
|
|
484
|
+
shape.absarc(-hx + r, -hz + r, r, Math.PI, Math.PI * 1.5, false);
|
|
485
|
+
}
|
|
486
|
+
else {
|
|
487
|
+
shape.moveTo(-hx, -hz);
|
|
488
|
+
shape.lineTo(hx, -hz);
|
|
489
|
+
shape.lineTo(hx, hz);
|
|
490
|
+
shape.lineTo(-hx, hz);
|
|
491
|
+
shape.closePath();
|
|
492
|
+
}
|
|
493
|
+
// one slab 6 cm thick (top face at y = 0.02): a single geometry, so nothing can z-fight under the markings
|
|
494
|
+
const g = new THREE.ExtrudeGeometry(shape, { depth: 0.06, bevelEnabled: false, curveSegments: 12 + Math.round(12 * q) });
|
|
495
|
+
g.rotateX(Math.PI / 2);
|
|
496
|
+
g.translate(0, 0.02, 0); // XY → XZ, extruded downward; the top sits 2 cm proud of the ground
|
|
497
|
+
g.computeVertexNormals();
|
|
498
|
+
geos.push(g);
|
|
499
|
+
object.add(propMesh(g, pair, 'surface', { cast: false, receive: true }));
|
|
500
|
+
}
|
|
501
|
+
if (c.fixtures !== false) {
|
|
502
|
+
const G = GOAL_COLORS[S.fixtures[0] && S.fixtures[0].kind];
|
|
503
|
+
if (G) {
|
|
504
|
+
setColor(u.fixtureU.uColor, G.colors[0]);
|
|
505
|
+
setColor(u.fixtureU.uSecondaryColor, G.colors[1]);
|
|
506
|
+
setColor(u.fixtureU.uAccentColor, G.colors[2]);
|
|
507
|
+
}
|
|
508
|
+
for (const f of S.fixtures) {
|
|
509
|
+
const gl = buildGoal(f.kind, u.fixtureU, { quality: q, sag: 0.25, mesh: G ? G.mesh : undefined });
|
|
510
|
+
gl.object.position.set(f.x, S.table ? S.table : 0, 0);
|
|
511
|
+
gl.object.rotation.y = f.rot * Math.PI / 2;
|
|
512
|
+
object.add(gl.object);
|
|
513
|
+
fixtures.push(gl);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
// ---- floodlights: masts with heads that glow at night, registered in the lamp list
|
|
517
|
+
const lamps = [], heads = [], aims = [];
|
|
518
|
+
const F = FLOOD[sportKey(c.sport)] || null;
|
|
519
|
+
if (c.floodlights !== false && F && !S.table) {
|
|
520
|
+
let lensP = null;
|
|
521
|
+
const poleP = partMaterial(u, { kind: 'metal', slot: 3, tint: '#8c9196', roughness: 0.45, metalness: 1, axis: [0, 1, 0] });
|
|
522
|
+
mats.push(poleP);
|
|
523
|
+
const headP = litMaterial(u, {
|
|
524
|
+
name: 'flood-head', roughness: 0.35, metalness: 0.6,
|
|
525
|
+
pars: /* glsl */ `uniform vec3 uFloodColor; uniform float uFloodGlow; uniform float uNight;`,
|
|
526
|
+
color: /* glsl */ `diffuseColor.rgb *= vec3(0.16);`,
|
|
527
|
+
// the lens faces down toward the court: it glows by the night factor, brighter than 1 so bloom can take it
|
|
528
|
+
emissive: /* glsl */ `{ vec3 nw = normalize(inverseTransformDirection(normal, viewMatrix)); totalEmissiveRadiance += uFloodColor * (uFloodGlow * uNight * 6.0 * (1.0 - smoothstep(-0.6, -0.2, nw.y))); }`,
|
|
529
|
+
});
|
|
530
|
+
mats.push(headP);
|
|
531
|
+
const poles = [], headGeos = [];
|
|
532
|
+
const addHead = (pole, head, tiltX, tiltZ, size) => {
|
|
533
|
+
const [w, d] = size;
|
|
534
|
+
headGeos.push(box(w, 0.14, d, head, [tiltX, 0, tiltZ]));
|
|
535
|
+
heads.push(new THREE.Vector3(head[0], head[1] - 0.15, head[2]));
|
|
536
|
+
};
|
|
537
|
+
if (F.mode === 'sides') {
|
|
538
|
+
// poles stand ON the slab's outer edge line: courts laid side by side share them (their poles
|
|
539
|
+
// coincide), as at a real club, instead of two poles a step apart
|
|
540
|
+
const zEdge = W / 2, reach = 1.6;
|
|
541
|
+
for (let i = 0; i < F.n; i++) {
|
|
542
|
+
const x = -L / 2 + L * (i + 0.5) / F.n;
|
|
543
|
+
for (const sz of [-1, 1]) {
|
|
544
|
+
const zp = sz * zEdge, zh = sz * (zEdge - reach);
|
|
545
|
+
poles.push(bar([x, 0, zp], [x, F.h + 0.2, zp], 0.07 + F.h * 0.004, 10), bar([x, F.h + 0.15, zp], [x, F.h + 0.15, zh], 0.04, 8));
|
|
546
|
+
addHead([x, 0, zp], [x, F.h, zh], sz * -0.5, 0, [1.0, 0.55]);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
// stadium towers: a lattice-like mast (four legs braced to a platform) with a bank of
|
|
552
|
+
// projectors — dark housings, each with a lens that glows by the night factor
|
|
553
|
+
lensP = litMaterial(u, {
|
|
554
|
+
name: 'flood-lens', roughness: 0.2, metalness: 0,
|
|
555
|
+
pars: /* glsl */ `uniform vec3 uFloodColor; uniform float uFloodGlow; uniform float uNight;`,
|
|
556
|
+
color: /* glsl */ `diffuseColor.rgb = mix(vec3(0.55), uFloodColor, 0.3);`,
|
|
557
|
+
emissive: /* glsl */ `totalEmissiveRadiance += uFloodColor * (uFloodGlow * uNight * 9.0);`,
|
|
558
|
+
});
|
|
559
|
+
mats.push(lensP);
|
|
560
|
+
const lensGeos = [];
|
|
561
|
+
const o3 = new THREE.Object3D();
|
|
562
|
+
for (const sx of [-1, 1])
|
|
563
|
+
for (const sz of [-1, 1]) {
|
|
564
|
+
const xp = sx * (L / 2 + F.set), zp = sz * (W / 2 + F.set), H = F.h;
|
|
565
|
+
// the mast: four legs from a wide base to the platform, a few braces
|
|
566
|
+
const b0 = 1.6, b1 = 0.7;
|
|
567
|
+
for (const lx of [-1, 1])
|
|
568
|
+
for (const lz of [-1, 1])
|
|
569
|
+
poles.push(bar([xp + lx * b0, 0, zp + lz * b0], [xp + lx * b1, H - 2.2, zp + lz * b1], 0.16, 8));
|
|
570
|
+
for (let k = 1; k <= 4; k++) {
|
|
571
|
+
const y = (H - 2.2) * k / 5, t = k / 5, bb = b0 + (b1 - b0) * t;
|
|
572
|
+
poles.push(bar([xp - bb, y, zp - bb], [xp + bb, y, zp - bb], 0.07, 6), bar([xp - bb, y, zp + bb], [xp + bb, y, zp + bb], 0.07, 6), bar([xp - bb, y, zp - bb], [xp - bb, y, zp + bb], 0.07, 6), bar([xp + bb, y, zp - bb], [xp + bb, y, zp + bb], 0.07, 6));
|
|
573
|
+
}
|
|
574
|
+
// the bank: a frame facing the field centre, tilted down toward it
|
|
575
|
+
const to = new THREE.Vector3(-xp, -H, -zp).normalize();
|
|
576
|
+
const yaw = Math.atan2(to.x, to.z);
|
|
577
|
+
const bw = F.cols * 1.0 + 0.4, bh = F.rows * 0.85 + 0.4;
|
|
578
|
+
const bankC = new THREE.Vector3(xp, H, zp).addScaledVector(new THREE.Vector3(to.x, 0, to.z).normalize(), 0.9);
|
|
579
|
+
o3.position.copy(bankC);
|
|
580
|
+
o3.rotation.set(0, yaw, 0);
|
|
581
|
+
o3.rotateX(0.55);
|
|
582
|
+
o3.updateMatrix();
|
|
583
|
+
const frame = new THREE.BoxGeometry(bw, bh, 0.25);
|
|
584
|
+
frame.applyMatrix4(new THREE.Matrix4().makeTranslation(0, 0, -0.45));
|
|
585
|
+
frame.applyMatrix4(o3.matrix);
|
|
586
|
+
poles.push(frame);
|
|
587
|
+
poles.push(box(bw * 0.8, 0.3, 3.2, [xp, H - 2.2, zp], [0, yaw, 0])); // the service platform
|
|
588
|
+
for (let r = 0; r < F.rows; r++)
|
|
589
|
+
for (let k = 0; k < F.cols; k++) {
|
|
590
|
+
const lx = (k - (F.cols - 1) / 2) * 1.0, ly = (r - (F.rows - 1) / 2) * 0.85;
|
|
591
|
+
const m = new THREE.Matrix4().makeTranslation(lx, ly, 0).premultiply(o3.matrix);
|
|
592
|
+
const hous = new THREE.BoxGeometry(0.82, 0.68, 0.5);
|
|
593
|
+
hous.applyMatrix4(new THREE.Matrix4().makeTranslation(0, 0, -0.1));
|
|
594
|
+
hous.applyMatrix4(m);
|
|
595
|
+
poles.push(hous);
|
|
596
|
+
const lens = new THREE.PlaneGeometry(0.7, 0.56);
|
|
597
|
+
lens.applyMatrix4(new THREE.Matrix4().makeTranslation(0, 0, 0.152));
|
|
598
|
+
lens.applyMatrix4(m);
|
|
599
|
+
lensGeos.push(lens);
|
|
600
|
+
}
|
|
601
|
+
// one projector beam per field quarter, from the bank
|
|
602
|
+
for (const qx of [-1, 1])
|
|
603
|
+
for (const qz of [-1, 1]) {
|
|
604
|
+
const tgt = new THREE.Vector3(qx * L / 4, 0, qz * W / 4);
|
|
605
|
+
heads.push(bankC.clone());
|
|
606
|
+
aims.push(tgt.sub(bankC).normalize());
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
const lg = mergeGeos(lensGeos);
|
|
610
|
+
geos.push(lg);
|
|
611
|
+
object.add(propMesh(lg, lensP, 'projector lenses', { cast: false, receive: false }));
|
|
612
|
+
}
|
|
613
|
+
const pg = mergeGeos(poles);
|
|
614
|
+
geos.push(pg);
|
|
615
|
+
object.add(propMesh(pg, poleP, 'floodlight masts'));
|
|
616
|
+
if (headGeos.length) {
|
|
617
|
+
const hg = mergeGeos(headGeos);
|
|
618
|
+
geos.push(hg);
|
|
619
|
+
object.add(propMesh(hg, headP, 'floodlight heads', { receive: false }));
|
|
620
|
+
}
|
|
621
|
+
heads.forEach((p, i) => lamps.push(registerLamp({ id: aims[i] ? 'court-projector' : 'court-flood', position: p.clone(), color: new THREE.Color(c.floodColor || '#fff1dc'), radius: F.radius, intensity: F.I * (c.floodIntensity ?? 1), base: F.I, on: true,
|
|
622
|
+
aim: aims[i] ? aims[i].clone() : undefined, spread: F.spread })));
|
|
623
|
+
}
|
|
624
|
+
const inst = { mats: mats.map((p) => p.material), fixtures, fixtureMats: fixtures.flatMap((f) => f.mats.map((p) => p.material)), lamps };
|
|
625
|
+
applyConfig(u, c, inst);
|
|
626
|
+
// the playing surface's local bounds: the shared time-lighting hook (useTimeLighting) gathers
|
|
627
|
+
// the lamps that reach it, in world space, whenever the lamp list changes or the court moves
|
|
628
|
+
const localBox = new THREE.Box3(new THREE.Vector3(-L / 2, -0.1, -W / 2), new THREE.Vector3(L / 2, (S.table || 0) + 0.2, W / 2));
|
|
629
|
+
const lastWorld = new THREE.Matrix4();
|
|
630
|
+
return {
|
|
631
|
+
object,
|
|
632
|
+
materials: inst.mats.concat(inst.fixtureMats),
|
|
633
|
+
/** the uniform sets that take the sun block (uNight) and gather lamps — the TimeControls pattern */
|
|
634
|
+
uniformSets: [u],
|
|
635
|
+
bounds: function () { return localBox; },
|
|
636
|
+
apply: function (cfg) { applyConfig(u, cfg, inst); },
|
|
637
|
+
/** per frame: the shared clock, and this court's floodlights kept at their world positions (like urban's lamps) */
|
|
638
|
+
update: function (dt) {
|
|
639
|
+
updateCommon(u, dt);
|
|
640
|
+
if (!lamps.length)
|
|
641
|
+
return;
|
|
642
|
+
object.updateWorldMatrix(true, false);
|
|
643
|
+
if (!lastWorld.equals(object.matrixWorld)) {
|
|
644
|
+
lastWorld.copy(object.matrixWorld);
|
|
645
|
+
placeLamps(lamps, heads, object.matrixWorld); // positions, reach and falloff follow the object's scale
|
|
646
|
+
for (let i = 0; i < lamps.length; i++)
|
|
647
|
+
if (aims[i])
|
|
648
|
+
lamps[i].aim.copy(aims[i]).transformDirection(object.matrixWorld);
|
|
649
|
+
touchLamps();
|
|
650
|
+
}
|
|
651
|
+
},
|
|
652
|
+
stats: { size: [L, W], fixtures: fixtures.length, floodlights: lamps.length },
|
|
653
|
+
dispose: function () { for (const Lp of lamps)
|
|
654
|
+
unregisterLamp(Lp); geos.forEach((g) => g.dispose()); fixtures.forEach((f) => f.dispose()); mats.forEach(disposePair); },
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
/** Knobs whose change rebuilds the object (dispose + build); every other knob is a live push through apply. */
|
|
658
|
+
export const STRUCTURAL = ['sport', 'surface', 'margin', 'fixtures', 'floodlights', 'quality', 'seed'];
|