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
à implémenter.
La version **beta.130** ajoute un bloom réglable, les inclusions émissives des
minerais et une **Précision** commune aux ombres et au highlight. Par défaut :
ombres activées à 128 blocs, highlight à 32 blocs, précision 16 pixels/bloc.
**Options → Shaders → Sanctuary · Vanilla Light**. Les réglages personnalisés
sont conservés. Le [ticket de livraison](docs/shader-beta130.md) précise le
résultat et les vérifications. Release publiée et même instance **Sanctuary Beta**
synchronisée, sauvegardes et réglages conservés.
La version **beta.131** active par défaut le bloom, les minerais émissifs et
le highlight. Couper le bloom ou mettre son intensité à zéro conserve les
inclusions émissives sans halo. La précision commune ajoute 64 et 128 pixels
par bloc en options ; sa valeur initiale reste 16. Distances initiales :
ombres 128 blocs et highlight 32 blocs. **Options → Shaders → Sanctuary ·
Vanilla Light**. Les réglages personnalisés sont 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à
latelier, les œufs et la neige saisonnière dans linstance **Sanctuary Beta**.
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.
## 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
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
# Release counter: beta.001, .002, .003, ... (see docs/versioning.md).
mod_version=beta.130
pack_version=beta.130
mod_version=beta.131
pack_version=beta.131
resource_pack_version=beta.121
maven_group=fr.koka.sanctuary
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");}
result.add("minecraft:nether_quartz_ore");result.add("minecraft:nether_gold_ore");return List.copyOf(result);}
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");
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());
@@ -40,6 +40,19 @@ public final class Bloom130ClientChecks implements FabricClientGameTest {
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 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(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);
@@ -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"));
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);});
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 void preferences(){try{
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.bloom()&&VanillaLight.bloomIntensity()==35&&VanillaLight.bloomRadius()==50,"Bloom is opt-in with usable defaults");
Files.writeString(path,"{\"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.bloomIntensity()==35&&VanillaLight.bloomRadius()==50,"Bloom, ore emission and edge highlights default to ON");
Files.writeString(path,"{\"bloom\":false,\"oreEmission\":false,\"edgeHighlights\":false,\"pixelShadows\":false,\"shadowDistance\":64,\"shadowPixels\":8,\"edgeDistance\":16}");forgetPreferences();
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");}
VanillaLight.setBloomIntensity(35);VanillaLight.setBloomRadius(50);VanillaLight.setOreIntensity(50);VanillaLight.setShadowPixels(16);
}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"));
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);
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);
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.
Files.writeString(path,"{\"enabled\":true,\"saturation\":100,\"pixelShadows\":true,\"shadowPixels\":16,\"shadowDistance\":32}");
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");
for(int value:new int[]{-100,0,30,100,1000}) {
VanillaLight.setEdgeIntensity(value);forgetPreferences();
@@ -154,6 +159,7 @@ final class EdgeHighlights129ClientChecks {
VanillaLight.setEdgeHighlights(true);forgetPreferences();
check(VanillaLight.edgeHighlights(),"Toggle persists independently");
VanillaLight.setEdgeHighlights(false);
VanillaLight.setBloom(false);VanillaLight.setOreEmission(false);
} 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().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));
activeFrames(c);
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.takeScreenshot("sanctuary-beta130-shader-options-" + locale);
c.takeScreenshot("sanctuary-beta131-shader-options-" + locale);
}
c.runOnClient(m -> m.gui.setScreen(null));
}
@@ -424,10 +424,11 @@ public final class PixelShadows122ClientChecks implements FabricClientGameTest {
private static void checkPreferences() {
VanillaLight.setBloom(false);
VanillaLight.setOreEmission(false);
VanillaLight.setEnabled(true);
VanillaLight.setEdgeHighlights(false);
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]);
forgetPreferences();
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) {
if (name != null) c.takeScreenshot("sanctuary-beta130-shader-" + name);
if (name != null) c.takeScreenshot("sanctuary-beta131-shader-" + name);
var result = new CompletableFuture<Frame>();
c.runOnClient(m -> Screenshot.takeScreenshot(m.gameRenderer.mainRenderTarget(), 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 render(){
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;
var state=mc.gameRenderer.gameRenderState().levelRenderState;var camera=state.cameraRenderState;
if(camera.fogType!=FogType.NONE)return;
var main=mc.gameRenderer.mainRenderTarget();
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 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);
@@ -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(fog.renderDistanceStart,fog.renderDistanceEnd,fog.environmentalStart,fog.environmentalEnd).putVec4(fog.color.w,0,0,0);
}
float radius=.25f+VanillaLight.bloomRadius()*.0075f;
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);}
if(halo){
float radius=.25f+VanillaLight.bloomRadius()*.0075f;
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).
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));
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 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())){
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.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);}
}
screen(DOWNSAMPLE,small.getColorTextureView(),emission.getColorTextureView(),false,null);
screen(BLUR,ping.getColorTextureView(),small.getColorTextureView(),false,horizontal);
screen(BLUR,small.getColorTextureView(),ping.getColorTextureView(),false,vertical);
screen(CORE,main.getColorTextureView(),emission.getColorTextureView(),false,null);
screen(APPLY,main.getColorTextureView(),small.getColorTextureView(),true,null);
if(halo){
screen(DOWNSAMPLE,small.getColorTextureView(),emission.getColorTextureView(),false,null);
screen(BLUR,ping.getColorTextureView(),small.getColorTextureView(),false,horizontal);
screen(BLUR,small.getColorTextureView(),ping.getColorTextureView(),false,vertical);
}
if(cores)screen(CORE,main.getColorTextureView(),emission.getColorTextureView(),false,null);
if(halo)screen(APPLY,main.getColorTextureView(),small.getColorTextureView(),true,null);
applied=true;frames++;
}
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 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;}}
public static void release(){TERRAIN.close();targetsClose();if(scene!=null){scene.close();horizontal.close();vertical.close();scene=horizontal=vertical=null;}applied=false;}
private static void haloClose(){
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 allocated(){return emission!=null;}
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));
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),
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(
Component.translatable("sanctuary.shaders.bloom_help")),VanillaLight.bloom(),VanillaLight::setBloom));
slider("bloom_intensity",VanillaLight.bloomIntensity(),VanillaLight::setBloomIntensity);
@@ -18,12 +18,12 @@ public final class VanillaLight {
boolean enabled=true;
int saturation=142;
boolean pixelShadows=true;
boolean bloom=false;
boolean bloom=true;
int bloomIntensity=35;
int bloomRadius=50;
boolean oreEmission=true;
int oreIntensity=50;
boolean edgeHighlights=false;
boolean edgeHighlights=true;
int edgeIntensity=30;
int edgeDistance=32;
int shadowPixels=16;
@@ -41,7 +41,7 @@ public final class VanillaLight {
preferences.edgeIntensity=Math.clamp(preferences.edgeIntensity,0,100);
preferences.edgeDistance=normalizeShadowDistance(preferences.edgeDistance);
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);
}
return preferences.enabled;
@@ -70,16 +70,18 @@ public final class VanillaLight {
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 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 setEnabled(boolean value){
enabled();preferences.enabled=value;
save();
}
/** Nearest supported value, clamped at either end; midpoint ties round up. */
private static int normalizeShadowValue(int value,int low,int middle,int high){
if(value<(low+middle)/2)return low;
return value<(middle+high)/2?middle:high;
private static int normalizePrecision(int value){
if(value<12)return 8;
if(value<24)return 16;
if(value<48)return 32;
return value<96?64:128;
}
private static int normalizeShadowDistance(int value){
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.invalid": "Choose a discoverable block, item or species.",
"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_help": "Highlight strength along edges. Independent of cast shadows.",
"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.shadow_pixels": "Shadow precision",
"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_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.",
@@ -2274,18 +2274,18 @@
"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.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.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_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_radius": "Bloom spread",
"sanctuary.shaders.bloom_radius_help": "Halo size around luminous pixels. Texture details stay sharp.",
"sanctuary.shaders.bloom_radius_value": "Spread: %s%%",
"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_help": "Inclusion brightness. Does not change world light levels or mob spawning.",
"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.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_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_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 %%",
@@ -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.shadow_pixels": "Précision des ombres",
"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_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.",
@@ -2274,18 +2274,18 @@
"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.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.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_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_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_value": "Diffusion : %s %%",
"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_help": "Luminosité des inclusions. Aucun changement de la lumière du monde ou des apparitions de mobs.",
"sanctuary.shaders.ore_intensity_value": "Minerais : %s %%"
+1 -1
View File
@@ -1,6 +1,6 @@
name = "Sanctuary"
author = "KOKA99CAB"
version = "beta.130"
version = "beta.131"
pack-format = "packwiz:1.1.0"
[index]