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]