This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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`.
|
||||
+2
-2
@@ -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
|
||||
|
||||
+2
-2
@@ -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<Frame>();
|
||||
c.runOnClient(m -> Screenshot.takeScreenshot(m.gameRenderer.mainRenderTarget(), image -> {
|
||||
try (image) {
|
||||
|
||||
+17
-6
@@ -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<off.pixels().length;i++){
|
||||
private record Gain(int changed,int visible,int strong,double red,double green,double blue){}
|
||||
private static Gain measure(Frame off,Frame on){int count=0,visible=0,strong=0;double r=0,g=0,b=0;for(int i=0;i<off.pixels().length;i++){
|
||||
int a=off.pixels()[i],ar=a>>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);}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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%%"
|
||||
|
||||
@@ -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 %%"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
name = "Sanctuary"
|
||||
author = "KOKA99CAB"
|
||||
version = "beta.132"
|
||||
version = "beta.133"
|
||||
pack-format = "packwiz:1.1.0"
|
||||
|
||||
[index]
|
||||
|
||||
Reference in New Issue
Block a user