diff --git a/README.md b/README.md index 81e8726..38a020f 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,10 @@ La [vision complète](docs/vision.md) conserve les intentions ; le L’économie, les claims et les dimensions décrits dans la vision restent à implémenter. -La version **beta.132** ajoute le **SSGI · couleurs diffusées** expérimental : -les surfaces visibles proches se transmettent une légère teinte. Effet -optionnel, intensité réglable, rayon local de 2,5 blocs. -**Options → Shaders** ; les réglages existants restent conservés. -Le [ticket de livraison](docs/shader-beta132.md) décrit le rendu, les limites -et la validation. Release publiée et même instance **Sanctuary Beta** -synchronisée, sauvegardes et réglages conservés. +La version **beta.133** renforce le **SSGI · couleurs diffusées** : atténuation +spatiale revue et composition lumineuse plus visible dès 35 %. +**Options → Shaders** ; intensité réglable, préférences existantes conservées. +Le [ticket de livraison](docs/shader-beta133.md) décrit le rendu et ses limites. La [livraison précédente](docs/clay-workshop-integration-beta110.md) réunit déjà l’atelier, les œufs et la neige saisonnière dans l’instance **Sanctuary Beta**. Les [synchronisations antérieures](docs/git-sync-beta092.md) restent documentées. @@ -37,6 +34,13 @@ La [carte native beta.005](docs/atlas-beta005.md) prend le relais après l’étude de Xaero et des alternatives libres. +## beta.133 — SSGI renforcé + +Couleurs voisines plus visibles, même budget de rayons et de cibles GPU. +[Contrat et vérifications](docs/shader-beta133.md) · +[Pack normal](https://git.botsu.net/koka/sanctuary-beta/releases/download/beta.133/Sanctuary-beta.133.mrpack) · +[Pack de test](https://git.botsu.net/koka/sanctuary-beta/releases/download/beta.133/Sanctuary-Test-beta.133.mrpack). + ## beta.132 — SSGI : diffusion locale des couleurs Rebond diffus des couleurs visibles, intensité réglable et reconstruction diff --git a/docs/shader-beta133.md b/docs/shader-beta133.md new file mode 100644 index 0000000..932e766 --- /dev/null +++ b/docs/shader-beta133.md @@ -0,0 +1,89 @@ +# SHADER-133 — SSGI visible au réglage courant + +Demande : le rebond diffus de beta.132 est trop discret pour être distingué. +Branche `codex/ssgi-strength-beta133`, socle beta.132, Minecraft 26.3 / Java 25. + +## Changement + +La collecte conserve douze directions, dix étapes, une demi-résolution et +un rayon de 2,5 blocs. L'atténuation spatiale devient linéaire plutôt que +quadratique. Le mélange est reconstruit en lumière approximativement linéaire, +puis réencodé une seule fois. Un gain artistique plus fort rend la couleur +lisible et une courbe progressive évite de couper brutalement les canaux +à blanc. Les surfaces sans rebond restent intactes. La force demeure réglable +de 0 à 100, avec le même réglage initial de 35 ; aucune préférence enregistrée +n'est écrasée. SSGI reste optionnel, initialement désactivé. + +Aucun rayon, cible GPU ou texture de matériau supplémentaire. La composition +ajoute une exponentielle et une racine carrée par canal ; le coût exact en FPS +reste à mesurer sur la machine du joueur. Les normales de géométrie orientent +déjà le rebond. Pas de PBR ni de normales procédurales de textures ajoutés. + +## Piste matériaux + +Pour une étape distincte, des normales de faible amplitude calculées au +chargement des textures, mises en cache, et une rugosité par famille de matériaux +permettraient d'étudier du relief et des reflets orientés. Une simple conversion +luminosité → hauteur ne connaît pas le relief réel : un motif peint peut devenir +une bosse artificielle. Commencer sur pierre, briques et bois avec une amplitude +réglable serait préférable à une génération aveugle pour tous les blocs. +La passe actuelle ne possède ni atlas de normales, ni identifiants de matériaux, +ni albédo non éclairé ; des images seules ne suffiraient pas à les exploiter. + +## Limites conservées + +Approximation diffuse à partir de la couleur déjà éclairée, pas un transport +physique complet. Seules les surfaces visibles contribuent, avec variations +possibles aux entrées/sorties d'écran. Premier obstacle bloquant, pas d'historique +ni de bruit temporel ; aucune modification d'eau, monde ou lumière serveur. + +## Vérifications + +Suite client native complète réussie en **4 min 29 s**, sur macOS / Apple M1 / +OpenGL, dans un monde de test plat (graine 122). Les comparaisons ON/OFF à 35 % +mesurent, sur les pixels neutres du sol : + +| Mur | Pixels avec gain ≥ 8/255 | Pixels avec gain ≥ 16/255 | Gain cumulé du canal dominant | +| --- | ---: | ---: | ---: | +| Rouge | 16 487 | 7 311 | 305 221 | +| Bleu | 14 954 | 7 328 | 309 991 | + +À 90 %, les gains dominants atteignent 654 683 et 655 867, contre 8 968 et +9 168 au même réglage dans la fixture beta.132. Ce rapport concerne uniquement +cette scène et ces pixels, pas une promesse de gain uniforme dans tous les mondes. +Les captures confirment une bande colorée au pied du mur. Un premier réglage +intermédiaire a été rejeté car aucun pixel du sol ne dépassait 8/255 à 35 % ; +un second a passé les contrôles ciblés, puis la force a encore été augmentée +après examen visuel. Les valeurs finales sont celles de la suite complète. + +Le test impose maintenant plus de 5 000 pixels à 8/255 et plus de 500 à 16/255 +au réglage 35, pour les deux couleurs. Intensité, OFF/zéro, absence de rebond +coplanaire, occultation d'un mur changeant de couleur, caméra fixe, déplacement +infinitésimal, retour de caméra, redimensionnement et rechargement passent. +Ombres, lune, feuillage, CTM, cinq précisions, bloom, émissifs indépendants et +interfaces FR/EN restent validés, y compris avec le SSGI actif. + +Commande : `./gradlew :sanctuary:runClientGameTest -PsanctuaryClientTests=true +-PsanctuaryPixelShadows122ClientTests=true -PsanctuaryClientNoVsync=true +-PsanctuaryQuickTests=true`. Log : `build/shader133-client-full.log`. +Le nom de la propriété ciblée `sanctuarySsgi132ClientTests` est conservé. + +Comparateur local autonome : `build/SSGI-beta.133-comparaison.html`, captures +natives OFF/35/90 des murs rouge/bleu, sans retouche. Pas de validation +Windows/Vulkan ni de mesure de coût FPS revendiquée. + + +`./gradlew check build assemblePack assembleTestPack -x :sanctuary:runGameTest` +réussit en **2 min 21 s**, 126 tâches. Le serveur GameTest dédié reste exclu +conformément au refus EULA antérieur. Log : `build/shader133-build.log`. +Les archives normal/Test contiennent le même JAR ; sources archivées et template +de ressources correspondent aux sources. Comparaison avec beta.132 : **5 entrées +de production** changées (classe du compositeur, deux shaders, libellés FR/EN). +Gameplay, textures, sauvegardes et dépendances inchangés. + +## Artefacts + +- `Sanctuary-beta.133.mrpack` : 10394282 octets, SHA-256 `0c90a070da7f969706abeeec1bdfb0830bb52244c20fccbca4fd876f3fbe0564`. +- `Sanctuary-Test-beta.133.mrpack` : 10413204 octets, SHA-256 `e01f0355bf2cce18156fe94a069e142bedc498624ba0b6e2729ae0f23ea73e80`. + +JAR : `a01cae4a98606007b533ca09ec9f072f19a1db2e9b8de466f4ad075d5c1fc185`. diff --git a/gradle.properties b/gradle.properties index 1baeb4e..cc9ecae 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,8 +9,8 @@ loom_version=1.17.20 fabric_api_version=0.160.5+26.3 # Release counter: beta.001, .002, .003, ... (see docs/versioning.md). -mod_version=beta.132 -pack_version=beta.132 +mod_version=beta.133 +pack_version=beta.133 resource_pack_version=beta.121 maven_group=fr.koka.sanctuary jei_version=30.32.0-sanctuary.3 diff --git a/mods/sanctuary/src/clientGametest/java/fr/koka/sanctuary/client/shader/PixelShadows122ClientChecks.java b/mods/sanctuary/src/clientGametest/java/fr/koka/sanctuary/client/shader/PixelShadows122ClientChecks.java index d67abcb..6adf886 100644 --- a/mods/sanctuary/src/clientGametest/java/fr/koka/sanctuary/client/shader/PixelShadows122ClientChecks.java +++ b/mods/sanctuary/src/clientGametest/java/fr/koka/sanctuary/client/shader/PixelShadows122ClientChecks.java @@ -261,7 +261,7 @@ public final class PixelShadows122ClientChecks implements FabricClientGameTest { }); }); c.waitTicks(3); - c.takeScreenshot("sanctuary-beta132-shader-options-" + locale); + c.takeScreenshot("sanctuary-beta133-shader-options-" + locale); } c.runOnClient(m -> m.gui.setScreen(null)); } @@ -528,7 +528,7 @@ public final class PixelShadows122ClientChecks implements FabricClientGameTest { } static Frame capture(ClientGameTestContext c, String name) { - if (name != null) c.takeScreenshot("sanctuary-beta132-shader-" + name); + if (name != null) c.takeScreenshot("sanctuary-beta133-shader-" + name); var result = new CompletableFuture(); c.runOnClient(m -> Screenshot.takeScreenshot(m.gameRenderer.mainRenderTarget(), image -> { try (image) { diff --git a/mods/sanctuary/src/clientGametest/java/fr/koka/sanctuary/client/shader/Ssgi132ClientChecks.java b/mods/sanctuary/src/clientGametest/java/fr/koka/sanctuary/client/shader/Ssgi132ClientChecks.java index 67249e9..f6cfdaa 100644 --- a/mods/sanctuary/src/clientGametest/java/fr/koka/sanctuary/client/shader/Ssgi132ClientChecks.java +++ b/mods/sanctuary/src/clientGametest/java/fr/koka/sanctuary/client/shader/Ssgi132ClientChecks.java @@ -21,7 +21,12 @@ public final class Ssgi132ClientChecks implements FabricClientGameTest { camera(c,server,10.5,69,5.5,65);look(c,server,0,40);settle(c); var flatOff=capture(c,"ssgi-flat-off");enable(c,true);unchanged(flatOff,capture(c,"ssgi-flat-on"),"Coplanar ground does not bounce light onto itself"); wall(server,12,Blocks.CONCRETE.red().defaultBlockState());settle(c);enable(c,false);var redOff=capture(c,"ssgi-red-off"); - enable(c,true);var redOn=capture(c,"ssgi-red-on");var red=measure(redOff,redOn);System.out.println("SSGI132_RED "+red); + c.runOnClient(m->VanillaLight.setSsgiIntensity(35)); + enable(c,true);var defaultRed=measure(redOff,capture(c,"ssgi-red-default-35")); + System.out.println("SSGI133_DEFAULT "+defaultRed); + check(defaultRed.visible>5000&&defaultRed.strong>500,"Default intensity produces 8/255 gain over 5000 pixels and 16/255 over 500 pixels: "+defaultRed); + c.runOnClient(m->VanillaLight.setSsgiIntensity(90));frames(c); + var redOn=capture(c,"ssgi-red-on");var red=measure(redOff,redOn);System.out.println("SSGI133_RED "+red); check(red.changed>30&&red.red>red.blue*1.5+20,"Visible red wall tints neutral ground: "+red); unchanged(redOn,capture(c,null),"Stationary SSGI has no animated noise or accumulating feedback"); look(c,server,0.00002f,40.00002f);frames(c);unchanged(redOn,capture(c,null),"Subpixel motion keeps actual red bounce stable"); @@ -40,7 +45,11 @@ public final class Ssgi132ClientChecks implements FabricClientGameTest { c.runOnClient(m->m.getWindow().setWindowed(oldWidth,oldHeight)); c.waitFor(m->m.gameRenderer.mainRenderTarget().width==redOn.width(),200);frames(c); wall(server,12,Blocks.CONCRETE.blue().defaultBlockState());settle(c);enable(c,false);var blueOff=capture(c,"ssgi-blue-off");enable(c,true);var blue=measure(blueOff,capture(c,"ssgi-blue-on")); - System.out.println("SSGI132_BLUE "+blue);check(blue.changed>30&&blue.blue>blue.red*1.5+20,"Live blue wall changes bounced hue: "+blue); + c.runOnClient(m->VanillaLight.setSsgiIntensity(35));frames(c); + var defaultBlue=measure(blueOff,capture(c,"ssgi-blue-default-35")); + check(defaultBlue.visible>5000&&defaultBlue.strong>500&&defaultBlue.blue>defaultBlue.red*1.5+20,"Default blue bounce is visible too: "+defaultBlue); + c.runOnClient(m->VanillaLight.setSsgiIntensity(90));frames(c); + System.out.println("SSGI133_BLUE "+blue+" default="+defaultBlue);check(blue.changed>30&&blue.blue>blue.red*1.5+20,"Live blue wall changes bounced hue: "+blue); wall(server,11,Blocks.CONCRETE.white().defaultBlockState());settle(c);enable(c,false);var coveredOff=capture(c,null);enable(c,true);var covered=capture(c,"ssgi-covered-blue"); wall(server,12,Blocks.CONCRETE.red().defaultBlockState());settle(c);unchanged(covered,capture(c,"ssgi-covered-red"),"Hidden wall color cannot pass through foreground wall"); var reload=c.computeOnClient(net.minecraft.client.Minecraft::reloadResourcePacks);c.waitFor(m->reload.isDone()&&m.gui.overlay()==null,1200);reload.join();frames(c);unchanged(covered,capture(c,"ssgi-reloaded"),"Resource reload restores SSGI"); @@ -53,7 +62,7 @@ public final class Ssgi132ClientChecks implements FabricClientGameTest { c.runOnClient(m->VanillaLight.setEnabled(false));c.waitTicks(8); c.runOnClient(m->check(!ScreenSpaceGI.allocated(),"Main shader OFF releases SSGI too")); c.runOnClient(m->VanillaLight.setEnabled(true));frames(c);enable(c,false); - System.out.println("SSGI132_PASS red/blue diffuse bounce; intensity; flat rejection; foreground occlusion; static stability; tiny camera motion; resize; reload; combined shader; OFF/zero; preferences; red="+red+" blue="+blue); + System.out.println("SSGI133_PASS red/blue diffuse bounce; intensity; flat rejection; foreground occlusion; static stability; tiny camera motion; resize; reload; combined shader; OFF/zero; preferences; red="+red+" blue="+blue); } private static void wall(TestServerContext server,int z,BlockState state){server.runOnServer(s->{for(int x=6;x<=15;x++)for(int y=65;y<=(z==11?72:69);y++)s.overworld().setBlockAndUpdate(new BlockPos(x,y,z),state);});} private static void settle(ClientGameTestContext c){c.waitTicks(30);c.waitFor(m->m.levelRenderer.hasRenderedAllSections(),1200);c.waitTicks(8);} @@ -65,11 +74,13 @@ public final class Ssgi132ClientChecks implements FabricClientGameTest { for(int i:new int[]{-10,0,35,90,140}){VanillaLight.setSsgiIntensity(i);VanillaLight.setSsgi(true);forgetPreferences();check(VanillaLight.ssgi()&&VanillaLight.ssgiIntensity()==Math.clamp(i,0,100),"SSGI persists and clamps");} VanillaLight.setSsgiIntensity(90); }catch(Exception e){throw new AssertionError(e);}} - private record Gain(int changed,double red,double green,double blue){} - private static Gain measure(Frame off,Frame on){int count=0;double r=0,g=0,b=0;for(int i=0;i>16&255,ag=a>>8&255,ab=a&255; if(Math.max(ar,Math.max(ag,ab))-Math.min(ar,Math.min(ag,ab))>25||ar<60||ar>245)continue; int z=on.pixels()[i];int dr=(z>>16&255)-ar,dg=(z>>8&255)-ag,db=(z&255)-ab; + if(Math.max(dr,Math.max(dg,db))>=16)strong++; + if(Math.max(dr,Math.max(dg,db))>=8)visible++; if(Math.max(dr,Math.max(dg,db))>1)count++;r+=Math.max(0,dr);g+=Math.max(0,dg);b+=Math.max(0,db); - }return new Gain(count,r,g,b);} + }return new Gain(count,visible,strong,r,g,b);} } diff --git a/mods/sanctuary/src/main/java/fr/koka/sanctuary/client/shader/ScreenSpaceGI.java b/mods/sanctuary/src/main/java/fr/koka/sanctuary/client/shader/ScreenSpaceGI.java index 5afc4b3..45caedb 100644 --- a/mods/sanctuary/src/main/java/fr/koka/sanctuary/client/shader/ScreenSpaceGI.java +++ b/mods/sanctuary/src/main/java/fr/koka/sanctuary/client/shader/ScreenSpaceGI.java @@ -27,7 +27,7 @@ public final class ScreenSpaceGI { return RenderPipelines.register(RenderPipeline.builder().withLocation(Identifier.parse("sanctuary:pipeline/"+name)) .withVertexShader("core/screenquad").withFragmentShader(Identifier.parse("sanctuary:core/"+name)) .withBindGroupLayout(LAYOUT).withPrimitiveTopology(PrimitiveTopology.TRIANGLES).withCull(false) - .withColorTargetState(new ColorTargetState(composite?Optional.of(new BlendFunction(BlendFactor.ONE,BlendFactor.ONE_MINUS_SRC_COLOR,BlendFactor.ZERO,BlendFactor.ONE)):Optional.empty(), + .withColorTargetState(new ColorTargetState(composite?Optional.of(new BlendFunction(BlendFactor.ONE,BlendFactor.ZERO,BlendFactor.ZERO,BlendFactor.ONE)):Optional.empty(), composite?GpuFormat.RGBA8_UNORM:GpuFormat.RGBA16_FLOAT,composite?ColorTargetState.WRITE_COLOR:ColorTargetState.WRITE_ALL)) .withDepthStencilState(Optional.empty()).build()); } diff --git a/mods/sanctuary/src/main/resources/assets/sanctuary/lang/en_us.json b/mods/sanctuary/src/main/resources/assets/sanctuary/lang/en_us.json index 5acae43..f040ea6 100644 --- a/mods/sanctuary/src/main/resources/assets/sanctuary/lang/en_us.json +++ b/mods/sanctuary/src/main/resources/assets/sanctuary/lang/en_us.json @@ -2290,7 +2290,7 @@ "sanctuary.shaders.ore_intensity_help": "Inclusion brightness. Does not change world light levels or mob spawning.", "sanctuary.shaders.ore_intensity_value": "Ores: %s%%", "sanctuary.shaders.ssgi": "SSGI · color bounce", - "sanctuary.shaders.ssgi_help": "Experimental: subtle color bounce between nearby visible surfaces. Radius 2.5 blocks. Off-screen surfaces do not contribute. OFF by default.", + "sanctuary.shaders.ssgi_help": "Experimental: enhanced color bounce between nearby visible surfaces. Radius 2.5 blocks. Off-screen surfaces do not contribute. OFF by default.", "sanctuary.shaders.ssgi_intensity": "SSGI strength", "sanctuary.shaders.ssgi_intensity_help": "Strength of diffuse color bounce. Zero stops rendering and frees its resources. Does not change world light.", "sanctuary.shaders.ssgi_intensity_value": "SSGI: %s%%" diff --git a/mods/sanctuary/src/main/resources/assets/sanctuary/lang/fr_fr.json b/mods/sanctuary/src/main/resources/assets/sanctuary/lang/fr_fr.json index 899158f..a917219 100644 --- a/mods/sanctuary/src/main/resources/assets/sanctuary/lang/fr_fr.json +++ b/mods/sanctuary/src/main/resources/assets/sanctuary/lang/fr_fr.json @@ -2290,7 +2290,7 @@ "sanctuary.shaders.ore_intensity_help": "Luminosité des inclusions. Aucun changement de la lumière du monde ou des apparitions de mobs.", "sanctuary.shaders.ore_intensity_value": "Minerais : %s %%", "sanctuary.shaders.ssgi": "SSGI · couleurs diffusées", - "sanctuary.shaders.ssgi_help": "Expérimental : légère diffusion des couleurs entre surfaces visibles proches. Rayon 2,5 blocs. Les surfaces hors écran ne contribuent pas. Désactivé par défaut.", + "sanctuary.shaders.ssgi_help": "Expérimental : diffusion renforcée des couleurs entre surfaces visibles proches. Rayon 2,5 blocs. Les surfaces hors écran ne contribuent pas. Désactivé par défaut.", "sanctuary.shaders.ssgi_intensity": "Intensité du SSGI", "sanctuary.shaders.ssgi_intensity_help": "Force de la teinte diffusée. Zéro coupe le calcul et libère ses ressources. Aucun changement de lumière du monde.", "sanctuary.shaders.ssgi_intensity_value": "SSGI : %s %%" diff --git a/mods/sanctuary/src/main/resources/assets/sanctuary/shaders/core/ssgi_apply.fsh b/mods/sanctuary/src/main/resources/assets/sanctuary/shaders/core/ssgi_apply.fsh index 08c614a..fe31ba8 100644 --- a/mods/sanctuary/src/main/resources/assets/sanctuary/shaders/core/ssgi_apply.fsh +++ b/mods/sanctuary/src/main/resources/assets/sanctuary/shaders/core/ssgi_apply.fsh @@ -21,6 +21,14 @@ void main(){ bounce+=sampleLight.rgb*weight;total+=weight; } if(total<=0.0001)discard; - vec3 albedo=texture(SceneColor,texCoord).rgb; - fragColor=vec4(clamp(albedo*bounce/total*GISettings.x*2.0,0.0,0.25),0.0); + if(max(bounce.r,max(bounce.g,bounce.b))<=0.0)discard; + vec3 scene=texture(SceneColor,texCoord).rgb; + vec3 linearScene=scene*scene; + // Artistic single-bounce gain: the old gamma-space screen blend hid almost all + // of the transport on bright blocks. Compose in approximate linear light and + // encode once; a soft shoulder keeps strong bounce below channel clipping. + vec3 irradiance=bounce/total*(GISettings.x*96.0); + vec3 reflected=linearScene*irradiance; + vec3 lit=linearScene+(1.0-linearScene)*(1.0-exp(-reflected)); + fragColor=vec4(sqrt(clamp(lit,0.0,1.0)),0.0); } diff --git a/mods/sanctuary/src/main/resources/assets/sanctuary/shaders/core/ssgi_gather.fsh b/mods/sanctuary/src/main/resources/assets/sanctuary/shaders/core/ssgi_gather.fsh index 31eb3c9..880ef71 100644 --- a/mods/sanctuary/src/main/resources/assets/sanctuary/shaders/core/ssgi_gather.fsh +++ b/mods/sanctuary/src/main/resources/assets/sanctuary/shaders/core/ssgi_gather.fsh @@ -38,7 +38,8 @@ void main(){ float edge=smoothstep(0.0,0.06,min(min(hitUV.x,hitUV.y),min(1.0-hitUV.x,1.0-hitUV.y))); vec3 color=texture(SceneColor,hitUV).rgb; float falloff=1.0-separation/GISettings.z; - sum+=color*color*facing*falloff*falloff*edge*giFog(hit); + // Decode the scene approximately to linear light; one spatial falloff is enough. + sum+=color*color*facing*falloff*edge*giFog(hit); } break; } diff --git a/packwiz/pack.toml b/packwiz/pack.toml index eabcfe5..8350f9b 100644 --- a/packwiz/pack.toml +++ b/packwiz/pack.toml @@ -1,6 +1,6 @@ name = "Sanctuary" author = "KOKA99CAB" -version = "beta.132" +version = "beta.133" pack-format = "packwiz:1.1.0" [index]