feat(shader): independent emissive cores and precision options in beta.131
Build Sanctuary / build (push) Canceled after 0s

This commit is contained in:
koka
2026-09-17 21:32:28 +02:00
parent afa77f3d62
commit 078d3e6833
12 changed files with 182 additions and 54 deletions
+13 -7
View File
@@ -20,13 +20,13 @@ La [vision complète](docs/vision.md) conserve les intentions ; le
L’économie, les claims et les dimensions décrits dans la vision restent L’économie, les claims et les dimensions décrits dans la vision restent
à implémenter. à implémenter.
La version **beta.130** ajoute un bloom réglable, les inclusions émissives des La version **beta.131** active par défaut le bloom, les minerais émissifs et
minerais et une **Précision** commune aux ombres et au highlight. Par défaut : le highlight. Couper le bloom ou mettre son intensité à zéro conserve les
ombres activées à 128 blocs, highlight à 32 blocs, précision 16 pixels/bloc. inclusions émissives sans halo. La précision commune ajoute 64 et 128 pixels
**Options → Shaders → Sanctuary · Vanilla Light**. Les réglages personnalisés par bloc en options ; sa valeur initiale reste 16. Distances initiales :
sont conservés. Le [ticket de livraison](docs/shader-beta130.md) précise le ombres 128 blocs et highlight 32 blocs. **Options → Shaders → Sanctuary ·
résultat et les vérifications. Release publiée et même instance **Sanctuary Beta** Vanilla Light**. Les réglages personnalisés sont conservés.
synchronisée, sauvegardes et réglages conservés. Le [ticket de livraison](docs/shader-beta131.md) suit la validation et la distribution.
La [livraison précédente](docs/clay-workshop-integration-beta110.md) réunit déjà La [livraison précédente](docs/clay-workshop-integration-beta110.md) réunit déjà
latelier, les œufs et la neige saisonnière dans linstance **Sanctuary Beta**. latelier, les œufs et la neige saisonnière dans linstance **Sanctuary Beta**.
Les [synchronisations antérieures](docs/git-sync-beta092.md) restent documentées. Les [synchronisations antérieures](docs/git-sync-beta092.md) restent documentées.
@@ -37,6 +37,12 @@ La [carte native beta.005](docs/atlas-beta005.md) prend le relais après
l’étude de Xaero et des alternatives libres. l’étude de Xaero et des alternatives libres.
## beta.131 — Émissifs indépendants et précision étendue
Bloom, émissifs et highlight activés initialement ; halo facultatif et cinq
précisions communes de 8 à 128 pixels/bloc.
[Contrat et vérifications](docs/shader-beta131.md).
## beta.130 — Bloom, minerais émissifs et précision commune ## beta.130 — Bloom, minerais émissifs et précision commune
Halo réglable des sources lumineuses et inclusions des vingt textures de Halo réglable des sources lumineuses et inclusions des vingt textures de
+83
View File
@@ -0,0 +1,83 @@
# SHADER-131 — émissifs indépendants et réglages initiaux
Demande : activer par défaut bloom, minerais émissifs et highlight ; garder
les émissifs avec halo coupé ou intensité du bloom à zéro, sans bouton ajouté ;
ajouter 64 et 128 pixels/bloc en options. Précision initiale 16, distances
highlight 32 et ombres 128 conservées. Préférences personnalisées préservées.
Branche `codex/emissive-beta131`, socle beta.130, Minecraft 26.3 / Java 25.
Le futur effet demandé est une légère teinte diffusée depuis les blocs
voisins, pas des reflets reconnaissables. Étude seulement pour ce ticket ;
aucun SSR ou éclairage indirect expérimental activé.
## Comportement et validation
Le curseur à zéro et l'interrupteur Bloom coupent uniquement le halo.
Le réglage existant des minerais contrôle leurs inclusions nettes séparément.
Sans halo, les cibles de diffusion GPU sont libérées ; l'émission garde
seulement les ressources nécessaires. Tout désactiver libère l'ensemble.
La grille commune propose 8, 16, 32, 64 et 128, sans augmenter le plafond
4096 de la carte d'ombres. Libellés FR/EN et essais clients natifs sur les
inclusions, l'absence de halo, les transitions et les nouvelles précisions.
Aucun changement de lumière serveur, de génération ou de sauvegardes.
Le cœur émissif et le halo utilisent maintenant deux chemins indépendants.
Les textures et leur analyse restent celles de beta.130. Avec le halo coupé,
la carte d'émission est effacée avant les faces, le cœur net est composé,
et les passes de ciel, réduction, diffusion et application du halo sont
omises. Le retour au bloom recrée ses cibles. Aucun bouton ajouté, aides
FR/EN adaptées et choix explicitement désactivés toujours conservés.
## Vérifications
Suite client native réussie en **3 min 46 s**, monde plat neuf de graine 122,
macOS / Apple M1 / OpenGL. Cinq précisions sauvegardées et chargées, bornes
et seuils de normalisation, carte d'ombres plafonnée et arêtes CTM rendues
à 64/128. Le gain mesuré des traits diminue de 0,02778 à précision 32 à
0,02094 à 64, puis 0,01013 à 128 dans la même scène.
Les inclusions restent nettes sans halo : le rendu Bloom OFF correspond
au rendu intensité zéro. Aucun gain mesuré hors du masque source, ressources
de diffusion absentes ; couper aussi les émissifs libère l'ensemble et
restitue l'image initiale. Réactiver le bloom restitue son image précédente.
Captures OFF/zéro inspectées. Valeurs initiales ON vérifiées ; un ancien
choix explicitement OFF reste OFF. Les essais beta.130 (vingt masques,
occultation, sources, rechargement), lune, feuillage et realtime passent.
Le premier essai rencontrait une assertion historique attendant le highlight
OFF lorsqu'une clé était absente. Elle attend désormais la nouvelle valeur
ON ; les cas de préférences explicitement désactivées restent testés.
Commande : `./gradlew :sanctuary:runClientGameTest -PsanctuaryClientTests=true
-PsanctuaryPixelShadows122ClientTests=true -PsanctuaryClientNoVsync=true
-PsanctuaryQuickTests=true`. Log : `build/shader131-client-full.log` ; captures
sous `mods/sanctuary/build/run/clientGameTest/screenshots/`.
`./gradlew check build assemblePack assembleTestPack -x :sanctuary:runGameTest`
réussit en **2 min 30 s**, 126 tâches. Les archives normal/Test, leurs sources
et le template sont vérifiés. Six entrées de production changent : moteur
Bloom, préférences, interface et libellés. Gameplay, shaders GLSL et textures
restent identiques à beta.130. Aucun résultat Windows/Vulkan
revendiqué ; le serveur GameTest dédié reste exclu conformément au refus
antérieur de son EULA.
## Piste suivante — diffusion des couleurs
Choix confirmé : légère teinte des surfaces voisines. Une estimation SSGI
utilise la couleur et la profondeur visibles pour des rebonds diffus ; voir
la [documentation primaire Unity](https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@17.0/manual/Override-Screen-Space-GI.html).
Proposition à expérimenter : faible intensité, courte portée autour des
surfaces, calcul réduit, rejet par profondeur pour ne pas teinter au travers
des murs. Vérifier les bords de l'écran, les blocs hors champ, la stabilité
en mouvement et les textures avant de fixer une qualité. Cette piste n'est
pas implémentée dans beta.131.
## Livraison
- `Sanctuary-beta.131.mrpack` : 10386312 octets ; SHA-256 `e02067e424bf4f54512d5cfb1b5cde0fe232aa6bdadc0d38981cd15817a6387a`.
- `Sanctuary-Test-beta.131.mrpack` : 10405238 octets ; SHA-256 `298387cce5a5b7cdc09b3a9d24859b674a736b25abcbafa7995b813757641265`.
JAR : `87210da23f7781efccdbdbf5d4e2d3c1ff1857a7f326027b93d6a301c7dfdb0d`.
Archives vérifiées recopiées dans `sanctuary-beta/build/`. Publication puis
synchronisation de la même instance après le commit source.
+2 -2
View File
@@ -9,8 +9,8 @@ loom_version=1.17.20
fabric_api_version=0.160.5+26.3 fabric_api_version=0.160.5+26.3
# Release counter: beta.001, .002, .003, ... (see docs/versioning.md). # Release counter: beta.001, .002, .003, ... (see docs/versioning.md).
mod_version=beta.130 mod_version=beta.131
pack_version=beta.130 pack_version=beta.131
resource_pack_version=beta.121 resource_pack_version=beta.121
maven_group=fr.koka.sanctuary maven_group=fr.koka.sanctuary
jei_version=30.32.0-sanctuary.3 jei_version=30.32.0-sanctuary.3
@@ -23,7 +23,7 @@ public final class Bloom130ClientChecks implements FabricClientGameTest {
String ns=name.equals("ruby")||name.equals("sapphire")?"sanctuary:":"minecraft:";result.add(ns+name+"_ore");result.add(ns+"deepslate_"+name+"_ore");} String ns=name.equals("ruby")||name.equals("sapphire")?"sanctuary:":"minecraft:";result.add(ns+name+"_ore");result.add(ns+"deepslate_"+name+"_ore");}
result.add("minecraft:nether_quartz_ore");result.add("minecraft:nether_gold_ore");return List.copyOf(result);} result.add("minecraft:nether_quartz_ore");result.add("minecraft:nether_gold_ore");return List.copyOf(result);}
static void run(ClientGameTestContext c,TestServerContext server){ static void run(ClientGameTestContext c,TestServerContext server){
c.runOnClient(m->{preferences();analyseTextures();VanillaLight.setSaturation(100);VanillaLight.setPixelShadows(false);VanillaLight.setEdgeHighlights(false);VanillaLight.setBloom(false);}); c.runOnClient(m->{preferences();analyseTextures();VanillaLight.setSaturation(100);VanillaLight.setPixelShadows(false);VanillaLight.setEdgeHighlights(false);VanillaLight.setBloom(false);VanillaLight.setOreEmission(false);});
server.runOnServer(s->{command(s,"time set 18000"); server.runOnServer(s->{command(s,"time set 18000");
for(int x=4;x<=20;x++)for(int z=4;z<=20;z++){ for(int x=4;x<=20;x++)for(int z=4;z<=20;z++){
s.overworld().setBlockAndUpdate(new BlockPos(x,64,z),Blocks.CONCRETE.black().defaultBlockState()); s.overworld().setBlockAndUpdate(new BlockPos(x,64,z),Blocks.CONCRETE.black().defaultBlockState());
@@ -40,6 +40,19 @@ public final class Bloom130ClientChecks implements FabricClientGameTest {
c.runOnClient(m->{VanillaLight.setOreEmission(true);VanillaLight.setOreIntensity(100);});frames(c); c.runOnClient(m->{VanillaLight.setOreEmission(true);VanillaLight.setOreIntensity(100);});frames(c);
var source=emission(c);int orePixels=luminous(source);check(orePixels>100,"Actual exposed ore inclusions enter the GPU mask: "+orePixels); var source=emission(c);int orePixels=luminous(source);check(orePixels>100,"Actual exposed ore inclusions enter the GPU mask: "+orePixels);
var on=capture(c,"bloom-ores-on");double oreGain=gain(off,on,null);check(oreGain>1000,"Ores visibly glow in the native night scene: "+oreGain); var on=capture(c,"bloom-ores-on");double oreGain=gain(off,on,null);check(oreGain>1000,"Ores visibly glow in the native night scene: "+oreGain);
c.runOnClient(m->VanillaLight.setBloom(false));frames(c);
var coreOnly=capture(c,"emissive-bloom-off");
check(gain(off,coreOnly,null)>1000,"Emissive cores survive bloom OFF");
check(gain(off,coreOnly,source)<1,"No halo outside source texels with bloom OFF");
c.runOnClient(m->check(!Bloom.haloAllocated(),"Bloom OFF frees blur targets and uniforms"));
c.runOnClient(m->{VanillaLight.setBloom(true);VanillaLight.setBloomIntensity(0);});frames(c);
unchanged(coreOnly,capture(c,"emissive-bloom-zero"),"Zero bloom matches OFF while retaining emissive cores");
c.runOnClient(m->check(!Bloom.haloAllocated(),"Zero bloom frees blur resources"));
c.runOnClient(m->VanillaLight.setOreEmission(false));c.waitTicks(8);
c.runOnClient(m->check(!Bloom.allocated()&&!Bloom.applied(),"Zero halo and disabled cores release everything"));
unchanged(off,capture(c,null),"Disabling both restores the original scene");
c.runOnClient(m->{VanillaLight.setOreEmission(true);VanillaLight.setBloomIntensity(35);});frames(c);
unchanged(on,capture(c,null),"Re-enabling bloom restores its original image");
c.runOnClient(m->VanillaLight.setBloomIntensity(10));frames(c);double low=gain(off,capture(c,null),source); c.runOnClient(m->VanillaLight.setBloomIntensity(10));frames(c);double low=gain(off,capture(c,null),source);
c.runOnClient(m->VanillaLight.setBloomIntensity(90));frames(c);double high=gain(off,capture(c,"bloom-strength-90"),source); c.runOnClient(m->VanillaLight.setBloomIntensity(90));frames(c);double high=gain(off,capture(c,"bloom-strength-90"),source);
check(high>Math.max(30,low*2),"Bloom strength changes the halo outside source pixels: low="+low+" high="+high); check(high>Math.max(30,low*2),"Bloom strength changes the halo outside source pixels: low="+low+" high="+high);
@@ -83,15 +96,15 @@ public final class Bloom130ClientChecks implements FabricClientGameTest {
c.runOnClient(m->{VanillaLight.setBloom(true);VanillaLight.setBloomIntensity(0);});c.waitTicks(6);c.runOnClient(m->check(!Bloom.applied()&&!Bloom.allocated(),"Zero bloom releases GPU resources")); c.runOnClient(m->{VanillaLight.setBloom(true);VanillaLight.setBloomIntensity(0);});c.waitTicks(6);c.runOnClient(m->check(!Bloom.applied()&&!Bloom.allocated(),"Zero bloom releases GPU resources"));
unchanged(coveredOff,capture(c,null),"Zero bloom leaves no residual glow"); unchanged(coveredOff,capture(c,null),"Zero bloom leaves no residual glow");
c.runOnClient(m->{VanillaLight.setBloomIntensity(35);VanillaLight.setBloom(false);VanillaLight.setOreEmission(true);VanillaLight.setOreIntensity(50);}); c.runOnClient(m->{VanillaLight.setBloomIntensity(35);VanillaLight.setBloom(false);VanillaLight.setOreEmission(true);VanillaLight.setOreIntensity(50);});
System.out.println("BLOOM130_PASS masks for 20 ore textures; selective night glow; halo intensity/spread; no through-wall glow; live edits; torch/glowstone/lamp/lava/sun; resource reload; defaults/migration; orePixels="+orePixels+" oreGain="+oreGain+" haloLow="+low+" haloHigh="+high+" sunHalo="+sunlight); System.out.println("EMISSIVE131_PASS independent cores with halo OFF/zero; blur resources released; defaults; masks for 20 ore textures; selective night glow; halo intensity/spread; no through-wall glow; live edits; torch/glowstone/lamp/lava/sun; resource reload; defaults/migration; orePixels="+orePixels+" oreGain="+oreGain+" haloLow="+low+" haloHigh="+high+" sunHalo="+sunlight);
} }
private static BlockPos orePos(int i){return new BlockPos(8+i%5,65,8+i/5);} private static BlockPos orePos(int i){return new BlockPos(8+i%5,65,8+i/5);}
private static void preferences(){try{ private static void preferences(){try{
var path=FabricLoader.getInstance().getConfigDir().resolve("sanctuary-shaders.json");Files.deleteIfExists(path);forgetPreferences(); var path=FabricLoader.getInstance().getConfigDir().resolve("sanctuary-shaders.json");Files.deleteIfExists(path);forgetPreferences();
check(VanillaLight.pixelShadows()&&VanillaLight.shadowDistance()==128&&VanillaLight.shadowPixels()==16&&VanillaLight.edgeDistance()==32,"Fresh requested defaults: shadows ON, 128; highlights 32; shared precision 16"); check(VanillaLight.pixelShadows()&&VanillaLight.shadowDistance()==128&&VanillaLight.shadowPixels()==16&&VanillaLight.edgeDistance()==32,"Fresh requested defaults: shadows ON, 128; highlights 32; shared precision 16");
check(!VanillaLight.bloom()&&VanillaLight.bloomIntensity()==35&&VanillaLight.bloomRadius()==50,"Bloom is opt-in with usable defaults"); check(VanillaLight.bloom()&&VanillaLight.oreEmission()&&VanillaLight.edgeHighlights()&&VanillaLight.bloomIntensity()==35&&VanillaLight.bloomRadius()==50,"Bloom, ore emission and edge highlights default to ON");
Files.writeString(path,"{\"pixelShadows\":false,\"shadowDistance\":64,\"shadowPixels\":8,\"edgeDistance\":16}");forgetPreferences(); Files.writeString(path,"{\"bloom\":false,\"oreEmission\":false,\"edgeHighlights\":false,\"pixelShadows\":false,\"shadowDistance\":64,\"shadowPixels\":8,\"edgeDistance\":16}");forgetPreferences();
check(!VanillaLight.pixelShadows()&&VanillaLight.shadowDistance()==64&&VanillaLight.shadowPixels()==8&&VanillaLight.edgeDistance()==16,"Existing user choices are retained"); check(!VanillaLight.bloom()&&!VanillaLight.oreEmission()&&!VanillaLight.edgeHighlights()&&!VanillaLight.pixelShadows()&&VanillaLight.shadowDistance()==64&&VanillaLight.shadowPixels()==8&&VanillaLight.edgeDistance()==16,"Existing user choices are retained");
for(int n:new int[]{-10,0,35,100,400}){VanillaLight.setBloomIntensity(n);VanillaLight.setBloomRadius(n);VanillaLight.setOreIntensity(n);forgetPreferences();check(VanillaLight.bloomIntensity()==Math.clamp(n,0,100)&&VanillaLight.bloomRadius()==Math.clamp(n,0,100)&&VanillaLight.oreIntensity()==Math.clamp(n,0,100),"Persisted bloom controls are bounded");} for(int n:new int[]{-10,0,35,100,400}){VanillaLight.setBloomIntensity(n);VanillaLight.setBloomRadius(n);VanillaLight.setOreIntensity(n);forgetPreferences();check(VanillaLight.bloomIntensity()==Math.clamp(n,0,100)&&VanillaLight.bloomRadius()==Math.clamp(n,0,100)&&VanillaLight.oreIntensity()==Math.clamp(n,0,100),"Persisted bloom controls are bounded");}
VanillaLight.setBloomIntensity(35);VanillaLight.setBloomRadius(50);VanillaLight.setOreIntensity(50);VanillaLight.setShadowPixels(16); VanillaLight.setBloomIntensity(35);VanillaLight.setBloomRadius(50);VanillaLight.setOreIntensity(50);VanillaLight.setShadowPixels(16);
}catch(java.io.IOException e){throw new AssertionError(e);}} }catch(java.io.IOException e){throw new AssertionError(e);}}
@@ -41,6 +41,11 @@ final class EdgeHighlights129ClientChecks {
var fine=measure(off,capture(c,"edges-shared-precision-32")); var fine=measure(off,capture(c,"edges-shared-precision-32"));
check(coarse.brighter()>low.brighter()*1.4 && fine.brighter()<low.brighter()*.8, check(coarse.brighter()>low.brighter()*1.4 && fine.brighter()<low.brighter()*.8,
"One precision setting controls the visible highlight width: coarse="+coarse+" middle="+low+" fine="+fine); "One precision setting controls the visible highlight width: coarse="+coarse+" middle="+low+" fine="+fine);
for(int pixels:new int[]{64,128}){
c.runOnClient(m -> VanillaLight.setShadowPixels(pixels));frames(c);
var finer=measure(off,capture(c,"edges-shared-precision-"+pixels));
check(finer.meanGain()<fine.meanGain() && finer.darker()==0,"High precision refines CTM without darkening: "+pixels+" "+finer);
}
c.runOnClient(m -> VanillaLight.setShadowPixels(16));frames(c); c.runOnClient(m -> VanillaLight.setShadowPixels(16));frames(c);
for (int distance : new int[]{16,32,64,128,256}) { for (int distance : new int[]{16,32,64,128,256}) {
@@ -139,7 +144,7 @@ final class EdgeHighlights129ClientChecks {
// Real prior-version JSON, without either new field. Preserve its existing settings. // Real prior-version JSON, without either new field. Preserve its existing settings.
Files.writeString(path,"{\"enabled\":true,\"saturation\":100,\"pixelShadows\":true,\"shadowPixels\":16,\"shadowDistance\":32}"); Files.writeString(path,"{\"enabled\":true,\"saturation\":100,\"pixelShadows\":true,\"shadowPixels\":16,\"shadowDistance\":32}");
forgetPreferences(); forgetPreferences();
check(!VanillaLight.edgeHighlights() && VanillaLight.edgeIntensity()==30 && VanillaLight.edgeDistance()==32,"Old configuration defaults highlights OFF at intensity 30"); check(VanillaLight.edgeHighlights() && VanillaLight.edgeIntensity()==30 && VanillaLight.edgeDistance()==32,"Missing preference uses the new highlight ON default at intensity 30");
check(VanillaLight.pixelShadows() && VanillaLight.saturation()==100,"Migration retains existing shader choices"); check(VanillaLight.pixelShadows() && VanillaLight.saturation()==100,"Migration retains existing shader choices");
for(int value:new int[]{-100,0,30,100,1000}) { for(int value:new int[]{-100,0,30,100,1000}) {
VanillaLight.setEdgeIntensity(value);forgetPreferences(); VanillaLight.setEdgeIntensity(value);forgetPreferences();
@@ -154,6 +159,7 @@ final class EdgeHighlights129ClientChecks {
VanillaLight.setEdgeHighlights(true);forgetPreferences(); VanillaLight.setEdgeHighlights(true);forgetPreferences();
check(VanillaLight.edgeHighlights(),"Toggle persists independently"); check(VanillaLight.edgeHighlights(),"Toggle persists independently");
VanillaLight.setEdgeHighlights(false); VanillaLight.setEdgeHighlights(false);
VanillaLight.setBloom(false);VanillaLight.setOreEmission(false);
} catch(java.io.IOException e) { throw new AssertionError(e); } } catch(java.io.IOException e) { throw new AssertionError(e); }
} }
@@ -149,7 +149,7 @@ public final class PixelShadows122ClientChecks implements FabricClientGameTest {
check(PixelShadows.shadowMap() != null, "Daylight allocates a real shadow target"); check(PixelShadows.shadowMap() != null, "Daylight allocates a real shadow target");
check(PixelShadows.shadowMap().width == PixelShadows.mapSize(32, 16), "Shadow map follows selected quality"); check(PixelShadows.shadowMap().width == PixelShadows.mapSize(32, 16), "Shadow map follows selected quality");
}); });
for (int pixels : new int[]{8, 32, 16}) { for (int pixels : new int[]{8, 32, 64, 128, 16}) {
c.runOnClient(m -> VanillaLight.setShadowPixels(pixels)); c.runOnClient(m -> VanillaLight.setShadowPixels(pixels));
activeFrames(c); activeFrames(c);
c.runOnClient(m -> check(PixelShadows.shadowMap().width == PixelShadows.mapSize(32, pixels), c.runOnClient(m -> check(PixelShadows.shadowMap().width == PixelShadows.mapSize(32, pixels),
@@ -258,7 +258,7 @@ public final class PixelShadows122ClientChecks implements FabricClientGameTest {
}); });
}); });
c.waitTicks(3); c.waitTicks(3);
c.takeScreenshot("sanctuary-beta130-shader-options-" + locale); c.takeScreenshot("sanctuary-beta131-shader-options-" + locale);
} }
c.runOnClient(m -> m.gui.setScreen(null)); c.runOnClient(m -> m.gui.setScreen(null));
} }
@@ -424,10 +424,11 @@ public final class PixelShadows122ClientChecks implements FabricClientGameTest {
private static void checkPreferences() { private static void checkPreferences() {
VanillaLight.setBloom(false); VanillaLight.setBloom(false);
VanillaLight.setOreEmission(false);
VanillaLight.setEnabled(true); VanillaLight.setEnabled(true);
VanillaLight.setEdgeHighlights(false); VanillaLight.setEdgeHighlights(false);
VanillaLight.setSaturation(100); VanillaLight.setSaturation(100);
for (int[] pair : new int[][]{{Integer.MIN_VALUE, 8}, {11, 8}, {12, 16}, {16, 16}, {23, 16}, {24, 32}, {Integer.MAX_VALUE, 32}}) { for (int[] pair : new int[][]{{Integer.MIN_VALUE, 8}, {11, 8}, {12, 16}, {16, 16}, {23, 16}, {24, 32}, {47,32}, {48,64}, {64,64}, {95,64}, {96,128}, {128,128}, {Integer.MAX_VALUE,128}}) {
VanillaLight.setShadowPixels(pair[0]); VanillaLight.setShadowPixels(pair[0]);
forgetPreferences(); forgetPreferences();
check(VanillaLight.shadowPixels() == pair[1], "Persisted pixel density rounds/clamps " + pair[0]); check(VanillaLight.shadowPixels() == pair[1], "Persisted pixel density rounds/clamps " + pair[0]);
@@ -523,7 +524,7 @@ public final class PixelShadows122ClientChecks implements FabricClientGameTest {
} }
static Frame capture(ClientGameTestContext c, String name) { static Frame capture(ClientGameTestContext c, String name) {
if (name != null) c.takeScreenshot("sanctuary-beta130-shader-" + name); if (name != null) c.takeScreenshot("sanctuary-beta131-shader-" + name);
var result = new CompletableFuture<Frame>(); var result = new CompletableFuture<Frame>();
c.runOnClient(m -> Screenshot.takeScreenshot(m.gameRenderer.mainRenderTarget(), image -> { c.runOnClient(m -> Screenshot.takeScreenshot(m.gameRenderer.mainRenderTarget(), image -> {
try (image) { try (image) {
@@ -61,15 +61,21 @@ public final class Bloom {
public static void dirtyChunk(int x,int z){TERRAIN.dirtyChunk(x,z);} public static void dirtyChunk(int x,int z){TERRAIN.dirtyChunk(x,z);}
public static void render(){ public static void render(){
applied=false;var mc=Minecraft.getInstance(); applied=false;var mc=Minecraft.getInstance();
if(!VanillaLight.active()||!VanillaLight.bloom()||VanillaLight.bloomIntensity()==0||mc.level==null){release();return;} boolean halo=VanillaLight.bloom()&&VanillaLight.bloomIntensity()>0;
boolean cores=VanillaLight.oreEmission()&&VanillaLight.oreIntensity()>0;
if(!VanillaLight.active()||(!halo&&!cores)||mc.level==null){release();return;}
if(PanoramaCapture.rendering())return; if(PanoramaCapture.rendering())return;
var state=mc.gameRenderer.gameRenderState().levelRenderState;var camera=state.cameraRenderState; var state=mc.gameRenderer.gameRenderState().levelRenderState;var camera=state.cameraRenderState;
if(camera.fogType!=FogType.NONE)return; if(camera.fogType!=FogType.NONE)return;
var main=mc.gameRenderer.mainRenderTarget(); var main=mc.gameRenderer.mainRenderTarget();
if(emission==null||emission.width!=main.width||emission.height!=main.height){ if(emission==null||emission.width!=main.width||emission.height!=main.height){
targetsClose();emission=target("emission",main.width,main.height);small=target("bloom low",Math.max(1,main.width/8),Math.max(1,main.height/8));ping=target("bloom ping",small.width,small.height); targetsClose();emission=target("emission",main.width,main.height);
} }
if(scene==null){scene=uniforms("bloom scene",144);horizontal=uniforms("bloom horizontal",16);vertical=uniforms("bloom vertical",16);} if(scene==null)scene=uniforms("bloom scene",144);
if(halo){
if(small==null){small=target("bloom low",Math.max(1,main.width/8),Math.max(1,main.height/8));ping=target("bloom ping",small.width,small.height);}
if(horizontal==null){horizontal=uniforms("bloom horizontal",16);vertical=uniforms("bloom vertical",16);}
}else haloClose();
var entries=TERRAIN.update();var atlas=TERRAIN.materials.atlas(); var entries=TERRAIN.update();var atlas=TERRAIN.materials.atlas();
var vp=new Matrix4f(projection).mul(camera.viewRotationMatrix);var inverse=new Matrix4f(vp).invert(); var vp=new Matrix4f(projection).mul(camera.viewRotationMatrix);var inverse=new Matrix4f(vp).invert();
var sun=PixelShadows.sunDirection(state.skyRenderState.sunAngle);var moon=PixelShadows.sunDirection(state.skyRenderState.moonAngle); var sun=PixelShadows.sunDirection(state.skyRenderState.sunAngle);var moon=PixelShadows.sunDirection(state.skyRenderState.moonAngle);
@@ -81,27 +87,33 @@ public final class Bloom {
.putVec4(sun.x,sun.y,sun.z,celestial).putVec4(moon.x,moon.y,moon.z,celestial*.35f) .putVec4(sun.x,sun.y,sun.z,celestial).putVec4(moon.x,moon.y,moon.z,celestial*.35f)
.putVec4(fog.renderDistanceStart,fog.renderDistanceEnd,fog.environmentalStart,fog.environmentalEnd).putVec4(fog.color.w,0,0,0); .putVec4(fog.renderDistanceStart,fog.renderDistanceEnd,fog.environmentalStart,fog.environmentalEnd).putVec4(fog.color.w,0,0,0);
} }
float radius=.25f+VanillaLight.bloomRadius()*.0075f; if(halo){
horizontal.rotate();try(var mapped=horizontal.currentBuffer().map(false,true)){Std140Builder.intoBuffer(mapped.data()).putVec4(radius/small.width,0,0,0);} float radius=.25f+VanillaLight.bloomRadius()*.0075f;
vertical.rotate();try(var mapped=vertical.currentBuffer().map(false,true)){Std140Builder.intoBuffer(mapped.data()).putVec4(0,radius/small.height,0,0);} horizontal.rotate();try(var mapped=horizontal.currentBuffer().map(false,true)){Std140Builder.intoBuffer(mapped.data()).putVec4(radius/small.width,0,0,0);}
vertical.rotate();try(var mapped=vertical.currentBuffer().map(false,true)){Std140Builder.intoBuffer(mapped.data()).putVec4(0,radius/small.height,0,0);}
}
// Gather transforms before opening any pass (the native dynamic ring may resize). // Gather transforms before opening any pass (the native dynamic ring may resize).
var transforms=new ArrayList<GpuBufferSlice>(entries.size());int max=0; var transforms=new ArrayList<GpuBufferSlice>(entries.size());int max=0;
for(var entry:entries){var pos=entry.origin();var offset=new Vector3f((float)(pos.getX()-camera.pos.x),(float)(pos.getY()-camera.pos.y),(float)(pos.getZ()-camera.pos.z)); for(var entry:entries){var pos=entry.origin();var offset=new Vector3f((float)(pos.getX()-camera.pos.x),(float)(pos.getY()-camera.pos.y),(float)(pos.getZ()-camera.pos.z));
transforms.add(RenderSystem.getDynamicUniforms().writeTransform(new Matrix4f(vp).translate(offset),new Vector4f(1,1,1,1),offset,new Matrix4f()));max=Math.max(max,entry.indices());} transforms.add(RenderSystem.getDynamicUniforms().writeTransform(new Matrix4f(vp).translate(offset),new Vector4f(1,1,1,1),offset,new Matrix4f()));max=Math.max(max,entry.indices());}
var indices=RenderSystem.getSequentialBuffer(PrimitiveTopology.QUADS);indices.requestIndexCount(max); var indices=RenderSystem.getSequentialBuffer(PrimitiveTopology.QUADS);indices.requestIndexCount(max);
var nearest=RenderSystem.getSamplerCache().getClampToEdge(FilterMode.NEAREST); var nearest=RenderSystem.getSamplerCache().getClampToEdge(FilterMode.NEAREST);
screen(SKY,emission.getColorTextureView(),main.getColorTextureView(),true,null); if(halo)screen(SKY,emission.getColorTextureView(),main.getColorTextureView(),true,null);
else try(var clear=RenderSystem.getDevice().createCommandEncoder().createRenderPass(()->"Sanctuary clear emission",emission.getColorTextureView(),Optional.of(new Vector4f(0,0,0,0)))){ }
if(atlas!=null&&!entries.isEmpty())try(var pass=RenderSystem.getDevice().createCommandEncoder().createRenderPass(()->"Sanctuary visible emitters",emission.getColorTextureView(),Optional.empty())){ if(atlas!=null&&!entries.isEmpty())try(var pass=RenderSystem.getDevice().createCommandEncoder().createRenderPass(()->"Sanctuary visible emitters",emission.getColorTextureView(),Optional.empty())){
pass.setPipeline(RenderSystem.getCompiledPipeline(EMITTERS));pass.setUniform("BloomScene",scene.currentBuffer());pass.setUniform("WorldDepth",main.getDepthTextureView(),nearest); pass.setPipeline(RenderSystem.getCompiledPipeline(EMITTERS));pass.setUniform("BloomScene",scene.currentBuffer());pass.setUniform("WorldDepth",main.getDepthTextureView(),nearest);
pass.setUniform("BlockAtlas",mc.getTextureManager().getTexture(TextureAtlas.LOCATION_BLOCKS).getTextureView(),nearest);pass.setUniform("EmissionMasks",atlas.getTextureView(),nearest); pass.setUniform("BlockAtlas",mc.getTextureManager().getTexture(TextureAtlas.LOCATION_BLOCKS).getTextureView(),nearest);pass.setUniform("EmissionMasks",atlas.getTextureView(),nearest);
pass.setIndexBuffer(indices.getBuffer(),indices.type()); pass.setIndexBuffer(indices.getBuffer(),indices.type());
for(int i=0;i<entries.size();i++){var entry=entries.get(i);pass.setUniform("DynamicTransforms",transforms.get(i));pass.setVertexBuffer(0,entry.vertices().slice());pass.drawIndexed(entry.indices(),1,0,0,0);} for(int i=0;i<entries.size();i++){var entry=entries.get(i);pass.setUniform("DynamicTransforms",transforms.get(i));pass.setVertexBuffer(0,entry.vertices().slice());pass.drawIndexed(entry.indices(),1,0,0,0);}
} }
screen(DOWNSAMPLE,small.getColorTextureView(),emission.getColorTextureView(),false,null); if(halo){
screen(BLUR,ping.getColorTextureView(),small.getColorTextureView(),false,horizontal); screen(DOWNSAMPLE,small.getColorTextureView(),emission.getColorTextureView(),false,null);
screen(BLUR,small.getColorTextureView(),ping.getColorTextureView(),false,vertical); screen(BLUR,ping.getColorTextureView(),small.getColorTextureView(),false,horizontal);
screen(CORE,main.getColorTextureView(),emission.getColorTextureView(),false,null); screen(BLUR,small.getColorTextureView(),ping.getColorTextureView(),false,vertical);
screen(APPLY,main.getColorTextureView(),small.getColorTextureView(),true,null); }
if(cores)screen(CORE,main.getColorTextureView(),emission.getColorTextureView(),false,null);
if(halo)screen(APPLY,main.getColorTextureView(),small.getColorTextureView(),true,null);
applied=true;frames++; applied=true;frames++;
} }
private static void screen(RenderPipeline pipeline,GpuTextureView output,GpuTextureView input,boolean useScene,MappableRingBuffer blur){ private static void screen(RenderPipeline pipeline,GpuTextureView output,GpuTextureView input,boolean useScene,MappableRingBuffer blur){
@@ -113,8 +125,13 @@ public final class Bloom {
} }
private static TextureTarget target(String name,int w,int h){return new TextureTarget("Sanctuary "+name,w,h,name.equals("emission")?GpuFormat.RGBA8_UNORM:GpuFormat.RGBA16_FLOAT,null);} private static TextureTarget target(String name,int w,int h){return new TextureTarget("Sanctuary "+name,w,h,name.equals("emission")?GpuFormat.RGBA8_UNORM:GpuFormat.RGBA16_FLOAT,null);}
private static MappableRingBuffer uniforms(String name,int size){return new MappableRingBuffer(()->"Sanctuary "+name,GpuBuffer.USAGE_UNIFORM|GpuBuffer.USAGE_MAP_WRITE,size);} private static MappableRingBuffer uniforms(String name,int size){return new MappableRingBuffer(()->"Sanctuary "+name,GpuBuffer.USAGE_UNIFORM|GpuBuffer.USAGE_MAP_WRITE,size);}
private static void targetsClose(){if(emission!=null){emission.destroyBuffers();small.destroyBuffers();ping.destroyBuffers();emission=small=ping=null;}} private static void haloClose(){
public static void release(){TERRAIN.close();targetsClose();if(scene!=null){scene.close();horizontal.close();vertical.close();scene=horizontal=vertical=null;}applied=false;} if(small!=null){small.destroyBuffers();ping.destroyBuffers();small=ping=null;}
if(horizontal!=null){horizontal.close();vertical.close();horizontal=vertical=null;}
}
private static void targetsClose(){haloClose();if(emission!=null){emission.destroyBuffers();emission=null;}}
public static void release(){TERRAIN.close();targetsClose();if(scene!=null){scene.close();scene=null;}applied=false;}
static boolean haloAllocated(){return small!=null||horizontal!=null;}
static boolean applied(){return applied;} static boolean applied(){return applied;}
static boolean allocated(){return emission!=null;} static boolean allocated(){return emission!=null;}
static boolean ready(){return TERRAIN.settled();} static boolean ready(){return TERRAIN.settled();}
@@ -19,7 +19,7 @@ public final class ShaderOptionsScreen extends OptionsSubScreen {
new OptionInstance.IntRange(0,200),VanillaLight.saturation(),VanillaLight::setSaturation)); new OptionInstance.IntRange(0,200),VanillaLight.saturation(),VanillaLight::setSaturation));
list.addBig(new OptionInstance<Integer>("sanctuary.shaders.precision",OptionInstance.cachedConstantTooltip( list.addBig(new OptionInstance<Integer>("sanctuary.shaders.precision",OptionInstance.cachedConstantTooltip(
Component.translatable("sanctuary.shaders.precision_help")),(caption,value)->Component.translatable("sanctuary.shaders.precision_value",value), Component.translatable("sanctuary.shaders.precision_help")),(caption,value)->Component.translatable("sanctuary.shaders.precision_value",value),
new OptionInstance.Enum<>(List.of(8,16,32),Codec.INT),VanillaLight.shadowPixels(),VanillaLight::setShadowPixels)); new OptionInstance.Enum<>(List.of(8,16,32,64,128),Codec.INT),VanillaLight.shadowPixels(),VanillaLight::setShadowPixels));
list.addBig(OptionInstance.createBoolean("sanctuary.shaders.bloom",OptionInstance.cachedConstantTooltip( list.addBig(OptionInstance.createBoolean("sanctuary.shaders.bloom",OptionInstance.cachedConstantTooltip(
Component.translatable("sanctuary.shaders.bloom_help")),VanillaLight.bloom(),VanillaLight::setBloom)); Component.translatable("sanctuary.shaders.bloom_help")),VanillaLight.bloom(),VanillaLight::setBloom));
slider("bloom_intensity",VanillaLight.bloomIntensity(),VanillaLight::setBloomIntensity); slider("bloom_intensity",VanillaLight.bloomIntensity(),VanillaLight::setBloomIntensity);
@@ -18,12 +18,12 @@ public final class VanillaLight {
boolean enabled=true; boolean enabled=true;
int saturation=142; int saturation=142;
boolean pixelShadows=true; boolean pixelShadows=true;
boolean bloom=false; boolean bloom=true;
int bloomIntensity=35; int bloomIntensity=35;
int bloomRadius=50; int bloomRadius=50;
boolean oreEmission=true; boolean oreEmission=true;
int oreIntensity=50; int oreIntensity=50;
boolean edgeHighlights=false; boolean edgeHighlights=true;
int edgeIntensity=30; int edgeIntensity=30;
int edgeDistance=32; int edgeDistance=32;
int shadowPixels=16; int shadowPixels=16;
@@ -41,7 +41,7 @@ public final class VanillaLight {
preferences.edgeIntensity=Math.clamp(preferences.edgeIntensity,0,100); preferences.edgeIntensity=Math.clamp(preferences.edgeIntensity,0,100);
preferences.edgeDistance=normalizeShadowDistance(preferences.edgeDistance); preferences.edgeDistance=normalizeShadowDistance(preferences.edgeDistance);
preferences.saturation=Math.clamp(preferences.saturation,0,200); preferences.saturation=Math.clamp(preferences.saturation,0,200);
preferences.shadowPixels=normalizeShadowValue(preferences.shadowPixels,8,16,32); preferences.shadowPixels=normalizePrecision(preferences.shadowPixels);
preferences.shadowDistance=normalizeShadowDistance(preferences.shadowDistance); preferences.shadowDistance=normalizeShadowDistance(preferences.shadowDistance);
} }
return preferences.enabled; return preferences.enabled;
@@ -70,16 +70,18 @@ public final class VanillaLight {
public static int shadowDistance(){enabled();return preferences.shadowDistance;} public static int shadowDistance(){enabled();return preferences.shadowDistance;}
public static void setSaturation(int value){enabled();preferences.saturation=Math.clamp(value,0,200);save();} public static void setSaturation(int value){enabled();preferences.saturation=Math.clamp(value,0,200);save();}
public static void setPixelShadows(boolean value){enabled();preferences.pixelShadows=value;save();} public static void setPixelShadows(boolean value){enabled();preferences.pixelShadows=value;save();}
public static void setShadowPixels(int value){enabled();preferences.shadowPixels=normalizeShadowValue(value,8,16,32);save();} public static void setShadowPixels(int value){enabled();preferences.shadowPixels=normalizePrecision(value);save();}
public static void setShadowDistance(int value){enabled();preferences.shadowDistance=normalizeShadowDistance(value);save();} public static void setShadowDistance(int value){enabled();preferences.shadowDistance=normalizeShadowDistance(value);save();}
public static void setEnabled(boolean value){ public static void setEnabled(boolean value){
enabled();preferences.enabled=value; enabled();preferences.enabled=value;
save(); save();
} }
/** Nearest supported value, clamped at either end; midpoint ties round up. */ /** Nearest supported value, clamped at either end; midpoint ties round up. */
private static int normalizeShadowValue(int value,int low,int middle,int high){ private static int normalizePrecision(int value){
if(value<(low+middle)/2)return low; if(value<12)return 8;
return value<(middle+high)/2?middle:high; if(value<24)return 16;
if(value<48)return 32;
return value<96?64:128;
} }
private static int normalizeShadowDistance(int value){ private static int normalizeShadowDistance(int value){
if(value<24)return 16; if(value<24)return 16;
@@ -2258,7 +2258,7 @@
"sanctuary.discovery.granted": "Discoveries added for %s: %s blocks, %s items, %s species. Linked recipes updated; reopen catalogues.", "sanctuary.discovery.granted": "Discoveries added for %s: %s blocks, %s items, %s species. Linked recipes updated; reopen catalogues.",
"sanctuary.discovery.invalid": "Choose a discoverable block, item or species.", "sanctuary.discovery.invalid": "Choose a discoverable block, item or species.",
"sanctuary.shaders.edge_highlights": "Edge highlights", "sanctuary.shaders.edge_highlights": "Edge highlights",
"sanctuary.shaders.edge_highlights_help": "Connected highlights along terrain contours. Flat surfaces connect, even across different blocks. Preserves textures. OFF by default; requires Vanilla Light.", "sanctuary.shaders.edge_highlights_help": "Connected highlights along terrain contours. Flat surfaces connect, even across different blocks. Preserves textures. ON by default; requires Vanilla Light.",
"sanctuary.shaders.edge_intensity": "Edge intensity", "sanctuary.shaders.edge_intensity": "Edge intensity",
"sanctuary.shaders.edge_intensity_help": "Highlight strength along edges. Independent of cast shadows.", "sanctuary.shaders.edge_intensity_help": "Highlight strength along edges. Independent of cast shadows.",
"sanctuary.shaders.edge_intensity_value": "Edge intensity: %s %%", "sanctuary.shaders.edge_intensity_value": "Edge intensity: %s %%",
@@ -2266,7 +2266,7 @@
"sanctuary.shaders.pixel_shadows_help": "Sun shadows and subtle moon shadows on a pixel grid. Dappled foliage and stable contours. Enabled by default at 128 blocks; requires Vanilla Light.", "sanctuary.shaders.pixel_shadows_help": "Sun shadows and subtle moon shadows on a pixel grid. Dappled foliage and stable contours. Enabled by default at 128 blocks; requires Vanilla Light.",
"sanctuary.shaders.shadow_pixels": "Shadow precision", "sanctuary.shaders.shadow_pixels": "Shadow precision",
"sanctuary.shaders.shadow_pixels_value": "%s pixels/block", "sanctuary.shaders.shadow_pixels_value": "%s pixels/block",
"sanctuary.shaders.shadow_pixels_help": "Grid precision: 8, 16 or 32 pixels per block. Higher values make shadow pixels finer. Requires Vanilla Light and pixel shadows.", "sanctuary.shaders.shadow_pixels_help": "Grid precision: 8, 16, 32, 64 or 128 pixels per block. Higher values make shadow pixels finer. Requires Vanilla Light and pixel shadows.",
"sanctuary.shaders.shadow_distance": "Shadow distance", "sanctuary.shaders.shadow_distance": "Shadow distance",
"sanctuary.shaders.shadow_distance_value": "%s blocks", "sanctuary.shaders.shadow_distance_value": "%s blocks",
"sanctuary.shaders.shadow_distance_help": "Shadow range: 16, 32, 64, 128 or 256 blocks, within loaded terrain. Higher distances cost more performance. Requires Vanilla Light and pixel shadows.", "sanctuary.shaders.shadow_distance_help": "Shadow range: 16, 32, 64, 128 or 256 blocks, within loaded terrain. Higher distances cost more performance. Requires Vanilla Light and pixel shadows.",
@@ -2274,18 +2274,18 @@
"sanctuary.shaders.edge_distance_value": "%s blocks", "sanctuary.shaders.edge_distance_value": "%s blocks",
"sanctuary.shaders.edge_distance_help": "Independent range: 16, 32, 64, 128 or 256 blocks. Limited to visible terrain and render distance. Distant contours become naturally finer.", "sanctuary.shaders.edge_distance_help": "Independent range: 16, 32, 64, 128 or 256 blocks. Limited to visible terrain and render distance. Distant contours become naturally finer.",
"sanctuary.shaders.precision": "Precision", "sanctuary.shaders.precision": "Precision",
"sanctuary.shaders.precision_help": "Shared grid for shadows and edge highlights: 8, 16 or 32 pixels per block.", "sanctuary.shaders.precision_help": "Shared grid for shadows and edge highlights: 8, 16, 32, 64 or 128 pixels per block. The shadow map retains its resolution cap.",
"sanctuary.shaders.precision_value": "%s pixels/block", "sanctuary.shaders.precision_value": "%s pixels/block",
"sanctuary.shaders.bloom": "Bloom", "sanctuary.shaders.bloom": "Bloom",
"sanctuary.shaders.bloom_help": "Glow around the sun and luminous surfaces. Ores can also become emissive. Requires Vanilla Light. OFF by default.", "sanctuary.shaders.bloom_help": "Glow around the sun and luminous surfaces. ON by default. Turning it off removes halos while keeping emissive ores. Requires Vanilla Light.",
"sanctuary.shaders.bloom_intensity": "Bloom strength", "sanctuary.shaders.bloom_intensity": "Bloom strength",
"sanctuary.shaders.bloom_intensity_help": "Halo strength. Zero disables bloom and frees its resources.", "sanctuary.shaders.bloom_intensity_help": "Halo strength. Zero removes halos and their blur passes while keeping emissive ores.",
"sanctuary.shaders.bloom_intensity_value": "Bloom: %s%%", "sanctuary.shaders.bloom_intensity_value": "Bloom: %s%%",
"sanctuary.shaders.bloom_radius": "Bloom spread", "sanctuary.shaders.bloom_radius": "Bloom spread",
"sanctuary.shaders.bloom_radius_help": "Halo size around luminous pixels. Texture details stay sharp.", "sanctuary.shaders.bloom_radius_help": "Halo size around luminous pixels. Texture details stay sharp.",
"sanctuary.shaders.bloom_radius_value": "Spread: %s%%", "sanctuary.shaders.bloom_radius_value": "Spread: %s%%",
"sanctuary.shaders.ore_emission": "Emissive ores", "sanctuary.shaders.ore_emission": "Emissive ores",
"sanctuary.shaders.ore_emission_help": "With bloom: makes ore inclusions glow while preserving their host rock. Visual effect only.", "sanctuary.shaders.ore_emission_help": "Makes ore inclusions glow while preserving their host rock, even with bloom off or at zero. ON by default. Visual effect only.",
"sanctuary.shaders.ore_intensity": "Ore emission", "sanctuary.shaders.ore_intensity": "Ore emission",
"sanctuary.shaders.ore_intensity_help": "Inclusion brightness. Does not change world light levels or mob spawning.", "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.ore_intensity_value": "Ores: %s%%"
@@ -2258,7 +2258,7 @@
"sanctuary.discovery.granted": "Découvertes ajoutées pour %s : %s blocs, %s objets, %s espèces. Recettes liées actualisées ; rouvre les catalogues.", "sanctuary.discovery.granted": "Découvertes ajoutées pour %s : %s blocs, %s objets, %s espèces. Recettes liées actualisées ; rouvre les catalogues.",
"sanctuary.discovery.invalid": "Choisis un bloc, un objet ou une espèce découvrable.", "sanctuary.discovery.invalid": "Choisis un bloc, un objet ou une espèce découvrable.",
"sanctuary.shaders.edge_highlights": "Reflets sur les arêtes", "sanctuary.shaders.edge_highlights": "Reflets sur les arêtes",
"sanctuary.shaders.edge_highlights_help": "Reflets connectés sur les contours du relief. Les surfaces plates se raccordent, même entre blocs différents. Préserve les textures. Désactivé par défaut ; nécessite Vanilla Light.", "sanctuary.shaders.edge_highlights_help": "Reflets connectés sur les contours du relief. Les surfaces plates se raccordent, même entre blocs différents. Préserve les textures. Activé par défaut ; nécessite Vanilla Light.",
"sanctuary.shaders.edge_intensity": "Intensité des arêtes", "sanctuary.shaders.edge_intensity": "Intensité des arêtes",
"sanctuary.shaders.edge_intensity_help": "Force du reflet sur les arêtes. Le réglage est indépendant des ombres portées.", "sanctuary.shaders.edge_intensity_help": "Force du reflet sur les arêtes. Le réglage est indépendant des ombres portées.",
"sanctuary.shaders.edge_intensity_value": "Intensité des arêtes : %s %%", "sanctuary.shaders.edge_intensity_value": "Intensité des arêtes : %s %%",
@@ -2266,7 +2266,7 @@
"sanctuary.shaders.pixel_shadows_help": "Ombres du soleil et ombres légères de la lune, sur une grille de pixels. Feuillage irrégulier et contours stables. Activées par défaut, portée 128 blocs ; nécessite Vanilla Light.", "sanctuary.shaders.pixel_shadows_help": "Ombres du soleil et ombres légères de la lune, sur une grille de pixels. Feuillage irrégulier et contours stables. Activées par défaut, portée 128 blocs ; nécessite Vanilla Light.",
"sanctuary.shaders.shadow_pixels": "Précision des ombres", "sanctuary.shaders.shadow_pixels": "Précision des ombres",
"sanctuary.shaders.shadow_pixels_value": "%s pixels/bloc", "sanctuary.shaders.shadow_pixels_value": "%s pixels/bloc",
"sanctuary.shaders.shadow_pixels_help": "Précision de la grille : 8, 16 ou 32 pixels par bloc. Plus la valeur est élevée, plus les pixels des ombres sont fins. Nécessite Vanilla Light et les ombres pixelisées.", "sanctuary.shaders.shadow_pixels_help": "Précision de la grille : 8, 16, 32, 64 ou 128 pixels par bloc. Plus la valeur est élevée, plus les pixels des ombres sont fins. Nécessite Vanilla Light et les ombres pixelisées.",
"sanctuary.shaders.shadow_distance": "Distance des ombres", "sanctuary.shaders.shadow_distance": "Distance des ombres",
"sanctuary.shaders.shadow_distance_value": "%s blocs", "sanctuary.shaders.shadow_distance_value": "%s blocs",
"sanctuary.shaders.shadow_distance_help": "Portée des ombres : 16, 32, 64, 128 ou 256 blocs, dans le terrain chargé. Une distance élevée coûte davantage en performances. Nécessite Vanilla Light et les ombres pixelisées.", "sanctuary.shaders.shadow_distance_help": "Portée des ombres : 16, 32, 64, 128 ou 256 blocs, dans le terrain chargé. Une distance élevée coûte davantage en performances. Nécessite Vanilla Light et les ombres pixelisées.",
@@ -2274,18 +2274,18 @@
"sanctuary.shaders.edge_distance_value": "%s blocs", "sanctuary.shaders.edge_distance_value": "%s blocs",
"sanctuary.shaders.edge_distance_help": "Portée indépendante : 16, 32, 64, 128 ou 256 blocs. Limitée au terrain visible et à la distance de rendu. Les contours lointains saffinent naturellement.", "sanctuary.shaders.edge_distance_help": "Portée indépendante : 16, 32, 64, 128 ou 256 blocs. Limitée au terrain visible et à la distance de rendu. Les contours lointains saffinent naturellement.",
"sanctuary.shaders.precision": "Précision", "sanctuary.shaders.precision": "Précision",
"sanctuary.shaders.precision_help": "Grille commune aux ombres et aux reflets sur les arêtes : 8, 16 ou 32 pixels par bloc.", "sanctuary.shaders.precision_help": "Grille commune aux ombres et aux reflets sur les arêtes : 8, 16, 32, 64 ou 128 pixels par bloc. La carte dombres conserve sa résolution maximale.",
"sanctuary.shaders.precision_value": "%s pixels/bloc", "sanctuary.shaders.precision_value": "%s pixels/bloc",
"sanctuary.shaders.bloom": "Bloom", "sanctuary.shaders.bloom": "Bloom",
"sanctuary.shaders.bloom_help": "Halo du soleil et des surfaces lumineuses. Les minerais peuvent aussi devenir émissifs. Nécessite Vanilla Light. Désactivé par défaut.", "sanctuary.shaders.bloom_help": "Halo du soleil et des surfaces lumineuses. Activé par défaut. Larrêt coupe le halo et conserve les minerais émissifs. Nécessite Vanilla Light.",
"sanctuary.shaders.bloom_intensity": "Intensité du bloom", "sanctuary.shaders.bloom_intensity": "Intensité du bloom",
"sanctuary.shaders.bloom_intensity_help": "Force du halo. Zéro désactive le bloom et libère ses ressources.", "sanctuary.shaders.bloom_intensity_help": "Force du halo. Zéro supprime le halo et ses passes de diffusion, tout en conservant les minerais émissifs.",
"sanctuary.shaders.bloom_intensity_value": "Bloom : %s %%", "sanctuary.shaders.bloom_intensity_value": "Bloom : %s %%",
"sanctuary.shaders.bloom_radius": "Diffusion du bloom", "sanctuary.shaders.bloom_radius": "Diffusion du bloom",
"sanctuary.shaders.bloom_radius_help": "Taille du halo autour des pixels lumineux. Les détails des textures restent nets.", "sanctuary.shaders.bloom_radius_help": "Taille du halo autour des pixels lumineux. Les détails des textures restent nets.",
"sanctuary.shaders.bloom_radius_value": "Diffusion : %s %%", "sanctuary.shaders.bloom_radius_value": "Diffusion : %s %%",
"sanctuary.shaders.ore_emission": "Minerais émissifs", "sanctuary.shaders.ore_emission": "Minerais émissifs",
"sanctuary.shaders.ore_emission_help": "Avec le bloom : fait briller les inclusions des minerais sans éclairer leur roche. Effet visuel uniquement.", "sanctuary.shaders.ore_emission_help": "Fait briller les inclusions des minerais sans éclairer leur roche, même avec le bloom coupé ou à zéro. Activé par défaut. Effet visuel uniquement.",
"sanctuary.shaders.ore_intensity": "Émission des minerais", "sanctuary.shaders.ore_intensity": "Émission des minerais",
"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_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.ore_intensity_value": "Minerais : %s %%"
+1 -1
View File
@@ -1,6 +1,6 @@
name = "Sanctuary" name = "Sanctuary"
author = "KOKA99CAB" author = "KOKA99CAB"
version = "beta.130" version = "beta.131"
pack-format = "packwiz:1.1.0" pack-format = "packwiz:1.1.0"
[index] [index]