Thank you very much for the quick response. I have added the control for another purpose earlier here and didn’t remove it from here because it seemed to work. After shifting the update to the appstate update (see below) no change in behavior occurred.
Currently I am investigating the code once more and preparing a test case to reconstruct the warnings because obviously I didn’t understand the update sequence properly.
I would like to share the code of the appstate:
package sk.util.scene.infinity;
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.BaseAppState;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.BloomFilter;
import com.jme3.renderer.Camera;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import java.util.Optional;
import java.util.logging.Logger;
/**
* the InfinityViewAppState works as an view extender to visualize objects
* beyond the far plane of the cameras viewport by adding another viewport with
* a camera of a larger frustum for scene offscreen rendering.
*
* @author harryschwenk
*/
public class InfinityViewAppState extends BaseAppState {
private static final Logger LOG = Logger
.getLogger(InfinityViewAppState.class.getName());
// init --> cleanup
private ViewPort offView = null;
private Node farView;
// Finals
private final float farPlaneDistance;
private final int resolutionScaleShift;
private SimpleApplication sApp;
private Camera newCam;
/**
* Constructor of the Infinity app state. The first argument represents the
* distance of the screen which shall be just inside the camera frustum to
* be the farthest object visible.
*
*
* @param farPlaneDistance Distance of the background screen for the far
* view beyond the frustum of current view.
* @param resolutionScaleShift Resolution factor (*2^-n) for the next view.
* 1 halfs the resolutionn, 2 quarters it.
*/
public InfinityViewAppState(float farPlaneDistance, int resolutionScaleShift) {
this.farPlaneDistance = farPlaneDistance;
this.resolutionScaleShift = resolutionScaleShift;
}
/**
*
* @param tpf
*/
@Override
public void update(float tpf) {
updateGraphic();
}
/**
* The node which contains the background screen.
*
* @return
*/
public Optional<Spatial> getFarView() {
return Optional.ofNullable(farView);
}
/**
* private method where the background element and the offscreen viewport is being updated.
*/
private void updateGraphic() {
newCam.setFrustum(
sApp.getCamera().getFrustumNear() * farPlaneDistance,
sApp.getCamera().getFrustumFar() * farPlaneDistance,
sApp.getCamera().getFrustumLeft() * farPlaneDistance,
sApp.getCamera().getFrustumRight() * farPlaneDistance,
sApp.getCamera().getFrustumTop() * farPlaneDistance,
sApp.getCamera().getFrustumBottom() * farPlaneDistance);
farView.setLocalTranslation(sApp.getCamera().getLocation()
.add(sApp.getCamera().getRotation()
.mult(new Vector3f(0, 0, farPlaneDistance))));
farView.setLocalRotation(sApp.getCamera().getRotation());
newCam.setLocation(sApp.getCamera().getLocation());
newCam.setRotation(sApp.getCamera().getRotation());
// Reattach root node: Yes I know it is slow. I'll care about performance later...
offView.clearScenes();
sApp.getRootNode().getChildren()
.stream()
// Exclude the plane at the outer border of the frustum. Otherwise pictures will be recursive
// .filter(child -> planeForExclusion.get().map(other -> !child.equals(other)).orElse(true))
// // Exclude the plane at the inner border of the frustum. Otherwise picutres will be recursive
.filter(child -> !child.equals(farView))
.forEach(offView::attachScene);
}
/**
* Initialize viewport to perform offscreen rendering of the whole scene
* with a camera with a bigger frustum: the background and the viewport are
* generated here.
*
* @param app
*/
@Override
protected void initialize(Application app) {
sApp = ((SimpleApplication) app);
newCam = sApp.getCamera().clone();
int width = newCam.getWidth() >> resolutionScaleShift;
int height = newCam.getHeight() >> resolutionScaleShift;
Texture2D offTex = new Texture2D(width, height, Image.Format.RGBA8);
offTex.setMinFilter(Texture.MinFilter.Trilinear);
offTex.setMagFilter(Texture.MagFilter.Bilinear);
FrameBuffer offBuffer = new FrameBuffer(width, height, 1);
offBuffer.setDepthBuffer(Image.Format.Depth);
offBuffer.setColorTexture(offTex);
offView = sApp.getRenderManager().createPreView("farView", newCam);
offView.setClearFlags(true, true, true);
offView.setOutputFrameBuffer(offBuffer);
FilterPostProcessor fpp = new FilterPostProcessor(sApp.getAssetManager());
BloomFilter bf = new BloomFilter(BloomFilter.GlowMode.Objects);
fpp.addFilter(bf);
bf.setBlurScale(0.0f);
offView.addProcessor(fpp);
Geometry screen = new Geometry();
screen
.setMesh(new Box(sApp.getCamera().getFrustumRight() * farPlaneDistance, sApp
.getCamera().getFrustumTop() * farPlaneDistance, 0F));
screen
.setMaterial(new Material(sApp.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"));
screen.getMaterial().setColor("Color", ColorRGBA.White);
screen.getMaterial().setTexture("ColorMap", offTex);
screen.rotate(0, FastMath.PI, 0);
screen.getMaterial().getAdditionalRenderState().setDepthWrite(true);
screen.getMaterial().getAdditionalRenderState().setDepthTest(true);
farView = new Node("~farplane" + this);
farView.setQueueBucket(RenderQueue.Bucket.Opaque);
farView.attachChild(screen);
sApp.getRootNode().attachChild(farView);
}
/**
* Cleanup.
*
* @param app
*/
@Override
protected void cleanup(Application app) {
offView.clearScenes();
offView.clearProcessors();
((SimpleApplication) app).getRootNode().detachChild(farView);
farView = null;
app.getRenderManager().removePreView(offView);
offView = null;
}
@Override
protected void onEnable() {
}
@Override
protected void onDisable() {
}
}
Also the test case (part of simple application):
@Override
public void simpleInitApp() {
for (long cntr = 0; cntr < 64; cntr++) {
// Some colored boxes: the next one is twice as big than the precursor and also moved
// twice as far away
// box sizes: 1: 2m * 2m * 2m
// 2: 4m * 4m * 4m
// 3: 8m * 8m * 8m
// ...
// 64: 1948 light years * 1948 light years * 1948 light years
Box boxMesh = new Box(1 << cntr, 1 << cntr, 1 << cntr);
Geometry boxGeo = new Geometry("Colored Box", boxMesh);
Material boxMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
boxMat.setColor("Color", new ColorRGBA(1 - (cntr / 32F), cntr / 32F, (0.25F * cntr) % 1, 0.1F));
boxGeo.setMaterial(boxMat);
System.out.println("box " + cntr + " moved " + 4 * FastMath.pow(1.98F, cntr) + " away");
boxGeo.move(100, 100, -150 - 4 * FastMath.pow(1.98F, cntr));
final long cntrA = 32 - cntr;
boxGeo.addControl(new AbstractControl() {
@Override
protected void controlUpdate(float tpf) {
getSpatial().rotate(0.1F * tpf * cntrA / 32F, 0.1F * tpf * cntrA / 32F, 0.1F * tpf * cntrA / 32F);
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
});
rootNode.attachChild(boxGeo);
}
// Common use case: Stack the Infinity app states like this and view should increase
// to 1000000 km without artefacts at close distance.
getStateManager().attach(new InfinityViewAppState(999.9F * 999.9F * 999.9F, 0)); // 1e6 km - 1e9 km
getStateManager().attach(new InfinityViewAppState(999.9F * 999.9F, 0)); // 1000 km - 1e6 km
getStateManager().attach(new InfinityViewAppState(999.9F, 0)); // 1 km - 1000 km
}
unfortunately with this test case I couldn’t find the problem. I continue investigating. Maybe some of you can say anything whats wrong with the sequence of the appstate. Thanks in advance.
Regards, Harry