Problem mit der Beleuchtungder Imposter Images behoben

This commit is contained in:
2026-07-21 08:40:02 +02:00
parent 40be463ced
commit e651f12475
4 changed files with 93 additions and 9 deletions

View File

@@ -197,6 +197,7 @@ public class BlightGame extends SimpleApplication {
keyBindings = KeyBindingStore.load(); keyBindings = KeyBindingStore.load();
graphicsSettings = GraphicsStore.load(); graphicsSettings = GraphicsStore.load();
audioSettings = AudioSettingsStore.load(); audioSettings = AudioSettingsStore.load();
de.blight.game.state.ModelLodControl.debugLod2 = graphicsSettings.debugLod2;
startTimeMs = System.currentTimeMillis(); startTimeMs = System.currentTimeMillis();
initialFixDone = false; initialFixDone = false;
@@ -478,6 +479,8 @@ public class BlightGame extends SimpleApplication {
rebuildState(HudState.class); rebuildState(HudState.class);
rebuildState(HotbarState.class); rebuildState(HotbarState.class);
rebuildState(LoadingScreenState.class); rebuildState(LoadingScreenState.class);
JmeConsole console = stateManager.getState(JmeConsole.class);
if (console != null) console.rebuild();
} }
private <T extends com.jme3.app.state.BaseAppState> void rebuildState(Class<T> cls) { private <T extends com.jme3.app.state.BaseAppState> void rebuildState(Class<T> cls) {
@@ -550,6 +553,73 @@ public class BlightGame extends SimpleApplication {
return "Unbekanntes Wetter. Erlaubt: sunny, cloudy, overcast, storm"; return "Unbekanntes Wetter. Erlaubt: sunny, cloudy, overcast, storm";
} }
}); });
console.registerCommand("set", args -> {
if (args.length < 3)
return "Syntax: set <schlüssel> <wert>"
+ " | debugLod2, width, height, fullscreen, vsync, samples, viewDistance, shadowQuality";
String key = args[1].toLowerCase();
String val = args[2];
return switch (key) {
case "debuglod2" -> {
boolean v = Boolean.parseBoolean(val);
graphicsSettings.debugLod2 = v;
de.blight.game.state.ModelLodControl.debugLod2 = v;
GraphicsStore.save(graphicsSettings);
yield "debugLod2 = " + v;
}
case "width" -> {
try { graphicsSettings.width = Integer.parseInt(val); }
catch (NumberFormatException e) { yield "Fehler: ganze Zahl erwartet"; }
GraphicsStore.save(graphicsSettings);
yield "width = " + graphicsSettings.width + " (Neustart erforderlich)";
}
case "height" -> {
try { graphicsSettings.height = Integer.parseInt(val); }
catch (NumberFormatException e) { yield "Fehler: ganze Zahl erwartet"; }
GraphicsStore.save(graphicsSettings);
yield "height = " + graphicsSettings.height + " (Neustart erforderlich)";
}
case "fullscreen" -> {
graphicsSettings.fullscreen = Boolean.parseBoolean(val);
GraphicsStore.save(graphicsSettings);
yield "fullscreen = " + graphicsSettings.fullscreen + " (Neustart erforderlich)";
}
case "vsync" -> {
graphicsSettings.vsync = Boolean.parseBoolean(val);
GraphicsStore.save(graphicsSettings);
yield "vsync = " + graphicsSettings.vsync + " (Neustart erforderlich)";
}
case "samples" -> {
try { graphicsSettings.samples = Integer.parseInt(val); }
catch (NumberFormatException e) { yield "Fehler: ganze Zahl erwartet"; }
GraphicsStore.save(graphicsSettings);
yield "samples = " + graphicsSettings.samples + " (Neustart erforderlich)";
}
case "viewdistance" -> {
try {
graphicsSettings.viewDistance =
GraphicsSettings.ViewDistance.valueOf(val.toUpperCase());
} catch (IllegalArgumentException e) {
yield "Unbekannt. Erlaubt: SHORT, NORMAL, FAR";
}
GraphicsStore.save(graphicsSettings);
yield "viewDistance = " + graphicsSettings.viewDistance + " (Neustart erforderlich)";
}
case "shadowquality" -> {
try {
graphicsSettings.shadowQuality =
GraphicsSettings.ShadowQuality.valueOf(val.toUpperCase());
} catch (IllegalArgumentException e) {
yield "Unbekannt. Erlaubt: LOW, MEDIUM, HIGH";
}
GraphicsStore.save(graphicsSettings);
yield "shadowQuality = " + graphicsSettings.shadowQuality + " (Neustart erforderlich)";
}
default -> "Unbekannter Schlüssel: " + args[1]
+ " | Erlaubt: debugLod2, width, height, fullscreen, vsync, samples, viewDistance, shadowQuality";
};
});
} }
// Vollbild sicherstellen: GLFW ist hier bereits durch JME3 initialisiert. // Vollbild sicherstellen: GLFW ist hier bereits durch JME3 initialisiert.

View File

@@ -8,6 +8,8 @@ public class GraphicsSettings {
public int samples = 4; public int samples = 4;
public ViewDistance viewDistance = ViewDistance.NORMAL; public ViewDistance viewDistance = ViewDistance.NORMAL;
public ShadowQuality shadowQuality = ShadowQuality.MEDIUM; public ShadowQuality shadowQuality = ShadowQuality.MEDIUM;
/** Verstecktes Debug-Flag: erzwingt LOD2 (Impostor) für alle Objekte. Nur per Konsole setzbar. */
public boolean debugLod2 = false;
/** /**
* Schattenqualitäts-Stufen. * Schattenqualitäts-Stufen.

View File

@@ -31,6 +31,9 @@ public class ModelLodControl extends AbstractControl {
private static final Logger log = LoggerFactory.getLogger(ModelLodControl.class); private static final Logger log = LoggerFactory.getLogger(ModelLodControl.class);
/** Erzwingt LOD2 für alle Instanzen. Wird per Konsolen-Befehl "set debugLod2 true" gesetzt. */
public static volatile boolean debugLod2 = false;
private final Camera cam; private final Camera cam;
private final float lod1DistSq; private final float lod1DistSq;
private final float lod2DistSq; private final float lod2DistSq;
@@ -119,7 +122,10 @@ public class ModelLodControl extends AbstractControl {
// Fehlt LOD1 aber LOD2 vorhanden: bei lod1Distance direkt zu LOD2 wechseln (nicht ausblenden). // Fehlt LOD1 aber LOD2 vorhanden: bei lod1Distance direkt zu LOD2 wechseln (nicht ausblenden).
// Fehlt beides (z.B. Kaktusfeige): ab lod1Distance ausblenden. // Fehlt beides (z.B. Kaktusfeige): ab lod1Distance ausblenden.
int targetSlot; int targetSlot;
if (distSq >= lod2DistSq) { if (debugLod2) {
// Debug: erzwingt die niedrigste verfügbare LOD-Stufe
targetSlot = hasLod2 ? 2 : (hasLod1 ? 1 : 0);
} else if (distSq >= lod2DistSq) {
targetSlot = hasLod2 ? 2 : -1; targetSlot = hasLod2 ? 2 : -1;
} else if (distSq >= lod1DistSq) { } else if (distSq >= lod1DistSq) {
if (hasLod1) targetSlot = 1; if (hasLod1) targetSlot = 1;

View File

@@ -41,10 +41,16 @@ public class WorldObjectsState extends BaseAppState {
private final List<Material> sceneLitMaterials = new ArrayList<>(); private final List<Material> sceneLitMaterials = new ArrayList<>();
private final List<Material> windMaterials = new ArrayList<>(); private final List<Material> windMaterials = new ArrayList<>();
private final List<Material> pbrMaterials = new ArrayList<>(); private final List<Material> pbrMaterials = new ArrayList<>();
/** Impostor-Unshaded-Materialien: erhalten pro Frame einen Ambient-Tint (Color-Uniform). */ /** Impostor-Unshaded-Materialien: erhalten pro Frame einen Tint (Color-Uniform). */
private final List<Material> impostorMaterials = new ArrayList<>(); private final List<Material> impostorMaterials = new ArrayList<>();
/** Capture-Ambient, mit dem der Impostor-Atlas gerendert wurde. Normalisiert den Tint. */ // Licht-Werte beim Impostor-Atlas-Capture (aus ImpostorUtil): Haupt-Sonne + Ambient.
private static final float IMPOSTOR_CAP_AMB = 0.30f; // Tint = (aktSonne + aktAmbient) / (capSonne + capAmbient) → folgt dem Tageszyklus.
private static final float IMPOSTOR_CAP_SUN_R = 0.70f;
private static final float IMPOSTOR_CAP_SUN_G = 0.65f;
private static final float IMPOSTOR_CAP_SUN_B = 0.52f;
private static final float IMPOSTOR_CAP_AMB_R = 0.30f;
private static final float IMPOSTOR_CAP_AMB_G = 0.30f;
private static final float IMPOSTOR_CAP_AMB_B = 0.32f;
private float debugTimer = 0f; private float debugTimer = 0f;
private float lodFactor = 1.0f; private float lodFactor = 1.0f;
@@ -174,12 +180,12 @@ public class WorldObjectsState extends BaseAppState {
for (Material mat : pbrMaterials) { for (Material mat : pbrMaterials) {
mat.setColor("Emissive", new ColorRGBA(ac.r, ac.g, ac.b, 1f)); mat.setColor("Emissive", new ColorRGBA(ac.r, ac.g, ac.b, 1f));
} }
// Impostor-Tint: Unshaded-Atlas folgt dem Tag/Nacht-Zyklus über den Color-Multiplikator. // Impostor-Tint: (aktSonne + aktAmbient) / (captureSonne + captureAmbient)
// Normiert auf die Capture-Ambient (0.30): Bei gleichem Ambient = 1.0, Nacht ≈ 0.05. // → Impostor folgt Sonne und Ambient; ≈1.0 bei gleichem Licht wie beim Capture.
if (!impostorMaterials.isEmpty()) { if (!impostorMaterials.isEmpty()) {
float tR = Math.min(1.2f, ac.r / IMPOSTOR_CAP_AMB); float tR = Math.min(1.5f, (sc.r + ac.r) / (IMPOSTOR_CAP_SUN_R + IMPOSTOR_CAP_AMB_R));
float tG = Math.min(1.2f, ac.g / IMPOSTOR_CAP_AMB); float tG = Math.min(1.5f, (sc.g + ac.g) / (IMPOSTOR_CAP_SUN_G + IMPOSTOR_CAP_AMB_G));
float tB = Math.min(1.2f, ac.b / IMPOSTOR_CAP_AMB); float tB = Math.min(1.5f, (sc.b + ac.b) / (IMPOSTOR_CAP_SUN_B + IMPOSTOR_CAP_AMB_B));
ColorRGBA tint = new ColorRGBA(tR, tG, tB, 1f); ColorRGBA tint = new ColorRGBA(tR, tG, tB, 1f);
for (Material mat : impostorMaterials) { for (Material mat : impostorMaterials) {
mat.setColor("Color", tint); mat.setColor("Color", tint);