Am Lightning rumgeschraubt (Nicht mc queen)

This commit is contained in:
2026-07-19 12:30:11 +02:00
parent bdd69e282c
commit ad37720edd
4 changed files with 44 additions and 22 deletions

View File

@@ -219,8 +219,11 @@ public class WorldScene extends BaseAppState {
animLib = new AnimationLibrary(); animLib = new AnimationLibrary();
app.getStateManager().attach(animLib); app.getStateManager().attach(animLib);
// Früh starten damit DayNightState bis onEnable() bereits initialisiert ist // Früh starten damit DayNightState bis onEnable() bereits initialisiert ist.
// withShadows=false: Shadow-Filter wird in buildLighting() extern übergeben.
// setGameMode(true): Spiel-Beleuchtungswerte statt Editor-Werte verwenden.
dayNight = new DayNightState(false); dayNight = new DayNightState(false);
dayNight.setGameMode(true);
app.getStateManager().attach(dayNight); app.getStateManager().attach(dayNight);
} }

View File

@@ -57,6 +57,8 @@ public class DayNightState extends BaseAppState implements TimeListener {
private ColorRGBA sunBaseColor = new ColorRGBA(1, 1, 1, 1); private ColorRGBA sunBaseColor = new ColorRGBA(1, 1, 1, 1);
private float shadowBaseIntensity = 0f; private float shadowBaseIntensity = 0f;
private ColorRGBA customAmbient = new ColorRGBA(); private ColorRGBA customAmbient = new ColorRGBA();
/** true = Spiel-Beleuchtungswerte, false = Editor-Werte. Standardmäßig = withShadows. */
private boolean gameMode;
private static final float CAVE_RAY_HEIGHT = 12f; private static final float CAVE_RAY_HEIGHT = 12f;
private static final float CAVE_CHECK_INTERVAL = 0.2f; private static final float CAVE_CHECK_INTERVAL = 0.2f;
@@ -69,14 +71,23 @@ public class DayNightState extends BaseAppState implements TimeListener {
this(new DayTime(), true); this(new DayTime(), true);
} }
/** @param withShadows false für Editor (kein Shadow-Renderer) */ /** @param withShadows false für Editor (kein Shadow-Renderer, Editor-Beleuchtungswerte) */
public DayNightState(boolean withShadows) { public DayNightState(boolean withShadows) {
this(new DayTime(), withShadows); this(new DayTime(), withShadows);
} }
public DayNightState(DayTime dayTime, boolean withShadows) { public DayNightState(DayTime dayTime, boolean withShadows) {
this.dayTime = dayTime; this.dayTime = dayTime;
this.withShadows = withShadows; this.withShadows = withShadows;
this.gameMode = withShadows;
}
/**
* Schaltet auf Spiel-Beleuchtungswerte um, unabhängig vom withShadows-Flag.
* Nützlich wenn der Shadow-Filter von außen gesetzt wird (z.B. WorldScene).
*/
public void setGameMode(boolean gameMode) {
this.gameMode = gameMode;
} }
public DayTime getDayTime() { return dayTime; } public DayTime getDayTime() { return dayTime; }
@@ -234,24 +245,28 @@ public class DayNightState extends BaseAppState implements TimeListener {
float elevC = FastMath.clamp(elevation, 0f, 1f); float elevC = FastMath.clamp(elevation, 0f, 1f);
// Spiel vs. Editor: unterschiedliche Helligkeitswerte aus LightingConfig // Spiel vs. Editor: unterschiedliche Helligkeitswerte aus LightingConfig
ColorRGBA ambDay = withShadows ? LightingConfig.AMB_DAY : LightingConfig.EDITOR_AMB_DAY; ColorRGBA ambDay = gameMode ? LightingConfig.AMB_DAY : LightingConfig.EDITOR_AMB_DAY;
ColorRGBA ambNight = withShadows ? LightingConfig.AMB_NIGHT : LightingConfig.EDITOR_AMB_NIGHT; ColorRGBA ambNight = gameMode ? LightingConfig.AMB_NIGHT : LightingConfig.EDITOR_AMB_NIGHT;
ColorRGBA custDay = withShadows ? LightingConfig.CUSTOM_AMB_DAY : LightingConfig.EDITOR_CUSTOM_AMB_DAY; ColorRGBA custDay = gameMode ? LightingConfig.CUSTOM_AMB_DAY : LightingConfig.EDITOR_CUSTOM_AMB_DAY;
ColorRGBA custNight = withShadows ? LightingConfig.CUSTOM_AMB_NIGHT : LightingConfig.EDITOR_CUSTOM_AMB_NIGHT; ColorRGBA custNight = gameMode ? LightingConfig.CUSTOM_AMB_NIGHT : LightingConfig.EDITOR_CUSTOM_AMB_NIGHT;
float sunIntensity = withShadows ? LightingConfig.SUN_INTENSITY : LightingConfig.EDITOR_SUN_INTENSITY; float sunIntensity = gameMode ? LightingConfig.SUN_INTENSITY : LightingConfig.EDITOR_SUN_INTENSITY;
// ── Sonnenfarbe: Dämmerung (orange) → Tag (warm-weiß) — jedes Frame ── // ── Sonnenfarbe: Dämmerung (orange) → Tag (warm-weiß) — jedes Frame ──
float dawnFactor = 1f - FastMath.clamp(elevation * LightingConfig.SUN_DAWN_SLOPE, 0f, 1f); float dawnFactor = 1f - FastMath.clamp(elevation * LightingConfig.SUN_DAWN_SLOPE, 0f, 1f);
ColorRGBA sunColor = LightingConfig.SUN_COLOR_DAWN.clone() ColorRGBA sunTint = LightingConfig.SUN_COLOR_DAWN.clone()
.interpolateLocal(LightingConfig.SUN_COLOR_DAY, 1f - dawnFactor); .interpolateLocal(LightingConfig.SUN_COLOR_DAY, 1f - dawnFactor);
sunBaseColor = sunColor.mult(elevC * sunIntensity); sunBaseColor = sunTint.mult(elevC * sunIntensity);
sun.setColor(sunBaseColor.mult(1f - caveFactor)); sun.setColor(sunBaseColor.mult(1f - caveFactor));
// ── Ambient: Nacht → Tag — jedes Frame ───────────────────────────── // ── Ambient: Nacht (blau) → Tag (Sonnenfarbe-tinted) — jedes Frame ──
// Tages-Ambient bekommt den Farbton der Sonne: orange bei Dämmerung,
// warm-gelb tagsüber. Nachts bleibt das fixe Blau von AMB_NIGHT.
ColorRGBA ambDayTinted = ambDay.mult(sunTint);
ColorRGBA custDayTinted = custDay.mult(sunTint);
float ambFactor = FastMath.clamp( float ambFactor = FastMath.clamp(
(elevation - LightingConfig.AMB_ELEV_LOW) / LightingConfig.AMB_ELEV_RANGE, 0f, 1f); (elevation - LightingConfig.AMB_ELEV_LOW) / LightingConfig.AMB_ELEV_RANGE, 0f, 1f);
ambient.setColor(ambNight.clone().interpolateLocal(ambDay, ambFactor)); ambient.setColor(ambNight.clone().interpolateLocal(ambDayTinted, ambFactor));
customAmbient.set(custNight.clone().interpolateLocal(custDay, ambFactor)); customAmbient.set(custNight.clone().interpolateLocal(custDayTinted, ambFactor));
shadowBaseIntensity = FastMath.clamp( shadowBaseIntensity = FastMath.clamp(
elevation * LightingConfig.SHADOW_SLOPE, 0f, LightingConfig.SHADOW_MAX); elevation * LightingConfig.SHADOW_SLOPE, 0f, LightingConfig.SHADOW_MAX);

View File

@@ -77,16 +77,17 @@ public final class LightingConfig {
/** /**
* AmbientLight-Farbe am Mittag. * AmbientLight-Farbe am Mittag.
* Skaliert den LightProbe-IBL: envLight = probeIBL × AMB_DAY. * Skaliert den LightProbe-IBL: envLight = probeIBL × AMB_DAY.
* Hoch halten (≥ 0.7) damit PBR-Reflexionen sichtbar bleiben. * Nicht zu hoch LightProbe bäckt bereits Mittags-Beleuchtung ein;
* bei AMB_DAY=0.90 wäre probeIBL + direkte Sonne (0.68) zu hell für weiße Flächen.
* Hat keinen Effekt solange kein LightProbe in der Szene ist. * Hat keinen Effekt solange kein LightProbe in der Szene ist.
*/ */
public static final ColorRGBA AMB_DAY = new ColorRGBA(0.90f, 0.90f, 0.90f, 1f); public static final ColorRGBA AMB_DAY = new ColorRGBA(0.28f, 0.28f, 0.28f, 1f);
/** /**
* AmbientLight-Farbe in der Nacht (LightProbe-Multiplikator). * AmbientLight-Farbe in der Nacht (LightProbe-Multiplikator).
* Leichter Blaustich simuliert Mondlicht-Reflexionen auf PBR-Flächen. * Leichter Blaustich simuliert Mondlicht-Reflexionen auf PBR-Flächen.
*/ */
public static final ColorRGBA AMB_NIGHT = new ColorRGBA(0.10f, 0.10f, 0.25f, 1f); public static final ColorRGBA AMB_NIGHT = new ColorRGBA(0.05f, 0.05f, 0.125f, 1f);
// ╔══════════════════════════════════════════════════════════════════════════╗ // ╔══════════════════════════════════════════════════════════════════════════╗
@@ -103,7 +104,7 @@ public final class LightingConfig {
* ↓ senken: mehr Kontrast, tiefere Schatten (wirkt moodiger/dramatischer). * ↓ senken: mehr Kontrast, tiefere Schatten (wirkt moodiger/dramatischer).
* Empfehlung: 0.030.10 pro Kanal. * Empfehlung: 0.030.10 pro Kanal.
*/ */
public static final ColorRGBA CUSTOM_AMB_DAY = new ColorRGBA(0.04f, 0.05f, 0.08f, 1f); public static final ColorRGBA CUSTOM_AMB_DAY = new ColorRGBA(0.03f, 0.04f, 0.06f, 1f);
/** /**
* Ambient-Farbe in der Nacht. * Ambient-Farbe in der Nacht.
@@ -111,7 +112,7 @@ public final class LightingConfig {
* Zu hoch → Nacht wirkt grau statt dunkel. * Zu hoch → Nacht wirkt grau statt dunkel.
* Empfehlung: 0.010.04 pro Kanal, Blau-Kanal darf höher sein. * Empfehlung: 0.010.04 pro Kanal, Blau-Kanal darf höher sein.
*/ */
public static final ColorRGBA CUSTOM_AMB_NIGHT = new ColorRGBA(0.025f, 0.025f, 0.06f, 1f); public static final ColorRGBA CUSTOM_AMB_NIGHT = new ColorRGBA(0.012f, 0.012f, 0.03f, 1f);
// ╔══════════════════════════════════════════════════════════════════════════╗ // ╔══════════════════════════════════════════════════════════════════════════╗

View File

@@ -291,6 +291,7 @@ public class WorldObjectsState extends BaseAppState {
geo.setMaterial(pbrMat); geo.setMaterial(pbrMat);
} else if (spatial instanceof Node node) { } else if (spatial instanceof Node node) {
if ("lod2".equals(node.getName())) return;
for (Spatial child : new ArrayList<>(node.getChildren())) { for (Spatial child : new ArrayList<>(node.getChildren())) {
convertUnshadedToPbr(child); convertUnshadedToPbr(child);
} }
@@ -303,10 +304,11 @@ public class WorldObjectsState extends BaseAppState {
if (mat == null) return; if (mat == null) return;
String name = mat.getMaterialDef().getName(); String name = mat.getMaterialDef().getName();
if ("Tree".equals(name) || "TreeLeaf".equals(name)) { if ("Tree".equals(name) || "TreeLeaf".equals(name)) {
// j3o-Loading setzt keine j3md-Defaults → Uniforms explizit setzen // j3o-Loading setzt keine j3md-Defaults → Uniforms explizit setzen.
// (Werte für Mittag; werden sofort in update() durch DayNightState überschrieben) // SunColor = SUN_COLOR_DAY × SUN_INTENSITY (wie in update() bei Mittag),
mat.setVector3("SunColor", new Vector3f(1.00f, 0.95f, 0.88f)); // sonst leuchten Bäume weiß bis DayNightState das erste Mal überschreibt.
mat.setVector3("AmbientColor", new Vector3f(0.08f, 0.10f, 0.16f)); mat.setVector3("SunColor", new Vector3f(0.68f, 0.65f, 0.60f));
mat.setVector3("AmbientColor", new Vector3f(0.04f, 0.05f, 0.08f));
mat.setVector3("LightDir", new Vector3f(0f, -1f, 0f)); mat.setVector3("LightDir", new Vector3f(0f, -1f, 0f));
sceneLitMaterials.add(mat); sceneLitMaterials.add(mat);
} else if ("Fern".equals(name)) { } else if ("Fern".equals(name)) {
@@ -325,6 +327,7 @@ public class WorldObjectsState extends BaseAppState {
log.info("[WorldObjects] Material-Def '{}' an '{}' unbekannt, übersprungen.", name, geo.getName()); log.info("[WorldObjects] Material-Def '{}' an '{}' unbekannt, übersprungen.", name, geo.getName());
} }
} else if (spatial instanceof Node node) { } else if (spatial instanceof Node node) {
if ("lod2".equals(node.getName())) return;
for (Spatial child : node.getChildren()) { for (Spatial child : node.getChildren()) {
collectSceneLitMaterials(child); collectSceneLitMaterials(child);
} }