An den LOD im Editor gearbeitet

This commit is contained in:
2026-07-20 13:35:27 +02:00
parent e6440e3a46
commit b17a71286a
20 changed files with 758 additions and 150 deletions

View File

@@ -0,0 +1,56 @@
package de.blight.game.state;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import java.util.List;
/**
* Wählt pro Frame das passende Quad-Paar eines 8-Richtungs-Impostors.
* Pass d wurde mit Kamera bei sin(d·2π/8), cos(d·2π/8) aufgenommen.
* Es werden immer zwei gegenüberliegende Quads (eine Ebene) angezeigt;
* die anderen 6 werden per CullHint.Always ausgeblendet.
*/
public class ImpostorViewControl extends AbstractControl {
private static final int DIRS = 8;
private Camera cam;
public ImpostorViewControl() {}
public ImpostorViewControl(Camera cam) { this.cam = cam; }
public void setCamera(Camera cam) { this.cam = cam; }
@Override
protected void controlUpdate(float tpf) {
if (cam == null || !(spatial instanceof Node n)) return;
List<Spatial> quads = n.getChildren();
int dirs = quads.size();
if (dirs < 2) return;
Vector3f toCamera = cam.getLocation().subtract(spatial.getWorldTranslation());
float dx = toCamera.x, dz = toCamera.z;
if (Math.abs(dx) < 0.001f && Math.abs(dz) < 0.001f) return;
float angle = (float) Math.atan2(dx, dz);
float t = angle * dirs / FastMath.TWO_PI;
int best = ((int) Math.round(t) % dirs + dirs) % dirs;
int opp = (best + dirs / 2) % dirs;
for (int i = 0; i < dirs; i++) {
quads.get(i).setCullHint(i == best || i == opp
? Spatial.CullHint.Inherit
: Spatial.CullHint.Always);
}
}
@Override protected void controlRender(RenderManager rm, ViewPort vp) {}
}

View File

@@ -14,7 +14,6 @@ import com.jme3.material.RenderState;
import com.jme3.math.*;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.*;
import com.jme3.scene.control.BillboardControl;
import com.jme3.scene.shape.*;
import com.jme3.texture.Texture;
import de.blight.common.PlacedModel;
@@ -221,11 +220,20 @@ public class WorldObjectsState extends BaseAppState {
lodRoot.attachChild(lod2); // index 1 = lod2 (Impostor-Karte)
treeNode.setCullHint(Spatial.CullHint.Inherit);
lod2.setCullHint(Spatial.CullHint.Always);
// Billboard: Impostor-Karte dreht sich immer zur Kamera,
// unabhängig von der Baum-Rotation im BLO.
BillboardControl bc = new BillboardControl();
bc.setAlignment(BillboardControl.Alignment.Camera);
lod2.addControl(bc);
// Pivot-Korrektur: Stammbasis auf Y=0 ausrichten (Sicherungsnetz für
// j3o-Dateien, deren 1/3-Scale-Offset nicht eingebacken wurde).
// treeNode und lod2 gemeinsam verschieben → Geometrie und Impostor-Bild
// bleiben deckungsgleich.
lodRoot.updateGeometricState();
if (treeNode.getWorldBound() instanceof com.jme3.bounding.BoundingBox treeBb) {
float groundY = treeBb.getCenter().y - treeBb.getYExtent();
if (Math.abs(groundY) > 0.01f) {
treeNode.setLocalTranslation(0f, -groundY, 0f);
lod2.setLocalTranslation(0f, -groundY, 0f);
}
}
// Impostor: wählt pro Frame das kamerawinkelrichtige Quad-Paar.
lod2.addControl(new ImpostorViewControl(app.getCamera()));
lodRoot.addControl(new ModelLodControl(
app.getCamera(), treeNode, null, lod2,
m.lod1Distance() * lodFactor, m.lod2Distance() * lodFactor, m.cullDistance() * lodFactor));

View File

@@ -1,9 +1,6 @@
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>%d{HH:mm:ss.SSS} %-5level [%logger{30}] %msg%n%ex</pattern>
</encoder>
@@ -20,6 +17,9 @@
</encoder>
</appender>
<!-- LOD-Slot-Wechsel auf DEBUG aktivieren -->
<logger name="de.blight.game.state.ModelLodControl" level="DEBUG"/>
<!-- JME-interne JUL-Logs auf WARN reduzieren -->
<logger name="com.jme3" level="WARN"/>
<!-- GltfLoader meldet bei jeder Animation "only supports linear interpolation" bekanntes JME-Verhalten, kein Fehler -->