TestRenderToCubemap only renders on one of the sides


#1

TestRenderToCubemap seems to be only rendering one of the cube sides onto the sky box.

In the below example the cubemap viewport is rendering a cube which is rotating around the origin, which should show up in all of the skybox faces. But it only shows up in one of them - the one the camera is facing at the start.

Here is the example (note its modified slightly from the github version here):

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.system.AppSettings;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture;
import com.jme3.texture.TextureCubeMap;
import com.jme3.util.SkyFactory;
import com.jme3.util.SkyFactory.EnvMapType;

/**
 * Renders a rotating box to a cubemap texture, then applies the cubemap
 * texture as a sky.
 * Modified for a test my murph9.
 */
public class TestRenderToCubemap  extends SimpleApplication {
 
    private Geometry offBox;
    private float angle = 0;
    private ViewPort offView;
 
    public static void main(String[] args){
        TestRenderToCubemap app = new TestRenderToCubemap();
        AppSettings settings = new AppSettings(true);
        settings.setVSync(true);
        app.setSettings(settings);
        app.start();
    }
 
    public Texture setupOffscreenView(){
        Camera offCamera = new Camera(512, 512);
 
        offView = renderManager.createPreView("Offscreen View", offCamera);
        offView.setClearFlags(true, true, true);
        offView.setBackgroundColor(ColorRGBA.DarkGray);
 
        // create offscreen framebuffer
        FrameBuffer offBuffer = new FrameBuffer(512, 512, 1);
 
        //setup framebuffer's cam
        offCamera.setFrustumPerspective(45f, 1f, 0.1f, 1000f);
        offCamera.setLocation(new Vector3f(0f, 0f, 0f));
        offCamera.lookAt(new Vector3f(-1f, 0f, 0f), Vector3f.UNIT_Y);
 
        //setup framebuffer's texture
        TextureCubeMap offTex = new TextureCubeMap(512, 512, Format.RGBA8);
        offTex.setMinFilter(Texture.MinFilter.Trilinear);
        offTex.setMagFilter(Texture.MagFilter.Bilinear);
 
        //setup framebuffer to use texture
        offBuffer.setDepthBuffer(Format.Depth);
        offBuffer.setMultiTarget(true);
        offBuffer.addColorTexture(offTex, TextureCubeMap.Face.NegativeX);
        offBuffer.addColorTexture(offTex, TextureCubeMap.Face.PositiveX);
        offBuffer.addColorTexture(offTex, TextureCubeMap.Face.NegativeY);
        offBuffer.addColorTexture(offTex, TextureCubeMap.Face.PositiveY);
        offBuffer.addColorTexture(offTex, TextureCubeMap.Face.NegativeZ);
        offBuffer.addColorTexture(offTex, TextureCubeMap.Face.PositiveZ);
        
        //set viewport to render to offscreen framebuffer
        offView.setOutputFrameBuffer(offBuffer);
 
        // setup framebuffer's scene
        Box boxMesh = new Box(0.1f,0.1f,0.1f);
        Material material = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
        material.setColor("Color", ColorRGBA.White);
        offBox = new Geometry("box", boxMesh);
        offBox.setMaterial(material);
 
        // attach the scene to the viewport to be rendered
        offView.attachScene(offBox);
 
        return offTex;
    }
 
    @Override
    public void simpleInitApp() {
    	cam.setLocation(new Vector3f());
        cam.lookAt(Vector3f.UNIT_X, Vector3f.UNIT_Y);
 
        Texture offTex = setupOffscreenView();
        Spatial sky = SkyFactory.createSky(assetManager, offTex, EnvMapType.CubeMap);
        rootNode.attachChild(sky);
    }
 
    
    private int frameCount = 0;
    @Override
    public void simpleUpdate(float tpf){
    	frameCount++;
    	
        Quaternion q = new Quaternion();
 
        angle += tpf;
        angle %= FastMath.TWO_PI;
        q.fromAngles(angle, 0, angle);

        
        offBox.setLocalTranslation(new Quaternion().fromAngleAxis(FastMath.PI*(((float)frameCount)/120), Vector3f.UNIT_Y).mult(new Vector3f(1,0,0)));
        
        offBox.setLocalRotation(q);
        offBox.updateLogicalState(tpf);
        offBox.updateGeometricState();
        
    }
}

In my actual use case which i am attempting to get real time reflections like this. Although using this method has every face have the same ambient light and only one has colour. (i’m hoping the above example will prevent the need to go into this)

Thanks,
Jake


#2

what do you want the reflections for ?


#3

I’d echo exactly what @thetoucher just asked… But I’ll also just throw one thing out here… Is back face culling still enabled on your geometries?

Would that not remove the geo’s from the other areas as well? I could be wrong. I haven’t finished 1 coffee yet this morning.


#4

Real time cube map reflections

The geometries themselves are fine, and i have used them with default culling for a while.

Here is the actual usecase as screenshots (using a high poly sphere):
First is the view infront, last is to show the reflection
Imgur
Imgur

Problem is that 5 of the 6 faces are the same as the first face but without colour.
So i tried to see if that was a problem with the cubemap generation, and created that first test case.


#5

I wonder if it would be worth looking at how the PBR light probe rendering does it. I’ve never looked at the code but JME has a feature where you can generate light probes for your scene… which is effectively rendering the scene from all directions.


#6

This is probably the one:

I was trying to avoid this method as the test class from my first post seemed a lot less expensive.
And I don’t know enough to fix it.


#7

I mean, if it’s needlessly more expensive then something is wrong because it needs to be as fast as possible.

…but note that ultimately it’s doing a bunch of stuff you won’t need to do since it needs to bake the results into something that PBR can use.


#8

Yeah makes sense.

My point was that the first test doesn’t work and that it “looks” like it maps the 360d environment to a cube map: https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-examples/src/main/java/jme3test/post/TestRenderToCubemap.java

I am fine to modify the EnvironmentCamera for my own needs, it just looked much more expensive compared to the test. In this case I’m now just concerned that the test doesn’t work.


#9

Yes, so someone will have to figure out why the test doesn’t work. Perhaps by comparing it to code that does work.

That someone is probably you, I guess.


#10

Yep, figured that was going to be on me.
So just to clarify a few things that I’m pretty sure are true:

6 cameras are required for each face of the cube?
And each needs a viewport right?

Oh maybe @thetoucher knows something, as i’m try to replicate this Real-time Reflections


#11

I had a quick look for this old code, of course I can’t find it.

6 camera’s sounds correct, it could be done with rotating a single camera, but I’m pretty sure I used 6.
I don’t think they need a viewport each, I think they can all use the same viewport ?

Edit: I stopped using real time reflections a long time ago in favour of faster less brute force methods like screen space reflections. I try to fake it before having to fall back on accurate reflections. I imagine RTX will replace these sorts of methods moving forward.


#12

Thanks for searching for the old code unlucky it wasn’t found just trying not to reinvent anything and I will look into screen space reflections if the performance gets bad.

I’m not well versed on jme but 6 viewports seems like the only way i can even use the 6 cameras - its also what the EnvironmentCamera does.


#13

The test does work.

This is a hack of the test.


#14

Have you tried positioning the logo cube to show on any of the other sides of the cube map?

The minimal adjustment required would be to position the box at new Vector3f(0,0,-10), it has because:

offCamera.setLocation(new Vector3f(0f, 0f, -5f));
offCamera.lookAt(new Vector3f(0f, 0f, 0f), Vector3f.UNIT_Y);

#15

I just ran it again and it works fine. Maybe I am supposed to see something other than the monkey logo on a spinning cube?

Running your file shows it is working fine for me, all you see is a white cube spinning and rotating around the camera.

Isn’t that what I would/should see if I was using this for the material,

Material material = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");

rather than this?

Material material = assetManager.loadMaterial("Interface/Logo/Logo.j3m");

When the material has a texture rather than a definition, I see everything working just fine also.

        // setup framebuffer's scene
        Box boxMesh = new Box(0.1f,0.1f,0.1f);
        Material material = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
        offBox = new Geometry("box", boxMesh);
        Texture boxTex = assetManager.loadTexture("Interface/Logo/Monkey.jpg");
        material.setTexture("ColorMap", boxTex);
        offBox.setMaterial(material);

I am kinda confused as what is it I am supposed to be seeing?

I was going to suggest PBR materials myself but since I am just now getting a handle on them I didn’t want to make a suggestion I couldn’t go into without more knowledge of the entire process.


#16

I’m pretty sure the material used shouldn’t matter, the project a pasted this into didn’t have the logo referenced so i changed it to unshaded.

On my test this is the result if i rotate the camera a little to the right, so that id be looking at the front cube map face and the one to the right of it.
Screenshot while the cube is in between them it is being cut off by the neighbouring cube map face because that face doesn’t get rendered properly:
Imgur

So i gather you see it go all the way round?

Might be a hardware issue so: i5-6600k, AMD RX 480, windows 10 and graphics driver is new.


#17

I see what you see when there is no texture.

The test used a material file with Unshaded.j3md and it has a texture set to the jMonkey logo for ColorMap.

I wasn’t aware a material would work without a texture.

I just go by what I read in wiki so what you are doing may be possible and I just wasn’t aware you could do it.

•All Geometries must have Materials that defines color or texture.
•Each Material is based on a Material Definition file.
Examples of included Material Definitions: Lighting.j3md, Unshaded.j3md

When I use your example and set a color only it also works fine.


#18

Yes i seem to have missed the colour set line in the example in the first post, a line approximately like:

material.setColor("Color", ColorRGBA.White);

is what its missing. (don’t have access to run this code now, but will add it to the original post)

What I am trying to say is that the test only shows the white/textured box on one of the skybox cubemap faces.
The white box is only displaying on one of the sky box faces, in my demo (with the added color line), move the camera left or right and see that when the box comes around again it is cut off like the image below, the white (red) cube is no longer visible.

Outside, with the camera on the inside
Imgur

From inside when the test runs, you are looking at the one shy box face (black lines) which works, move the camera right and the box doesn’t show.
Imgur

Just like my screenshot in my previous post.

I hope this makes sense, I’m trying to say that the TestRenderToCubeMap test is incomplete.


#19

In the test as JME provides it, I see textured cubes no matter which direction I look.


#20

I ran the test, and yes the box is textured and spins, but it still doesn’t leave the one cubemap face.
If you add this you can see that it doesn’t ‘leave’ that one face and is cut off on the edges.

private int frameCount = 0;
    @Override
    public void simpleUpdate(float tpf){
    	frameCount++;
    	offBox.setLocalTranslation(new Quaternion().fromAngleAxis(FastMath.PI*(((float)frameCount)/180), Vector3f.UNIT_Y).mult(new Vector3f(2,0,0)));

And here is what i see, it cuts off at the edges of the ‘front’ face of the cube map. (had to update OBS for this…)