Using procedural texture for a skybox. Possible?

I’m new to this and still a little vague on how shaders work but wouldn’t a custom shader be the solution here? That could even animate the texture and would run fast as there is no texture generating/saving/transmitting work - you just draw the correct pixels for your generated texture in the shader.

Yes and no.



Noise generation is not that expensive when you do it once or twice using a 3d texture. It’s almost trivial when using 2d. But to properly texture a 3d object you need a 4d noise function and those are harder to generate. For good video cards it’s not that much of a problem (nvidia 260+), but it’ll be much harder for older generation of cards.



Add to the fact that, currently, I’m doing 5 noise function calls for a single object.



Let’s say you have a big solar system… 2 suns then add 5-8 planets. Each planet can have between 0-5 moons… Then you add the skybox… That’s a lot of calls for each object. Yes it would look really great, but at this time it’s not the best avenue for everyone. I’m sure that in 5 years you’ll see a lot of that though. Technology will have developed enough to enable this. At least gamers will have adopted it.



With the way I’m doing it right now I don’t see much of a problem, FPS-wise, so it’s all good. Although I can’t say I’ve had the right textures on the skybox… but I’m working on it. :wink:

Actually, that’s not true.



You need a 3d noise function for 3D objects. 4D when you need animated texture on a 3D object.



Sorry about that.

Getting a weird problem. Maybe @normen can help…



I seem to be able to generate the textures fine. Once they’re done I add them to the asset manager using:



[java]

((DesktopAssetManager) gMgrs.getAssetManager()).addToCache(new TextureKey(“west.png”), west);

[… etc for the 5 others]

[/java]



Using the following debug println:

[java]

System.out.println(“Adding textures to cache (” + ((DesktopAssetManager) gMgrs.getAssetManager()).toString() + “).n” + west + “n” + east + “n” + north + “n” + south + “n” + up + “n” + down);

[/java]



I get this:

Adding textures to cache (com.jme3.asset.DesktopAssetManager@25d480f6).

Texture2D[name=null, image=Image[size=1024x1024, format=RGBA8]]

Texture2D[name=null, image=Image[size=1024x1024, format=RGBA8]]

Texture2D[name=null, image=Image[size=1024x1024, format=RGBA8]]

Texture2D[name=null, image=Image[size=1024x1024, format=RGBA8]]

Texture2D[name=null, image=Image[size=1024x1024, format=RGBA8]]

Texture2D[name=null, image=Image[size=1024x1024, format=RGBA8]]



But when I try to fetch them from the asset manager I get an asset not found:

[java]

Fetching skybox textures…

From com.jme3.asset.DesktopAssetManager@25d480f6

Mar 21, 2012 4:12:30 PM com.jme3.app.Application handleError

SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]

com.jme3.asset.AssetNotFoundException: west.png (Flipped) (Mipmaped)

at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:268)

at com.jme3.asset.DesktopAssetManager.loadTexture(DesktopAssetManager.java:325)

at com.jme3.asset.DesktopAssetManager.loadTexture(DesktopAssetManager.java:344)

at com.jme3.asset.DesktopAssetManager.loadTexture(DesktopAssetManager.java:356)

at com.madjack.games.disenthral.scenes.ArenaScene.createSky(ArenaScene.java:87)

at com.madjack.games.disenthral.scenes.ArenaScene.update(ArenaScene.java:124)

at com.jme3.app.state.AppStateManager.update(AppStateManager.java:255)

at com.jme3.app.SimpleApplication.update(SimpleApplication.java:241)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:149)

at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:182)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:223)

at java.lang.Thread.run(Thread.java:722)

[/java]



What could cause these textures to suddenly disappear?



I’m using pretty much the same thing for the preview viewport and it works fine. I don’t understand why the textures suddenly vanish. :confused:



I’m doing this to fetch the textures:

[java]

Spatial skybox = SkyFactory.createSky(gMgrs.getAssetManager(),

gMgrs.getAssetManager().loadTexture(“west.png”),

gMgrs.getAssetManager().loadTexture(“east.png”),

gMgrs.getAssetManager().loadTexture(“north.png”),

gMgrs.getAssetManager().loadTexture(“south.png”),

gMgrs.getAssetManager().loadTexture(“up.png”),

gMgrs.getAssetManager().loadTexture(“down.png”));

[/java]

You are totally abusing the system, thats why. Create a loader and a locator that takes paths that describe the generated images. So you go e.g. assetManager.load(“procedural_textures/noise/perlin/default.prcd”);

I do something similar (albeit with actually existing files) with the NeoTexture loader here:

http://code.google.com/p/jmonkeyplatform-contributions/source/browse/#svn%2Ftrunk%2FNeoTexturePlugin



Edit: Why you use the assetManager at all?

@normen said:
Edit: Why you use the assetManager at all?


I didn't at first but I decided to try that after getting black textures. After doing some head-butting I decided to try it the way I do it with the list preview.

Hitting another wall. -.-

Reverted and getting this:





http://www.danyrioux.com/files/badskybox.png



Textures seem to be random video memory bits… :cry:

Going forward at snail’s pace…



Actually. Not going forward at all. I noticed a strange behavior though, but it’s probably just me misunderstanding what’s going on. Help appreciated.



The test here is simple:



I generate a procedural offscreen texture on a cube.



I make 1st box using unshaded material and gives the procedural texture as colormap.



I make a 2nd box using the clone of the first just to verify that it was correctly made and is rendering okay.



I make a 3rd box using the procedural shader on its own.



Using the offscreen texture I used in the first box, I use it again on the SkyFactory.createSky(…) method. The result of that can be seen in the screenshot below as it is the “skybox”. It doesn’t look good. Random bits except the texture I sent.



I’d like to understand why that is happening. Anyone has a theory?





http://www.disenthral.com/files/offscreentosky.png



Thanks.

Forgot to post the code. Doh.



Here it is:

[java]

package com.madjack.games.disenthral.utils;



import com.jme3.app.SimpleApplication;

import com.jme3.input.KeyInput;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.light.AmbientLight;

import com.jme3.material.Material;

import com.jme3.material.RenderState.FaceCullMode;

import com.jme3.math.ColorRGBA;

import com.jme3.math.Vector3f;

import com.jme3.renderer.Camera;

import com.jme3.renderer.ViewPort;

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.Format;

import com.jme3.texture.Texture;

import com.jme3.texture.Texture2D;

import com.jme3.util.SkyFactory;

/**

*

  • This test renders a scene to a texture, then displays the texture on a cube.

    *
  • @author Dany

    */



    public class Test extends SimpleApplication implements ActionListener {



    private static final String TOGGLE_UPDATE = “Toggle Update”;

    private Texture offTexture;

    private Node offNode;

    private float angle = 0;

    private ViewPort offView;

    private Geometry offBox;



    public static void main(String[] args){

    Test app = new Test();

    app.start();

    }



    public void setupOffscreenView(){

    int size = 1024;

    Camera offCamera = new Camera(size, size);



    offView = renderManager.createPreView(“Offscreen View”, offCamera);

    offView.setClearFlags(true, true, true);

    offView.setBackgroundColor(ColorRGBA.DarkGray);



    // create offscreen framebuffer

    FrameBuffer offBuffer = new FrameBuffer(size, size, 1);



    //setup framebuffer’s cam

    offCamera.setFrustumPerspective(45f, 1f, 1f, 1000f);

    offCamera.setLocation(new Vector3f(0f, 0f, 0f));

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



    //setup framebuffer’s texture

    Texture2D offTex = new Texture2D(size, size, Format.RGBA8);

    offTex.setMinFilter(Texture.MinFilter.Trilinear);

    offTex.setMagFilter(Texture.MagFilter.Bilinear);



    //setup framebuffer to use texture

    offBuffer.setDepthBuffer(Format.Depth);

    offBuffer.setColorTexture(offTex);



    //set viewport to render to offscreen framebuffer

    offView.setOutputFrameBuffer(offBuffer);



    // setup framebuffer’s scene

    Box boxMesh = new Box(Vector3f.ZERO, 10,10,10);

    Material material = assetManager.loadMaterial(“Materials/Sky/ProcSkyBox.j3m”);

    material.setColor(“Color”, ColorRGBA.Blue);

    material.setFloat(“Radius”, 10.0f);

    material.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Front);

    offBox = new Geometry(“box”, boxMesh);

    offBox.setMaterial(material);



    offNode = new Node();

    offNode.attachChild(offBox);



    AmbientLight light = new AmbientLight();

    light.setColor(ColorRGBA.Blue);



    offNode.addLight(light);

    // attach the scene to the viewport to be rendered

    offView.attachScene(offNode);

    offNode.updateGeometricState();

    offTexture = offTex;

    }



    @Override

    public void simpleInitApp() {

    cam.setLocation(new Vector3f(3, 3, 3));

    cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);

    flyCam.setMoveSpeed(10f);



    viewPort.setBackgroundColor(ColorRGBA.LightGray);



    // Generate off screen texture.

    setupOffscreenView();



    // Draw 1st Quad with offTexture as Texture

    Geometry quad = new Geometry(“box”, new Box(Vector3f.ZERO, 5, 5, 5));

    Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

    mat.setTexture(“ColorMap”, offTexture);

    quad.setMaterial(mat);



    // Draw 2nd Quad with cloned box from OffScreenSetup

    Geometry quad2 = offBox.clone();

    quad2.setLocalTranslation(new Vector3f(0, 3, 0));



    // Draw 3rd Quad using noise shader.

    Box box = new Box(Vector3f.ZERO, 15, 15, 15);

    Geometry quad3 = new Geometry(“skybox”, box);

    Material boxMat = assetManager.loadMaterial(“Materials/Sky/ProcSkyBox.j3m”);

    boxMat.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Front);

    boxMat.setColor(“Color”, ColorRGBA.randomColor());

    boxMat.setFloat(“Radius”, 20);

    quad3.setMaterial(boxMat);



    // Make skybox using offTexture

    Texture test = offTexture.clone();



    Spatial skybox = SkyFactory.createSky(assetManager,

    test,

    test,

    test,

    test,

    test,

    test);



    rootNode.attachChild(quad);

    rootNode.attachChild(skybox);

    rootNode.attachChild(quad2);

    rootNode.attachChild(quad3);



    inputManager.addMapping(TOGGLE_UPDATE, new KeyTrigger(KeyInput.KEY_SPACE));

    inputManager.addListener(this, TOGGLE_UPDATE);

    }



    @Override

    public void simpleUpdate(float tpf){

    }



    @Override

    public void onAction(String name, boolean isPressed, float tpf) {

    if (name.equals(TOGGLE_UPDATE) && isPressed) {

    offView.setEnabled(!offView.isEnabled());

    }

    }

    }

    [/java]



    The only missing thing here is the shader itself.