Slow model clones ...( CloneImportExport )

Hi, I have to fill a terrain with lods of models(trees). The models are described in a tileset and the mapdescription holds the info where which tree is set. I decided to first load one instance of every model and then cloning them using CloneImportExport. But the whole loading is still a bit slow. Anyone has an idea how to speed it up?

One thing i saw is that he always tries to reach the textures . Maybe this is the reason why its slow because he tries to load every texture again for every clone?



This is my current code to load/clone:


private void fillTerrainWithModels(
         Node rootNode, Tileset tileset, GTerrain terrain) throws IOException,
         URISyntaxException
   {
      TilesetModels tilesetModels = readModelsFromTileset(tileset);

      for (int y = 0; y < terrain.getHeight(); y++)
      {
         for (int x = 0; x < terrain.getWidth(); x++)
         {
            int i = terrain.getObjects()[y * terrain.getWidth() + x];
            if (i != 0)
            {
               Node node = tilesetModels.getNodeForNumber(i - 1);
               if (node != null)
               {
                  Node newNode = getCloneNode(node);
                  newNode.setLocalTranslation(new Vector3f(x
                        - terrain.getWidth() / 2,
                        terrain.getAltFactor()
                              * terrain.getTerrainHeight()[y
                                    * terrain.getWidth() + x], y
                              - terrain.getHeight() / 2));
                  newNode.lock();
                  rootNode.attachChild(newNode);
               }
            }
         }
      }
   }


   CloneImportExport ie = new CloneImportExport();

   private Node getCloneNode(Node node)
   {
      ie.saveClone(node);
      Node nodeneu = (Node) ie.loadClone();
      return nodeneu;
   }



SharedNode,SharedMesh



Spawning them delayed on a frame basis would be another idea, so the basially flop up a bit delayed.

Is there a reason for needing to clone rather than using something like sharedmesh?

yes there is a reason … I'm a noob  ://

Thanks a lot for the replies! Its not much faster now, but I think much better :slight_smile: .

I think I will try to speed up this later by loading them if they are needed,framebased  or whatever.













…I fear I will have some other beginners questions soon …






I use a precacher for the models, and load every model needed at the beginning, then just use SharedNodes to repliate them when atually needed in world. (Kinda long laoding, but then ti works without problems, Idea here would be a loading screen showing progress ("Precaching cookie.mdl"))

precaching is what I do to here:



TilesetModels tilesetModels = readModelsFromTileset(tileset);



But after this I have to populate my world with lots of SharedNodes and this takes some time. Its ok for now (5 seconds), but there will be other things to load too before the game starts. I will go on now.  If its to slow It can be optimized later.

Thats why i say a loading screen with a visible progress, 10 seconds waiting when you see something happens is shorter than 5 looking at a black window saying no response in title ^^




package de.empirephoenix.nh.client;

import com.acarter.scenemonitor.SceneMonitor;
import com.jme.image.Image;
import com.jme.image.Texture;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.renderer.pass.Pass;
import com.jme.scene.Node;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;
import com.jmex.angelfont.BitmapFont;
import com.jmex.angelfont.BitmapFontLoader;
import com.jmex.angelfont.BitmapText;
import com.jmex.angelfont.Rectangle;

public class LoadingScreen extends Pass {
   private static final long serialVersionUID = 1L;
   private static LoadingScreen myself;
   private Node rootnode;
   private Quad backgroundnode;
   private DisplaySystem display;
   private BitmapText txt;
   private BlendState blendstate;
   
   
   LoadingScreen(){
      this.display = DisplaySystem.getDisplaySystem();
      this.rootnode = new Node();
      rootnode.setRenderQueueMode(Renderer.QUEUE_ORTHO);
      
      this.backgroundnode = new Quad("Background",Settings.Get().getResolutionx(),Settings.Get().getResolutiony());
      this.backgroundnode.setLocalTranslation(Settings.Get().getResolutionx()/2f,Settings.Get().getResolutiony()/2f,0);
      

      rootnode.attachChild(backgroundnode);
      rootnode.setName("LoadingScreen");
      if(Settings.Get().isDebug()){
         SceneMonitor.getMonitor().registerNode(rootnode);
      }
      blendstate = display.getRenderer().createBlendState();
      
      rootnode.setRenderState(blendstate);
      
      TextureState initialbackground = display.getRenderer().createTextureState();
      initialbackground.setTexture(TextureManager.loadTexture(LoadingScreen.class.getClassLoader().getResource("de/empirephoenix/nh/client/loadingscreens/LoadingScreen_01.png"),Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear, Image.Format.RGBA8,0.0f, true));
      initialbackground.setEnabled(true);
      this.SetBackground(initialbackground);
      
      BitmapFont fnt = BitmapFontLoader.loadDefaultFont();
      txt = new BitmapText(fnt, false);
       txt.setBox(new Rectangle(0,display.getHeight()/2,display.getWidth(),-display.getHeight()));
       txt.setSize(32);
       txt.setDefaultColor(ColorRGBA.blue);
       rootnode.attachChild(txt);
       txt.setText("Initializing");
        txt.update();
   }
   
   public void SetInfo(String info){
      System.out.println(info);
      txt.setText(info);
         txt.update();
         LoadingScreen.Get().renderPass(display.getRenderer());
         display.getRenderer().displayBackBuffer();
   }
   
   public static LoadingScreen Get(){
      if(myself == null){
         myself = new LoadingScreen();
      }
      return myself;
   }
   
   public void SetBackground(TextureState background){
      backgroundnode.setRenderState(background);
      this.rootnode.updateRenderState();
   }
   
   @Override
   protected void doRender(Renderer r) {
      this.rootnode.updateGeometricState(1,true);
      
      CameraController.Get().setLocalTranslation(new Vector3f(0,0,0));
      CameraController.Get().setLocalRotation(new Quaternion());
      CameraController.Get().updateGeometricState(1,true);
      
      r.clearBuffers();
      r.draw(this.rootnode);
   }
   
   @Override
   protected void doUpdate(float interpolation) {
      assert false:"Update Called in LoadingScreen";
   }

}



Just create it and only use setinfo after setting a background and it will work.