From 4be13823d45d84d5ff7f06adab9b5c9d105e871d Mon Sep 17 00:00:00 2001 From: Bitik-original Date: Wed, 6 May 2026 17:25:11 +0000 Subject: [PATCH] Automated Extension submission for issue #2109 --- extensions/community/CinematicSky.json | 312 +++++++++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 extensions/community/CinematicSky.json diff --git a/extensions/community/CinematicSky.json b/extensions/community/CinematicSky.json new file mode 100644 index 000000000..3f4158532 --- /dev/null +++ b/extensions/community/CinematicSky.json @@ -0,0 +1,312 @@ +{ + "author": "", + "category": "Visual Effect", + "dimension": "3D", + "extensionNamespace": "", + "fullName": "Cinematic Sky", + "gdevelopVersion": "", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXdoaXRlLWJhbGFuY2Utc3VubnkiIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMy41NSwxOC41NEw0Ljk2LDE5Ljk1TDYuNzYsMTguMTZMNS4zNCwxNi43NE0xMSwyMi40NUMxMS4zMiwyMi40NSAxMywyMi40NSAxMywyMi40NVYxOS41SDExTTEyLDUuNUE2LDYgMCAwLDAgNiwxMS41QTYsNiAwIDAsMCAxMiwxNy41QTYsNiAwIDAsMCAxOCwxMS41QzE4LDguMTggMTUuMzEsNS41IDEyLDUuNU0yMCwxMi41SDIzVjEwLjVIMjBNMTcuMjQsMTguMTZMMTkuMDQsMTkuOTVMMjAuNDUsMTguNTRMMTguNjYsMTYuNzRNMjAuNDUsNC40NkwxOS4wNCwzLjA1TDE3LjI0LDQuODRMMTguNjYsNi4yNk0xMywwLjU1SDExVjMuNUgxM000LDEwLjVIMVYxMi41SDRNNi43Niw0Ljg0TDQuOTYsMy4wNUwzLjU1LDQuNDZMNS4zNCw2LjI2TDYuNzYsNC44NFoiIC8+PC9zdmc+", + "name": "CinematicSky", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/9a2997986e89ee7f6d0b59c84f13a70c246fd201958496d48f63ab758ff9848e_white-balance-sunny.svg", + "shortDescription": "Adds a cinematic PBR sky with volumetric clouds.", + "version": "1.0.0", + "description": "An extension for creating a realistic sky (Unreal Engine-style) with dynamic clouds.", + "tags": [ + "sky", + "3d", + "pbr", + "clouds" + ], + "authorIds": [ + "eDINELUbuNcjEaC9yA128lGrjmF2" + ], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [ + { + "description": "Sets up the sky, configures lighting, and shadows.", + "fullName": "Set cinematic sky", + "functionType": "Action", + "name": "SetupCinematicSky", + "sentence": "Set sky (Sun X: _PARAM1_, Y: _PARAM2_, Z: _PARAM3_, Cloud Speed: _PARAM4_)", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "// Get scene parameters", + "const sunX = eventsFunctionContext.getArgument(\"SunX\") || 400.0;", + "const sunY = eventsFunctionContext.getArgument(\"SunY\") || 200.0;", + "const sunZ = eventsFunctionContext.getArgument(\"SunZ\") || 150.0;", + "const cloudSpeed = eventsFunctionContext.getArgument(\"CloudSpeed\") || 1.0;", + "", + "// Access Three.js components", + "const layer = runtimeScene.getLayer(\"\");", + "const renderer = layer.getRenderer();", + "const threeScene = renderer.getThreeScene ? renderer.getThreeScene() : null;", + "const threeRenderer = renderer.getThreeRenderer ? renderer.getThreeRenderer() : null;", + "const camera = renderer.getThreeCamera ? renderer.getThreeCamera() : null;", + "", + "// Exit if Three.js not available", + "if (!threeScene || typeof THREE === \"undefined\") return;", + "", + "// Initialize sky if not already present", + "if (!threeScene.userData.customSkyInstalled) {", + " threeScene.userData.cloudSpeed = cloudSpeed;", + " const sunPos = new THREE.Vector3(sunX, sunY, sunZ);", + "", + " // --- Renderer Configuration ---", + " if (threeRenderer) {", + " ", + " // if (threeRenderer.useLegacyLights !== undefined) threeRenderer.useLegacyLights = false;", + " // if (threeRenderer.physicallyCorrectLights !== undefined) threeRenderer.physicallyCorrectLights = true;", + " // threeRenderer.outputColorSpace = THREE.SRGBColorSpace || 3001;", + " // if (threeRenderer.outputEncoding) threeRenderer.outputEncoding = 3001;", + " // threeRenderer.toneMapping = THREE.ACESFilmicToneMapping;", + " // threeRenderer.toneMappingExposure = 1.15;", + "", + " threeRenderer.shadowMap.enabled = true;", + " threeRenderer.shadowMap.type = THREE.PCFSoftShadowMap;", + " }", + "", + " // Set camera far plane", + " if (camera) camera.far = 50000;", + "", + " // --- Lighting Setup ---", + " // Atmospheric fog", + " threeScene.fog = new THREE.FogExp2(0x7aa5e8, 0.00015);", + "", + " // Ambient light from hemisphere", + " const hemiLight = new THREE.HemisphereLight(0xbbeeff, 0x222233, 0.6);", + " threeScene.add(hemiLight);", + "", + " // Main directional light (sun)", + " const sunLight = new THREE.DirectionalLight(0xfff5e6, 1.5); ", + " sunLight.position.copy(sunPos);", + " sunLight.castShadow = true;", + "", + " // High-res shadows", + " sunLight.shadow.mapSize.width = 4096;", + " sunLight.shadow.mapSize.height = 4096;", + " sunLight.shadow.camera.near = 10;", + " sunLight.shadow.camera.far = 4000;", + " sunLight.shadow.bias = -0.0002;", + " // Shadow camera frustum", + " const d = 1000;", + " sunLight.shadow.camera.left = -d;", + " sunLight.shadow.camera.right = d;", + " sunLight.shadow.camera.top = d;", + " sunLight.shadow.camera.bottom = -d;", + " threeScene.add(sunLight);", + "", + " // Fill light for softer shadows", + " const fillLight = new THREE.DirectionalLight(0x5577aa, 1.0);", + " fillLight.position.set(-sunPos.x, -sunPos.y, 100.0);", + " threeScene.add(fillLight);", + "", + " // --- Sky Shader ---", + " const vShader = `", + " varying vec3 vWorldPosition;", + " void main() {", + " vec4 worldPosition = modelMatrix * vec4(position, 1.0);", + " vWorldPosition = worldPosition.xyz;", + " gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);", + " }", + " `;", + "", + " const fShader = `", + " uniform float time;", + " uniform vec3 sunPosition;", + " varying vec3 vWorldPosition;", + "", + " // Noise functions for clouds", + " float hash(vec2 p) { return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453); }", + " float noise(vec2 p) {", + " vec2 i = floor(p), f = fract(p);", + " vec2 u = f*f*(3.0-2.0*f);", + " return mix(mix(hash(i + vec2(0.0,0.0)), hash(i + vec2(1.0,0.0)), u.x),", + " mix(hash(i + vec2(0.0,1.0)), hash(i + vec2(1.0,1.0)), u.x), u.y);", + " }", + " float fbm(vec2 p) {", + " float f = 0.0, a = 0.5;", + " for(int i=0; i<7; i++) { f += a*noise(p); p*=2.01; a*=0.5; }", + " return f;", + " }", + "", + " void main() {", + " vec3 dir = normalize(vWorldPosition);", + " vec3 sunDir = normalize(sunPosition);", + " float height = max(dir.z, 0.0);", + "", + " // Sky gradient from horizon to zenith", + " vec3 zenithColor = vec3(0.03, 0.12, 0.40);", + " vec3 horizonColor = vec3(0.55, 0.70, 0.95);", + " vec3 skyColor = mix(horizonColor, zenithColor, pow(height, 0.6));", + "", + " // Sun glow effects", + " float sunDot = clamp(dot(dir, sunDir), 0.0, 1.0);", + " float sunCore = pow(sunDot, 40000.0) * 20.0;", + " float sunHalo = pow(sunDot, 500.0) * 1.5;", + " float sunAtmosphere = pow(sunDot, 20.0) * 0.4;", + " vec3 sunColor = vec3(1.0, 0.98, 0.95) * sunCore +", + " vec3(1.0, 0.85, 0.6) * sunHalo +", + " vec3(1.0, 0.7, 0.4) * sunAtmosphere;", + "", + " // Cloud generation", + " vec2 cloudUV = dir.xy / (height + 0.1) * 1.2;", + " vec2 warp = vec2(fbm(cloudUV + time * 0.01), fbm(cloudUV + vec2(5.2, 1.3) - time * 0.008));", + " float baseClouds = fbm(cloudUV + warp * 1.2 + time * 0.01);", + " float detailNoise = noise(cloudUV * 8.0 - time * 0.05) * 0.15;", + " float cloudNoise = baseClouds - detailNoise;", + " float cloudMask = smoothstep(0.4, 0.8, cloudNoise);", + " cloudMask *= smoothstep(0.0, 0.2, height); // Fade clouds near horizon", + "", + " // Cloud shading and light scattering", + " float cloudShade = fbm(cloudUV + warp * 1.5 + time * 0.01 + vec2(0.15));", + " vec3 cloudBaseColor = mix(vec3(0.25, 0.3, 0.4), vec3(1.0, 1.0, 1.0), smoothstep(0.2, 0.8, cloudShade));", + " float sss = pow(sunDot, 5.0) * (1.0 - cloudShade) * cloudMask * 2.0; // Subsurface scattering", + " vec3 sssColor = vec3(1.0, 0.75, 0.3) * sss;", + " float silverLining = pow(sunDot, 10.0) * 2.0;", + " vec3 cloudHighlight = vec3(1.0, 0.9, 0.7) * silverLining * (1.0 - cloudShade);", + " vec3 finalCloudColor = cloudBaseColor + cloudHighlight + sssColor;", + " float distanceFade = smoothstep(0.0, 0.4, height);", + " finalCloudColor = mix(horizonColor, finalCloudColor, distanceFade);", + "", + " // Combine sky, sun, and clouds", + " vec3 finalColor = skyColor + sunColor;", + " finalColor = mix(finalColor, finalCloudColor, cloudMask * 0.98);", + "", + " gl_FragColor = vec4(finalColor, 1.0);", + " }", + " `;", + "", + " const uniforms = {", + " time: { value: 0.0 },", + " sunPosition: { value: sunPos }", + " };", + "", + " // Create sky material and mesh", + " const skyMat = new THREE.ShaderMaterial({", + " vertexShader: vShader,", + " fragmentShader: fShader,", + " uniforms: uniforms,", + " side: THREE.BackSide,", + " depthWrite: false,", + " depthTest: false,", + " fog: false", + " });", + "", + " const skyGeo = new THREE.SphereGeometry(5000, 32, 32);", + " const skyMesh = new THREE.Mesh(skyGeo, skyMat);", + " ", + " skyMesh.renderOrder = -10000; ", + " skyMesh.frustumCulled = false; ", + "", + " threeScene.add(skyMesh);", + "", + "", + "", + " // --- IBL Generator (for reflections) ---", + " if (threeRenderer) {", + " const pmremGenerator = new THREE.PMREMGenerator(threeRenderer);", + " pmremGenerator.compileEquirectangularShader();", + " threeScene.userData.pmremGenerator = pmremGenerator;", + " }", + "", + " // Mark sky as installed and store references", + " threeScene.userData.customSkyInstalled = true;", + " threeScene.userData.skyMaterial = skyMat;", + " threeScene.userData.skyMesh = skyMesh;", + " threeScene.userData.envMapGenerated = false;", + "", + " // --- Automatic Update Loop ---", + " const updateSkyAuto = () => {", + " // Stop if scene reloaded or sky removed", + " if (!threeScene || !threeScene.userData.customSkyInstalled || !skyMesh.parent) {", + " return;", + " }", + "", + " const speed = threeScene.userData.cloudSpeed || 1.0;", + " // Boost speed for noticeable cloud movement at default '1'", + " const timeNow = (runtimeScene.getTimeManager().getTimeFromStart() / 1000.0) * speed * 1.0;", + "", + " // Update shader time uniform", + " skyMat.uniforms.time.value = timeNow;", + "", + " // Keep sky centered on camera", + " const activeCamera = renderer.getThreeCamera ? renderer.getThreeCamera() : camera;", + " if (activeCamera) {", + " skyMesh.position.copy(activeCamera.position);", + " }", + "", + "", + " // Generate environment map after a short delay", + " if (!threeScene.userData.envMapGenerated && threeScene.userData.pmremGenerator && timeNow > 0.5) {", + " const envScene = new THREE.Scene();", + " const tempSky = new THREE.Mesh(", + " new THREE.SphereGeometry(1000, 32, 32),", + " skyMat", + " );", + " envScene.add(tempSky);", + "", + " const renderTarget = threeScene.userData.pmremGenerator.fromScene(envScene);", + " threeScene.environment = renderTarget.texture;", + " threeScene.userData.pmremGenerator.dispose();", + " threeScene.userData.envMapGenerated = true;", + " }", + "", + " // Request next frame", + " requestAnimationFrame(updateSkyAuto);", + " };", + "", + " // Start the auto-update loop once", + " updateSkyAuto();", + "", + "} else {", + " // If sky already installed, just update parameters", + " threeScene.userData.cloudSpeed = cloudSpeed;", + "}", + "" + ], + "parameterObjects": "", + "useStrict": false, + "eventsSheetExpanded": true + } + ], + "parameters": [ + { + "description": "Sun X position (default 400)", + "name": "SunX", + "type": "expression" + }, + { + "description": "Sun Y position (default 200)", + "name": "SunY", + "type": "expression" + }, + { + "description": "Sun Z position (default 150)", + "name": "SunZ", + "type": "expression" + }, + { + "description": "Cloud speed (default 1.0)", + "name": "CloudSpeed", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "SetupCinematicSky" + } + ] + }, + "eventsBasedBehaviors": [], + "eventsBasedObjects": [] +}