@3driseai/3drise-viewer 0.1.41 → 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/ui/UiLayers.d.ts +17 -1
- package/dist/ui/UiLayers.d.ts.map +1 -1
- package/dist/ui/UiLayers.js +76 -3
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.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,741 @@
|
|
|
1
|
+
// Emitted from Claude outputs/urban-lab/building.mjs by emit_object.mjs — edit the lab module and re-emit.
|
|
2
|
+
// =============================================================================
|
|
3
|
+
// urban/building — a parametric building: boxes with a facade drawn per fragment
|
|
4
|
+
// =============================================================================
|
|
5
|
+
// Construction. A building is a few VOLUMES — unit cubes, plus a gable prism, a frustum
|
|
6
|
+
// (mansard) and a cylinder (round towers, helipads) — each an instance of ONE unit geometry
|
|
7
|
+
// in one InstancedMesh per geometry kind, all sharing the facade material: a building is
|
|
8
|
+
// at most four draw calls and ~12 triangles per volume. Footprints: box, L, U, courtyard,
|
|
9
|
+
// stepped setbacks, slab, tower-on-podium, twin towers on a podium, cylinder. The facade
|
|
10
|
+
// is not geometry: the fragment shader turns the face-local metres (u along the face, v
|
|
11
|
+
// up; around the circumference on a cylinder) into floors and bays, then into glass /
|
|
12
|
+
// spandrel / mullion / wall, anti-aliased with fwidth. Eight window patterns: curtain wall,
|
|
13
|
+
// punched, ribbon, brick (running bond + lintels), balconies (recessed, slab + railing),
|
|
14
|
+
// concrete panel (joints), glass fins (vertical louvres) and industrial (tall windows,
|
|
15
|
+
// roller doors). Roofs: flat, parapet, mechanical box, pitched (gable), mansard, helipad
|
|
16
|
+
// (marked disc), hip, crown (an emissive band at night), green (lawn).
|
|
17
|
+
//
|
|
18
|
+
// Optics. Glass = a dark interior tinted by the glass colour under a Fresnel-weighted sky
|
|
19
|
+
// reflection (sky above the horizon, ground below) plus a sun glint; the wall is a
|
|
20
|
+
// library texture set (colour / normal / roughness) whose colour is normalised to its
|
|
21
|
+
// mean so the wall colour knob decides the albedo. At night a per-window hash lights a
|
|
22
|
+
// share of the rooms (windowLights) in a warm / cool mix; the emissive is in the shader,
|
|
23
|
+
// never a light. Street lamps reach the facade through the shared lamp list (lampLight).
|
|
24
|
+
//
|
|
25
|
+
// The same geometry builder is used by `block`, which adds many buildings to the same
|
|
26
|
+
// InstancedMesh.
|
|
27
|
+
import * as THREE from 'three';
|
|
28
|
+
import { mulberry32, createSunUniforms, createLampUniforms, createTextureUniforms, applyTextureSet, glslTextureBlock, GLSL_COMMON, GLSL_FOG_PARS, GLSL_FOG_VERT_PARS, GLSL_OUT, loadTextureSet, } from '../urbanCore.js';
|
|
29
|
+
export const FOOTPRINTS = ['box', 'lShape', 'podiumTower', 'uShape', 'courtyard', 'stepped', 'slab', 'twinTowers', 'cylinder'];
|
|
30
|
+
export const FACADES = ['curtainWall', 'punched', 'ribbon', 'brick', 'balconies', 'concretePanel', 'glassFins', 'industrial'];
|
|
31
|
+
export const ROOFS = ['flat', 'parapet', 'mechanical', 'pitched', 'hip', 'mansard', 'helipad', 'crown', 'green'];
|
|
32
|
+
export const LIGHTING = ['auto', 'day', 'night'];
|
|
33
|
+
// ---------------------------------------------------------------------------- mixes
|
|
34
|
+
// A mix is a city character: weights over footprints, facades and roofs, a floor range and
|
|
35
|
+
// whether ground floors are lobbies. `block` and `skyline` draw their buildings from one.
|
|
36
|
+
export const MIXES = ['custom', 'downtown', 'residential', 'oldTown', 'industrial', 'suburb'];
|
|
37
|
+
const MIX_TABLE = {
|
|
38
|
+
downtown: { footprints: { box: 3, podiumTower: 3, twinTowers: 1, stepped: 2, cylinder: 1 }, facades: { curtainWall: 4, ribbon: 2, glassFins: 3, concretePanel: 1 }, roofs: { parapet: 3, mechanical: 3, helipad: 1, crown: 2, flat: 1 }, floors: [8, 40], lobby: true },
|
|
39
|
+
residential: { footprints: { slab: 3, uShape: 2, courtyard: 2, box: 2, lShape: 1 }, facades: { balconies: 4, ribbon: 1, punched: 2 }, roofs: { parapet: 2, flat: 2, green: 1, mechanical: 1 }, floors: [4, 12], lobby: false },
|
|
40
|
+
oldTown: { footprints: { box: 4, lShape: 2, courtyard: 2 }, facades: { brick: 4, punched: 3 }, roofs: { mansard: 3, pitched: 2, hip: 1, parapet: 1 }, floors: [3, 6], lobby: false },
|
|
41
|
+
industrial: { footprints: { box: 4, slab: 2, lShape: 1 }, facades: { industrial: 4, concretePanel: 2 }, roofs: { flat: 3, pitched: 2, parapet: 1 }, floors: [1, 3], lobby: false },
|
|
42
|
+
suburb: { footprints: { box: 4, lShape: 3 }, facades: { punched: 3, brick: 2 }, roofs: { pitched: 3, hip: 3, mansard: 1 }, floors: [1, 3], lobby: false },
|
|
43
|
+
};
|
|
44
|
+
function weighted(rng, table) {
|
|
45
|
+
let total = 0;
|
|
46
|
+
for (const k in table)
|
|
47
|
+
total += table[k];
|
|
48
|
+
let r = rng() * total;
|
|
49
|
+
for (const k in table) {
|
|
50
|
+
r -= table[k];
|
|
51
|
+
if (r <= 0)
|
|
52
|
+
return k;
|
|
53
|
+
}
|
|
54
|
+
return Object.keys(table)[0];
|
|
55
|
+
}
|
|
56
|
+
/** One building's picks from a mix (null for 'custom'): { footprint, facade, roof, floors, lobby }. */
|
|
57
|
+
export function pickMix(rng, mix) {
|
|
58
|
+
const m = MIX_TABLE[mix];
|
|
59
|
+
if (!m)
|
|
60
|
+
return null;
|
|
61
|
+
const floors = Math.round(m.floors[0] + (m.floors[1] - m.floors[0]) * Math.pow(rng(), 1.4));
|
|
62
|
+
return { footprint: weighted(rng, m.footprints), facade: weighted(rng, m.facades), roof: weighted(rng, m.roofs), floors, lobby: m.lobby };
|
|
63
|
+
}
|
|
64
|
+
/** Structural knobs: the instance list is rebuilt when one changes. */
|
|
65
|
+
export const STRUCTURAL = ['footprint', 'width', 'depth', 'floors', 'floorHeight', 'lobby', 'roof', 'seed', 'texture', 'facade', 'windowRatio', 'bayWidth', 'windowLights'];
|
|
66
|
+
// ---------------------------------------------------------------------------- instance list
|
|
67
|
+
// Each entry is one unit-geometry instance: { geo, x, y, z, ry, w, h, d, seed, floors, floorH, style, kind, ratio, bay, lights, tint }.
|
|
68
|
+
// geo: 'box' (default) | 'prism' (gable roof) | 'hipEnd' (one sloped end of a hip roof) | 'frustum' (mansard) | 'cyl' (round tower, helipad, discs).
|
|
69
|
+
// style: 0 facade volume with lobby, 1 solid wall-coloured, 2 facade volume without lobby,
|
|
70
|
+
// 3 roof-coloured solid (kind = marking: 0 plain, 1 helipad, 2 lawn), 4 crown (emissive band at night).
|
|
71
|
+
// +10 on a cylinder facade: the shader maps bays around the circumference.
|
|
72
|
+
export const STYLE_FACADE = 0, STYLE_SOLID = 1, STYLE_UPPER = 2, STYLE_ROOF = 3, STYLE_CROWN = 4, ROUND = 10;
|
|
73
|
+
export const MARK_NONE = 0, MARK_HELIPAD = 1, MARK_LAWN = 2;
|
|
74
|
+
function lobbyHeight(c) { return c.lobby ? c.floorHeight * 1.6 : c.floorHeight; }
|
|
75
|
+
/** Push the instances of one building described by `c` (building knobs) at (x, z) turned ry, into `list`. */
|
|
76
|
+
export function addBuilding(list, c, x, z, ry = 0, tint = [1, 1, 1], seed = undefined) {
|
|
77
|
+
const rng = mulberry32((seed === undefined ? c.seed : seed) * 1013 + 17);
|
|
78
|
+
const fl = Math.max(1, Math.round(c.floors));
|
|
79
|
+
const fh = c.floorHeight;
|
|
80
|
+
const hTotal = lobbyHeight(c) + (fl - 1) * fh;
|
|
81
|
+
const kind = Math.max(0, FACADES.indexOf(c.facade));
|
|
82
|
+
const base = { seed: Math.floor(rng() * 100000), floorH: fh, kind, ratio: c.windowRatio, bay: c.bayWidth, lights: c.windowLights, tint: tint || [1, 1, 1] };
|
|
83
|
+
const cs = Math.cos(ry), sn = Math.sin(ry);
|
|
84
|
+
/** One volume at a local offset (rotated by ry about the building origin). extra: { y, geo, kind }. */
|
|
85
|
+
const vol = (lx, lz, w, h, d, floors, style, extra = {}) => {
|
|
86
|
+
const it = Object.assign({ geo: 'box', x: x + lx * cs + lz * sn, z: z - lx * sn + lz * cs, ry, w, h, d, floors, style }, base, style === STYLE_ROOF ? { kind: MARK_NONE } : {}, extra);
|
|
87
|
+
list.push(it);
|
|
88
|
+
return it;
|
|
89
|
+
};
|
|
90
|
+
const floorsH = (n) => lobbyHeight(c) + (n - 1) * fh;
|
|
91
|
+
/** Parapet walls around a rectangle at height `top`. */
|
|
92
|
+
const parapet = (lx, lz, w, d, top, style = STYLE_SOLID, ph = 0.9) => {
|
|
93
|
+
const t = 0.3;
|
|
94
|
+
vol(lx, lz - d / 2 + t / 2, w, ph, t, 0, style, { y: top });
|
|
95
|
+
vol(lx, lz + d / 2 - t / 2, w, ph, t, 0, style, { y: top });
|
|
96
|
+
vol(lx - w / 2 + t / 2, lz, t, ph, d - 2 * t, 0, style, { y: top });
|
|
97
|
+
vol(lx + w / 2 - t / 2, lz, t, ph, d - 2 * t, 0, style, { y: top });
|
|
98
|
+
};
|
|
99
|
+
const plantBox = (lx, lz, w, d, top) => {
|
|
100
|
+
const mw = Math.max(2.5, w * (0.25 + rng() * 0.15)), md = Math.max(2.5, d * (0.25 + rng() * 0.15));
|
|
101
|
+
vol(lx + (rng() - 0.5) * (w - mw) * 0.7, lz + (rng() - 0.5) * (d - md) * 0.7, mw, 2.6 + rng() * 1.2, md, 0, STYLE_SOLID, { y: top });
|
|
102
|
+
};
|
|
103
|
+
/** The roof of a rectangular volume (w x d, top at `top`) per c.roof. */
|
|
104
|
+
const roofBits = (lx, lz, w, d, top) => {
|
|
105
|
+
const r = c.roof;
|
|
106
|
+
if (r === 'parapet' || r === 'mechanical' || r === 'helipad' || r === 'green')
|
|
107
|
+
parapet(lx, lz, w, d, top);
|
|
108
|
+
if (r === 'mechanical')
|
|
109
|
+
plantBox(lx, lz, w, d, top);
|
|
110
|
+
if (r === 'pitched' || r === 'hip') {
|
|
111
|
+
// Ridge along the longer side, ~29 degrees, eaves of 0.3 m, a fascia board under it.
|
|
112
|
+
const along = w >= d;
|
|
113
|
+
const span = (along ? d : w) + 0.6, len = (along ? w : d) + 0.6;
|
|
114
|
+
const rise = span * 0.5 * 0.55;
|
|
115
|
+
const rot = along ? ry : ry + Math.PI / 2;
|
|
116
|
+
vol(lx, lz, len, 0.3, span, 0, STYLE_ROOF, { y: top });
|
|
117
|
+
if (r === 'pitched') {
|
|
118
|
+
vol(lx, lz, len, rise, span, 0, STYLE_ROOF, { y: top + 0.3, geo: 'prism', ry: rot });
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
// Hip: a shorter ridge prism and two sloped ends (half-pyramids, same pitch as the sides).
|
|
122
|
+
const endL = Math.min(span * 0.5, len * 0.5), mid = len - 2 * endL;
|
|
123
|
+
const off = (t) => along ? [lx + t, lz] : [lx, lz + t];
|
|
124
|
+
if (mid > 0.05)
|
|
125
|
+
vol(lx, lz, mid, rise, span, 0, STYLE_ROOF, { y: top + 0.3, geo: 'prism', ry: rot });
|
|
126
|
+
const [ex1, ez1] = off(mid / 2 + endL / 2), [ex2, ez2] = off(-(mid / 2 + endL / 2));
|
|
127
|
+
vol(ex1, ez1, endL, rise, span, 0, STYLE_ROOF, { y: top + 0.3, geo: 'hipEnd', ry: rot });
|
|
128
|
+
vol(ex2, ez2, endL, rise, span, 0, STYLE_ROOF, { y: top + 0.3, geo: 'hipEnd', ry: rot + Math.PI });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (r === 'mansard') {
|
|
132
|
+
const h = Math.min(3.2, 0.9 + Math.min(w, d) * 0.12);
|
|
133
|
+
vol(lx, lz, w + 0.4, h, d + 0.4, 0, STYLE_ROOF, { y: top, geo: 'frustum' });
|
|
134
|
+
}
|
|
135
|
+
if (r === 'helipad') {
|
|
136
|
+
const rad = Math.min(w, d) * 0.34;
|
|
137
|
+
vol(lx, lz, rad * 2, 0.3, rad * 2, 0, STYLE_ROOF, { y: top, geo: 'cyl', kind: MARK_HELIPAD });
|
|
138
|
+
}
|
|
139
|
+
if (r === 'crown') {
|
|
140
|
+
parapet(lx, lz, w, d, top, STYLE_CROWN, 1.4);
|
|
141
|
+
plantBox(lx, lz, w, d, top);
|
|
142
|
+
}
|
|
143
|
+
if (r === 'green')
|
|
144
|
+
vol(lx, lz, w - 0.8, 0.14, d - 0.8, 0, STYLE_ROOF, { y: top, kind: MARK_LAWN });
|
|
145
|
+
};
|
|
146
|
+
/** The roof of a round volume (diameter dia, top at `top`). */
|
|
147
|
+
const roundRoof = (lx, lz, dia, top) => {
|
|
148
|
+
const r = c.roof;
|
|
149
|
+
if (r === 'parapet' || r === 'mechanical' || r === 'green' || r === 'pitched' || r === 'hip' || r === 'mansard')
|
|
150
|
+
vol(lx, lz, dia + 0.6, 0.9, dia + 0.6, 0, STYLE_SOLID, { y: top, geo: 'cyl' });
|
|
151
|
+
if (r === 'mechanical' || r === 'pitched' || r === 'hip' || r === 'mansard')
|
|
152
|
+
vol(lx, lz, dia * 0.35, 2.8, dia * 0.35, 0, STYLE_SOLID, { y: top, geo: 'cyl' });
|
|
153
|
+
if (r === 'helipad')
|
|
154
|
+
vol(lx, lz, dia * 0.7, 0.3, dia * 0.7, 0, STYLE_ROOF, { y: top, geo: 'cyl', kind: MARK_HELIPAD });
|
|
155
|
+
if (r === 'crown')
|
|
156
|
+
vol(lx, lz, dia + 0.6, 1.4, dia + 0.6, 0, STYLE_CROWN, { y: top, geo: 'cyl' });
|
|
157
|
+
if (r === 'green')
|
|
158
|
+
vol(lx, lz, dia - 0.8, 0.14, dia - 0.8, 0, STYLE_ROOF, { y: top, geo: 'cyl', kind: MARK_LAWN });
|
|
159
|
+
};
|
|
160
|
+
/** A facade block: volume + its roof. */
|
|
161
|
+
const block = (lx, lz, w, d, floors, style = STYLE_FACADE, y = 0) => {
|
|
162
|
+
const h = style === STYLE_FACADE ? floorsH(floors) : floors * fh;
|
|
163
|
+
vol(lx, lz, w, h, d, floors, style, { y });
|
|
164
|
+
roofBits(lx, lz, w, d, y + h);
|
|
165
|
+
return y + h;
|
|
166
|
+
};
|
|
167
|
+
const W = c.width, D = c.depth;
|
|
168
|
+
switch (c.footprint) {
|
|
169
|
+
case 'lShape': {
|
|
170
|
+
// An L: the full-width front bar and a deeper wing on one side.
|
|
171
|
+
const wingW = W * 0.42, barD = D * 0.45;
|
|
172
|
+
block(0, D / 2 - barD / 2, W, barD, fl);
|
|
173
|
+
const wingFl = Math.max(1, Math.round(fl * (0.7 + rng() * 0.3)));
|
|
174
|
+
block(-W / 2 + wingW / 2, -barD / 2, wingW, D - barD, wingFl);
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
case 'uShape': {
|
|
178
|
+
// A U: the back bar and two wings reaching forward, the court open to the front.
|
|
179
|
+
const wingW = Math.min(W * 0.3, 14), barD = Math.min(D * 0.4, 16);
|
|
180
|
+
block(0, D / 2 - barD / 2, W, barD, fl);
|
|
181
|
+
block(-W / 2 + wingW / 2, -barD / 2, wingW, D - barD, fl);
|
|
182
|
+
block(W / 2 - wingW / 2, -barD / 2, wingW, D - barD, fl);
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
case 'courtyard': {
|
|
186
|
+
// A ring of four bars around an inner court (bar depth capped so the court stays).
|
|
187
|
+
const bd = Math.min(W, D) * 0.3;
|
|
188
|
+
block(0, D / 2 - bd / 2, W, bd, fl);
|
|
189
|
+
block(0, -D / 2 + bd / 2, W, bd, fl);
|
|
190
|
+
block(-W / 2 + bd / 2, 0, bd, D - 2 * bd, fl);
|
|
191
|
+
block(W / 2 - bd / 2, 0, bd, D - 2 * bd, fl);
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
case 'stepped': {
|
|
195
|
+
// Setbacks: three tiers, each narrower, the upper ones without a lobby.
|
|
196
|
+
const f1 = Math.max(1, Math.round(fl * 0.45)), f2 = Math.max(0, Math.round(fl * 0.3)), f3 = Math.max(0, fl - f1 - f2);
|
|
197
|
+
let top = block(0, 0, W, D, f1);
|
|
198
|
+
if (f2 > 0)
|
|
199
|
+
top = block((rng() - 0.5) * W * 0.1, (rng() - 0.5) * D * 0.1, W * 0.74, D * 0.74, f2, STYLE_UPPER, top);
|
|
200
|
+
if (f3 > 0)
|
|
201
|
+
block((rng() - 0.5) * W * 0.08, (rng() - 0.5) * D * 0.08, W * 0.5, D * 0.5, f3, STYLE_UPPER, top);
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
case 'slab': {
|
|
205
|
+
// A long thin bar (depth capped at 14 m) with stair / lift cores on the roof.
|
|
206
|
+
const d = Math.min(D, 14);
|
|
207
|
+
const top = block(0, 0, W, d, fl);
|
|
208
|
+
const cores = Math.max(1, Math.round(W / 28));
|
|
209
|
+
for (let i = 0; i < cores; i++)
|
|
210
|
+
vol(-W / 2 + W * (i + 0.5) / cores, 0, 3.2, 2.8, Math.min(d * 0.5, 5), 0, STYLE_SOLID, { y: top });
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
case 'podiumTower': {
|
|
214
|
+
// Podium (2-3 floors, full footprint, lobby) with a slimmer tower on it.
|
|
215
|
+
const podFl = Math.min(fl, 2 + Math.round(rng()));
|
|
216
|
+
const top = block(0, 0, W, D, podFl);
|
|
217
|
+
const towFl = fl - podFl;
|
|
218
|
+
if (towFl > 0) {
|
|
219
|
+
const tw = W * 0.62, td = D * 0.62;
|
|
220
|
+
block((rng() - 0.5) * (W - tw) * 0.8, (rng() - 0.5) * (D - td) * 0.8, tw, td, towFl, STYLE_UPPER, top);
|
|
221
|
+
}
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
case 'twinTowers': {
|
|
225
|
+
// Two towers side by side on one podium, one a little shorter.
|
|
226
|
+
const podFl = Math.min(fl, 2 + Math.round(rng()));
|
|
227
|
+
const top = block(0, 0, W, D, podFl);
|
|
228
|
+
const towFl = fl - podFl;
|
|
229
|
+
if (towFl > 0) {
|
|
230
|
+
const tw = W * 0.36, td = D * 0.62;
|
|
231
|
+
block(-W * 0.28, 0, tw, td, towFl, STYLE_UPPER, top);
|
|
232
|
+
block(W * 0.28, 0, tw, td, Math.max(1, Math.round(towFl * (0.7 + rng() * 0.3))), STYLE_UPPER, top);
|
|
233
|
+
}
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
case 'cylinder': {
|
|
237
|
+
// A round tower: diameter = the smaller side; bays run around the circumference.
|
|
238
|
+
const dia = Math.min(W, D);
|
|
239
|
+
const h = floorsH(fl);
|
|
240
|
+
vol(0, 0, dia, h, dia, fl, STYLE_FACADE + ROUND, { geo: 'cyl' });
|
|
241
|
+
roundRoof(0, 0, dia, h);
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
default:
|
|
245
|
+
block(0, 0, W, D, fl);
|
|
246
|
+
}
|
|
247
|
+
return list;
|
|
248
|
+
}
|
|
249
|
+
// ---------------------------------------------------------------------------- geometry
|
|
250
|
+
const _m = new THREE.Matrix4(), _q = new THREE.Quaternion(), _p = new THREE.Vector3(), _s = new THREE.Vector3(1, 1, 1), _up = new THREE.Vector3(0, 1, 0);
|
|
251
|
+
/** Flat-shaded geometry from triangles (each a list of 3 [x,y,z]). */
|
|
252
|
+
function flatGeometry(tris) {
|
|
253
|
+
const pos = new Float32Array(tris.length * 9), nor = new Float32Array(tris.length * 9);
|
|
254
|
+
const a = new THREE.Vector3(), b = new THREE.Vector3(), c = new THREE.Vector3(), n = new THREE.Vector3();
|
|
255
|
+
tris.forEach((t, i) => {
|
|
256
|
+
a.fromArray(t[0]);
|
|
257
|
+
b.fromArray(t[1]);
|
|
258
|
+
c.fromArray(t[2]);
|
|
259
|
+
n.subVectors(b, a).cross(c.clone().sub(a)).normalize();
|
|
260
|
+
for (let k = 0; k < 3; k++) {
|
|
261
|
+
pos.set(t[k], i * 9 + k * 3);
|
|
262
|
+
nor.set([n.x, n.y, n.z], i * 9 + k * 3);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
const g = new THREE.BufferGeometry();
|
|
266
|
+
g.setAttribute('position', new THREE.BufferAttribute(pos, 3));
|
|
267
|
+
g.setAttribute('normal', new THREE.BufferAttribute(nor, 3));
|
|
268
|
+
return g;
|
|
269
|
+
}
|
|
270
|
+
const quad = (p0, p1, p2, p3) => [[p0, p1, p2], [p0, p2, p3]];
|
|
271
|
+
/** Unit gable prism: base 1 x 1 at y = 0, ridge along x at y = 1, z = 0. */
|
|
272
|
+
function prismGeometry() {
|
|
273
|
+
const A = [-0.5, 0, -0.5], B = [0.5, 0, -0.5], C = [0.5, 0, 0.5], Dd = [-0.5, 0, 0.5], R0 = [-0.5, 1, 0], R1 = [0.5, 1, 0];
|
|
274
|
+
return flatGeometry([
|
|
275
|
+
...quad(Dd, C, R1, R0), // front slope (+z)
|
|
276
|
+
...quad(B, A, R0, R1), // back slope (-z)
|
|
277
|
+
[A, Dd, R0], [C, B, R1], // gables
|
|
278
|
+
...quad(A, B, C, Dd), // bottom
|
|
279
|
+
]);
|
|
280
|
+
}
|
|
281
|
+
/** Unit hip end: base 1 (x) x 1 (z) at y = 0, the ridge point at (-0.5, 1, 0); slopes down to the +x end and both sides. */
|
|
282
|
+
function hipEndGeometry() {
|
|
283
|
+
const A = [-0.5, 0, -0.5], B = [0.5, 0, -0.5], C = [0.5, 0, 0.5], Dd = [-0.5, 0, 0.5], R = [-0.5, 1, 0];
|
|
284
|
+
return flatGeometry([
|
|
285
|
+
[Dd, C, R], // front slope (+z)
|
|
286
|
+
[B, A, R], // back slope (-z)
|
|
287
|
+
[C, B, R], // end slope (+x)
|
|
288
|
+
...quad(A, B, C, Dd), // bottom
|
|
289
|
+
]);
|
|
290
|
+
}
|
|
291
|
+
/** Unit frustum (mansard): base 1 x 1 at y = 0, top 0.7 x 0.7 at y = 1. */
|
|
292
|
+
function frustumGeometry() {
|
|
293
|
+
const k = 0.35;
|
|
294
|
+
const A = [-0.5, 0, -0.5], B = [0.5, 0, -0.5], C = [0.5, 0, 0.5], Dd = [-0.5, 0, 0.5];
|
|
295
|
+
const a = [-k, 1, -k], b = [k, 1, -k], c = [k, 1, k], d = [-k, 1, k];
|
|
296
|
+
return flatGeometry([...quad(Dd, C, c, d), ...quad(C, B, b, c), ...quad(B, A, a, b), ...quad(A, Dd, d, a), ...quad(a, b, c, d), ...quad(A, B, C, Dd)]);
|
|
297
|
+
}
|
|
298
|
+
const UNIT = {
|
|
299
|
+
box: () => { const g = new THREE.BoxGeometry(1, 1, 1); g.translate(0, 0.5, 0); return g; },
|
|
300
|
+
prism: prismGeometry,
|
|
301
|
+
hipEnd: hipEndGeometry,
|
|
302
|
+
frustum: frustumGeometry,
|
|
303
|
+
cyl: () => { const g = new THREE.CylinderGeometry(0.5, 0.5, 1, 32, 1); g.translate(0, 0.5, 0); return g; },
|
|
304
|
+
};
|
|
305
|
+
function instanced(geo, items, material) {
|
|
306
|
+
const n = items.length;
|
|
307
|
+
const aParams = new Float32Array(n * 4), aFacade = new Float32Array(n * 4), aTint = new Float32Array(n * 3);
|
|
308
|
+
const mesh = new THREE.InstancedMesh(geo, material, n);
|
|
309
|
+
for (let i = 0; i < n; i++) {
|
|
310
|
+
const it = items[i];
|
|
311
|
+
aParams[i * 4] = it.seed;
|
|
312
|
+
aParams[i * 4 + 1] = it.floors;
|
|
313
|
+
aParams[i * 4 + 2] = it.floorH;
|
|
314
|
+
aParams[i * 4 + 3] = it.style;
|
|
315
|
+
aFacade[i * 4] = it.kind;
|
|
316
|
+
aFacade[i * 4 + 1] = it.ratio;
|
|
317
|
+
aFacade[i * 4 + 2] = it.bay;
|
|
318
|
+
aFacade[i * 4 + 3] = it.lights;
|
|
319
|
+
aTint[i * 3] = it.tint[0];
|
|
320
|
+
aTint[i * 3 + 1] = it.tint[1];
|
|
321
|
+
aTint[i * 3 + 2] = it.tint[2];
|
|
322
|
+
_p.set(it.x, it.y || 0, it.z);
|
|
323
|
+
_q.setFromAxisAngle(_up, it.ry || 0);
|
|
324
|
+
_s.set(it.w, it.h, it.d);
|
|
325
|
+
_m.compose(_p, _q, _s);
|
|
326
|
+
mesh.setMatrixAt(i, _m);
|
|
327
|
+
}
|
|
328
|
+
geo.setAttribute('aParams', new THREE.InstancedBufferAttribute(aParams, 4));
|
|
329
|
+
geo.setAttribute('aFacade', new THREE.InstancedBufferAttribute(aFacade, 4));
|
|
330
|
+
geo.setAttribute('aTint', new THREE.InstancedBufferAttribute(aTint, 3));
|
|
331
|
+
mesh.instanceMatrix.needsUpdate = true;
|
|
332
|
+
mesh.computeBoundingBox();
|
|
333
|
+
mesh.computeBoundingSphere();
|
|
334
|
+
mesh.castShadow = true;
|
|
335
|
+
return mesh;
|
|
336
|
+
}
|
|
337
|
+
/** Turn an instance list into InstancedMeshes (one per unit geometry) with the facade attributes.
|
|
338
|
+
* The volume's metres go into the instance matrix SCALE (so raycasts, bounds and the
|
|
339
|
+
* selection gizmo see the real volumes); the shader reads the size back from the matrix.
|
|
340
|
+
* Returns the box mesh; the other geometries are its children. userData.bounds is the union;
|
|
341
|
+
* dispose with disposeInstanced(mesh). */
|
|
342
|
+
export function buildInstancedBoxes(list, material) {
|
|
343
|
+
const by = { box: [], prism: [], hipEnd: [], frustum: [], cyl: [] };
|
|
344
|
+
for (const it of list)
|
|
345
|
+
(by[it.geo] || by.box).push(it);
|
|
346
|
+
const mesh = instanced(UNIT.box(), by.box, material);
|
|
347
|
+
const bounds = by.box.length ? mesh.boundingBox.clone() : new THREE.Box3();
|
|
348
|
+
for (const k of ['prism', 'hipEnd', 'frustum', 'cyl']) {
|
|
349
|
+
if (!by[k].length)
|
|
350
|
+
continue;
|
|
351
|
+
const child = instanced(UNIT[k](), by[k], material);
|
|
352
|
+
mesh.add(child);
|
|
353
|
+
bounds.union(child.boundingBox);
|
|
354
|
+
}
|
|
355
|
+
if (!by.box.length) {
|
|
356
|
+
mesh.boundingBox = bounds.clone();
|
|
357
|
+
mesh.boundingSphere = bounds.getBoundingSphere(new THREE.Sphere());
|
|
358
|
+
}
|
|
359
|
+
mesh.userData.bounds = bounds;
|
|
360
|
+
return mesh;
|
|
361
|
+
}
|
|
362
|
+
/** Free every geometry of a buildInstancedBoxes result (the material is shared; dispose it separately). */
|
|
363
|
+
export function disposeInstanced(mesh) {
|
|
364
|
+
if (!mesh)
|
|
365
|
+
return;
|
|
366
|
+
mesh.geometry.dispose();
|
|
367
|
+
for (const ch of mesh.children)
|
|
368
|
+
if (ch.geometry)
|
|
369
|
+
ch.geometry.dispose();
|
|
370
|
+
}
|
|
371
|
+
// ---------------------------------------------------------------------------- material
|
|
372
|
+
export function createUniforms() {
|
|
373
|
+
return Object.assign(createSunUniforms(), createLampUniforms(), createTextureUniforms('uWall'), {
|
|
374
|
+
uWallColor: { value: new THREE.Color() },
|
|
375
|
+
uGlassColor: { value: new THREE.Color() },
|
|
376
|
+
uGlassReflect: { value: 0.9 },
|
|
377
|
+
uMullionColor: { value: new THREE.Color() },
|
|
378
|
+
uRoofColor: { value: new THREE.Color() },
|
|
379
|
+
uMullionWidth: { value: 0.08 },
|
|
380
|
+
uLobby: { value: 1 },
|
|
381
|
+
uLightColor: { value: new THREE.Color() },
|
|
382
|
+
uCoolLightColor: { value: new THREE.Color() },
|
|
383
|
+
uLightWarmth: { value: 0.7 },
|
|
384
|
+
uWindowGlow: { value: 1 },
|
|
385
|
+
uFlicker: { value: 0.25 },
|
|
386
|
+
uTime: { value: 0 },
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
/** Per-frame knobs. `tex` = the loaded texture set (or null). */
|
|
390
|
+
export function applyConfig(u, c, tex = undefined) {
|
|
391
|
+
if (c.wallColor !== undefined)
|
|
392
|
+
u.uWallColor.value.set(c.wallColor);
|
|
393
|
+
if (c.glassColor !== undefined)
|
|
394
|
+
u.uGlassColor.value.set(c.glassColor);
|
|
395
|
+
if (c.glassReflect !== undefined)
|
|
396
|
+
u.uGlassReflect.value = c.glassReflect;
|
|
397
|
+
if (c.mullionColor !== undefined)
|
|
398
|
+
u.uMullionColor.value.set(c.mullionColor);
|
|
399
|
+
if (c.roofColor !== undefined)
|
|
400
|
+
u.uRoofColor.value.set(c.roofColor);
|
|
401
|
+
if (c.mullionWidth !== undefined)
|
|
402
|
+
u.uMullionWidth.value = c.mullionWidth;
|
|
403
|
+
if (c.lobby !== undefined)
|
|
404
|
+
u.uLobby.value = c.lobby ? 1 : 0;
|
|
405
|
+
if (c.lightColor !== undefined)
|
|
406
|
+
u.uLightColor.value.set(c.lightColor);
|
|
407
|
+
if (c.coolLightColor !== undefined)
|
|
408
|
+
u.uCoolLightColor.value.set(c.coolLightColor);
|
|
409
|
+
if (c.lightWarmth !== undefined)
|
|
410
|
+
u.uLightWarmth.value = c.lightWarmth;
|
|
411
|
+
if (c.windowGlow !== undefined)
|
|
412
|
+
u.uWindowGlow.value = c.windowGlow;
|
|
413
|
+
if (c.flicker !== undefined)
|
|
414
|
+
u.uFlicker.value = c.flicker;
|
|
415
|
+
if (tex !== undefined)
|
|
416
|
+
applyTextureSet(u, 'uWall', tex, c.texture && c.texture.tileSize, c.textureStrength);
|
|
417
|
+
else if (c.textureStrength !== undefined)
|
|
418
|
+
u.uWallNormalStrength.value = c.textureStrength;
|
|
419
|
+
}
|
|
420
|
+
export const VERT = /* glsl */ `
|
|
421
|
+
attribute vec4 aParams;
|
|
422
|
+
attribute vec4 aFacade;
|
|
423
|
+
attribute vec3 aTint;
|
|
424
|
+
varying vec3 vLocal; // metres inside the volume (x,z centred, y from the base)
|
|
425
|
+
varying vec3 vLocalN; // face normal in the volume's own frame
|
|
426
|
+
varying vec3 vSize;
|
|
427
|
+
varying vec4 vParams;
|
|
428
|
+
varying vec4 vFacade;
|
|
429
|
+
varying vec3 vTint;
|
|
430
|
+
varying vec3 vP; // world position
|
|
431
|
+
varying vec3 vN; // world normal
|
|
432
|
+
${GLSL_FOG_VERT_PARS}
|
|
433
|
+
void main() {
|
|
434
|
+
// The volume's size is the instance matrix scale (metres); the cube is unit.
|
|
435
|
+
vec3 size = vec3(length(instanceMatrix[0].xyz), length(instanceMatrix[1].xyz), length(instanceMatrix[2].xyz));
|
|
436
|
+
vLocal = position * size;
|
|
437
|
+
vLocalN = normal;
|
|
438
|
+
vSize = size; vParams = aParams; vFacade = aFacade; vTint = aTint;
|
|
439
|
+
mat4 m = modelMatrix * instanceMatrix;
|
|
440
|
+
vec4 wp = m * vec4(position, 1.0);
|
|
441
|
+
vP = wp.xyz;
|
|
442
|
+
vN = normalize(mat3(m) * normal);
|
|
443
|
+
vec4 mvPosition = viewMatrix * wp;
|
|
444
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
445
|
+
#include <fog_vertex>
|
|
446
|
+
}`;
|
|
447
|
+
export const FRAG = /* glsl */ `
|
|
448
|
+
precision highp float;
|
|
449
|
+
${GLSL_COMMON}
|
|
450
|
+
${glslTextureBlock('uWall')}
|
|
451
|
+
uniform vec3 uWallColor; uniform vec3 uGlassColor; uniform float uGlassReflect; uniform vec3 uMullionColor; uniform vec3 uRoofColor;
|
|
452
|
+
uniform float uMullionWidth; uniform float uLobby;
|
|
453
|
+
uniform vec3 uLightColor; uniform vec3 uCoolLightColor; uniform float uLightWarmth; uniform float uWindowGlow;
|
|
454
|
+
uniform float uFlicker; uniform float uTime;
|
|
455
|
+
varying vec3 vLocal; varying vec3 vLocalN; varying vec3 vSize; varying vec4 vParams; varying vec4 vFacade; varying vec3 vTint;
|
|
456
|
+
varying vec3 vP; varying vec3 vN;
|
|
457
|
+
${GLSL_FOG_PARS}
|
|
458
|
+
|
|
459
|
+
// Glass: a tinted interior (dark room, or blinds down) under a Fresnel-weighted sky reflection,
|
|
460
|
+
// a sun glint, and at night the lit room. panel is a per-pane hash: real curtain walls are
|
|
461
|
+
// never perfectly coplanar, so each pane reflects a slightly different patch of sky.
|
|
462
|
+
vec3 glassColor(vec3 N, vec3 V, float lit, float roomHash, float panel, float vf) {
|
|
463
|
+
vec3 R = reflect(-V, N);
|
|
464
|
+
float fres = 0.04 + 0.96 * pow(1.0 - max(dot(N, V), 0.0), 5.0);
|
|
465
|
+
float horizon = smoothstep(-0.3, 0.6, R.y + (panel - 0.5) * 0.12);
|
|
466
|
+
vec3 skyRefl = mix(uGroundAmbient * 1.4, uSkyAmbient * 2.6 + uSunColor * 0.10, horizon);
|
|
467
|
+
float blinds = step(fract(roomHash * 13.7), 0.14);
|
|
468
|
+
vec3 interior = mix(uGlassColor * 0.22, vec3(0.55, 0.53, 0.5) * 0.6, blinds) * (uSkyAmbient + uSunColor * 0.3);
|
|
469
|
+
float k = clamp(fres * uGlassReflect + 0.42 * uGlassReflect, 0.0, 1.0);
|
|
470
|
+
vec3 col = mix(interior, skyRefl * uGlassColor * 1.9 * (0.94 + 0.12 * panel), k);
|
|
471
|
+
float glint = pow(max(dot(R, uSunDir), 0.0), 500.0) * 1.2;
|
|
472
|
+
col += uSunColor * glint * uGlassReflect;
|
|
473
|
+
// The lit room: warm / cool coin, brighter toward the ceiling, dimmed by blinds.
|
|
474
|
+
vec3 room = mix(uCoolLightColor, uLightColor, step(roomHash, uLightWarmth));
|
|
475
|
+
float ceiling = 0.65 + 0.45 * vf;
|
|
476
|
+
col += room * (lit * uNight * uWindowGlow * 0.75 * ceiling * (0.5 + 0.5 * fract(roomHash * 7.31)) * (1.0 - 0.55 * blinds));
|
|
477
|
+
return col;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// 1 inside (x < e), anti-aliased over w.
|
|
481
|
+
float inside(float x, float e, float w) { return 1.0 - smoothstep(e - w, e + w, x); }
|
|
482
|
+
|
|
483
|
+
void main() {
|
|
484
|
+
vec3 N = normalize(vN);
|
|
485
|
+
vec3 V = normalize(cameraPosition - vP);
|
|
486
|
+
vec3 n = vLocalN;
|
|
487
|
+
float styleRaw = floor(vParams.w + 0.5);
|
|
488
|
+
float round = step(9.5, styleRaw);
|
|
489
|
+
float style = styleRaw - round * 10.0;
|
|
490
|
+
// The seed is an integer per instance; snap it, because a varying is interpolated and a
|
|
491
|
+
// hash of a value off by 1e-5 is a different value (that reads as per-pixel confetti).
|
|
492
|
+
float seed = floor(vParams.x + 0.5);
|
|
493
|
+
float mark = floor(vFacade.x + 0.5); // on solid styles: the roof marking
|
|
494
|
+
bool solid = style > 0.5 && style < 1.5;
|
|
495
|
+
bool roofStyle = style > 2.5 && style < 3.5;
|
|
496
|
+
bool crown = style > 3.5;
|
|
497
|
+
// Roof pieces are coloured by their world slope (a gable or mansard face is still a roof).
|
|
498
|
+
bool topFace = roofStyle ? (N.y > 0.2) : (n.y > 0.5);
|
|
499
|
+
vec3 col;
|
|
500
|
+
if (topFace || solid || roofStyle || crown || n.y < -0.5) {
|
|
501
|
+
// Roof top, parapet / plant boxes, roof pieces, crown band: wall or roof colour with the texture.
|
|
502
|
+
vec3 T = abs(n.y) > 0.5 ? vec3(1.0, 0.0, 0.0) : normalize(cross(vec3(0.0, 1.0, 0.0), N));
|
|
503
|
+
vec3 B = abs(n.y) > 0.5 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
|
|
504
|
+
vec2 uvM = abs(n.y) > 0.5 ? vLocal.xz : (abs(n.x) > 0.5 ? vec2(vLocal.z, vLocal.y) : vec2(vLocal.x, vLocal.y));
|
|
505
|
+
float rough;
|
|
506
|
+
vec3 Nb = N;
|
|
507
|
+
vec3 mul = uWallSample(uvM + seed, Nb, T, B, rough);
|
|
508
|
+
bool useRoof = roofStyle ? topFace : (n.y > 0.5 && !solid && !crown);
|
|
509
|
+
vec3 base = useRoof ? uRoofColor : uWallColor * vTint;
|
|
510
|
+
float grain = 0.92 + 0.16 * hash21(floor(uvM * 2.0) + seed);
|
|
511
|
+
float ao = n.y > 0.5 ? 1.0 : 0.65 + 0.35 * smoothstep(0.0, 1.0, vLocal.y / max(vSize.y, 0.01));
|
|
512
|
+
vec3 albedo = base * mul * grain;
|
|
513
|
+
if (roofStyle && topFace && mark > 1.5) {
|
|
514
|
+
// Green roof: two greens broken by cells and a soft gradient, no texture relief.
|
|
515
|
+
vec2 q = vLocal.xz + seed;
|
|
516
|
+
albedo = mix(vec3(0.16, 0.30, 0.09), vec3(0.28, 0.42, 0.14), hash21(floor(q * 1.7)) * 0.6 + 0.2 * sin(q.x * 0.7) * cos(q.y * 0.5));
|
|
517
|
+
rough = 0.95; Nb = N;
|
|
518
|
+
}
|
|
519
|
+
if (roofStyle && topFace && mark > 0.5 && mark < 1.5) {
|
|
520
|
+
// Helipad: a dark disc, a white ring and an H.
|
|
521
|
+
vec2 q = vLocal.xz / max(vSize.x * 0.5, 0.01);
|
|
522
|
+
float r = length(q);
|
|
523
|
+
float w = fwidth(r) + 0.004;
|
|
524
|
+
float ring = inside(r, 0.95, w) * (1.0 - inside(r, 0.86, w));
|
|
525
|
+
float H = inside(abs(abs(q.x) - 0.33), 0.09, w) * inside(abs(q.y), 0.45, w) + inside(abs(q.y), 0.08, w) * inside(abs(q.x), 0.33, w);
|
|
526
|
+
float paint = clamp(ring + H, 0.0, 1.0);
|
|
527
|
+
albedo = mix(vec3(0.21, 0.21, 0.22), vec3(0.92), paint);
|
|
528
|
+
rough = 0.8; Nb = N;
|
|
529
|
+
}
|
|
530
|
+
col = shadeSurface(albedo, Nb, vP, V, rough, ao);
|
|
531
|
+
if (crown) {
|
|
532
|
+
// Crown band: pale by day, an emissive band at night (bloom picks it up).
|
|
533
|
+
vec3 lightC = mix(uCoolLightColor, uLightColor, uLightWarmth);
|
|
534
|
+
col = shadeSurface(mix(uWallColor * vTint, lightC, 0.5), N, vP, V, 0.5, 1.0) + lightC * uNight * uWindowGlow * 1.6;
|
|
535
|
+
}
|
|
536
|
+
} else {
|
|
537
|
+
// A facade face: u along the face (from its left corner; around the circumference on a
|
|
538
|
+
// cylinder), v up from the base.
|
|
539
|
+
float faceW, u;
|
|
540
|
+
if (round > 0.5) {
|
|
541
|
+
faceW = 3.14159265 * vSize.x;
|
|
542
|
+
u = (atan(vLocal.z, vLocal.x) / 6.2831853 + 0.5) * faceW;
|
|
543
|
+
} else {
|
|
544
|
+
faceW = abs(n.x) > 0.5 ? vSize.z : vSize.x;
|
|
545
|
+
u = abs(n.x) > 0.5 ? (vLocal.z * sign(n.x) + vSize.z * 0.5) : (vLocal.x * -sign(n.z) + vSize.x * 0.5);
|
|
546
|
+
}
|
|
547
|
+
float v = vLocal.y;
|
|
548
|
+
float floorH = vParams.z;
|
|
549
|
+
float lobbyH = (style < 0.5 && uLobby > 0.5) ? floorH * 1.6 : floorH;
|
|
550
|
+
// Floors: the lobby counts as floor 0, the rest are floorH each above it.
|
|
551
|
+
float fIdx = v < lobbyH ? 0.0 : 1.0 + floor((v - lobbyH) / floorH);
|
|
552
|
+
float fBase = fIdx < 0.5 ? 0.0 : lobbyH + (fIdx - 1.0) * floorH;
|
|
553
|
+
float fH = fIdx < 0.5 ? lobbyH : floorH;
|
|
554
|
+
float vf = (v - fBase) / fH;
|
|
555
|
+
// Bays fit the face exactly.
|
|
556
|
+
float nBays = max(1.0, floor(faceW / vFacade.z + 0.5));
|
|
557
|
+
float bayW = faceW / nBays;
|
|
558
|
+
float bIdx = floor(u / bayW);
|
|
559
|
+
float uf = (u - bIdx * bayW) / bayW;
|
|
560
|
+
float kind = vFacade.x;
|
|
561
|
+
float ratio = vFacade.y;
|
|
562
|
+
float mw = uMullionWidth;
|
|
563
|
+
// Pixel-size terms in bay / floor fractions, for anti-aliasing.
|
|
564
|
+
float wu = fwidth(uf), wv = fwidth(vf);
|
|
565
|
+
float glass = 0.0, mullion = 0.0;
|
|
566
|
+
float wallMul = 1.0; // tone of the wall where it is not glass: trims lighter, recesses darker
|
|
567
|
+
float door = 0.0; // industrial roller doors
|
|
568
|
+
bool lobby = fIdx < 0.5 && style < 0.5 && uLobby > 0.5;
|
|
569
|
+
if (lobby) {
|
|
570
|
+
// Lobby: full-height glass, a frame at the floor line and thicker mullions per bay.
|
|
571
|
+
glass = 1.0;
|
|
572
|
+
float frameM = (mw * 2.0) / bayW, frameV = 0.25 / fH;
|
|
573
|
+
mullion = max(1.0 - bandAA(uf, frameM, 1.0 - frameM), 1.0 - bandAA(vf, frameV, 1.0 - 0.12 / fH));
|
|
574
|
+
// Doors: a darker pair in the middle bay, drawn as mullion colour.
|
|
575
|
+
float mid = step(abs(bIdx + 0.5 - nBays * 0.5), 0.75);
|
|
576
|
+
mullion = max(mullion, mid * (1.0 - bandAA(abs(uf - 0.5), 0.012, 1.0)));
|
|
577
|
+
} else if (kind < 0.5) {
|
|
578
|
+
// Curtain wall: glass above a spandrel band; mullions on every bay and floor edge.
|
|
579
|
+
float spandrel = clamp(1.0 - ratio, 0.08, 0.7);
|
|
580
|
+
glass = bandAA(vf, spandrel, 1.0);
|
|
581
|
+
float mU = mw / bayW, mV = mw / fH;
|
|
582
|
+
mullion = max(1.0 - bandAA(uf, mU, 1.0 - mU), 1.0 - bandAA(vf, mV, 1.0 - mV));
|
|
583
|
+
// A thin transom line at the spandrel top reads as the slab edge.
|
|
584
|
+
mullion = max(mullion, bandAA(vf, spandrel - mV, spandrel + mV));
|
|
585
|
+
} else if (kind < 1.5) {
|
|
586
|
+
// Punched windows: one opening per bay, sill at 0.22, head at 0.82 of the floor.
|
|
587
|
+
float halfW = clamp(ratio, 0.15, 0.95) * 0.45;
|
|
588
|
+
float inX = bandAA(uf, 0.5 - halfW, 0.5 + halfW);
|
|
589
|
+
float inY = bandAA(vf, 0.22, 0.82);
|
|
590
|
+
glass = inX * inY;
|
|
591
|
+
// Frame: the opening's rim, and a reveal shadow on the side away from the sun.
|
|
592
|
+
float fU = 0.06 / bayW, fV = 0.06 / fH;
|
|
593
|
+
float inner = bandAA(uf, 0.5 - halfW + fU, 0.5 + halfW - fU) * bandAA(vf, 0.22 + fV, 0.82 - fV);
|
|
594
|
+
mullion = glass - inner;
|
|
595
|
+
glass = inner;
|
|
596
|
+
} else if (kind < 2.5) {
|
|
597
|
+
// Ribbon: a horizontal glass band per floor, thin mullions every bay.
|
|
598
|
+
float band = clamp(ratio, 0.15, 0.95) * 0.62;
|
|
599
|
+
glass = bandAA(vf, 0.3, 0.3 + band);
|
|
600
|
+
float mU = mw * 0.8 / bayW;
|
|
601
|
+
mullion = glass * (1.0 - bandAA(uf, mU, 1.0 - mU));
|
|
602
|
+
mullion = max(mullion, bandAA(vf, 0.3 - 0.02 / fH, 0.3 + 0.02 / fH) + bandAA(vf, 0.3 + band - 0.02 / fH, 0.3 + band + 0.02 / fH));
|
|
603
|
+
} else if (kind < 3.5) {
|
|
604
|
+
// Brick: a punched window per bay with a lintel above and a sill below, in a running-bond wall.
|
|
605
|
+
float halfW = clamp(ratio, 0.15, 0.95) * 0.4;
|
|
606
|
+
float fU = 0.07 / bayW, fV = 0.07 / fH;
|
|
607
|
+
float open = bandAA(uf, 0.5 - halfW, 0.5 + halfW) * bandAA(vf, 0.2, 0.78);
|
|
608
|
+
float inner = bandAA(uf, 0.5 - halfW + fU, 0.5 + halfW - fU) * bandAA(vf, 0.2 + fV, 0.78 - fV);
|
|
609
|
+
mullion = open - inner; glass = inner;
|
|
610
|
+
float trim = bandAA(uf, 0.5 - halfW - fU, 0.5 + halfW + fU) * (bandAA(vf, 0.78, 0.84) + bandAA(vf, 0.16, 0.2));
|
|
611
|
+
// Running bond: courses of 7.5 cm, bricks of 23 cm, darker mortar; fades out before it aliases.
|
|
612
|
+
float row = floor(v / 0.075), cy = fract(v / 0.075), cx = fract((u + mod(row, 2.0) * 0.115) / 0.23);
|
|
613
|
+
float mortar = max(step(cy, 0.12), step(cx, 0.045));
|
|
614
|
+
float tone = 0.9 + 0.2 * hash21(vec2(floor((u + mod(row, 2.0) * 0.115) / 0.23), row) + seed);
|
|
615
|
+
float fade = 1.0 - smoothstep(0.015, 0.05, fwidth(v));
|
|
616
|
+
wallMul = mix(1.0, mix(tone, 0.68, mortar), fade);
|
|
617
|
+
wallMul = mix(wallMul, 1.25, clamp(trim, 0.0, 1.0));
|
|
618
|
+
} else if (kind < 4.5) {
|
|
619
|
+
// Balconies: a recessed balcony per bay — slab, railing, the glass door behind it.
|
|
620
|
+
float band = clamp(ratio, 0.15, 0.95) * 0.5;
|
|
621
|
+
float span = bandAA(uf, 0.1, 0.9);
|
|
622
|
+
glass = bandAA(vf, 0.45, 0.45 + band) * bandAA(uf, 0.14, 0.86);
|
|
623
|
+
float recess = bandAA(vf, 0.1, 0.45) * span;
|
|
624
|
+
float slab = bandAA(vf, 0.0, 0.1) * bandAA(uf, 0.06, 0.94);
|
|
625
|
+
float railFade = 1.0 - smoothstep(0.03, 0.08, fwidth(u));
|
|
626
|
+
float rails = recess * (1.0 - bandAA(fract(u / 0.16), 0.14, 0.86)) * railFade;
|
|
627
|
+
float topRail = bandAA(vf, 0.41, 0.45) * span;
|
|
628
|
+
mullion = max(glass * (1.0 - bandAA(uf, 0.14 + mw / bayW, 0.86 - mw / bayW)), max(rails, topRail));
|
|
629
|
+
wallMul = mix(1.0, 0.5, recess);
|
|
630
|
+
wallMul = mix(wallMul, 0.82, slab);
|
|
631
|
+
} else if (kind < 5.5) {
|
|
632
|
+
// Concrete panels: a small window per panel, dark joints on every panel edge, a tone per panel.
|
|
633
|
+
float halfW = clamp(ratio, 0.15, 0.95) * 0.35;
|
|
634
|
+
float fU = 0.06 / bayW, fV = 0.06 / fH;
|
|
635
|
+
float open = bandAA(uf, 0.5 - halfW, 0.5 + halfW) * bandAA(vf, 0.3, 0.78);
|
|
636
|
+
float inner = bandAA(uf, 0.5 - halfW + fU, 0.5 + halfW - fU) * bandAA(vf, 0.3 + fV, 0.78 - fV);
|
|
637
|
+
mullion = open - inner; glass = inner;
|
|
638
|
+
float jU = 0.03 / bayW, jV = 0.03 / fH;
|
|
639
|
+
float joint = max(1.0 - bandAA(uf, jU, 1.0 - jU), 1.0 - bandAA(vf, jV, 1.0 - jV));
|
|
640
|
+
float tone = 0.93 + 0.14 * hash21(vec2(bIdx, fIdx) + seed);
|
|
641
|
+
wallMul = mix(tone, 0.55, joint);
|
|
642
|
+
} else if (kind < 6.5) {
|
|
643
|
+
// Glass fins: near-full glass with a vertical fin on every bay edge and a slab line.
|
|
644
|
+
glass = bandAA(vf, 0.07, 1.0);
|
|
645
|
+
float finU = 0.15 / bayW;
|
|
646
|
+
float fin = 1.0 - bandAA(uf, finU, 1.0 - finU);
|
|
647
|
+
mullion = max(fin, bandAA(vf, 0.0, 0.07));
|
|
648
|
+
} else {
|
|
649
|
+
// Industrial: tall narrow windows, a roller door every third ground-floor bay, a dark eaves band.
|
|
650
|
+
float halfW = clamp(ratio, 0.15, 0.95) * 0.3;
|
|
651
|
+
float fU = 0.05 / bayW, fV = 0.05 / fH;
|
|
652
|
+
float open = bandAA(uf, 0.5 - halfW, 0.5 + halfW) * bandAA(vf, 0.35, 0.86);
|
|
653
|
+
float inner = bandAA(uf, 0.5 - halfW + fU, 0.5 + halfW - fU) * bandAA(vf, 0.35 + fV, 0.86 - fV);
|
|
654
|
+
mullion = open - inner; glass = inner;
|
|
655
|
+
if (fIdx < 0.5 && mod(bIdx, 3.0) < 0.5) {
|
|
656
|
+
door = bandAA(uf, 0.12, 0.88) * bandAA(vf, 0.0, 0.8);
|
|
657
|
+
glass *= 1.0 - door; mullion *= 1.0 - door;
|
|
658
|
+
}
|
|
659
|
+
float eaves = bandAA(vf, 0.9, 1.0) * step(vParams.y - 0.5, fIdx);
|
|
660
|
+
float jU = 0.02 / bayW;
|
|
661
|
+
wallMul = mix(1.0, 0.8, max(eaves, 1.0 - bandAA(uf, jU, 1.0 - jU)));
|
|
662
|
+
}
|
|
663
|
+
mullion = clamp(mullion, 0.0, 1.0);
|
|
664
|
+
// Wall sample (texture in metres along the face), bumped normal for the wall only.
|
|
665
|
+
vec3 T = round > 0.5 ? normalize(cross(vec3(0.0, 1.0, 0.0), N)) : normalize(cross(vec3(0.0, 1.0, 0.0), N));
|
|
666
|
+
vec3 B = vec3(0.0, 1.0, 0.0);
|
|
667
|
+
float rough;
|
|
668
|
+
vec3 Nw = N;
|
|
669
|
+
vec3 mul = uWallSample(vec2(u, v) + seed, Nw, T, B, rough);
|
|
670
|
+
float ao = 0.6 + 0.4 * smoothstep(0.0, 2.5, v);
|
|
671
|
+
vec3 wallAlbedo = uWallColor * vTint * mul * wallMul;
|
|
672
|
+
vec3 wall = shadeSurface(wallAlbedo, Nw, vP, V, rough, ao);
|
|
673
|
+
// Window id -> lit coin and room hash, stable per building (seed) and face.
|
|
674
|
+
float faceId = round > 0.5 ? 1.0 : (n.x > 0.5 ? 1.0 : n.x < -0.5 ? 2.0 : n.z > 0.5 ? 3.0 : 4.0);
|
|
675
|
+
// Rooms span 1-3 bays (hashed per floor), so lit windows come in runs, not confetti.
|
|
676
|
+
float roomBays = 1.0 + floor(hash21(vec2(fIdx, faceId + seed)) * 3.0);
|
|
677
|
+
vec2 wid = vec2(floor(bIdx / roomBays) + faceId * 97.0, fIdx + seed);
|
|
678
|
+
// Each room has its own slow clock (20-80 s at flicker 1, slower below); the lit coin is
|
|
679
|
+
// re-rolled once per period, so at any moment only a few rooms switch, like a real city.
|
|
680
|
+
float period = (20.0 + 60.0 * hash21(wid + 5.3)) / max(uFlicker, 0.001);
|
|
681
|
+
float epoch = uFlicker > 0.001 ? floor((uTime + hash21(wid + 9.1) * period) / period) : 0.0;
|
|
682
|
+
float lit = lobby ? 0.45 : step(hash21(wid + epoch * 0.731), vFacade.w);
|
|
683
|
+
float roomHash = hash21(wid + 31.7);
|
|
684
|
+
float panel = hash21(vec2(bIdx + faceId * 31.0, fIdx + seed * 0.5));
|
|
685
|
+
vec3 glassCol = glassColor(N, V, lit, roomHash, panel, vf);
|
|
686
|
+
vec3 mullionCol = shadeSurface(uMullionColor, N, vP, V, 0.45, ao);
|
|
687
|
+
col = mix(wall, glassCol, glass);
|
|
688
|
+
col = mix(col, mullionCol, mullion);
|
|
689
|
+
if (door > 0.0) {
|
|
690
|
+
// A roller door: painted metal with horizontal slats.
|
|
691
|
+
float slat = 0.85 + 0.15 * bandAA(fract(v / 0.3), 0.15, 1.0);
|
|
692
|
+
col = mix(col, shadeSurface(mix(uMullionColor, uWallColor * vTint, 0.35) * slat, N, vP, V, 0.5, ao), door);
|
|
693
|
+
}
|
|
694
|
+
// Contact shadow at the pavement and under the slab edge of each floor.
|
|
695
|
+
col *= 0.75 + 0.25 * smoothstep(0.0, 1.2, v);
|
|
696
|
+
}
|
|
697
|
+
${GLSL_OUT}
|
|
698
|
+
}`;
|
|
699
|
+
export function createMaterial(u) {
|
|
700
|
+
return new THREE.ShaderMaterial({ uniforms: Object.assign(THREE.UniformsUtils.clone(THREE.UniformsLib.fog), u), vertexShader: VERT, fragmentShader: FRAG, fog: true });
|
|
701
|
+
}
|
|
702
|
+
// ---------------------------------------------------------------------------- lab build
|
|
703
|
+
/** Lab entry: build(u, c) -> { object, mesh, apply, rebuild, update, dispose }. */
|
|
704
|
+
export function build(u, c) {
|
|
705
|
+
const group = new THREE.Group();
|
|
706
|
+
const mat = createMaterial(u);
|
|
707
|
+
let mesh = null;
|
|
708
|
+
const state = { tex: null };
|
|
709
|
+
const rebuild = (cfg) => {
|
|
710
|
+
if (mesh) {
|
|
711
|
+
group.remove(mesh);
|
|
712
|
+
disposeInstanced(mesh);
|
|
713
|
+
}
|
|
714
|
+
const list = addBuilding([], cfg, 0, 0, 0, [1, 1, 1]);
|
|
715
|
+
mesh = buildInstancedBoxes(list, mat);
|
|
716
|
+
group.add(mesh);
|
|
717
|
+
};
|
|
718
|
+
const setTexture = (cfg) => {
|
|
719
|
+
const maps = cfg.texture && cfg.texture.maps;
|
|
720
|
+
if (maps && maps.color) {
|
|
721
|
+
state.tex = loadTextureSet(maps);
|
|
722
|
+
state.tex.ready.then(() => applyConfig(u, cfg, state.tex));
|
|
723
|
+
}
|
|
724
|
+
else
|
|
725
|
+
state.tex = null;
|
|
726
|
+
applyConfig(u, cfg, state.tex && state.tex.color ? state.tex : null);
|
|
727
|
+
};
|
|
728
|
+
rebuild(c);
|
|
729
|
+
setTexture(c);
|
|
730
|
+
return {
|
|
731
|
+
object: group,
|
|
732
|
+
get mesh() { return mesh; },
|
|
733
|
+
materials: [mat],
|
|
734
|
+
uniformSets: [u],
|
|
735
|
+
apply(cfg) { applyConfig(u, cfg, undefined); },
|
|
736
|
+
rebuild(cfg) { rebuild(cfg); setTexture(cfg); },
|
|
737
|
+
bounds() { return mesh ? mesh.userData.bounds.clone() : new THREE.Box3(); },
|
|
738
|
+
update(dt) { u.uTime.value += dt; },
|
|
739
|
+
dispose() { disposeInstanced(mesh); mat.dispose(); },
|
|
740
|
+
};
|
|
741
|
+
}
|