Changing sphere coordinates after GeometryBatchFactory.optimize(node)

How can i change the positions of geometries/spheres after optimizations? Without optimizations, fps drops to 0-1 fps for 16k spheres.

(already tried BatchNode.batch() but did not get any performance)

Usual example:

http://i45.tinypic.com/2j0xkr8.jpg





Optimized example:

http://i50.tinypic.com/24e8az4.jpg



Unoptimized example:

http://i50.tinypic.com/11sp11t.jpg



BatchNode-Optimized example:

http://i48.tinypic.com/rc6gpz.jpg

I can’t see the pictures (at work)



You can update the mesh buffers for GeometryBatchFactory, I guess searching for voxels will help u there.



For Batch Node, you should be able to move them, just call batch afterwards.



Although i don’t really use these optimisations, so someone may have better advice.

You mean node-coordinates as mesh buffers or each voxel coordinates?

Already tried batchnode but did not increase . I need to update the spheres’ coordinates before the transformation for the vertices’ coordinates.

@wezrule said:
I can't see the pictures (at work)

You can update the mesh buffers for GeometryBatchFactory, I guess searching for voxels will help u there.

For Batch Node, you should be able to move them, just call batch afterwards.

Although i don't really use these optimisations, so someone may have better advice.

@tugrul said:
Already tried batchnode but did not increase . I need to update the spheres' coordinates before the transformation for the vertices' coordinates.

The BatchNode is made for situations where you want to move single geometry items in the batch. You do not need to re-batch it for that to work and it should work for your use case. Make sure you use the latest version of the SDK (RC2) and if the objects do not batch, make sure they have the same material.

All spheres have same material but different geometries . I also tried single node with 16k geometries that gave %50 improvement but still not enough(factory gives %1000 without any translation permission)

@tugrul said:
All spheres have same material but different geometries . I also tried single node with 16k geometries that gave %50 improvement but still not enough(factory gives %1000 without any translation permission)

Its strange that a normal node gives that kind of improvement, if you mean a BatchNode it should be in the range of the GeometryBatchFactory as it effectively does the same. You seem to be using it wrong then, make sure you read the javadoc of BatchNode. Whats it you want to do anyway? Given you want to use so many objects your approach should be different I guess. If this is some kind of "performance test" it makes no sense. 16k spheres on one screen are tiny so you should replace them with particles or impostors if they are all visible.

I tried using only 1 geometry for 16k nodes but only 1 sphere is drawn. Tried 16k nodes each having different geometry gives 11 fps with BatchNode. 1 node with 16k geometries gives 16 fps with BatchNode. (i reduced sphere resolution to 5x5 from 16x16 for this reply)

Again, if it performs much different than the GeometryBatchFactory you did not batch the geometries. You can see the object count in the camera in the lower right. Please read the javadoc and manual.

did you call batch() on the batchnode?

Yes, i called batch(). I am total noob about opengl but im sure there must be a way to send thousands of spheres’ center coordinates to gpu and make gpu calculate gigabytes of data. I am using pci-e with mode 2.0 (maybe only 5 GB/s so its not enough (only 1 fps) ). Thanks for replies.

@tugrul said:
Yes, i called batch(). I am total noob about opengl but im sure there must be a way to send thousands of spheres' center coordinates to gpu and make gpu calculate gigabytes of data. I am using pci-e with mode 2.0 (maybe only 5 GB/s so its not enough (only 1 fps) )


Instancing, Geometry Shader... but still no magic..
You are still drawing ~3mio triangles it does not matter if you batch/optimize or do something...
@zzuegg said:
Instancing, Geometry Shader... but still no magic..
You are still drawing ~3mio triangles it does not matter if you batch/optimize or do something...

He gets the desired performance with the batch factory, so its not the triangles.

@tugrul: Because you are a noob I try to help you but you don't react to anything I say. I shall explicitly ask you a question now, if that doesn't work I'm out. Does your object count decrease the same way as with the geometry batch factory when you use the batch node?
@normen said:
Because you are a noob I try to help you but you don't react to anything I say. I shall explicitly ask you a question now, if that doesn't work I'm out. Does your object count decrease the same way as with the geometry batch factory when you use the batch node?


In the pics above:

unoptimized: 49174 objects
batch: 166 objects
optimize: 19 objects

All in all, there is no advice which would make the above scene render at high frames easily. Too many verts.

Object count decreases by %99.999 when optimized. 10 of the objects must be the fps/triangle indicators. %99 decrease with batchNode.

BatchNode should batch exactly the same as GeometryBatchFactory. If it doesn’t there is something wrong either in your code either in mine.

Post your test case please.



Also with that amount of geometry you should make several sub batches. like make 8 batches of 2K geoms. You’ll have 8 objects in the scene and you’ll be able to move each sphere individually.

I noticed something similar… =S



I get better performance by using GeometryBatchFactory.optimize() instead of cube batchNode.batch() on 40x40 cubes in the deferred shading demo… I have not traced through the code, so I don’t have any guess on what is wrong :confused:

[java]package a_deneme;

/*

  • Copyright © 2009-2012 jMonkeyEngine
  • All rights reserved.

    *
  • Redistribution and use in source and binary forms, with or without
  • modification, are permitted provided that the following conditions are
  • met:

    *
    • Redistributions of source code must retain the above copyright
  • notice, this list of conditions and the following disclaimer.

    *
    • Redistributions in binary form must reproduce the above copyright
  • notice, this list of conditions and the following disclaimer in the
  • documentation and/or other materials provided with the distribution.

    *
    • Neither the name of ‘jMonkeyEngine’ nor the names of its contributors
  • may be used to endorse or promote products derived from this software
  • without specific prior written permission.

    *
  • THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  • "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  • TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  • PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  • CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  • EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  • PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  • PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  • LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  • NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  • SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    /



    /


    Copyright © 2010-2011, Advanced Micro Devices, Inc.

    All rights reserved.



    Redistribution and use in source and binary forms, with or without modification, are permitted provided that the

    following conditions are met:



    Redistributions of source code must retain the above copyright notice, this list of conditions and the following

    disclaimer.



    Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following

    disclaimer in the documentation and/or other materials provided with the distribution.



    Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products

    derived from this software without specific prior written permission.



    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,

    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR

    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,

    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.



    If you use the software (in whole or in part), you shall adhere to all applicable U.S., European, and other export

    laws, including but not limited to the U.S. Export Administration Regulations (“EAR”), (15 C.F.R. Sections 730 through

    774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR,

    you hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of

    Industry and Security or as otherwise permitted pursuant to a License Exception under the U.S. Export Administration

    Regulations (“EAR”), you will not (1) export, re-export or release to a national of a country in Country Groups D:1,

    E:1 or E:2 any restricted technology, software, or source code you receive hereunder, or (2) export to Country Groups

    D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject

    to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774

    of EAR). For the most current Country Group listings, or for additional information about the EAR or your obligations

    under those regulations, please refer to the U.S. Bureau of Industry and Security’s website at http://www.bis.doc.gov/.



    /





    import java.awt.GraphicsDevice;

    import java.awt.GraphicsEnvironment;

    import java.util.ArrayList;

    import java.util.concurrent.ScheduledThreadPoolExecutor;



    import javax.media.j3d.SharedGroup;



    import jme3tools.optimize.GeometryBatchFactory;



    import com.jme3.scene.
    ;

    import com.amd.aparapi.Kernel;

    import com.amd.aparapi.Range;



    import com.jme3.app.SimpleApplication;

    import com.jme3.effect.Particle;



    import com.jme3.light.AmbientLight;

    import com.jme3.light.DirectionalLight;

    import com.jme3.light.PointLight;



    import com.jme3.material.Material;

    import com.jme3.material.RenderState.BlendMode;

    import com.jme3.math.ColorRGBA;

    import com.jme3.math.Quaternion;

    import com.jme3.math.Vector3f;



    import com.jme3.renderer.RenderManager;

    import com.jme3.renderer.queue.RenderQueue;

    import com.jme3.renderer.queue.RenderQueue.ShadowMode;

    import com.jme3.scene.BatchNode;

    import com.jme3.scene.Geometry;

    import com.jme3.scene.Mesh.Mode;

    import com.jme3.scene.Node;

    import com.jme3.scene.Spatial.BatchHint;

    import com.jme3.scene.Spatial.CullHint;



    import com.jme3.scene.control.Control;

    import com.jme3.scene.shape.Sphere;



    import com.jme3.shader.Shader;

    import com.jme3.shadow.PointLightShadowRenderer;

    import com.jme3.shadow.PssmShadowRenderer;

    import com.jme3.shadow.PssmShadowRenderer.CompareMode;



    import com.jme3.system.AppSettings;



    import com.jme3.util.TangentBinormalGenerator;







    public class jmonkey_dene2 extends SimpleApplication{



    int adet = 81922;

    float xyz2[]=new float[adet
    3];

    int R2[]=new int[adet3+3];

    class calistir extends Thread

    {

    final int secim=1000;



    public void run()

    {

    final int[] secim = new int[adet];

    float kmx=0,kmy=0;



    final float[] xyz=new float[adet
    3+3];

    final int[]R=new int[adet3+3];

    final int[]M=new int[adet
    3+3];

    final int[] bag_indisleri=new int[adet16];

    final float[] bag_uzunlugu=new float[adet
    16];

    final boolean[]bag_var_mi=new boolean[adet];

    final int[]bag_sayisi=new int[adet]; //en fazla 16 bag



    final float mass=1;

    final float delT=0.03f;

    final float espSqr=1f;



    final float[] vxyz=new float[adet3+3];





    Kernel kutleler = new Kernel()

    {

    int adetx=adet;



    final float [] accx = new float[adet];

    final float [] accy = new float[adet];

    final float [] accz = new float[adet];



    @Override

    public void run()

    {





    @Local int body = getGlobalId();

    @Local int count = adetx * 3;

    @Local int globalId = body * 3;

    @Local float accx = 0.f;

    @Local float accy = 0.f;

    @Local float accz = 0.f;







    @Local float myPosx = xyz[globalId + 0];

    @Local float myPosy = xyz[globalId + 1];

    @Local float myPosz = xyz[globalId + 2];

    @Local int hedef=0;

    @Local int sayisi=0;

    @Local float uzunluk=0;

    @Local float dx=0;

    @Local float dy=0;

    @Local float dz=0;

    @Local float invDist=0;

    @Local float s=0;

    @Local float xx=0;

    @Local float yy=0;

    @Local float zz=0;



    float msf=0;

    for (int i = 0; i < count; i += 3)

    {

    float m2=M[body]+M[i/3];

    dx = xyz - myPosx;

    dy = xyz - myPosy;

    dz = xyz - myPosz;

    msf=sqrt(dx
    dx+dydy+dzdz+1f)-(R[body]+R[i/3]);

    invDist = rsqrt((dx * dx) + (dy * dy) + (dz * dz) + 0.1f);

    s = m2invDist * invDist * invDist60.19f;





    accx = accx + s * dx;

    accy = accy + s * dy;

    accz = accz + s * dz;



    if(msf<0)

    {

    accx = accx - 0.0010fdxpow(abs(msf),4.8f);

    accy = accy - 0.0010fdypow(abs(msf),4.8f);

    accz = accz - 0.0010fdzpow(abs(msf),4.8f);

    }



    }







    accx = accx * delT;

    accy = accy * delT;

    accz = accz * delT;

    /

    vxyz[globalId + 0] = vxyz[globalId + 0]0.9997f;

    vxyz[globalId + 1] = vxyz[globalId + 1]0.9997f;

    vxyz[globalId + 2] = vxyz[globalId + 2]0.9997f;

    /





    vxyz[globalId + 0] = vxyz[globalId + 0]+ accx/M[body];

    vxyz[globalId + 1] = vxyz[globalId + 1] + accy/M[body];

    vxyz[globalId + 2] = vxyz[globalId + 2] + accz/M[body];



    }

    };





    Kernel kutleler2 = new Kernel()

    {

    int adetx=adet;





    @Override

    public void run()

    {

    int body = getGlobalId();

    int count = adetx * 3;

    int globalId = body * 3;



    xyz[globalId + 0] = xyz[globalId + 0] + vxyz[globalId + 0] * delT;

    xyz[globalId + 1] = xyz[globalId + 1] + vxyz[globalId + 1] * delT;

    xyz[globalId + 2] = xyz[globalId + 2]+ vxyz[globalId + 2] * delT;











    }

    };















    int gg=0,hh=0,jj=0;

    for(int ind=0;ind<adet;ind++)

    {

    gg++;

    if(gg>Math.pow(adet,0.33f)){gg=0;hh++;}

    if(hh>Math.pow(adet,0.33f)){hh=0;gg=0;jj++;}



    vxyz[ind
    3]=(float)(0);

    vxyz[ind
    3+1]=(float)(0);

    vxyz[ind
    3+2]=(float)(0);

    if(ind<(adet-1))

    {

    R[ind]=15;R2[ind]=15;

    M[ind]=1;

    xyz[ind
    3]=(float)(gg
    25);

    xyz[ind3+1]=(float)(hh25+400);

    xyz[ind3+2]=(float)(jj25+400);

    }

    else

    {

    R[ind]=75;R2[ind]=75;

    M[ind]=1000;

    xyz[ind3]=(float)(1600);

    xyz[ind
    3+1]=(float)(0);

    xyz[ind3+2]=(float)(0);

    }





    }

    for(int say=0;say<500;say++)

    {

    System.out.println(500-say);

    for(int ii=0;ii<1;ii++)

    {

    kutleler.execute(Range.create(adet));

    kutleler2.execute(Range.create(adet));



    }

    for(int zzz=0;zzz<adet;zzz++)

    {

    xyz2[zzz
    3]=xyz[zzz3];

    xyz2[zzz
    3+1]=xyz[zzz3+1];

    xyz2[zzz
    3+2]=xyz[zzz*3+2];



    }

    try {

    Thread.sleep(5);

    } catch (InterruptedException e) {



    e.printStackTrace();

    }



    }



    kutleler.dispose();

    kutleler2.dispose();



    System.out.println(“program bitti”);

    }



    }



    float xx=0,yy=0,zz=0;







    public static void main(String[] args){

    //Logger.getLogger("").setLevel(Level.SEVERE);

    //AppSettings settings = new AppSettings(true);

    jmonkey_dene2 app = new jmonkey_dene2();

    // app.setSettings(settings);

    // settings.setRenderer(AppSettings.LWJGL_OPENGL_ANY);



    app.start();

    }



    calistir aaa=new calistir();

    Mode mm;



    Geometry[] geo=new Geometry[adet];





    Node[]n=new Node[adet];







    PointLight sun = new PointLight();

    AmbientLight sun2 = new AmbientLight();



    // private PssmShadowRenderer bsr;

    private PointLightShadowRenderer psr;



    Sphere sphr=new Sphere(5,5,(float)((float)15/10f));

    Sphere sphr2=new Sphere(64,64,(float)((float)75/10f));



    BatchNode batchNode = new BatchNode(“zzz”);



    Node nx = new Node();



    @Override

    public void simpleInitApp() {







    // bsr = new PssmShadowRenderer(assetManager, 1024,1);

    psr = new PointLightShadowRenderer(assetManager,4096);



    psr.setCompareMode(PointLightShadowRenderer.CompareMode.Hardware);

    psr.setLight(sun);

    psr.setShadowIntensity(0.8f);

    sun.setRadius(1000f);

    sun2.setColor(ColorRGBA.Red);



    // bsr.setCompareMode(CompareMode.Hardware);

    // bsr.setDirection(new Vector3f(0f,0.1f,1f).normalizeLocal()); // light direction



    // bsr.setShadowIntensity(1f);

    // viewPort.addProcessor(bsr);



    viewPort.addProcessor(psr);











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





    mat.setTexture(“DiffuseMap”, assetManager.loadTexture(“Textures/Terrain/Pond/Pond.jpg”));



    mat.setTexture(“NormalMap”, assetManager.loadTexture(“Textures/Terrain/Pond/Pond_normal.png”));

    mat.setBoolean(“UseMaterialColors”,true);

    mat.setColor(“Specular”,ColorRGBA.White);

    mat.setColor(“Diffuse”,ColorRGBA.White);

    mat.setBoolean(“LowQuality”,true);

    mat.setColor(“Ambient”, ColorRGBA.White);

    mat.setFloat(“Shininess”, 22f); // [1,128]

    mat.setBoolean(“HardwareShadows”, true);





    sun.setColor(ColorRGBA.White);





    // sun.setDirection(new Vector3f(0f,0.1f,1f));

    sun.setPosition(new Vector3f(80,-80,-20));





    rootNode.addLight(sun);

    rootNode.addLight(sun2);



    rootNode.setShadowMode(ShadowMode.CastAndReceive);



    aaa.start();



    TangentBinormalGenerator.generate(sphr);

    TangentBinormalGenerator.generate(sphr2);

    rootNode.setShadowMode(ShadowMode.CastAndReceive);

    sphr.setTextureMode(Sphere.TextureMode.Projected); // better quality on spheres

    sphr2.setTextureMode(Sphere.TextureMode.Projected); // better quality on spheres









    for(int i=0;i<adet;i++)

    {



    n=new Node();





    if(i<(adet-1))

    {

    geo = new Geometry(“Sphere”, sphr);

    geo.scale(1);

    //geo.setLocalRotation(new Quaternion(Math.random(),2,3) );

    }

    else

    {

    geo = new Geometry(“Sphere”, sphr);

    geo.scale(5);

    }



    geo.setMaterial(mat);



    //////// batchNode.attachChild(geo);

    batchNode.attachChild(geo);

    ///n[0].setShadowMode(ShadowMode.CastAndReceive);





    //n.rotate((float) (Math.random()2f3f), (float) (Math.random()2f3f), (float) (Math.random()2f3f));





    // batchNode.attachChild(n[0]);



    }

    // batchNode.attachChild(n[0]);

    // GeometryBatchFactory.optimize(n[0]);

    // rootNode.attachChild(n[0]);









    batchNode.batch();

    batchNode.setShadowMode(ShadowMode.CastAndReceive);



    rootNode.attachChild(batchNode);





    flyCam.setMoveSpeed(10);









    }

    float aci=0;

    int say2=0;





    @Override

    public void simpleUpdate(float tpf) {



    Vector3f v3=new Vector3f();



    say2++;





    for(int i=0;i<adet;i++)

    {

    v3.x=xyz2[i*3]/10f;

    v3.y=xyz2[i*3+1]/10f;

    v3.z=xyz2[i*3+2]/10f;





    ///n.setLocalTranslation(v3);

    geo.setLocalTranslation(v3);





    }



    // batchNode.forceRefresh(true, true, true);

    //batchNode.updateGeometricState();

    if(say2==1)

    {



    // batchNode=(BatchNode) GeometryBatchFactory.optimize(batchNode);

    //batchNode.batch();

    }







    }



    @Override

    public void simpleRender(RenderManager rm) {





    // rm.setUsingShaders(true);





    }

    }[/java]



    Please help! Thanks.

Thats not a test case but anyway you move all the objects, that explains the difference between BatchNode and Factory. So its probably the changing of the vertex positions, thats basically animation. Like nehon said, try to sub-batch the scene. And still, I don’t see how you could possibly get all those on one screen while having each so large that a full texture and mesh is necessary, you should optimize the way I indicated before.

Okay made n[0],n[1],n[2] and n[3] as sub nodes under batchNode. Same performance as single node.