cuju-render 0.1.0__py3-none-any.whl
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.
- cuju/render/__init__.py +759 -0
- cuju/render/__main__.py +1065 -0
- cuju/render/_export/__init__.py +3 -0
- cuju/render/_export/feed.py +542 -0
- cuju/render/_export/sizes.py +157 -0
- cuju/render/_export/video.py +1618 -0
- cuju/render/_export/video_jobs.py +408 -0
- cuju/render/_format/__init__.py +3 -0
- cuju/render/_format/annotations.py +235 -0
- cuju/render/_format/codec.py +307 -0
- cuju/render/_format/keep.py +121 -0
- cuju/render/_format/recording.py +860 -0
- cuju/render/_format/writer.py +54 -0
- cuju/render/_guide/__init__.py +3 -0
- cuju/render/_guide/doctor.py +523 -0
- cuju/render/_guide/help.py +62 -0
- cuju/render/_guide/tutorial.py +254 -0
- cuju/render/_http/__init__.py +3 -0
- cuju/render/_http/commands.py +57 -0
- cuju/render/_http/headers.py +103 -0
- cuju/render/_http/launch.py +500 -0
- cuju/render/_http/launchers.py +408 -0
- cuju/render/_http/pwa.py +128 -0
- cuju/render/_http/server.py +2105 -0
- cuju/render/_http/window.py +360 -0
- cuju/render/_moments/__init__.py +3 -0
- cuju/render/_moments/captions.py +284 -0
- cuju/render/_moments/events.py +1123 -0
- cuju/render/_moments/search.py +694 -0
- cuju/render/_packages/__init__.py +3 -0
- cuju/render/_packages/glsl.py +746 -0
- cuju/render/_packages/loudness.py +334 -0
- cuju/render/_packages/pack.py +1959 -0
- cuju/render/_packages/presentation.py +1376 -0
- cuju/render/_packages/vocabulary.py +609 -0
- cuju/render/_playing/__init__.py +3 -0
- cuju/render/_playing/achievements.py +463 -0
- cuju/render/_playing/bench.py +609 -0
- cuju/render/_playing/challenges.py +1813 -0
- cuju/render/_playing/demo.py +323 -0
- cuju/render/_playing/draw.py +211 -0
- cuju/render/_playing/errors.py +20 -0
- cuju/render/_playing/game.py +645 -0
- cuju/render/_playing/limits.py +339 -0
- cuju/render/_playing/play.py +926 -0
- cuju/render/_playing/policy_worker.py +250 -0
- cuju/render/_playing/strict.py +810 -0
- cuju/render/_registry/__init__.py +3 -0
- cuju/render/_registry/clips.py +394 -0
- cuju/render/_registry/joints.py +108 -0
- cuju/render/_registry/teams.py +2058 -0
- cuju/render/_store/__init__.py +3 -0
- cuju/render/_store/home.py +70 -0
- cuju/render/_store/library.py +604 -0
- cuju/render/_store/samples.py +163 -0
- cuju/render/_text/__init__.py +3 -0
- cuju/render/_text/languages.py +637 -0
- cuju/render/_text/messages.py +1396 -0
- cuju/render/_tournaments/__init__.py +3 -0
- cuju/render/_tournaments/results.py +547 -0
- cuju/render/_tournaments/tournament.py +2742 -0
- cuju/render/_tournaments/tournament_cli.py +587 -0
- cuju/render/_tournaments/tournament_runner.py +1975 -0
- cuju/render/_version.py +6 -0
- cuju/render/_watch/__init__.py +3 -0
- cuju/render/_watch/grid.py +265 -0
- cuju/render/_watch/live.py +664 -0
- cuju/render/_watch/notebook.py +79 -0
- cuju/render/_watch/show.py +171 -0
- cuju/render/samples/sample-11v11.cjr +0 -0
- cuju/render/samples/sample-5v5.cjr +0 -0
- cuju/render/samples/teams/starter/main.py +33 -0
- cuju/render/scenarios/benchmark_full_game_11_vs_11_easy.py +46 -0
- cuju/render/scenarios/benchmark_full_game_11_vs_11_hard.py +46 -0
- cuju/render/scenarios/benchmark_full_game_11_vs_11_medium.py +46 -0
- cuju/render/scenarios/benchmark_full_game_5_vs_5_easy.py +34 -0
- cuju/render/scenarios/benchmark_full_game_5_vs_5_hard.py +34 -0
- cuju/render/scenarios/benchmark_full_game_5_vs_5_medium.py +34 -0
- cuju/render/web/assets/adboard_polygon.webp +0 -0
- cuju/render/web/assets/adboard_your_ad_here.webp +0 -0
- cuju/render/web/assets/animations/kaykit-rig-medium-combatmelee.glb +0 -0
- cuju/render/web/assets/animations/kaykit-rig-medium-general.glb +0 -0
- cuju/render/web/assets/animations/kaykit-rig-medium-movementadvanced.glb +0 -0
- cuju/render/web/assets/animations/kaykit-rig-medium-movementbasic.glb +0 -0
- cuju/render/web/assets/animations/kaykit-rig-medium-simulation.glb +0 -0
- cuju/render/web/assets/animations/kaykit-rig-medium-special.glb +0 -0
- cuju/render/web/assets/ball.glb +0 -0
- cuju/render/web/assets/challenges/3_vs_1_with_keeper.mp4 +0 -0
- cuju/render/web/assets/challenges/3_vs_1_with_keeper.webp +0 -0
- cuju/render/web/assets/challenges/corner.mp4 +0 -0
- cuju/render/web/assets/challenges/corner.webp +0 -0
- cuju/render/web/assets/challenges/counterattack_easy.mp4 +0 -0
- cuju/render/web/assets/challenges/counterattack_easy.webp +0 -0
- cuju/render/web/assets/challenges/counterattack_hard.mp4 +0 -0
- cuju/render/web/assets/challenges/counterattack_hard.webp +0 -0
- cuju/render/web/assets/challenges/empty_goal.mp4 +0 -0
- cuju/render/web/assets/challenges/empty_goal.webp +0 -0
- cuju/render/web/assets/challenges/empty_goal_close.mp4 +0 -0
- cuju/render/web/assets/challenges/empty_goal_close.webp +0 -0
- cuju/render/web/assets/challenges/manifest.json +375 -0
- cuju/render/web/assets/challenges/one_on_one.mp4 +0 -0
- cuju/render/web/assets/challenges/one_on_one.webp +0 -0
- cuju/render/web/assets/challenges/one_on_one_hard.mp4 +0 -0
- cuju/render/web/assets/challenges/one_on_one_hard.webp +0 -0
- cuju/render/web/assets/challenges/pass_and_shoot_with_keeper.mp4 +0 -0
- cuju/render/web/assets/challenges/pass_and_shoot_with_keeper.webp +0 -0
- cuju/render/web/assets/challenges/run_pass_and_shoot_with_keeper.mp4 +0 -0
- cuju/render/web/assets/challenges/run_pass_and_shoot_with_keeper.webp +0 -0
- cuju/render/web/assets/challenges/run_to_score.mp4 +0 -0
- cuju/render/web/assets/challenges/run_to_score.webp +0 -0
- cuju/render/web/assets/challenges/run_to_score_with_keeper.mp4 +0 -0
- cuju/render/web/assets/challenges/run_to_score_with_keeper.webp +0 -0
- cuju/render/web/assets/challenges/single_goal_versus_lazy.mp4 +0 -0
- cuju/render/web/assets/challenges/single_goal_versus_lazy.webp +0 -0
- cuju/render/web/assets/crowd.webp +0 -0
- cuju/render/web/assets/crowd_normal.webp +0 -0
- cuju/render/web/assets/cuju-logo-384.png +0 -0
- cuju/render/web/assets/cuju-logo.png +0 -0
- cuju/render/web/assets/cuju-logo.svg +46 -0
- cuju/render/web/assets/cuju-mark-light.svg +33 -0
- cuju/render/web/assets/cuju-mark.svg +33 -0
- cuju/render/web/assets/goal.glb +0 -0
- cuju/render/web/assets/grass.webp +0 -0
- cuju/render/web/assets/hair_black.png +0 -0
- cuju/render/web/assets/hair_blonde.png +0 -0
- cuju/render/web/assets/hair_brown.png +0 -0
- cuju/render/web/assets/hair_darkblonde.png +0 -0
- cuju/render/web/assets/hair_long01.glb +0 -0
- cuju/render/web/assets/hair_long02.glb +0 -0
- cuju/render/web/assets/hair_medium01.glb +0 -0
- cuju/render/web/assets/hair_red.png +0 -0
- cuju/render/web/assets/hair_short01.glb +0 -0
- cuju/render/web/assets/hair_short02.glb +0 -0
- cuju/render/web/assets/icons/cuju-192.png +0 -0
- cuju/render/web/assets/icons/cuju-512.png +0 -0
- cuju/render/web/assets/icons/cuju-maskable-512.png +0 -0
- cuju/render/web/assets/kit_goalkeeper.webp +0 -0
- cuju/render/web/assets/kit_mask.png +0 -0
- cuju/render/web/assets/kit_normal.webp +0 -0
- cuju/render/web/assets/manifest.json +601 -0
- cuju/render/web/assets/models/kaykit-barbarian.glb +0 -0
- cuju/render/web/assets/models/kaykit-barbarian.json +23 -0
- cuju/render/web/assets/models/kaykit-knight.glb +0 -0
- cuju/render/web/assets/models/kaykit-knight.json +23 -0
- cuju/render/web/assets/models/kaykit-mage.glb +0 -0
- cuju/render/web/assets/models/kaykit-mage.json +23 -0
- cuju/render/web/assets/models/kaykit-mannequin-medium.glb +0 -0
- cuju/render/web/assets/models/kaykit-mannequin-medium.json +23 -0
- cuju/render/web/assets/models/kaykit-ranger.glb +0 -0
- cuju/render/web/assets/models/kaykit-ranger.json +23 -0
- cuju/render/web/assets/models/kaykit-rogue-hooded.glb +0 -0
- cuju/render/web/assets/models/kaykit-rogue-hooded.json +23 -0
- cuju/render/web/assets/models/kaykit-rogue.glb +0 -0
- cuju/render/web/assets/models/kaykit-rogue.json +23 -0
- cuju/render/web/assets/models/kaykit-skeleton-mage.glb +0 -0
- cuju/render/web/assets/models/kaykit-skeleton-mage.json +23 -0
- cuju/render/web/assets/models/kaykit-skeleton-minion.glb +0 -0
- cuju/render/web/assets/models/kaykit-skeleton-minion.json +23 -0
- cuju/render/web/assets/models/kaykit-skeleton-rogue.glb +0 -0
- cuju/render/web/assets/models/kaykit-skeleton-rogue.json +23 -0
- cuju/render/web/assets/models/kaykit-skeleton-warrior.glb +0 -0
- cuju/render/web/assets/models/kaykit-skeleton-warrior.json +23 -0
- cuju/render/web/assets/pitch.webp +0 -0
- cuju/render/web/assets/pitch_normal.webp +0 -0
- cuju/render/web/assets/player.glb +0 -0
- cuju/render/web/assets/shoe.webp +0 -0
- cuju/render/web/assets/shoe_sole.png +0 -0
- cuju/render/web/assets/skin_01.png +0 -0
- cuju/render/web/assets/skin_02.png +0 -0
- cuju/render/web/assets/skin_03.png +0 -0
- cuju/render/web/assets/skin_04.png +0 -0
- cuju/render/web/assets/sounds/applause.ogg +0 -0
- cuju/render/web/assets/sounds/beach-wave-1.ogg +0 -0
- cuju/render/web/assets/sounds/beach-wave-2.ogg +0 -0
- cuju/render/web/assets/sounds/beach-wave-3.ogg +0 -0
- cuju/render/web/assets/sounds/beach-wave-4.ogg +0 -0
- cuju/render/web/assets/sounds/city-horn.ogg +0 -0
- cuju/render/web/assets/sounds/city-loop.ogg +0 -0
- cuju/render/web/assets/sounds/city-siren.ogg +0 -0
- cuju/render/web/assets/sounds/crowd-cheer.ogg +0 -0
- cuju/render/web/assets/sounds/crowd-loop.ogg +0 -0
- cuju/render/web/assets/sounds/crowd-ooh.ogg +0 -0
- cuju/render/web/assets/sounds/gulls.ogg +0 -0
- cuju/render/web/assets/sounds/neon-sting.ogg +0 -0
- cuju/render/web/assets/sounds/rain-loop.ogg +0 -0
- cuju/render/web/assets/sounds/sounds.json +46 -0
- cuju/render/web/assets/sounds/space-beep.ogg +0 -0
- cuju/render/web/assets/sounds/space-hum.ogg +0 -0
- cuju/render/web/assets/sounds/space-radio.ogg +0 -0
- cuju/render/web/assets/sounds/whistle-long.ogg +0 -0
- cuju/render/web/assets/sounds/whistle-short.ogg +0 -0
- cuju/render/web/assets/sounds/wind-loop.ogg +0 -0
- cuju/render/web/easy.css +357 -0
- cuju/render/web/export.html +23 -0
- cuju/render/web/feed.css +262 -0
- cuju/render/web/feed.html +28 -0
- cuju/render/web/flat.css +120 -0
- cuju/render/web/home.css +837 -0
- cuju/render/web/index.html +373 -0
- cuju/render/web/js/boot.js +50 -0
- cuju/render/web/js/broadcast/audio.js +2141 -0
- cuju/render/web/js/broadcast/celebrate.js +1238 -0
- cuju/render/web/js/broadcast/decisions.js +609 -0
- cuju/render/web/js/broadcast/hud.js +352 -0
- cuju/render/web/js/broadcast/show.js +3614 -0
- cuju/render/web/js/broadcast/transition.js +2231 -0
- cuju/render/web/js/broadcast/voices.js +153 -0
- cuju/render/web/js/capture.js +101 -0
- cuju/render/web/js/core/accessibility.js +90 -0
- cuju/render/web/js/core/api.js +429 -0
- cuju/render/web/js/core/comfort.js +135 -0
- cuju/render/web/js/core/i18n.js +705 -0
- cuju/render/web/js/core/icons.js +167 -0
- cuju/render/web/js/core/input-settings.js +156 -0
- cuju/render/web/js/core/keys.js +277 -0
- cuju/render/web/js/core/language-ui.js +125 -0
- cuju/render/web/js/core/menu.js +853 -0
- cuju/render/web/js/core/names.js +113 -0
- cuju/render/web/js/core/page-structure.js +110 -0
- cuju/render/web/js/core/scenarios.js +109 -0
- cuju/render/web/js/core/spoilers.js +236 -0
- cuju/render/web/js/core/typeahead.js +38 -0
- cuju/render/web/js/export/dom-picture.js +330 -0
- cuju/render/web/js/export/export-host.js +97 -0
- cuju/render/web/js/export/feed-dialog.js +191 -0
- cuju/render/web/js/export/feed-params.js +266 -0
- cuju/render/web/js/export/feed.js +363 -0
- cuju/render/web/js/export/mp4-mux.js +295 -0
- cuju/render/web/js/export/photo-core.js +313 -0
- cuju/render/web/js/export/photo.js +1314 -0
- cuju/render/web/js/export/safe-frame.js +59 -0
- cuju/render/web/js/export/size-fields.js +103 -0
- cuju/render/web/js/export/sizes.js +178 -0
- cuju/render/web/js/export/video-boot.js +55 -0
- cuju/render/web/js/export/video-browser.js +325 -0
- cuju/render/web/js/export/video-export.js +417 -0
- cuju/render/web/js/export/video-plan.js +207 -0
- cuju/render/web/js/export/video-range.js +185 -0
- cuju/render/web/js/export/webm-mux.js +198 -0
- cuju/render/web/js/feed-boot.js +151 -0
- cuju/render/web/js/feed-frame.js +101 -0
- cuju/render/web/js/help/doctor.js +488 -0
- cuju/render/web/js/help/firstrun.js +379 -0
- cuju/render/web/js/help/help-center.js +438 -0
- cuju/render/web/js/help/install-offer.js +164 -0
- cuju/render/web/js/help/install-state.js +104 -0
- cuju/render/web/js/help/lessons-core.js +207 -0
- cuju/render/web/js/help/lessons.js +463 -0
- cuju/render/web/js/help/palette.js +584 -0
- cuju/render/web/js/help/pwa.js +257 -0
- cuju/render/web/js/help/tour-core.js +241 -0
- cuju/render/web/js/help/tour.js +461 -0
- cuju/render/web/js/main.js +2513 -0
- cuju/render/web/js/pages/draw.js +188 -0
- cuju/render/web/js/pages/fieldpage.js +530 -0
- cuju/render/web/js/pages/home.js +521 -0
- cuju/render/web/js/pages/matches.js +779 -0
- cuju/render/web/js/pages/moments-ui.js +359 -0
- cuju/render/web/js/pages/queue-filters.js +63 -0
- cuju/render/web/js/pages/recording-groups.js +80 -0
- cuju/render/web/js/pages/recordings.js +1069 -0
- cuju/render/web/js/play/bench.js +347 -0
- cuju/render/web/js/play/challenges.js +1302 -0
- cuju/render/web/js/play/medals.js +127 -0
- cuju/render/web/js/play/play.js +1953 -0
- cuju/render/web/js/play/teasers.js +196 -0
- cuju/render/web/js/play/touch.js +350 -0
- cuju/render/web/js/play/tournament-layout.js +487 -0
- cuju/render/web/js/play/tournament-results.js +441 -0
- cuju/render/web/js/play/tournament-strict.js +560 -0
- cuju/render/web/js/play/tournament.js +2585 -0
- cuju/render/web/js/players/animate.js +972 -0
- cuju/render/web/js/players/clips.js +224 -0
- cuju/render/web/js/players/kaykit.js +162 -0
- cuju/render/web/js/players/kits.js +676 -0
- cuju/render/web/js/players/number-patch.js +82 -0
- cuju/render/web/js/players/players.js +2694 -0
- cuju/render/web/js/players/recolor.js +893 -0
- cuju/render/web/js/players/retarget.js +325 -0
- cuju/render/web/js/players/rig-numbers.js +174 -0
- cuju/render/web/js/presentation/animator.js +231 -0
- cuju/render/web/js/presentation/assign.js +85 -0
- cuju/render/web/js/presentation/behaviors.js +440 -0
- cuju/render/web/js/presentation/budget.js +209 -0
- cuju/render/web/js/presentation/catalog.js +1674 -0
- cuju/render/web/js/presentation/clocks.js +72 -0
- cuju/render/web/js/presentation/commands.js +301 -0
- cuju/render/web/js/presentation/contract.js +240 -0
- cuju/render/web/js/presentation/effects.js +904 -0
- cuju/render/web/js/presentation/flash.js +605 -0
- cuju/render/web/js/presentation/freeze-worklet.js +22 -0
- cuju/render/web/js/presentation/glsl.js +464 -0
- cuju/render/web/js/presentation/host.js +323 -0
- cuju/render/web/js/presentation/index.js +2066 -0
- cuju/render/web/js/presentation/loudness-worklet.js +235 -0
- cuju/render/web/js/presentation/loudness.js +740 -0
- cuju/render/web/js/presentation/moments.js +536 -0
- cuju/render/web/js/presentation/post.js +327 -0
- cuju/render/web/js/presentation/preview.js +180 -0
- cuju/render/web/js/presentation/protocol.js +174 -0
- cuju/render/web/js/presentation/reach.js +158 -0
- cuju/render/web/js/presentation/rigging.js +130 -0
- cuju/render/web/js/presentation/sandbox.js +157 -0
- cuju/render/web/js/presentation/shaders.js +235 -0
- cuju/render/web/js/presentation/stage.js +402 -0
- cuju/render/web/js/presentation/teamaudio.js +722 -0
- cuju/render/web/js/presentation/tracks.js +197 -0
- cuju/render/web/js/presentation/values.js +81 -0
- cuju/render/web/js/recording/annotation-data.js +203 -0
- cuju/render/web/js/recording/captions.js +491 -0
- cuju/render/web/js/recording/codec.js +185 -0
- cuju/render/web/js/recording/decode-worker.js +70 -0
- cuju/render/web/js/recording/decode.js +94 -0
- cuju/render/web/js/recording/episodes.js +46 -0
- cuju/render/web/js/recording/format.js +461 -0
- cuju/render/web/js/recording/live.js +348 -0
- cuju/render/web/js/recording/moments-query.js +59 -0
- cuju/render/web/js/recording/moments.js +149 -0
- cuju/render/web/js/recording/pose.js +86 -0
- cuju/render/web/js/recording/timeline.js +275 -0
- cuju/render/web/js/teams/art.js +50 -0
- cuju/render/web/js/teams/clip-editor.js +293 -0
- cuju/render/web/js/teams/editor.js +1979 -0
- cuju/render/web/js/teams/library.js +344 -0
- cuju/render/web/js/teams/painter.js +633 -0
- cuju/render/web/js/teams/surprise-ui.js +195 -0
- cuju/render/web/js/teams/surprise.js +497 -0
- cuju/render/web/js/teams/team-check.js +127 -0
- cuju/render/web/js/watch/annotations.js +270 -0
- cuju/render/web/js/watch/flat.js +366 -0
- cuju/render/web/js/watch/grid.js +436 -0
- cuju/render/web/js/watch/pitch2d.js +289 -0
- cuju/render/web/js/watch/player-tools.js +192 -0
- cuju/render/web/js/watch/presets.js +201 -0
- cuju/render/web/js/world/arenas.js +997 -0
- cuju/render/web/js/world/ball.js +204 -0
- cuju/render/web/js/world/cameras.js +982 -0
- cuju/render/web/js/world/crowd.js +376 -0
- cuju/render/web/js/world/field.js +227 -0
- cuju/render/web/js/world/framing.js +145 -0
- cuju/render/web/js/world/occlusion.js +48 -0
- cuju/render/web/js/world/pitch.js +703 -0
- cuju/render/web/js/world/scene.js +395 -0
- cuju/render/web/js/world/sky.js +325 -0
- cuju/render/web/js/world/stadium.js +1262 -0
- cuju/render/web/js/world/vendor-sky.js +367 -0
- cuju/render/web/js/world/weather.js +264 -0
- cuju/render/web/languages/en.json +4750 -0
- cuju/render/web/lessons.json +137 -0
- cuju/render/web/manifest.webmanifest +23 -0
- cuju/render/web/style.css +8399 -0
- cuju/render/web/sw.js +235 -0
- cuju/render/web/vendor/fabric/LICENSE +16 -0
- cuju/render/web/vendor/fabric/fabric.min.mjs +1 -0
- cuju/render/web/vendor/lucide/LICENSE +43 -0
- cuju/render/web/vendor/lucide/icons.js +141 -0
- cuju/render/web/vendor/three/LICENSE +21 -0
- cuju/render/web/vendor/three/build/three.core.js +60586 -0
- cuju/render/web/vendor/three/build/three.module.js +19719 -0
- cuju/render/web/vendor/three/examples/jsm/loaders/GLTFLoader.js +4925 -0
- cuju/render/web/vendor/three/examples/jsm/postprocessing/EffectComposer.js +365 -0
- cuju/render/web/vendor/three/examples/jsm/postprocessing/MaskPass.js +195 -0
- cuju/render/web/vendor/three/examples/jsm/postprocessing/OutputPass.js +148 -0
- cuju/render/web/vendor/three/examples/jsm/postprocessing/Pass.js +191 -0
- cuju/render/web/vendor/three/examples/jsm/postprocessing/RenderPass.js +193 -0
- cuju/render/web/vendor/three/examples/jsm/postprocessing/ShaderPass.js +135 -0
- cuju/render/web/vendor/three/examples/jsm/postprocessing/UnrealBloomPass.js +541 -0
- cuju/render/web/vendor/three/examples/jsm/shaders/CopyShader.js +52 -0
- cuju/render/web/vendor/three/examples/jsm/shaders/LuminosityHighPassShader.js +68 -0
- cuju/render/web/vendor/three/examples/jsm/shaders/OutputShader.js +103 -0
- cuju/render/web/vendor/three/examples/jsm/utils/BufferGeometryUtils.js +1501 -0
- cuju/render/web/vendor/three/examples/jsm/utils/SkeletonUtils.js +496 -0
- cuju_render-0.1.0.dist-info/METADATA +116 -0
- cuju_render-0.1.0.dist-info/RECORD +382 -0
- cuju_render-0.1.0.dist-info/WHEEL +4 -0
- cuju_render-0.1.0.dist-info/licenses/LICENSE +202 -0
- cuju_render-0.1.0.dist-info/licenses/LICENSES/CC-BY-4.0.txt +396 -0
- cuju_render-0.1.0.dist-info/licenses/LICENSES/CC0-1.0.txt +127 -0
- cuju_render-0.1.0.dist-info/licenses/LICENSES/ISC.txt +16 -0
- cuju_render-0.1.0.dist-info/licenses/LICENSES/MIT.txt +24 -0
- cuju_render-0.1.0.dist-info/licenses/LICENSES/Unlicense.txt +13 -0
- cuju_render-0.1.0.dist-info/licenses/NOTICE +35 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
// Sky.js from three.js r186, examples/jsm/objects/Sky.js, unchanged below this header.
|
|
2
|
+
// https://github.com/mrdoob/three.js/blob/r186/examples/jsm/objects/Sky.js
|
|
3
|
+
//
|
|
4
|
+
// The MIT License
|
|
5
|
+
//
|
|
6
|
+
// Copyright © 2010-2026 three.js authors
|
|
7
|
+
//
|
|
8
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
// in the Software without restriction, including without limitation the rights
|
|
11
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
// furnished to do so, subject to the following conditions:
|
|
14
|
+
//
|
|
15
|
+
// The above copyright notice and this permission notice shall be included in
|
|
16
|
+
// all copies or substantial portions of the Software.
|
|
17
|
+
//
|
|
18
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
24
|
+
// THE SOFTWARE.
|
|
25
|
+
|
|
26
|
+
import {
|
|
27
|
+
BackSide,
|
|
28
|
+
BoxGeometry,
|
|
29
|
+
Mesh,
|
|
30
|
+
ShaderMaterial,
|
|
31
|
+
UniformsUtils,
|
|
32
|
+
Vector3
|
|
33
|
+
} from 'three';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Represents a skydome for scene backgrounds. Based on [A Practical Analytic Model for Daylight](https://www.researchgate.net/publication/220720443_A_Practical_Analytic_Model_for_Daylight)
|
|
37
|
+
* aka The Preetham Model, the de facto standard for analytical skydomes.
|
|
38
|
+
*
|
|
39
|
+
* Note that this class can only be used with {@link WebGLRenderer}.
|
|
40
|
+
* When using {@link WebGPURenderer}, use {@link SkyMesh}.
|
|
41
|
+
*
|
|
42
|
+
* More references:
|
|
43
|
+
*
|
|
44
|
+
* - {@link http://simonwallner.at/project/atmospheric-scattering/}
|
|
45
|
+
* - {@link http://blenderartists.org/forum/showthread.php?245954-preethams-sky-impementation-HDR}
|
|
46
|
+
*
|
|
47
|
+
*
|
|
48
|
+
* ```js
|
|
49
|
+
* const sky = new Sky();
|
|
50
|
+
* sky.scale.setScalar( 10000 );
|
|
51
|
+
* scene.add( sky );
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* It can be useful to hide the sun disc when generating an environment map to avoid artifacts
|
|
55
|
+
*
|
|
56
|
+
* ```js
|
|
57
|
+
* // disable before rendering environment map
|
|
58
|
+
* sky.material.uniforms.showSunDisc.value = false;
|
|
59
|
+
* // ...
|
|
60
|
+
* // re-enable before scene sky box rendering
|
|
61
|
+
* sky.material.uniforms.showSunDisc.value = true;
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @augments Mesh
|
|
65
|
+
* @three_import import { Sky } from 'three/addons/objects/Sky.js';
|
|
66
|
+
*/
|
|
67
|
+
class Sky extends Mesh {
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Constructs a new skydome.
|
|
71
|
+
*/
|
|
72
|
+
constructor() {
|
|
73
|
+
|
|
74
|
+
const shader = Sky.SkyShader;
|
|
75
|
+
|
|
76
|
+
const material = new ShaderMaterial( {
|
|
77
|
+
name: shader.name,
|
|
78
|
+
uniforms: UniformsUtils.clone( shader.uniforms ),
|
|
79
|
+
vertexShader: shader.vertexShader,
|
|
80
|
+
fragmentShader: shader.fragmentShader,
|
|
81
|
+
side: BackSide,
|
|
82
|
+
depthWrite: false
|
|
83
|
+
} );
|
|
84
|
+
|
|
85
|
+
super( new BoxGeometry( 1, 1, 1 ), material );
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* This flag can be used for type testing.
|
|
89
|
+
*
|
|
90
|
+
* @type {boolean}
|
|
91
|
+
* @readonly
|
|
92
|
+
* @default true
|
|
93
|
+
*/
|
|
94
|
+
this.isSky = true;
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
Sky.SkyShader = {
|
|
101
|
+
|
|
102
|
+
name: 'SkyShader',
|
|
103
|
+
|
|
104
|
+
uniforms: {
|
|
105
|
+
'turbidity': { value: 2 },
|
|
106
|
+
'rayleigh': { value: 1 },
|
|
107
|
+
'mieCoefficient': { value: 0.005 },
|
|
108
|
+
'mieDirectionalG': { value: 0.8 },
|
|
109
|
+
'sunPosition': { value: new Vector3() },
|
|
110
|
+
'cloudScale': { value: 0.0002 },
|
|
111
|
+
'cloudSpeed': { value: 0.00002 },
|
|
112
|
+
'cloudCoverage': { value: 0.4 },
|
|
113
|
+
'cloudDensity': { value: 0.4 },
|
|
114
|
+
'cloudElevation': { value: 0.5 },
|
|
115
|
+
'showSunDisc': { value: 1 },
|
|
116
|
+
'time': { value: 0.0 }
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
vertexShader: /* glsl */`
|
|
120
|
+
uniform vec3 sunPosition;
|
|
121
|
+
uniform float rayleigh;
|
|
122
|
+
uniform float turbidity;
|
|
123
|
+
uniform float mieCoefficient;
|
|
124
|
+
|
|
125
|
+
varying vec3 vWorldPosition;
|
|
126
|
+
varying vec3 vSunDirection;
|
|
127
|
+
varying float vSunfade;
|
|
128
|
+
varying vec3 vBetaR;
|
|
129
|
+
varying vec3 vBetaM;
|
|
130
|
+
varying float vSunE;
|
|
131
|
+
|
|
132
|
+
// constants for atmospheric scattering
|
|
133
|
+
const float e = 2.71828182845904523536028747135266249775724709369995957;
|
|
134
|
+
const float pi = 3.141592653589793238462643383279502884197169;
|
|
135
|
+
|
|
136
|
+
// wavelength of used primaries, according to preetham
|
|
137
|
+
const vec3 lambda = vec3( 680E-9, 550E-9, 450E-9 );
|
|
138
|
+
// this pre-calculation replaces older TotalRayleigh(vec3 lambda) function:
|
|
139
|
+
// (8.0 * pow(pi, 3.0) * pow(pow(n, 2.0) - 1.0, 2.0) * (6.0 + 3.0 * pn)) / (3.0 * N * pow(lambda, vec3(4.0)) * (6.0 - 7.0 * pn))
|
|
140
|
+
const vec3 totalRayleigh = vec3( 5.804542996261093E-6, 1.3562911419845635E-5, 3.0265902468824876E-5 );
|
|
141
|
+
|
|
142
|
+
// mie stuff
|
|
143
|
+
// K coefficient for the primaries
|
|
144
|
+
const float v = 4.0;
|
|
145
|
+
const vec3 K = vec3( 0.686, 0.678, 0.666 );
|
|
146
|
+
// MieConst = pi * pow( ( 2.0 * pi ) / lambda, vec3( v - 2.0 ) ) * K
|
|
147
|
+
const vec3 MieConst = vec3( 1.8399918514433978E14, 2.7798023919660528E14, 4.0790479543861094E14 );
|
|
148
|
+
|
|
149
|
+
// earth shadow hack
|
|
150
|
+
// cutoffAngle = pi / 1.95;
|
|
151
|
+
const float cutoffAngle = 1.6110731556870734;
|
|
152
|
+
const float steepness = 1.5;
|
|
153
|
+
const float EE = 1000.0;
|
|
154
|
+
|
|
155
|
+
float sunIntensity( float zenithAngleCos ) {
|
|
156
|
+
zenithAngleCos = clamp( zenithAngleCos, -1.0, 1.0 );
|
|
157
|
+
return EE * max( 0.0, 1.0 - pow( e, -( ( cutoffAngle - acos( zenithAngleCos ) ) / steepness ) ) );
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
vec3 totalMie( float T ) {
|
|
161
|
+
float c = ( 0.2 * T ) * 10E-18;
|
|
162
|
+
return 0.434 * c * MieConst;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
void main() {
|
|
166
|
+
|
|
167
|
+
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
|
|
168
|
+
vWorldPosition = worldPosition.xyz;
|
|
169
|
+
|
|
170
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
171
|
+
gl_Position.z = gl_Position.w; // set z to camera.far
|
|
172
|
+
|
|
173
|
+
vSunDirection = normalize( sunPosition );
|
|
174
|
+
|
|
175
|
+
vSunE = sunIntensity( vSunDirection.y );
|
|
176
|
+
|
|
177
|
+
vSunfade = 1.0 - clamp( 1.0 - exp( ( sunPosition.y / 450000.0 ) ), 0.0, 1.0 );
|
|
178
|
+
|
|
179
|
+
float rayleighCoefficient = rayleigh - ( 1.0 * ( 1.0 - vSunfade ) );
|
|
180
|
+
|
|
181
|
+
// extinction (absorption + out scattering)
|
|
182
|
+
// rayleigh coefficients
|
|
183
|
+
vBetaR = totalRayleigh * rayleighCoefficient;
|
|
184
|
+
|
|
185
|
+
// mie coefficients
|
|
186
|
+
vBetaM = totalMie( turbidity ) * mieCoefficient;
|
|
187
|
+
|
|
188
|
+
}`,
|
|
189
|
+
|
|
190
|
+
fragmentShader: /* glsl */`
|
|
191
|
+
varying vec3 vWorldPosition;
|
|
192
|
+
varying vec3 vSunDirection;
|
|
193
|
+
varying vec3 vBetaR;
|
|
194
|
+
varying vec3 vBetaM;
|
|
195
|
+
varying float vSunE;
|
|
196
|
+
|
|
197
|
+
uniform float mieDirectionalG;
|
|
198
|
+
uniform float cloudScale;
|
|
199
|
+
uniform float cloudSpeed;
|
|
200
|
+
uniform float cloudCoverage;
|
|
201
|
+
uniform float cloudDensity;
|
|
202
|
+
uniform float cloudElevation;
|
|
203
|
+
uniform float showSunDisc;
|
|
204
|
+
uniform float time;
|
|
205
|
+
|
|
206
|
+
// gradient at a lattice corner; sinless hash so every GPU produces the same clouds
|
|
207
|
+
vec2 gradient( vec2 i ) {
|
|
208
|
+
vec3 p = fract( i.xyx * vec3( 0.1031, 0.1030, 0.0973 ) );
|
|
209
|
+
p += dot( p, p.yzx + 33.33 );
|
|
210
|
+
return fract( ( p.xx + p.yz ) * p.zy ) * 2.0 - 1.0;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// 2D gradient noise: isotropic lobes like Perlin at value-noise cost
|
|
214
|
+
float noise( vec2 p ) {
|
|
215
|
+
vec2 i = floor( p );
|
|
216
|
+
vec2 f = fract( p );
|
|
217
|
+
vec2 u = f * f * f * ( f * ( f * 6.0 - 15.0 ) + 10.0 ); // quintic fade
|
|
218
|
+
float a = dot( gradient( i ), f );
|
|
219
|
+
float b = dot( gradient( i + vec2( 1.0, 0.0 ) ), f - vec2( 1.0, 0.0 ) );
|
|
220
|
+
float c = dot( gradient( i + vec2( 0.0, 1.0 ) ), f - vec2( 0.0, 1.0 ) );
|
|
221
|
+
float d = dot( gradient( i + vec2( 1.0, 1.0 ) ), f - vec2( 1.0, 1.0 ) );
|
|
222
|
+
return mix( mix( a, b, u.x ), mix( c, d, u.x ), u.y ) * 1.6; // ~[-1,1]
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// fbm; per-octave drift makes clouds billow instead of scrolling as a rigid stamp
|
|
226
|
+
float fbm( vec2 p, float drift ) {
|
|
227
|
+
float result = 0.0;
|
|
228
|
+
float amplitude = 1.0;
|
|
229
|
+
for ( int i = 0; i < 4; i ++ ) {
|
|
230
|
+
result += amplitude * noise( p );
|
|
231
|
+
amplitude *= 0.5;
|
|
232
|
+
p = p * 2.0 + drift;
|
|
233
|
+
}
|
|
234
|
+
return result;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// constants for atmospheric scattering
|
|
238
|
+
const float pi = 3.141592653589793238462643383279502884197169;
|
|
239
|
+
|
|
240
|
+
const float n = 1.0003; // refractive index of air
|
|
241
|
+
const float N = 2.545E25; // number of molecules per unit volume for air at 288.15K and 1013mb (sea level -45 celsius)
|
|
242
|
+
|
|
243
|
+
// optical length at zenith for molecules
|
|
244
|
+
const float rayleighZenithLength = 8.4E3;
|
|
245
|
+
const float mieZenithLength = 1.25E3;
|
|
246
|
+
// 66 arc seconds -> degrees, and the cosine of that
|
|
247
|
+
const float sunAngularDiameterCos = 0.999956676946448443553574619906976478926848692873900859324;
|
|
248
|
+
|
|
249
|
+
// 3.0 / ( 16.0 * pi )
|
|
250
|
+
const float THREE_OVER_SIXTEENPI = 0.05968310365946075;
|
|
251
|
+
// 1.0 / ( 4.0 * pi )
|
|
252
|
+
const float ONE_OVER_FOURPI = 0.07957747154594767;
|
|
253
|
+
|
|
254
|
+
float rayleighPhase( float cosTheta ) {
|
|
255
|
+
return THREE_OVER_SIXTEENPI * ( 1.0 + pow( cosTheta, 2.0 ) );
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
float hgPhase( float cosTheta, float g ) {
|
|
259
|
+
float g2 = pow( g, 2.0 );
|
|
260
|
+
float inverse = 1.0 / pow( 1.0 - 2.0 * g * cosTheta + g2, 1.5 );
|
|
261
|
+
return ONE_OVER_FOURPI * ( ( 1.0 - g2 ) * inverse );
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
void main() {
|
|
265
|
+
|
|
266
|
+
vec3 direction = normalize( vWorldPosition - cameraPosition );
|
|
267
|
+
|
|
268
|
+
// optical length
|
|
269
|
+
// cutoff angle at 90 to avoid singularity in next formula.
|
|
270
|
+
float zenithAngle = acos( max( 0.0, direction.y ) );
|
|
271
|
+
float inverse = 1.0 / ( cos( zenithAngle ) + 0.15 * pow( 93.885 - ( ( zenithAngle * 180.0 ) / pi ), -1.253 ) );
|
|
272
|
+
float sR = rayleighZenithLength * inverse;
|
|
273
|
+
float sM = mieZenithLength * inverse;
|
|
274
|
+
|
|
275
|
+
// combined extinction factor
|
|
276
|
+
vec3 Fex = exp( -( vBetaR * sR + vBetaM * sM ) );
|
|
277
|
+
|
|
278
|
+
// in scattering
|
|
279
|
+
float cosTheta = dot( direction, vSunDirection );
|
|
280
|
+
|
|
281
|
+
float rPhase = rayleighPhase( cosTheta * 0.5 + 0.5 );
|
|
282
|
+
vec3 betaRTheta = vBetaR * rPhase;
|
|
283
|
+
|
|
284
|
+
float mPhase = hgPhase( cosTheta, mieDirectionalG );
|
|
285
|
+
vec3 betaMTheta = vBetaM * mPhase;
|
|
286
|
+
|
|
287
|
+
vec3 Lin = pow( vSunE * ( ( betaRTheta + betaMTheta ) / ( vBetaR + vBetaM ) ) * ( 1.0 - Fex ), vec3( 1.5 ) );
|
|
288
|
+
Lin *= mix( vec3( 1.0 ), pow( vSunE * ( ( betaRTheta + betaMTheta ) / ( vBetaR + vBetaM ) ) * Fex, vec3( 1.0 / 2.0 ) ), clamp( pow( 1.0 - vSunDirection.y, 5.0 ), 0.0, 1.0 ) );
|
|
289
|
+
|
|
290
|
+
// nightsky
|
|
291
|
+
float theta = acos( direction.y ); // elevation --> y-axis, [-pi/2, pi/2]
|
|
292
|
+
float phi = atan( direction.z, direction.x ); // azimuth --> x-axis [-pi/2, pi/2]
|
|
293
|
+
vec2 uv = vec2( phi, theta ) / vec2( 2.0 * pi, pi ) + vec2( 0.5, 0.0 );
|
|
294
|
+
vec3 L0 = vec3( 0.1 ) * Fex;
|
|
295
|
+
|
|
296
|
+
// composition + solar disc
|
|
297
|
+
float sundisc = clamp( ( cosTheta - sunAngularDiameterCos ) * 50000.0, 0.0, 1.0 ) * showSunDisc;
|
|
298
|
+
vec3 sundiscColor = ( 760.0 * sundisc ) * min( vSunE * Fex, 80.0 );
|
|
299
|
+
|
|
300
|
+
vec3 texColor = ( Lin + L0 ) * 0.04 + sundiscColor + vec3( 0.0, 0.0003, 0.00075 );
|
|
301
|
+
|
|
302
|
+
// Clouds
|
|
303
|
+
if ( direction.y > 0.0 && cloudCoverage > 0.0 ) {
|
|
304
|
+
|
|
305
|
+
// Project to cloud plane (higher elevation = clouds appear lower/closer)
|
|
306
|
+
float elevation = mix( 1.0, 0.1, cloudElevation );
|
|
307
|
+
vec2 cloudUV = direction.xz / ( direction.y * elevation );
|
|
308
|
+
cloudUV *= cloudScale;
|
|
309
|
+
cloudUV += time * cloudSpeed;
|
|
310
|
+
|
|
311
|
+
// Cloud density field
|
|
312
|
+
float evolve = time * cloudSpeed * 300.0;
|
|
313
|
+
float cloudNoise = clamp( fbm( cloudUV * 1000.0, evolve ) * 0.7 + 0.5, 0.0, 1.0 );
|
|
314
|
+
|
|
315
|
+
// Large-scale coverage variation: clear gaps next to dense banks
|
|
316
|
+
float region = noise( cloudUV * 300.0 ) * 0.37 + 0.5;
|
|
317
|
+
float cov = clamp( cloudCoverage + ( region - 0.5 ) * 0.6, 0.0, 1.0 );
|
|
318
|
+
|
|
319
|
+
// Carve clouds where noise rises above the coverage level
|
|
320
|
+
float threshold = 1.0 - cov;
|
|
321
|
+
float cloudMask = smoothstep( threshold, threshold + 0.3, cloudNoise );
|
|
322
|
+
|
|
323
|
+
// Fade clouds near horizon (adjusted by elevation)
|
|
324
|
+
float horizonFade = smoothstep( 0.0, 0.03 + 0.06 * cloudElevation, direction.y );
|
|
325
|
+
cloudMask *= horizonFade;
|
|
326
|
+
|
|
327
|
+
// Cloud lighting from the sky's own radiance
|
|
328
|
+
float dayFactor = smoothstep( -0.08, 0.3, vSunDirection.y );
|
|
329
|
+
vec3 sunColor = vSunE * Fex * 0.22 * 0.04; // 0.22 ~ albedo/pi, 0.04 = exposure; the aerial composite adds the eye-leg extinction
|
|
330
|
+
vec3 skyAmbient = Lin * 0.04 + vec3( 0.0, 0.0003, 0.00075 );
|
|
331
|
+
|
|
332
|
+
// Beer-powder self-shadow from the sampled density
|
|
333
|
+
float depth = max( 0.0, cloudNoise - threshold );
|
|
334
|
+
float beer = exp( depth * -4.0 );
|
|
335
|
+
float powder = 1.0 - beer * beer; // beer*beer == exp(-8*depth)
|
|
336
|
+
float shade = mix( 0.45, 1.0, clamp( beer * powder * 2.6, 0.0, 1.0 ) ); // 2.6 = 1/0.385, normalizes beer*powder peak to 1
|
|
337
|
+
|
|
338
|
+
// Henyey-Greenstein forward lobe ( g = 0.7 ): silver lining on rims toward the sun
|
|
339
|
+
float silver = clamp( 0.51 / pow( 1.49 - cosTheta * 1.4, 1.5 ), 0.0, 3.0 ); // 0.51=1-g^2, 1.49=1+g^2, 1.4=2g
|
|
340
|
+
float edge = cloudMask * ( 1.0 - cloudMask ) * 4.0;
|
|
341
|
+
|
|
342
|
+
vec3 cloudColor = skyAmbient + sunColor * shade;
|
|
343
|
+
cloudColor += sunColor * silver * edge * 0.6;
|
|
344
|
+
cloudColor *= max( dayFactor, 0.03 );
|
|
345
|
+
|
|
346
|
+
// Cloud opacity via Beer's law: density sets how solid the clouds get
|
|
347
|
+
float alpha = ( 1.0 - exp( depth * cloudDensity * -12.0 ) ) * horizonFade;
|
|
348
|
+
|
|
349
|
+
// Occlude the sun disc/glow behind opaque cloud
|
|
350
|
+
texColor -= L0 * 0.04 * alpha;
|
|
351
|
+
|
|
352
|
+
// Composite through the atmosphere so distant clouds dissolve into haze
|
|
353
|
+
vec3 cloudAerial = mix( texColor, cloudColor, Fex );
|
|
354
|
+
texColor = mix( texColor, cloudAerial, alpha );
|
|
355
|
+
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
gl_FragColor = vec4( texColor, 1.0 );
|
|
359
|
+
|
|
360
|
+
#include <tonemapping_fragment>
|
|
361
|
+
#include <colorspace_fragment>
|
|
362
|
+
|
|
363
|
+
}`
|
|
364
|
+
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
export { Sky };
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
// Copyright 2026 The cuju Authors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
// Rain, snow and splashes. Every particle is one instance of a small quad whose place comes from
|
|
5
|
+
// its seed and the time in the vertex shader, so the processor only sets a few uniforms a frame.
|
|
6
|
+
// The drops are anchored to the world and wrap around a box that follows the camera, so they
|
|
7
|
+
// never swim with it. Quality sets how many there are, the low quality draws none.
|
|
8
|
+
|
|
9
|
+
import * as THREE from 'three';
|
|
10
|
+
import { FULL_HALF_H, FULL_HALF_W } from './pitch.js';
|
|
11
|
+
|
|
12
|
+
const COUNTS = {
|
|
13
|
+
low: { rain: 0, snow: 0, splash: 0 },
|
|
14
|
+
medium: { rain: 6000, snow: 4000, splash: 900 },
|
|
15
|
+
high: { rain: 16000, snow: 9000, splash: 2400 },
|
|
16
|
+
};
|
|
17
|
+
// The box of drops around the camera, its half size in meters.
|
|
18
|
+
const RAIN_HALF = new THREE.Vector3(36, 22, 36);
|
|
19
|
+
const SNOW_HALF = new THREE.Vector3(30, 18, 30);
|
|
20
|
+
|
|
21
|
+
const COMMON = `
|
|
22
|
+
uniform float uTime;
|
|
23
|
+
uniform vec3 uCenter;
|
|
24
|
+
uniform vec3 uHalf;
|
|
25
|
+
uniform vec3 uVel;
|
|
26
|
+
attribute vec4 seed;
|
|
27
|
+
varying vec2 vUv;
|
|
28
|
+
varying float vFade;
|
|
29
|
+
vec3 cjWrap(vec3 p) {
|
|
30
|
+
vec3 rel = mod(p - uCenter + uHalf, uHalf * 2.0) - uHalf;
|
|
31
|
+
vFade = 1.0 - smoothstep(0.75, 1.0, length(rel.xz) / uHalf.x);
|
|
32
|
+
vFade *= 1.0 - smoothstep(0.8, 1.0, abs(rel.y) / uHalf.y);
|
|
33
|
+
return uCenter + rel;
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
const RAIN_VERTEX = `${COMMON}
|
|
38
|
+
uniform float uLen;
|
|
39
|
+
uniform float uWidth;
|
|
40
|
+
void main() {
|
|
41
|
+
float speed = 0.85 + 0.3 * seed.w;
|
|
42
|
+
vec3 head = cjWrap(seed.xyz * uHalf * 2.0 + uVel * speed * uTime);
|
|
43
|
+
vec3 dir = normalize(uVel);
|
|
44
|
+
vec3 p = head - dir * uLen * speed * position.y;
|
|
45
|
+
vec3 toCam = cameraPosition - p;
|
|
46
|
+
float dist = length(toCam);
|
|
47
|
+
// Far drops widen to about a pixel and fade to match, so they shimmer rather than flicker.
|
|
48
|
+
float width = max(uWidth, dist * 0.0022);
|
|
49
|
+
vFade *= uWidth / width * 0.5 + 0.5;
|
|
50
|
+
vFade *= step(0.0, p.y) * smoothstep(0.6, 3.0, dist);
|
|
51
|
+
p += normalize(cross(dir, toCam)) * width * position.x;
|
|
52
|
+
vUv = position.xy;
|
|
53
|
+
gl_Position = projectionMatrix * viewMatrix * vec4(p, 1.0);
|
|
54
|
+
}`;
|
|
55
|
+
|
|
56
|
+
const SNOW_VERTEX = `${COMMON}
|
|
57
|
+
uniform float uSize;
|
|
58
|
+
void main() {
|
|
59
|
+
float t = uTime * (0.7 + 0.6 * seed.w);
|
|
60
|
+
vec3 sway = vec3(sin(t * 1.3 + seed.x * 40.0), 0.0, cos(t * 1.1 + seed.z * 40.0)) * 0.5;
|
|
61
|
+
vec3 head = cjWrap(seed.xyz * uHalf * 2.0 + uVel * t + sway);
|
|
62
|
+
vec3 right = vec3(viewMatrix[0][0], viewMatrix[1][0], viewMatrix[2][0]);
|
|
63
|
+
vec3 up = vec3(viewMatrix[0][1], viewMatrix[1][1], viewMatrix[2][1]);
|
|
64
|
+
float dist = length(cameraPosition - head);
|
|
65
|
+
float size = max(uSize * (0.6 + 0.8 * seed.w), dist * 0.0016);
|
|
66
|
+
vFade *= step(0.0, head.y) * smoothstep(0.4, 2.0, dist) * min(1.0, uSize * 1.5 / size + 0.25);
|
|
67
|
+
vec3 p = head + (right * position.x + up * (position.y * 2.0 - 1.0)) * size;
|
|
68
|
+
vUv = vec2(position.x, position.y * 2.0 - 1.0);
|
|
69
|
+
gl_Position = projectionMatrix * viewMatrix * vec4(p, 1.0);
|
|
70
|
+
}`;
|
|
71
|
+
|
|
72
|
+
// Rings spreading on the ground where drops land, each at a new place every cycle.
|
|
73
|
+
const SPLASH_VERTEX = `
|
|
74
|
+
uniform float uTime;
|
|
75
|
+
uniform vec2 uArea;
|
|
76
|
+
attribute vec4 seed;
|
|
77
|
+
varying vec2 vUv;
|
|
78
|
+
varying float vFade;
|
|
79
|
+
float cjHash(vec2 p) {
|
|
80
|
+
p = fract(p * vec2(0.1031, 0.1030));
|
|
81
|
+
p += dot(p, p.yx + 33.33);
|
|
82
|
+
return fract((p.x + p.y) * p.x);
|
|
83
|
+
}
|
|
84
|
+
void main() {
|
|
85
|
+
float period = 0.45 + 0.35 * seed.w;
|
|
86
|
+
float c = uTime / period + seed.z * 7.0;
|
|
87
|
+
float cycle = floor(c);
|
|
88
|
+
float phase = fract(c);
|
|
89
|
+
vec2 at = (vec2(cjHash(seed.xy * 91.0 + cycle), cjHash(seed.yx * 57.0 + cycle * 1.7)) * 2.0 - 1.0) * uArea;
|
|
90
|
+
float r = 0.05 + 0.22 * phase;
|
|
91
|
+
vec3 p = vec3(at.x + position.x * r, 0.03, at.y + position.y * r);
|
|
92
|
+
vUv = position.xy;
|
|
93
|
+
vFade = 1.0 - phase;
|
|
94
|
+
gl_Position = projectionMatrix * viewMatrix * vec4(p, 1.0);
|
|
95
|
+
}`;
|
|
96
|
+
|
|
97
|
+
const FRAGMENT_HEAD = `
|
|
98
|
+
uniform vec3 uColor;
|
|
99
|
+
uniform float uOpacity;
|
|
100
|
+
varying vec2 vUv;
|
|
101
|
+
varying float vFade;
|
|
102
|
+
`;
|
|
103
|
+
const FRAGMENT_TAIL = `
|
|
104
|
+
if (a < 0.004) {
|
|
105
|
+
discard;
|
|
106
|
+
}
|
|
107
|
+
gl_FragColor = vec4(uColor, a);
|
|
108
|
+
#include <tonemapping_fragment>
|
|
109
|
+
#include <colorspace_fragment>
|
|
110
|
+
}`;
|
|
111
|
+
|
|
112
|
+
const RAIN_FRAGMENT = `${FRAGMENT_HEAD}
|
|
113
|
+
void main() {
|
|
114
|
+
float a = (1.0 - abs(vUv.x)) * (1.0 - 0.7 * vUv.y) * vFade * uOpacity;
|
|
115
|
+
${FRAGMENT_TAIL}`;
|
|
116
|
+
|
|
117
|
+
const SNOW_FRAGMENT = `${FRAGMENT_HEAD}
|
|
118
|
+
void main() {
|
|
119
|
+
float a = smoothstep(1.0, 0.3, length(vUv)) * vFade * uOpacity;
|
|
120
|
+
${FRAGMENT_TAIL}`;
|
|
121
|
+
|
|
122
|
+
const SPLASH_FRAGMENT = `${FRAGMENT_HEAD}
|
|
123
|
+
void main() {
|
|
124
|
+
float d = length(vUv);
|
|
125
|
+
float a = smoothstep(0.65, 0.85, d) * smoothstep(1.0, 0.88, d) * vFade * uOpacity;
|
|
126
|
+
${FRAGMENT_TAIL}`;
|
|
127
|
+
|
|
128
|
+
function rand(seed) {
|
|
129
|
+
let s = seed >>> 0;
|
|
130
|
+
return () => {
|
|
131
|
+
s = (s + 0x6d2b79f5) >>> 0;
|
|
132
|
+
let t = s;
|
|
133
|
+
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
134
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
135
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function particles(count, quad, vertexShader, fragmentShader, uniforms, seedValue) {
|
|
140
|
+
const geometry = new THREE.InstancedBufferGeometry();
|
|
141
|
+
geometry.setAttribute('position', new THREE.Float32BufferAttribute(quad, 3));
|
|
142
|
+
geometry.setIndex([0, 1, 2, 0, 2, 3]);
|
|
143
|
+
const seeds = new Float32Array(count * 4);
|
|
144
|
+
const r = rand(seedValue);
|
|
145
|
+
for (let i = 0; i < seeds.length; i++) {
|
|
146
|
+
seeds[i] = r();
|
|
147
|
+
}
|
|
148
|
+
geometry.setAttribute('seed', new THREE.InstancedBufferAttribute(seeds, 4));
|
|
149
|
+
geometry.instanceCount = 0;
|
|
150
|
+
const material = new THREE.ShaderMaterial({
|
|
151
|
+
uniforms, vertexShader, fragmentShader, transparent: true, depthWrite: false, side: THREE.DoubleSide,
|
|
152
|
+
});
|
|
153
|
+
const mesh = new THREE.Mesh(geometry, material);
|
|
154
|
+
mesh.frustumCulled = false;
|
|
155
|
+
mesh.visible = false;
|
|
156
|
+
mesh.renderOrder = 5;
|
|
157
|
+
return mesh;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export class Weather {
|
|
161
|
+
constructor(scene) {
|
|
162
|
+
this.group = new THREE.Group();
|
|
163
|
+
scene.add(this.group);
|
|
164
|
+
this.quality = 'medium';
|
|
165
|
+
this.state = { rain: 0, snow: 0, wind: 0 };
|
|
166
|
+
this.rainU = {
|
|
167
|
+
uTime: { value: 0 }, uCenter: { value: new THREE.Vector3() }, uHalf: { value: RAIN_HALF.clone() },
|
|
168
|
+
uVel: { value: new THREE.Vector3(0, -11, 0) }, uLen: { value: 0.9 }, uWidth: { value: 0.012 },
|
|
169
|
+
uColor: { value: new THREE.Color(0xc8d2dc) }, uOpacity: { value: 0.35 },
|
|
170
|
+
};
|
|
171
|
+
this.snowU = {
|
|
172
|
+
uTime: { value: 0 }, uCenter: { value: new THREE.Vector3() }, uHalf: { value: SNOW_HALF.clone() },
|
|
173
|
+
uVel: { value: new THREE.Vector3(0, -1.2, 0) }, uSize: { value: 0.035 },
|
|
174
|
+
uColor: { value: new THREE.Color(0xffffff) }, uOpacity: { value: 0.85 },
|
|
175
|
+
};
|
|
176
|
+
this.splashU = {
|
|
177
|
+
uTime: { value: 0 }, uArea: { value: new THREE.Vector2(FULL_HALF_W + 2, FULL_HALF_H + 2) },
|
|
178
|
+
uColor: { value: new THREE.Color(0xdfe6ee) }, uOpacity: { value: 0.5 },
|
|
179
|
+
};
|
|
180
|
+
this.build();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
build() {
|
|
184
|
+
this.disposeMeshes();
|
|
185
|
+
const c = COUNTS[this.quality] || COUNTS.medium;
|
|
186
|
+
this.max = c;
|
|
187
|
+
this.rain = particles(c.rain, [-1, 0, 0, 1, 0, 0, 1, 1, 0, -1, 1, 0], RAIN_VERTEX, RAIN_FRAGMENT, this.rainU, 7);
|
|
188
|
+
this.snow = particles(c.snow, [-1, 0, 0, 1, 0, 0, 1, 1, 0, -1, 1, 0], SNOW_VERTEX, SNOW_FRAGMENT, this.snowU, 11);
|
|
189
|
+
this.splash = particles(c.splash, [-1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0], SPLASH_VERTEX, SPLASH_FRAGMENT, this.splashU, 13);
|
|
190
|
+
this.group.add(this.rain, this.snow, this.splash);
|
|
191
|
+
this.applyCounts();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
setQuality(quality) {
|
|
195
|
+
if (quality === this.quality && this.rain) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
this.quality = quality;
|
|
199
|
+
this.build();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Takes the lighting of the hour and weather, see lightingAt.
|
|
203
|
+
set(L) {
|
|
204
|
+
this.state = { rain: L.rain, snow: L.snow, wind: L.wind };
|
|
205
|
+
const wind = L.wind;
|
|
206
|
+
// Wind blows along the pitch from the right end, and a little towards the camera.
|
|
207
|
+
const gust = new THREE.Vector3(-1, 0, 0.35).normalize();
|
|
208
|
+
this.rainU.uVel.value.set(0, -11 - 3 * L.rain, 0).addScaledVector(gust, 9 * wind);
|
|
209
|
+
this.snowU.uVel.value.set(0, -1.1, 0).addScaledVector(gust, 3.5 * wind);
|
|
210
|
+
// Drops catch the light around them, the floodlights at night.
|
|
211
|
+
const light = Math.min(1.2, 0.25 + 0.45 * L.hemiIntensity + 0.15 * L.lightIntensity + 0.8 * L.flood);
|
|
212
|
+
this.rainU.uColor.value.setRGB(0.78, 0.82, 0.88).multiplyScalar(light);
|
|
213
|
+
this.rainU.uOpacity.value = 0.3 + 0.25 * L.rain;
|
|
214
|
+
this.snowU.uColor.value.setRGB(0.95, 0.96, 1.0).multiplyScalar(Math.min(1.1, 0.35 + 0.5 * L.hemiIntensity + 0.15 * L.lightIntensity + 0.7 * L.flood));
|
|
215
|
+
this.splashU.uColor.value.copy(this.rainU.uColor.value);
|
|
216
|
+
this.applyCounts();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
applyCounts() {
|
|
220
|
+
const c = this.max;
|
|
221
|
+
const s = this.state;
|
|
222
|
+
this.rain.geometry.instanceCount = Math.round(c.rain * Math.min(1, s.rain));
|
|
223
|
+
this.snow.geometry.instanceCount = Math.round(c.snow * Math.min(1, s.snow));
|
|
224
|
+
this.splash.geometry.instanceCount = Math.round(c.splash * Math.min(1, s.rain));
|
|
225
|
+
this.rain.visible = this.rain.geometry.instanceCount > 0;
|
|
226
|
+
this.snow.visible = this.snow.geometry.instanceCount > 0;
|
|
227
|
+
this.splash.visible = this.splash.geometry.instanceCount > 0;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// The boxes sit a little ahead of the camera, where most of what it sees is.
|
|
231
|
+
update(seconds, camera) {
|
|
232
|
+
const t = seconds % 3600;
|
|
233
|
+
this.rainU.uTime.value = t;
|
|
234
|
+
this.snowU.uTime.value = t;
|
|
235
|
+
this.splashU.uTime.value = t;
|
|
236
|
+
if (!this.rain.visible && !this.snow.visible) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const ahead = camera.getWorldDirection(this.ahead || (this.ahead = new THREE.Vector3()));
|
|
240
|
+
ahead.y = 0;
|
|
241
|
+
if (ahead.lengthSq() > 1e-6) {
|
|
242
|
+
ahead.normalize();
|
|
243
|
+
}
|
|
244
|
+
this.rainU.uCenter.value.copy(camera.position).addScaledVector(ahead, RAIN_HALF.x * 0.55);
|
|
245
|
+
this.rainU.uCenter.value.y = Math.max(RAIN_HALF.y - 2, camera.position.y - 4);
|
|
246
|
+
this.snowU.uCenter.value.copy(camera.position).addScaledVector(ahead, SNOW_HALF.x * 0.55);
|
|
247
|
+
this.snowU.uCenter.value.y = Math.max(SNOW_HALF.y - 2, camera.position.y - 4);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
disposeMeshes() {
|
|
251
|
+
for (const mesh of [this.rain, this.snow, this.splash]) {
|
|
252
|
+
if (mesh) {
|
|
253
|
+
mesh.removeFromParent();
|
|
254
|
+
mesh.geometry.dispose();
|
|
255
|
+
mesh.material.dispose();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
dispose() {
|
|
261
|
+
this.disposeMeshes();
|
|
262
|
+
this.group.removeFromParent();
|
|
263
|
+
}
|
|
264
|
+
}
|