Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fada570ef | ||
|
|
b7cf4bc294 |
@@ -20,11 +20,12 @@ 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.134** ajoute le **PBR · relief des matériaux** optionnel :
|
||||
normales procédurales mises en cache, rugosité par matériau et reflets orientés.
|
||||
Le SSGI reçoit un filtre spatial guidé par la profondeur et des normales de faces
|
||||
stabilisées. **Options → Shaders** ; réglages existants conservés.
|
||||
Le [ticket de livraison](docs/shader-beta134.md) décrit le rendu et ses limites.
|
||||
La version **beta.135** corrige le SSGI en contre-plongée et près des surfaces :
|
||||
normales indépendantes de la taille des pixels et atténuation progressive au
|
||||
contact. Bloom initial à **20 %**, PBR et SSGI **activés par défaut**.
|
||||
**Options → Shaders** ; réglages existants conservés.
|
||||
Le [ticket de livraison](docs/shader-beta135.md) décrit le rendu et ses limites.
|
||||
Contrôles ciblés et archives vérifiés ; livraison prête.
|
||||
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.
|
||||
@@ -35,6 +36,13 @@ La [carte native beta.005](docs/atlas-beta005.md) prend le relais après
|
||||
l’étude de Xaero et des alternatives libres.
|
||||
|
||||
|
||||
## beta.135 — SSGI près des surfaces
|
||||
|
||||
Correction des coupures à courte distance, sans flouter les textures.
|
||||
[Contrat et vérifications](docs/shader-beta135.md) ·
|
||||
[Pack normal](https://git.botsu.net/koka/sanctuary-beta/releases/download/beta.135/Sanctuary-beta.135.mrpack) ·
|
||||
[Pack de test](https://git.botsu.net/koka/sanctuary-beta/releases/download/beta.135/Sanctuary-Test-beta.135.mrpack).
|
||||
|
||||
## beta.134 — PBR optionnel et SSGI filtré
|
||||
|
||||
Relief et reflets des matériaux ; lissage de la lumière indirecte.
|
||||
|
||||
@@ -14,6 +14,18 @@ JAR Sanctuary sont des pièces jointes de releases Gitea. Aucun JAR de mod ou
|
||||
dépendance téléchargée n'entre dans l'historique Git. Le canal Beta est distinct
|
||||
de l'ancien pack 26.2.
|
||||
|
||||
## beta.134 — PBR optionnel et SSGI filtré
|
||||
|
||||
Normales procédurales en cache, rugosité/métallicité par famille et reflets
|
||||
directionnels. Filtrage SSGI et suppression de sa forte réinjection neutre.
|
||||
[Contrat et vérifications](shader-beta134.md).
|
||||
[Release beta.134](https://git.botsu.net/koka/sanctuary-beta/releases/tag/beta.134)
|
||||
publiée ; canal `35ec0f6e145002f6367944df5b75e2703958eaef`. Deux synchronisations isolées,
|
||||
puis deux dans la même instance Sanctuary Beta réussies. Les 923 fichiers
|
||||
personnels suivis gardent leurs hashes. Aucun monde personnel ouvert ;
|
||||
sauvegarde préalable `sanctuary-backups/before-beta.134/`.
|
||||
Packs normal/Test/template vérifiés dans `sanctuary-beta/build/`.
|
||||
|
||||
## beta.133 — SSGI renforcé
|
||||
|
||||
Diffusion des couleurs rendue visible au réglage 35, même budget de rayons
|
||||
|
||||
@@ -91,3 +91,19 @@ JAR : `a6e69622a5e6629f70dd19b7494ad3b00916bc02169b73635f0e2d563929b7fa`.
|
||||
Comparateur local : `build/Shader-beta.134-comparaison.html`. Il contient les
|
||||
captures natives PBR OFF/50/100 et le parcours SSGI de 12 blocs OFF/35/100.
|
||||
Le parcours est une succession de positions enregistrées, pas une mesure des FPS.
|
||||
|
||||
|
||||
## Livraison
|
||||
|
||||
[Release beta.134](https://git.botsu.net/koka/sanctuary-beta/releases/tag/beta.134)
|
||||
publiée depuis `fc4a0cb68ed2d89163c8e74773976df5bab4f3f1`. Canal packwiz
|
||||
`35ec0f6e145002f6367944df5b75e2703958eaef` ; téléchargements publics vérifiés par SHA-256.
|
||||
Deux synchronisations isolées puis deux dans la même instance **Sanctuary Beta**
|
||||
réussissent. Un seul JAR beta.134 actif ; les **923 fichiers personnels suivis**,
|
||||
dont sauvegardes et préférences, gardent leurs hashes. Copie préalable dans
|
||||
`sanctuary-backups/before-beta.134/`, aucun monde personnel ouvert.
|
||||
|
||||
Packs normal/Test/template et comparateur natif vérifiés également dans
|
||||
`sanctuary-beta/build/`. Le checkout original garde ses changements préexistants.
|
||||
Reçus locaux ignorés : `build/shader134-artifact.json`, `build/shader134-isolated.json`,
|
||||
`build/shader134-prism.json`, `build/shader134-publication.log`.
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
# SHADER-135 — SSGI en contre-plongée et près des surfaces
|
||||
|
||||
Demande : supprimer les déchirures horizontales sous une surface, notamment
|
||||
près de la lave, et atténuer proprement le rebond quand la caméra s'approche
|
||||
d'une source ou d'un mur. Branche `codex/shader-closeup-beta135`, socle beta.134.
|
||||
Minecraft 26.3 / Java 25 ; aucune modification de monde ou de gameplay.
|
||||
|
||||
## Diagnostic et correction
|
||||
|
||||
Le calcul des normales comparait l'aire du pixel en unités du monde à un seuil
|
||||
fixe. À courte distance ou à haute résolution, cette aire devient naturellement
|
||||
très petite : le rejet pouvait couper une surface continue. Les deux directions
|
||||
sont maintenant normalisées avant leur produit vectoriel. Les texels de bord
|
||||
sont bornés et les voisins sans profondeur ne créent plus de fausse surface.
|
||||
|
||||
La composition utilise le centre exact du texel de profondeur. Le rebond
|
||||
s'atténue entre 0,4 et 0,06 bloc de distance au **plan** receveur, et lorsque la
|
||||
vue devient presque tangente. Cette distance évite une découpe circulaire sur
|
||||
un mur plat. L'image native reste nette ; aucune texture du décor n'est floutée.
|
||||
|
||||
Les sondes sortant du volume de projection sont rejetées. Leur contribution
|
||||
s'atténue près du plan de caméra et de la limite d'épaisseur d'un impact, au lieu
|
||||
d'une contribution pleine jusqu'à cette limite. Trois ressources GLSL modifiées ;
|
||||
aucune passe, cible GPU, lecture CPU, histoire temporelle ou option ajoutée.
|
||||
Les 12 rayons × 10 pas et les deux passes de filtrage spatial restent inchangés.
|
||||
|
||||
## Réglages initiaux
|
||||
|
||||
Demande ajoutée pendant la livraison : **bloom 20 %**, **PBR ON** et **SSGI ON**.
|
||||
Les intensités PBR 50 et SSGI 35 restent inchangées. Les champs absents du fichier
|
||||
de préférences prennent ces nouvelles valeurs ; les choix explicites du joueur
|
||||
restent conservés. Aides françaises et anglaises mises à jour. Vérification
|
||||
native supplémentaire des préférences vierges, partielles et personnalisées.
|
||||
|
||||
## Reproduction native
|
||||
|
||||
Deux scènes isolées : stone au-dessus de la lave, puis coin à 0,5 bloc d'une
|
||||
paroi rouge. Caméra en contre-plongée, sept distances au plafond de 2 à 0,04 bloc,
|
||||
comparaisons OFF/35/100 avant/après. Dans la première scène, à 0,1 bloc et
|
||||
intensité 100, le saut maximal de gain rouge moyen entre lignes de pixels neutres
|
||||
passe de **14,88 à 0,052** niveaux sur 255. Dans le coin, à 0,4 bloc et intensité
|
||||
35, le rebond auparavant rejeté revient (gain moyen de **6,01** niveaux), puis
|
||||
s'atténue à l'approche du contact. Ces chiffres concernent ces scènes uniquement.
|
||||
|
||||
Les deux essais ciblés corrigés réussissent en 1 min 18 s et 1 min 17 s sur
|
||||
Apple M1 / OpenGL. Images avant/après conservées dans `build/closeup-*` ;
|
||||
comparateur autonome `build/Shader-beta.135-comparaison.html`.
|
||||
|
||||
## Régression et livraison
|
||||
|
||||
Les contrôles natifs de la suite générale réussissent jusqu'au parcours SSGI :
|
||||
ombres, lune, feuillage, temps réel, CTM, émissifs/bloom, couleurs de rebond,
|
||||
occlusion, réglages, rechargement et déplacement latéral de 12 blocs à 35/100.
|
||||
Log : `build/shader135-client-main.log`. La suite n'est pas présentée comme
|
||||
entièrement réussie : elle s'est arrêtée sur une attente incorrecte du nouveau
|
||||
test, qui demandait du rebond alors que sa source était sortie du champ.
|
||||
|
||||
Le scénario corrigé distingue la haute résolution avec source visible de la
|
||||
vue très relevée sans source visible. Le bassin possède un fond pour isoler la
|
||||
lave des essais suivants ; les particules du scénario précédent sont effacées
|
||||
avant la comparaison PBR statique. Une première tentative avait aussi rencontré
|
||||
le refus natif de remettre l'horloge à sa valeur actuelle ; la préparation de
|
||||
l'heure est désormais répétable. Ces changements concernent uniquement les tests.
|
||||
|
||||
Le contrôle final ciblé **réussit en 2 min 52 s** : les deux scènes, 35/100,
|
||||
sept distances, 1280 × 720 avec source visible, source hors champ, mouvement
|
||||
minuscule, rendu combiné, puis contrôles PBR complets (cache, intensités,
|
||||
matériaux, soleil, toit, OFF/zéro, redimensionnement et rechargement).
|
||||
Log : `build/shader135-client-final.log` ; marqueurs `SSGI135_CLOSEUP_PASS` et
|
||||
`PBR134_PASS`. Les seuils de proximité et PBR sont conservés.
|
||||
Le contrôle supplémentaire des nouveaux défauts et du PBR **réussit en
|
||||
1 min 16 s** : préférences vierges, champs absents, valeurs personnelles conservées,
|
||||
puis rendu PBR et combinaison des effets. Log : `build/shader135-defaults-client.log`.
|
||||
`./gradlew check build assemblePack assembleTestPack -x :sanctuary:runGameTest`
|
||||
réussit en **2 min 18 s**, 126 tâches. Le serveur GameTest dédié demeure exclu
|
||||
conformément au refus EULA antérieur. Les classes des scénarios clients compilent
|
||||
aussi après leur isolation explicite des effets activés par défaut.
|
||||
Log : `build/shader135-build.log` ; compilation : `build/shader135-test-compile.log`.
|
||||
|
||||
## Archives vérifiées
|
||||
|
||||
Comparaison à beta.134 : **6 entrées de production** modifiées, limitées aux
|
||||
trois ressources SSGI, aux valeurs initiales et aux aides FR/EN. Gameplay et
|
||||
textures des gemmes inchangés. Packs normal/Test : JAR Sanctuary identique ;
|
||||
archives de sources et template conformes aux sources. Reçu local ignoré :
|
||||
`build/shader135-artifact.json`.
|
||||
|
||||
|
||||
## Limites
|
||||
|
||||
Le SSGI utilise seulement les surfaces visibles : les sources hors champ restent
|
||||
absentes et un grand changement de vue peut modifier le rebond. L'atténuation
|
||||
proche est volontaire ; ce n'est pas une simulation volumétrique. Le brouillard
|
||||
natif de submersion continue de suspendre le SSGI, comme en beta.134. Aucun
|
||||
résultat Windows/Vulkan ni mesure de FPS revendiqués.
|
||||
|
||||
- `Sanctuary-beta.135.mrpack` : 10422391 octets ; SHA-256 `36ac278f9f5ecd2cefd69da16ea7d153ff44c5fc8e6bf0b3a3d6b71f5d767af6`.
|
||||
|
||||
- `Sanctuary-Test-beta.135.mrpack` : 10441314 octets ; SHA-256 `e096374f7ea0856b20392e5d277e94f6c3d411723d7ffc10ceccdd9f0bf5c4d4`.
|
||||
|
||||
JAR : `a68ccd04a92a962c46a76b26a80cb44a4faf7a13a562094dde51010ade594c10`.
|
||||
+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.134
|
||||
pack_version=beta.134
|
||||
mod_version=beta.135
|
||||
pack_version=beta.135
|
||||
resource_pack_version=beta.121
|
||||
maven_group=fr.koka.sanctuary
|
||||
jei_version=30.32.0-sanctuary.3
|
||||
|
||||
@@ -99,6 +99,9 @@ tasks.named('processGametestResources') {
|
||||
def ssgi132Client = providers.gradleProperty('sanctuarySsgi132ClientTests').map { it.toBoolean() }.getOrElse(false)
|
||||
inputs.property('sanctuarySsgi132ClientTests', ssgi132Client)
|
||||
if (ssgi132Client) filter { line -> line.replace('fr.koka.sanctuary.gametest.SanctuaryClientRenderTests', 'fr.koka.sanctuary.client.shader.Ssgi132ClientChecks') }
|
||||
def closeup135Client = providers.gradleProperty('sanctuarySsgiCloseup135ClientTests').map { it.toBoolean() }.getOrElse(false)
|
||||
inputs.property('sanctuarySsgiCloseup135ClientTests', closeup135Client)
|
||||
if (closeup135Client) filter { line -> line.replace('fr.koka.sanctuary.gametest.SanctuaryClientRenderTests', 'fr.koka.sanctuary.client.shader.SsgiCloseup135ClientChecks') }
|
||||
|
||||
def bloom130Client = providers.gradleProperty('sanctuaryBloom130ClientTests').map { it.toBoolean() }.getOrElse(false)
|
||||
inputs.property('sanctuaryBloom130ClientTests', bloom130Client)
|
||||
|
||||
+2
-2
@@ -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);VanillaLight.setOreEmission(false);});
|
||||
c.runOnClient(m->{preferences();VanillaLight.setPbr(false);VanillaLight.setSsgi(false);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());
|
||||
@@ -102,7 +102,7 @@ public final class Bloom130ClientChecks implements FabricClientGameTest {
|
||||
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.oreEmission()&&VanillaLight.edgeHighlights()&&VanillaLight.bloomIntensity()==35&&VanillaLight.bloomRadius()==50,"Bloom, ore emission and edge highlights default to ON");
|
||||
check(VanillaLight.bloom()&&VanillaLight.oreEmission()&&VanillaLight.edgeHighlights()&&VanillaLight.bloomIntensity()==20&&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");}
|
||||
|
||||
+1
@@ -160,6 +160,7 @@ final class EdgeHighlights129ClientChecks {
|
||||
check(VanillaLight.edgeHighlights(),"Toggle persists independently");
|
||||
VanillaLight.setEdgeHighlights(false);
|
||||
VanillaLight.setBloom(false);VanillaLight.setOreEmission(false);
|
||||
VanillaLight.setPbr(false);VanillaLight.setSsgi(false);
|
||||
} catch(java.io.IOException e) { throw new AssertionError(e); }
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -19,6 +19,8 @@ public final class Pbr134ClientChecks implements FabricClientGameTest {
|
||||
for(int y=65;y<=102;y++)s.overworld().setBlockAndUpdate(new BlockPos(x,y,z),Blocks.AIR.defaultBlockState());
|
||||
}});
|
||||
camera(c,server,10.5,69,5.5,65);look(c,server,0,40);settle(c);
|
||||
// The preceding lava/mob fixture may leave animated particles after its blocks are removed.
|
||||
c.runOnClient(m->m.particleEngine.clearParticles());c.waitTicks(2);
|
||||
var off=capture(c,"pbr-off");enable(c,true);var on=capture(c,"pbr-50");
|
||||
var delta=difference(off,on);System.out.println("PBR134_DIFF "+delta);check(delta.changed>500&&delta.brighter>100&&delta.darker>100,"Texture relief has lit and shaded pixels: "+delta);
|
||||
int analyses=c.computeOnClient(m->ProceduralPbr.analyses());c.waitTicks(20);
|
||||
@@ -59,7 +61,7 @@ public final class Pbr134ClientChecks implements FabricClientGameTest {
|
||||
}
|
||||
private static void preferences(){try{
|
||||
var p=FabricLoader.getInstance().getConfigDir().resolve("sanctuary-shaders.json");Files.writeString(p,"{\"ssgi\":true,\"ssgiIntensity\":35,\"bloom\":false}");forgetPreferences();
|
||||
check(!VanillaLight.pbr()&&VanillaLight.pbrIntensity()==50&&VanillaLight.ssgi()&&!VanillaLight.bloom(),"PBR optional default preserves old choices");
|
||||
check(VanillaLight.pbr()&&VanillaLight.pbrIntensity()==50&&VanillaLight.ssgi()&&!VanillaLight.bloom(),"Missing PBR setting defaults ON while preserving explicit old choices");
|
||||
for(int n:new int[]{-1,0,50,100,101}){VanillaLight.setPbr(true);VanillaLight.setPbrIntensity(n);forgetPreferences();check(VanillaLight.pbr()&&VanillaLight.pbrIntensity()==Math.clamp(n,0,100),"PBR preference persistence/clamp");}
|
||||
VanillaLight.setPbrIntensity(50);
|
||||
}catch(Exception e){throw new AssertionError(e);}}
|
||||
|
||||
+22
-4
@@ -36,11 +36,12 @@ import net.minecraft.world.phys.Vec3;
|
||||
|
||||
/** Real terrain/depth-map checks on a new flat seed 122 world; GPU readback is test-only. */
|
||||
public final class PixelShadows122ClientChecks implements FabricClientGameTest {
|
||||
private final boolean bloomOnly,ssgiOnly,pbrOnly;
|
||||
private final boolean bloomOnly,ssgiOnly,pbrOnly,closeupOnly;
|
||||
public PixelShadows122ClientChecks(){this(false);}
|
||||
PixelShadows122ClientChecks(boolean bloomOnly){this(bloomOnly,false);}
|
||||
PixelShadows122ClientChecks(boolean bloomOnly,boolean ssgiOnly){this(bloomOnly,ssgiOnly,false);}
|
||||
PixelShadows122ClientChecks(boolean bloomOnly,boolean ssgiOnly,boolean pbrOnly){this.bloomOnly=bloomOnly;this.ssgiOnly=ssgiOnly;this.pbrOnly=pbrOnly;}
|
||||
PixelShadows122ClientChecks(boolean bloomOnly,boolean ssgiOnly,boolean pbrOnly){this(bloomOnly,ssgiOnly,pbrOnly,false);}
|
||||
PixelShadows122ClientChecks(boolean bloomOnly,boolean ssgiOnly,boolean pbrOnly,boolean closeupOnly){this.bloomOnly=bloomOnly;this.ssgiOnly=ssgiOnly;this.pbrOnly=pbrOnly;this.closeupOnly=closeupOnly;}
|
||||
private static final int FLOOR = 64;
|
||||
private static final AABB PILLAR = new AABB(0, FLOOR + 1, 0, 2, FLOOR + 9, 2);
|
||||
private static final BlockPos SLAB = new BlockPos(5, FLOOR + 3, -5);
|
||||
@@ -135,6 +136,7 @@ public final class PixelShadows122ClientChecks implements FabricClientGameTest {
|
||||
c.runOnClient(m -> check(VanillaLight.active(), "Native Sanctuary shader is active without an external engine"));
|
||||
float morning = c.computeOnClient(m -> m.gameRenderer.gameRenderState().levelRenderState.skyRenderState.sunAngle);
|
||||
|
||||
if(closeupOnly){SsgiCloseup135ClientChecks.run(c,server);Pbr134ClientChecks.run(c,server);return;}
|
||||
if(pbrOnly){Pbr134ClientChecks.run(c,server);return;}
|
||||
if(ssgiOnly){Ssgi132ClientChecks.run(c,server);return;}
|
||||
if(bloomOnly){Bloom130ClientChecks.run(c,server);return;}
|
||||
@@ -264,7 +266,7 @@ public final class PixelShadows122ClientChecks implements FabricClientGameTest {
|
||||
});
|
||||
});
|
||||
c.waitTicks(3);
|
||||
c.takeScreenshot("sanctuary-beta134-shader-options-" + locale);
|
||||
c.takeScreenshot("sanctuary-beta135-shader-options-" + locale);
|
||||
}
|
||||
c.runOnClient(m -> m.gui.setScreen(null));
|
||||
}
|
||||
@@ -428,7 +430,23 @@ public final class PixelShadows122ClientChecks implements FabricClientGameTest {
|
||||
? java.util.stream.Stream.concat(java.util.stream.Stream.of(widget), widgets(child)) : java.util.stream.Stream.of(widget));
|
||||
}
|
||||
|
||||
private static void checkDefaults135() {
|
||||
try {
|
||||
var path=FabricLoader.getInstance().getConfigDir().resolve("sanctuary-shaders.json");
|
||||
Files.deleteIfExists(path);forgetPreferences();
|
||||
check(VanillaLight.bloom()&&VanillaLight.bloomIntensity()==20&&VanillaLight.pbr()&&VanillaLight.ssgi(),"Fresh defaults: bloom20, PBR and SSGI ON");
|
||||
check(VanillaLight.pbrIntensity()==50&&VanillaLight.ssgiIntensity()==35,"Existing effect strengths retained");
|
||||
Files.writeString(path,"{\"pbr\":false,\"ssgi\":false,\"bloomIntensity\":73}");forgetPreferences();
|
||||
check(!VanillaLight.pbr()&&!VanillaLight.ssgi()&&VanillaLight.bloomIntensity()==73,"Explicit personal toggles and intensity survive changed defaults");
|
||||
Files.writeString(path,"{\"bloom\":false}");forgetPreferences();
|
||||
check(!VanillaLight.bloom()&&VanillaLight.bloomIntensity()==20&&VanillaLight.pbr()&&VanillaLight.ssgi(),"Missing fields get new defaults without replacing explicit values");
|
||||
System.out.println("SHADER135_DEFAULTS_PASS fresh, partial and personal preferences");
|
||||
} catch(IOException e){throw new AssertionError(e);}
|
||||
}
|
||||
|
||||
private static void checkPreferences() {
|
||||
checkDefaults135();
|
||||
VanillaLight.setPbr(false);
|
||||
VanillaLight.setSsgi(false);
|
||||
VanillaLight.setBloom(false);
|
||||
VanillaLight.setOreEmission(false);
|
||||
@@ -531,7 +549,7 @@ public final class PixelShadows122ClientChecks implements FabricClientGameTest {
|
||||
}
|
||||
|
||||
static Frame capture(ClientGameTestContext c, String name) {
|
||||
if (name != null) c.takeScreenshot("sanctuary-beta134-shader-" + name);
|
||||
if (name != null) c.takeScreenshot("sanctuary-beta135-shader-" + name);
|
||||
var result = new CompletableFuture<Frame>();
|
||||
c.runOnClient(m -> Screenshot.takeScreenshot(m.gameRenderer.mainRenderTarget(), image -> {
|
||||
try (image) {
|
||||
|
||||
+3
-2
@@ -13,7 +13,7 @@ import java.nio.file.Files;
|
||||
public final class Ssgi132ClientChecks implements FabricClientGameTest {
|
||||
public void runTest(ClientGameTestContext c){new PixelShadows122ClientChecks(false,true).runTest(c);}
|
||||
static void run(ClientGameTestContext c,TestServerContext server){
|
||||
c.runOnClient(m->{preferences();VanillaLight.setEnabled(true);VanillaLight.setSaturation(100);VanillaLight.setSsgi(false);VanillaLight.setBloom(false);VanillaLight.setOreEmission(false);VanillaLight.setPixelShadows(false);VanillaLight.setEdgeHighlights(false);});
|
||||
c.runOnClient(m->{preferences();VanillaLight.setPbr(false);VanillaLight.setEnabled(true);VanillaLight.setSaturation(100);VanillaLight.setSsgi(false);VanillaLight.setBloom(false);VanillaLight.setOreEmission(false);VanillaLight.setPixelShadows(false);VanillaLight.setEdgeHighlights(false);});
|
||||
server.runOnServer(s->{command(s,"time set 6000");for(int x=-5;x<=24;x++)for(int z=-5;z<=24;z++){
|
||||
s.overworld().setBlockAndUpdate(new BlockPos(x,64,z),Blocks.CONCRETE.white().defaultBlockState());
|
||||
for(int y=65;y<=102;y++)s.overworld().setBlockAndUpdate(new BlockPos(x,y,z),Blocks.AIR.defaultBlockState());
|
||||
@@ -63,6 +63,7 @@ public final class Ssgi132ClientChecks implements FabricClientGameTest {
|
||||
c.runOnClient(m->check(!ScreenSpaceGI.allocated(),"Main shader OFF releases SSGI too"));
|
||||
c.runOnClient(m->VanillaLight.setEnabled(true));frames(c);enable(c,false);
|
||||
motion(c,server);
|
||||
SsgiCloseup135ClientChecks.run(c,server);
|
||||
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 motion(ClientGameTestContext c,TestServerContext server){
|
||||
@@ -109,7 +110,7 @@ public final class Ssgi132ClientChecks implements FabricClientGameTest {
|
||||
private static void frames(ClientGameTestContext c){int start=c.computeOnClient(m->ScreenSpaceGI.renderedFrames());c.waitFor(m->ScreenSpaceGI.applied()&&ScreenSpaceGI.renderedFrames()>start+10,1200);c.waitTicks(6);}
|
||||
private static void preferences(){try{
|
||||
var p=FabricLoader.getInstance().getConfigDir().resolve("sanctuary-shaders.json");Files.writeString(p,"{\"bloom\":false,\"shadowPixels\":128}");forgetPreferences();
|
||||
check(!VanillaLight.ssgi()&&VanillaLight.ssgiIntensity()==35&&!VanillaLight.bloom()&&VanillaLight.shadowPixels()==128,"Legacy choices preserved; experimental SSGI defaults OFF at 35");
|
||||
check(VanillaLight.ssgi()&&VanillaLight.ssgiIntensity()==35&&!VanillaLight.bloom()&&VanillaLight.shadowPixels()==128,"Legacy choices preserved; missing SSGI setting defaults ON at 35");
|
||||
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);}}
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package fr.koka.sanctuary.client.shader;
|
||||
|
||||
import static fr.koka.sanctuary.client.shader.PixelShadows122ClientChecks.*;
|
||||
import net.fabricmc.fabric.api.client.gametest.v1.context.ClientGameTestContext;
|
||||
import net.fabricmc.fabric.api.client.gametest.v1.context.TestServerContext;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
|
||||
/** Native low-angle and near-plane regression fixture; never opens a personal world. */
|
||||
public final class SsgiCloseup135ClientChecks implements net.fabricmc.fabric.api.client.gametest.v1.FabricClientGameTest {
|
||||
public void runTest(ClientGameTestContext c){new PixelShadows122ClientChecks(false,false,false,true).runTest(c);}
|
||||
static void run(ClientGameTestContext c,TestServerContext server){
|
||||
c.runOnClient(m->{VanillaLight.setEnabled(true);VanillaLight.setSaturation(100);VanillaLight.setSsgi(false);VanillaLight.setPbr(false);VanillaLight.setBloom(false);VanillaLight.setOreEmission(false);VanillaLight.setPixelShadows(false);VanillaLight.setEdgeHighlights(false);});
|
||||
server.runOnServer(s->{
|
||||
// Minecraft 26.3 rejects setting a clock to its existing value.
|
||||
command(s,"time add 1");command(s,"time set 6000");
|
||||
for(int x=-5;x<=24;x++)for(int z=-5;z<=24;z++){
|
||||
// Contain lava: no flow below the platform into the following PBR fixture.
|
||||
s.overworld().setBlockAndUpdate(new BlockPos(x,63,z),Blocks.STONE.defaultBlockState());
|
||||
for(int y=64;y<=102;y++)s.overworld().setBlockAndUpdate(new BlockPos(x,y,z),y==64?Blocks.STONE.defaultBlockState():Blocks.AIR.defaultBlockState());
|
||||
if(x>=5&&x<=16&&z>=4&&z<=14)s.overworld().setBlockAndUpdate(new BlockPos(x,64,z),Blocks.LAVA.defaultBlockState());
|
||||
if(x>=5&&x<=16&&z>=8&&z<=14)s.overworld().setBlockAndUpdate(new BlockPos(x,68,z),Blocks.STONE.defaultBlockState());
|
||||
if(x>=5&&x<=16&&z==12)for(int y=65;y<=67;y++)s.overworld().setBlockAndUpdate(new BlockPos(x,y,z),Blocks.CONCRETE.red().defaultBlockState());
|
||||
}
|
||||
});c.waitTicks(40);c.waitFor(m->m.levelRenderer.hasRenderedAllSections(),1200);
|
||||
for(int scene=0;scene<2;scene++)for(int intensity:new int[]{35,100}){
|
||||
c.runOnClient(m->VanillaLight.setSsgiIntensity(intensity));
|
||||
for(int step=0;step<7;step++){
|
||||
// Eye approaches the underside, crossing the old fixed normal-area threshold.
|
||||
double gap=new double[]{2.0,1.0,.65,.4,.2,.1,.04}[step];
|
||||
camera(c,server,10.5,68-gap-1.62,scene==0?9.5:11.5,65);look(c,server,0,-25);
|
||||
c.runOnClient(m->VanillaLight.setSsgi(false));c.waitTicks(8);
|
||||
var off=capture(c,"closeup-"+scene+"-"+intensity+"-"+step+"-off");
|
||||
c.runOnClient(m->VanillaLight.setSsgi(true));c.waitFor(m->ScreenSpaceGI.applied(),1200);c.waitTicks(12);
|
||||
var on=capture(c,"closeup-"+scene+"-"+intensity+"-"+step+"-on");
|
||||
var stats=rowJump(off,on);
|
||||
System.out.println("SSGI135_CLOSEUP scene="+scene+" intensity="+intensity+" gap="+gap+" "+stats);
|
||||
if(scene==0&&gap<=.1)check(stats.jump<2&&stats.gain<.1,"Near-plane bounce fades without a horizontal bright strip: "+stats);
|
||||
if(scene==1&&gap==.4)check(stats.rows>30&&stats.gain>1,"Close corner retains actual bounce instead of rejecting small world pixels: "+stats);
|
||||
if(gap==.04)check(stats.gain<.05,"At contact, indirect light fades to the source image: "+stats);
|
||||
}
|
||||
}
|
||||
int width=c.computeOnClient(m->m.getWindow().getScreenWidth()),height=c.computeOnClient(m->m.getWindow().getScreenHeight());
|
||||
camera(c,server,10.5,65.98,11.5,65);look(c,server,0,-25);
|
||||
c.runOnClient(m->{VanillaLight.setSsgiIntensity(100);m.getWindow().setWindowed(1280,720);});
|
||||
c.waitFor(m->m.gameRenderer.mainRenderTarget().width!=width,200);c.waitTicks(15);
|
||||
c.runOnClient(m->VanillaLight.setSsgi(false));c.waitTicks(8);var largeOff=capture(c,"closeup-large-off");
|
||||
c.runOnClient(m->VanillaLight.setSsgi(true));c.waitTicks(15);var large=capture(c,"closeup-large-on");
|
||||
var largeStats=rowJump(largeOff,large);check(largeStats.rows>30&&largeStats.gain>1,"High resolution with a visible source retains bounce: "+largeStats);
|
||||
look(c,server,.00002f,-25.00002f);c.waitTicks(10);unchanged(large,capture(c,null),"Closeup has no subpixel normal threshold flicker");
|
||||
look(c,server,0,-65);c.runOnClient(m->VanillaLight.setSsgi(false));c.waitTicks(8);var steepOff=capture(c,"closeup-offscreen-source-off");
|
||||
c.runOnClient(m->VanillaLight.setSsgi(true));c.waitTicks(15);unchanged(steepOff,capture(c,"closeup-offscreen-source-on"),"Looking away from the source does not invent hidden light");
|
||||
c.runOnClient(m->m.getWindow().setWindowed(width,height));c.waitFor(m->m.gameRenderer.mainRenderTarget().width==width,200);c.waitTicks(15);
|
||||
c.runOnClient(m->{VanillaLight.setPbr(true);VanillaLight.setBloom(true);VanillaLight.setOreEmission(true);VanillaLight.setPixelShadows(true);VanillaLight.setEdgeHighlights(true);});
|
||||
c.waitFor(m->ProceduralPbr.applied()&&ProceduralPbr.ready()&&Bloom.applied()&&PixelShadows.applied()&&PixelShadows.ready(),1200);
|
||||
c.waitTicks(15);capture(c,"closeup-combined");
|
||||
c.runOnClient(m->{VanillaLight.setSsgi(false);VanillaLight.setSsgiIntensity(35);VanillaLight.setPbr(false);});
|
||||
System.out.println("SSGI135_CLOSEUP_PASS low-angle lava/stone and seven camera distances at 35/100");
|
||||
}
|
||||
private record Rows(double jump,double gain,int rows){}
|
||||
private static Rows rowJump(Frame a,Frame b){
|
||||
double previous=0,max=0,gain=0;int rows=0;
|
||||
for(int y=a.height()/8;y<a.height()*7/8;y++){
|
||||
double sum=0;int count=0;
|
||||
for(int x=a.width()/4;x<a.width()*3/4;x++){
|
||||
int i=y*a.width()+x,pa=a.pixels()[i],pb=b.pixels()[i];
|
||||
int r=pa>>16&255,g=pa>>8&255,blue=pa&255;
|
||||
if(Math.max(r,Math.max(g,blue))-Math.min(r,Math.min(g,blue))<12&&g>15){
|
||||
sum+=Math.max(0,(pb>>16&255)-r);count++;
|
||||
}
|
||||
}
|
||||
if(count<a.width()/8)continue;
|
||||
double mean=sum/count;if(rows>0)max=Math.max(max,Math.abs(mean-previous));
|
||||
previous=mean;gain+=mean;rows++;
|
||||
}
|
||||
return new Rows(max,gain/Math.max(rows,1),rows);
|
||||
}
|
||||
}
|
||||
@@ -19,11 +19,11 @@ public final class VanillaLight {
|
||||
int saturation=142;
|
||||
boolean pixelShadows=true;
|
||||
boolean bloom=true;
|
||||
boolean pbr=false;
|
||||
boolean pbr=true;
|
||||
int pbrIntensity=50;
|
||||
boolean ssgi=false;
|
||||
boolean ssgi=true;
|
||||
int ssgiIntensity=35;
|
||||
int bloomIntensity=35;
|
||||
int bloomIntensity=20;
|
||||
int bloomRadius=50;
|
||||
boolean oreEmission=true;
|
||||
int oreIntensity=50;
|
||||
|
||||
@@ -2279,7 +2279,7 @@
|
||||
"sanctuary.shaders.bloom": "Bloom",
|
||||
"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 removes halos and their blur passes while keeping emissive ores.",
|
||||
"sanctuary.shaders.bloom_intensity_help": "Halo strength, 20% by default. 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.",
|
||||
@@ -2290,12 +2290,12 @@
|
||||
"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: enhanced 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. ON 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%%",
|
||||
"sanctuary.shaders.pbr": "PBR · material relief",
|
||||
"sanctuary.shaders.pbr_help": "Experimental: procedural block normals and roughness, sun and moon highlights. Range 32 blocks. OFF by default.",
|
||||
"sanctuary.shaders.pbr_help": "Experimental: procedural block normals and roughness, sun and moon highlights. Range 32 blocks. ON by default.",
|
||||
"sanctuary.shaders.pbr_intensity": "PBR strength",
|
||||
"sanctuary.shaders.pbr_intensity_help": "Material relief and highlights. Zero stops rendering and frees the cache. Original textures remain unchanged.",
|
||||
"sanctuary.shaders.pbr_intensity_value": "PBR: %s%%"
|
||||
|
||||
@@ -2279,7 +2279,7 @@
|
||||
"sanctuary.shaders.bloom": "Bloom",
|
||||
"sanctuary.shaders.bloom_help": "Halo du soleil et des surfaces lumineuses. Activé par défaut. L’arrê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 supprime le halo et ses passes de diffusion, tout en conservant les minerais émissifs.",
|
||||
"sanctuary.shaders.bloom_intensity_help": "Force du halo, 20 % par défaut. 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.",
|
||||
@@ -2290,12 +2290,12 @@
|
||||
"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 : 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_help": "Expérimental : diffusion renforcée des couleurs entre surfaces visibles proches. Rayon 2,5 blocs. Les surfaces hors écran ne contribuent pas. Activé 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 %%",
|
||||
"sanctuary.shaders.pbr": "PBR · relief des matériaux",
|
||||
"sanctuary.shaders.pbr_help": "Expérimental : normales procédurales et rugosité des blocs, reflets du soleil et de la lune. Portée 32 blocs. Désactivé par défaut.",
|
||||
"sanctuary.shaders.pbr_help": "Expérimental : normales procédurales et rugosité des blocs, reflets du soleil et de la lune. Portée 32 blocs. Activé par défaut.",
|
||||
"sanctuary.shaders.pbr_intensity": "Intensité du PBR",
|
||||
"sanctuary.shaders.pbr_intensity_help": "Relief et reflets des matériaux. Zéro coupe le calcul et libère le cache. Ne modifie pas les textures originales.",
|
||||
"sanctuary.shaders.pbr_intensity_value": "PBR : %s %%"
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
layout(location=0) in vec2 texCoord;
|
||||
layout(location=0) out vec4 fragColor;
|
||||
void main(){
|
||||
float depth=texture(WorldDepth,texCoord).r;
|
||||
vec2 surface=giTexel(texCoord);float depth=texture(WorldDepth,surface).r;
|
||||
if(depth<=0.0)discard;
|
||||
vec3 p=giPosition(texCoord,depth),normal=giNormal(texCoord,p);
|
||||
vec3 p=giPosition(surface,depth),normal=giNormal(surface,p);
|
||||
float confidence=giConfidence(p,normal);if(confidence<=0.0)discard;
|
||||
vec2 size=vec2(textureSize(IndirectLight,0)),coord=texCoord*size-0.5,base=floor(coord),f=fract(coord);
|
||||
vec3 bounce=vec3(0.0);float total=0.0;
|
||||
for(int y=0;y<2;y++)for(int x=0;x<2;x++){
|
||||
@@ -27,7 +28,7 @@ void main(){
|
||||
// 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 irradiance=bounce/total*(GISettings.x*96.0*confidence);
|
||||
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);
|
||||
|
||||
@@ -23,7 +23,10 @@ void main(){
|
||||
float travel=GISettings.z*float(step)/10.0;
|
||||
vec3 probe=start+direction*travel;
|
||||
vec4 clip=ViewProjection*vec4(probe,1.0);
|
||||
if(clip.w<=0.0)break;
|
||||
if(clip.w<=0.05)break;
|
||||
float probeDepth=clip.z/clip.w;
|
||||
if(GISettings.y<0.5)probeDepth=probeDepth*.5+.5;
|
||||
if(probeDepth<=0.0||probeDepth>=1.0)break;
|
||||
vec2 hitUV=clip.xy/clip.w*0.5+0.5;
|
||||
if(any(lessThan(hitUV,vec2(0.002)))||any(greaterThan(hitUV,vec2(0.998))))break;
|
||||
hitUV=giTexel(hitUV);float hitDepth=texture(WorldDepth,hitUV).r;
|
||||
@@ -42,7 +45,8 @@ void main(){
|
||||
// remainder instead of re-injecting bright grey ground into every nearby face.
|
||||
vec3 linear=color*color;
|
||||
vec3 chroma=linear-vec3(min(linear.r,min(linear.g,linear.b)));
|
||||
sum+=chroma*facing*falloff*edge*giFog(hit);
|
||||
float confidence=smoothstep(.05,.3,clip.w)*(1.0-smoothstep(.12,.35,behind));
|
||||
sum+=chroma*facing*falloff*edge*giFog(hit)*confidence;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -12,23 +12,38 @@ vec3 giPosition(vec2 uv,float depth){
|
||||
vec4 p=InverseViewProjection*vec4(uv*2.0-1.0,GISettings.y>0.5?depth:depth*2.0-1.0,1.0);
|
||||
return p.xyz/p.w;
|
||||
}
|
||||
vec2 giTexel(vec2 uv){vec2 size=vec2(textureSize(WorldDepth,0));return (floor(uv*size)+0.5)/size;}
|
||||
vec2 giTexel(vec2 uv){
|
||||
vec2 size=vec2(textureSize(WorldDepth,0));
|
||||
return (clamp(floor(uv*size),vec2(0),size-1.0)+0.5)/size;
|
||||
}
|
||||
vec3 giNeighbor(vec2 uv,vec3 center){
|
||||
uv=giTexel(uv);float depth=texture(WorldDepth,uv).r;
|
||||
return depth>0.0?giPosition(uv,depth):center;
|
||||
}
|
||||
vec3 giNormal(vec2 uv,vec3 p){
|
||||
vec2 pixel=1.0/vec2(textureSize(WorldDepth,0));
|
||||
vec3 l=giPosition(uv-vec2(pixel.x,0),texture(WorldDepth,uv-vec2(pixel.x,0)).r);
|
||||
vec3 r=giPosition(uv+vec2(pixel.x,0),texture(WorldDepth,uv+vec2(pixel.x,0)).r);
|
||||
vec3 d=giPosition(uv-vec2(0,pixel.y),texture(WorldDepth,uv-vec2(0,pixel.y)).r);
|
||||
vec3 u=giPosition(uv+vec2(0,pixel.y),texture(WorldDepth,uv+vec2(0,pixel.y)).r);
|
||||
vec3 dx=length(r-p)<length(p-l)?r-p:p-l;
|
||||
vec3 dy=length(u-p)<length(p-d)?u-p:p-d;
|
||||
vec3 n=cross(dx,dy);n/=max(length(n),0.00001);
|
||||
// Keep voxel planes exact: tiny depth-reconstruction errors must not rotate an entire ray fan.
|
||||
vec3 l=p-giNeighbor(uv-vec2(pixel.x,0),p),r=giNeighbor(uv+vec2(pixel.x,0),p)-p;
|
||||
vec3 d=p-giNeighbor(uv-vec2(0,pixel.y),p),u=giNeighbor(uv+vec2(0,pixel.y),p)-p;
|
||||
vec3 dx=dot(l,l)>0.0&&(dot(l,l)<dot(r,r)||dot(r,r)==0.0)?l:r;
|
||||
vec3 dy=dot(d,d)>0.0&&(dot(d,d)<dot(u,u)||dot(u,u)==0.0)?d:u;
|
||||
// Normalize directions BEFORE the cross product. Pixel area approaches zero
|
||||
// near a surface (or at high resolution); it is not a validity criterion.
|
||||
float xx=dot(dx,dx),yy=dot(dy,dy);
|
||||
if(xx<1e-20||yy<1e-20)return vec3(0);
|
||||
vec3 n=cross(dx*inversesqrt(xx),dy*inversesqrt(yy));
|
||||
float nn=dot(n,n);if(nn<1e-12)return vec3(0);n*=inversesqrt(nn);
|
||||
vec3 a=abs(n);
|
||||
if(max(a.x,max(a.y,a.z))>.995){
|
||||
n=a.x>a.y&&a.x>a.z?vec3(sign(n.x),0,0):a.y>a.z?vec3(0,sign(n.y),0):vec3(0,0,sign(n.z));
|
||||
}
|
||||
return dot(n,-p)<0.0?-n:n;
|
||||
}
|
||||
float giConfidence(vec3 p,vec3 n){
|
||||
// Distance to the receiving plane, not radial distance: no circular cut in
|
||||
// a flat wall. Fade before entering it; also soften nearly tangent views.
|
||||
float planeDistance=abs(dot(p,n));
|
||||
return smoothstep(.06,.4,planeDistance)*smoothstep(.025,.12,planeDistance/max(length(p),.0001));
|
||||
}
|
||||
float giFog(vec3 p){
|
||||
float a=clamp((max(length(p.xz),abs(p.y))-GIFog.x)/max(GIFog.y-GIFog.x,0.001),0.0,1.0);
|
||||
float b=clamp((length(p)-GIFog.z)/max(GIFog.w-GIFog.z,0.001),0.0,1.0);
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
name = "Sanctuary"
|
||||
author = "KOKA99CAB"
|
||||
version = "beta.134"
|
||||
version = "beta.135"
|
||||
pack-format = "packwiz:1.1.0"
|
||||
|
||||
[index]
|
||||
|
||||
Reference in New Issue
Block a user