Author Topic: Dynamically addTriangles  (Read 3492 times)

Offline cnasich

  • byte
  • *
  • Posts: 8
    • View Profile
Dynamically addTriangles
« on: March 17, 2014, 08:23:28 pm »
Hi. I write a software for satellital guidance for farm equipment. The software must record and display the track of the machine (with GPS data).
The software is in the start yet.
The issue is the slower refresh when add 1000 or more triangles. But I need add 200000 triangles at least.

Code: [Select]
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;

import java.lang.reflect.Field;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;

import com.threed.jpct.*;
import com.threed.jpct.util.*;


public class MainActivity extends Activity {
   
   // Used to handle pause and resume...
   private static MainActivity master = null;

   private GLView mGLView;
   private TextView tv;
   private ImageButton bt;
   private MyRenderer renderer = null;
   private FrameBuffer fb = null;
   private World world = null;
   private RGBColor back = new RGBColor(50, 50, 100);

   private Object3D tractor = null;
   private Object3D sprayer = null;
   private Object3D floor = null;
   private Object3D track = null;
   private Object3D track2 = null;
   SimpleVector t0 = new SimpleVector(), t1 = new SimpleVector();   
   private float tractor_direction_angle = 0;
   private float turn_angle_click = 0.1f;
   private SimpleVector tractor_direction = new SimpleVector();
   final float working_width = 10;

   private Light sun = null;
   
   enum OpMode {
      ROTATE, ADD, DELETE, ZOOM
   }
   public OpMode currentMode = OpMode.ROTATE;

   private Button btIzquierda;

   private Button btDerecha;

   protected void onCreate(Bundle savedInstanceState) {

      Logger.log("onCreate");

      if (master != null) {
         copy(master);
      }

      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main); //or whatever the layout you want to use
      mGLView = (GLView) findViewById(R.id.graphics_glsurfaceview1);
      Config.useNormalsFromOBJ = true;
      Config.useRotationPivotFrom3DS = true;
     
      tv = (TextView) findViewById(R.id.textView1);
      bt = (ImageButton) findViewById(R.id.imageButton1);
      btIzquierda = (Button) findViewById(R.id.btIzquierda);
      btDerecha = (Button) findViewById(R.id.btDerecha);
      mGLView.setEGLContextClientVersion(2);
      mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() {
         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
            // Ensure that we get a 16bit framebuffer. Otherwise, we'll fall
            // back to Pixelflinger on some device (read: Samsung I7500)
            int[] attributes = new int[] { EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE };
            EGLConfig[] configs = new EGLConfig[1];
            int[] result = new int[1];
            egl.eglChooseConfig(display, attributes, configs, 1, result);
            return configs[0];
         }
         
      });
      mGLView.setEGLConfigChooser(new AAConfigChooser(mGLView));

      renderer = new MyRenderer();
      mGLView.setRenderer(renderer);
     
      tv.setText("Prueba");
   }

   @Override
   protected void onPause() {
      super.onPause();
      mGLView.onPause();
   }

   @Override
   protected void onResume() {
      super.onResume();
      mGLView.onResume();
   }

   @Override
   protected void onStop() {
      super.onStop();
   }
   
   public void OnClickDerecha(View v) {
      tractor_direction_angle += -turn_angle_click;
      tractor.rotateY(turn_angle_click);
      tractor_direction.set((float)(0.05 * Math.cos(tractor_direction_angle + (float)Math.PI / 2)), 0,
                       (float)(0.05 * Math.sin(tractor_direction_angle + (float)Math.PI / 2)));
   }

   public void OnClickIzquierda(View v) {
      tractor_direction_angle += turn_angle_click;
      tractor.rotateY(-turn_angle_click);
      tractor_direction.set((float)(0.05 * Math.cos(tractor_direction_angle + (float)Math.PI / 2)), 0,
                         (float)(0.05 * Math.sin(tractor_direction_angle + (float)Math.PI / 2)));
   }
   
   private void copy(Object src) {
      try {
         Logger.log("Copying data from master Activity!");
         Field[] fs = src.getClass().getDeclaredFields();
         for (Field f : fs) {
            f.setAccessible(true);
            f.set(this, f.get(src));
         }
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }   

   protected boolean isFullscreenOpaque() {
      return true;
   }

   class MyRenderer implements GLSurfaceView.Renderer {

      private Camera cam;

      public MyRenderer() {
      }

      public void onSurfaceChanged(GL10 gl, int w, int h) {
         Dibujar();
         if (fb != null) {
            fb.dispose();
         }
         fb = new FrameBuffer(w, h);
      }

     
      public void onSurfaceCreated(GL10 gl, EGLConfig config) {
         Dibujar();
         if (fb != null) {
            fb.dispose();
         }
      }

     
      private void Dibujar() {
         if (master == null) {

            world = new World();
            world.setAmbientLight(100, 100, 100);

            sun = new Light(world);           
            sun.setIntensity(1500, 1500, 1500);
           
            Texture tx_worked_area = new Texture(2, 2, new RGBColor(200, 10, 10));
            TextureManager.getInstance().addTexture("track", tx_worked_area);
            Texture tx_worked_area2 = new Texture(2, 2, new RGBColor(10, 200, 200));
            TextureManager.getInstance().addTexture("track2", tx_worked_area2);
            Texture tx_floor = new Texture(2, 2, new RGBColor(6, 120, 58));
            TextureManager.getInstance().addTexture("floor", tx_floor);

            tractor = Object3D.mergeAll(Loader.loadOBJ(getResources().openRawResource(R.raw.tractor_obj),
                  getResources().openRawResource(R.raw.tractor_mtl), 1.0f));
            sprayer = Object3D.mergeAll(Loader.loadOBJ(getResources().openRawResource(R.raw.fumigadora_de_arrastre_obj),
                  getResources().openRawResource(R.raw.fumigadora_de_arrastre_mtl),1.0f));
           
            floor = Primitives.getPlane(1, 10000);
            floor.rotateX((float) (90 * Math.PI / 180));
            floor.setTexture("floor");
           
            //Generate a track for testing propose
            track = new Object3D(2);
            SimpleVector v1 = new SimpleVector(), v2 = new SimpleVector(), v3 = new SimpleVector(), v4 = new SimpleVector();
            v1.set(-working_width / 2, 0, 0);
            v2.set( working_width / 2, 0, 0);
            v3.set( working_width / 2, 0, -1000);
            v4.set(-working_width / 2, 0, -1000);
            track.addTriangle(v2, 1, 0, v1, 1, 0, v3, 1, -1, TextureManager.getInstance().getTextureID("track"));
            track.addTriangle(v1, 0, 0, v4, 0, -1, v3, 1, -1, TextureManager.getInstance().getTextureID("track"));
           
            /*track2 = new Object3D(200000);
            track2.setTransparency((int)(2^12-1));
            track2.setTransparencyMode(Object3D.TRANSPARENCY_MODE_DEFAULT);
            track2.build();
            track2.compile(true, true);
            world.addObject(track2);*/
            tractor.strip();
            tractor.build();
            tractor.rotateZ((float) (180 * Math.PI / 180));
            tractor.translate(0, -tractor.getCenter().y * 2, 0);
            sprayer.build();
            sprayer.strip();
            sprayer.rotateZ((float) (180 * Math.PI / 180));
            sprayer.translate(0, -tractor.getCenter().y * 2, 0);
            floor.strip();
            floor.build();
            floor.translate(0,0,0);
            track.setTransparency((int)(2^12-1));
            track.setTransparencyMode(Object3D.TRANSPARENCY_MODE_DEFAULT);
            track.strip();
            track.build();
            track.translate(0, -0.5f, 0);
            world.addObject(tractor);
            world.addObject(sprayer);
            world.addObject(floor);
            world.addObject(track);

            cam = world.getCamera();
            cam.setPosition(0, 0, 0);
            cam.moveCamera(Camera.CAMERA_MOVEOUT, 10);
            cam.moveCamera(Camera.CAMERA_MOVEUP, 3);
            cam.lookAt(tractor.getTransformedCenter());

            SimpleVector sv = new SimpleVector();

            sv.x = 4000;
            sv.y = -4000;
            sv.z = 4000;
            sun.setPosition(sv);
            t0 = tractor.getTransformedCenter();
            t1 = tractor.getTransformedCenter();
           
            MemoryHelper.compact();

            if (master == null) {
               Logger.log("Saving master Activity!");
               master = MainActivity.this;
            }
         }
      }
     
     
      Matrix rotationmatrix, transformMatrix;
      SimpleVector camera_axis = new SimpleVector();
      SimpleVector v0 = new SimpleVector(), v1 = new SimpleVector(), v2 = new SimpleVector();
      int i = 0;
      boolean right_triangle = false;
     
      public void onDrawFrame(GL10 gl) {   
         camera_axis.set(0, 0, mGLView.touchTurnUp);
         
         if (mGLView.touchTurn != 0) {
            mGLView.touchTurn = 0;
         }
         if (mGLView.touchTurnUp != 0) {
            mGLView.touchTurnUp = 0;
         }
         tractor.translate(tractor_direction);
         
         
         SimpleVector t2 = tractor.getTransformedCenter();
         if (!t0.equals(t1) && !t1.equals(t2) && !t2.equals(t0)) {
            Object3D g = new Object3D(1);
            v0.set(v1);
            v1.set(v2);
            if (right_triangle) {
               v2.set(working_width / 2, 0, 0);
               v2.rotateY(tractor_direction_angle);
               v2.set(v2.calcAdd(t2));
            }
            else {
               v2.set(-working_width / 2, 0, 0);
               v2.rotateY(tractor_direction_angle);
               v2.set(v2.calcAdd(t2));
            }
            g.addTriangle(v0, 0, 0, v1, 1, 0, v2, 1, 1, TextureManager.getInstance().getTextureID("track2"));
            if (right_triangle) g.invert();
            /*track2.addChild(g);
            track2.touch();*/
            g.build();
            g.setTransparency((int)(2^12-1));
            g.setTransparencyMode(Object3D.TRANSPARENCY_MODE_DEFAULT);
            world.addObject(g);
            right_triangle = !right_triangle;

         }
         else {
            v1.set(t2.x + working_width / 2, t2.y, t2.z);
            v0.set(t2.x - working_width / 2, t2.y, t2.z);
         }
         t0.set(t1);
         t1.set(t2);

         cam.setPositionToCenter(tractor);
         cam.align(tractor);
         cam.moveCamera(Camera.CAMERA_MOVEOUT, 10);
         cam.moveCamera(Camera.CAMERA_MOVEUP, -4);

         cam.lookAt(tractor.getTransformedCenter());
         
         fb.clear(back);
         world.renderScene(fb);
         world.draw(fb);
         fb.display();
         tv.post(new Runnable() {
           
            @Override
            public void run() {
               tv.setText("x=" + String.valueOf(t0.x) +
                  "; y=" + String.valueOf(t0.z) +
                  "; thita=" + String.valueOf(Math.toDegrees(tractor_direction_angle)) + "; Nº=" +  String.valueOf(world.getSize()));
               MemoryHelper.printMemory();
            }
         });
      }
   }

   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.main, menu);
      return true;
   }
   
   /**
    * Obtiene las cotas maximas y minimas
    * @param obj
    * @return  float[0] = x.min;
    *          float[2] = y.min;
    *          float[4] = z.min;
    *        float[1] = x.max;
    *        float[3] = y.max;
    *        float[5] = z.max
    */
   public float[] getWorldSpaceBounds(Object3D obj) {
      float[] objectSpaceBounds = obj.getMesh().getBoundingBox();
      SimpleVector mins = new SimpleVector(objectSpaceBounds[0], objectSpaceBounds[2], objectSpaceBounds[4]);
      SimpleVector maxs = new SimpleVector(objectSpaceBounds[1], objectSpaceBounds[3], objectSpaceBounds[5]);
      SimpleVector[] p = new SimpleVector[8];
      p[0] = new SimpleVector(mins.x, mins.y, maxs.z); p[1] = new SimpleVector(mins.x, mins.y, mins.z); p[2] = new SimpleVector(maxs.x, mins.y, mins.z);
      p[3] = new SimpleVector(maxs.x, mins.y, maxs.z); p[4] = new SimpleVector(maxs.x, maxs.y, mins.z);
      p[5] = new SimpleVector(maxs.x, maxs.y, maxs.z); p[6] = new SimpleVector(mins.x, maxs.y, mins.z); p[7] = new SimpleVector(mins.x, maxs.y, maxs.z);
      float minX = Float.MAX_VALUE, minY = Float.MAX_VALUE, minZ = Float.MAX_VALUE, maxX = -Float.MAX_VALUE, maxY = -Float.MAX_VALUE, maxZ = -Float.MAX_VALUE;
      for (int i = 0; i < 8; i++) {
           p[i].matMul(obj.getWorldTransformation());
           if (p[i].x < minX)
         minX = p[i].x;
           if (p[i].y < minY)
         minY = p[i].y;
           if (p[i].z < minZ)
         minZ = p[i].z;
           if (p[i].x > maxX)
         maxX = p[i].x;
           if (p[i].y > maxY)
         maxY = p[i].y;
           if (p[i].z > maxZ)
         maxZ = p[i].z;
      }
      float[] worldSpaceBounds = new float[6];
      worldSpaceBounds[0] = minX;
      worldSpaceBounds[2] = minY;
      worldSpaceBounds[4] = minZ;
      worldSpaceBounds[1] = maxX;
      worldSpaceBounds[3] = maxY;
      worldSpaceBounds[5] = maxZ;
      return worldSpaceBounds;
   }

}

How can improve the refresh?
Is a VertexController a solution to the slow refresh? How I must use it?

Thanks in advance.
Claudio Nasich

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Dynamically addTriangles
« Reply #1 on: March 17, 2014, 08:39:48 pm »
Compiling and uploading new objects take it's time...so it's no wonder that this approach is slow. You could use an IVertexController implementation to speed this up, but it might get messy...the idea is to avoid recompilation of the object, so what you do is to create an Object3D of the final size and populate it with triangles. The ones that can't be seen have to have coordinates that are out of sight and if you would add a new triangle, you use the IVertexController instead to move it into view. On the plus side, this will make the updates faster. The negative side is that you render all triangles right from the beginning. They might not be visible, but it takes time to determine that, so it will slow down the process. Apart from that, it's hacky...

Anyway, 2,000,000 triangles are a LOT for a mobile device and i somehow doubt that it's feasible to do that. So i suggest to create a test case that simulates this to see if the result is fast enough (and fits into memory) before continueing.

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Dynamically addTriangles
« Reply #2 on: March 18, 2014, 12:59:11 am »
I haven't looked into your source, Egon, but I would think that an Object3D would be nothing but an array of triangles (themselves only 4 floats) and some overhead for the name and some booleans). 2 million triangles would be only around 8 megabytes in RAM, right?

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Dynamically addTriangles
« Reply #3 on: March 18, 2014, 08:49:20 pm »
Right?

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Dynamically addTriangles
« Reply #4 on: March 18, 2014, 09:18:46 pm »
Not quite. You have to store normals, texture coordinates and maybe additional vertex attributes as well. Plus you have to keep them in main memory as well as on the gpu, which roughly doubles the space needed (that's not 100% true, but it's a pretty good approximation).

Offline cnasich

  • byte
  • *
  • Posts: 8
    • View Profile
Re: Dynamically addTriangles
« Reply #5 on: March 18, 2014, 10:41:50 pm »
Thanks Egon and AGP.
I correct you: I need 200,000 triangles, no 2,000,000. The 200,000 triangles is stored in about 8MB.
I did a test with many triangles. The refresh rate to 100,000 is ok for my application (2-4 frames per second), but is very slow loading the triangles (more than 5 minutes). I not tried more.
I´ll try to split the load to work in threads.

Egon, following your suggestion, I tried using a GenericVertexController, but the triangles are not moving.
To be safe, I first put the triangles in a visible place and then move to the position that they should be as the machine moves.
The GenericVertexController class is RepositionVertexes.

Code: [Select]
public class MainActivity extends Activity {

// Used to handle pause and resume...
private static MainActivity master = null;

private GLView mGLView;
private TextView tv;
private ImageButton bt;
private MyRenderer renderer = null;
private FrameBuffer fb = null;
private World world = null;
private RGBColor back = new RGBColor(50, 50, 100);

private Object3D tractor = null;
private Object3D sprayer = null;
private Object3D floor = null;
private Object3D track = null;
private Object3D track2 = null;
public RepositionVertexes RepositionVertexes_ = new RepositionVertexes();
static SimpleVector t0 = new SimpleVector();
static SimpleVector t1 = new SimpleVector();
static SimpleVector t2 = new SimpleVector();
private float tractor_direction_angle = 0;
private float turn_angle_click = 0.1f;
private SimpleVector tractor_direction = new SimpleVector();
final float working_width = 10;

private Light sun = null;

enum OpMode {
ROTATE, ADD, DELETE, ZOOM
}
public OpMode currentMode = OpMode.ROTATE;

private Button btIzquierda;

private Button btDerecha;

protected void onCreate(Bundle savedInstanceState) {

Logger.log("onCreate");

if (master != null) {
copy(master);
}

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); //or whatever the layout you want to use
mGLView = (GLView) findViewById(R.id.graphics_glsurfaceview1);
Config.useNormalsFromOBJ = true;
Config.useRotationPivotFrom3DS = true;

tv = (TextView) findViewById(R.id.textView1);
bt = (ImageButton) findViewById(R.id.imageButton1);
btIzquierda = (Button) findViewById(R.id.btIzquierda);
btDerecha = (Button) findViewById(R.id.btDerecha);
mGLView.setEGLContextClientVersion(2);
mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() {
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
// Ensure that we get a 16bit framebuffer. Otherwise, we'll fall
// back to Pixelflinger on some device (read: Samsung I7500)
int[] attributes = new int[] { EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE };
EGLConfig[] configs = new EGLConfig[1];
int[] result = new int[1];
egl.eglChooseConfig(display, attributes, configs, 1, result);
return configs[0];
}

});
mGLView.setEGLConfigChooser(new AAConfigChooser(mGLView));

renderer = new MyRenderer();
mGLView.setRenderer(renderer);

tv.setText("Prueba");
}

@Override
protected void onPause() {
super.onPause();
mGLView.onPause();
}

@Override
protected void onResume() {
super.onResume();
mGLView.onResume();
}

@Override
protected void onStop() {
super.onStop();
}

public void OnClickDerecha(View v) {
tractor_direction_angle += -turn_angle_click;
tractor.rotateY(turn_angle_click);
tractor_direction.set((float)(0.05 * Math.cos(tractor_direction_angle + (float)Math.PI / 2)), 0,
  (float)(0.05 * Math.sin(tractor_direction_angle + (float)Math.PI / 2)));
}

public void OnClickIzquierda(View v) {
tractor_direction_angle += turn_angle_click;
tractor.rotateY(-turn_angle_click);
tractor_direction.set((float)(0.05 * Math.cos(tractor_direction_angle + (float)Math.PI / 2)), 0,
    (float)(0.05 * Math.sin(tractor_direction_angle + (float)Math.PI / 2)));
}

private void copy(Object src) {
try {
Logger.log("Copying data from master Activity!");
Field[] fs = src.getClass().getDeclaredFields();
for (Field f : fs) {
f.setAccessible(true);
f.set(this, f.get(src));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}

protected boolean isFullscreenOpaque() {
return true;
}

static class RepositionVertexes extends GenericVertexController {

/****************************************
* Move vertexes to it's final position *
****************************************/
private static final long serialVersionUID = 1L;
private SimpleVector v0 = new SimpleVector(), v1 = new SimpleVector(), v2 = new SimpleVector();
public float direction_angle, width;
public boolean right_triangle = false;
public static int i = 0;

@Override
public void apply() {
SimpleVector[] dstMesh=this.getDestinationMesh();


if (!t0.equals(t1) && !t1.equals(t2) && !t2.equals(t0)) {

v0.set(v1);
v1.set(v2);
if (right_triangle) {
v2.set(width / 2, 0, 0);
v2.rotateY(direction_angle);
v2.set(v2.calcAdd(t2));
}
else {
v2.set(-width / 2, 0, 0);
v2.rotateY(direction_angle);
v2.set(v2.calcAdd(t2));
}
dstMesh[i++].set(v0);
dstMesh[i++].set(v1);
dstMesh[i++].set(v2);

right_triangle = !right_triangle;
}
else {
v1.set(t2.x + width / 2, t2.y, t2.z);
v0.set(t2.x - width / 2, t2.y, t2.z);
}
}

}

class MyRenderer implements GLSurfaceView.Renderer {

private Camera cam;

public MyRenderer() {
}

public void onSurfaceChanged(GL10 gl, int w, int h) {
Dibujar();
if (fb != null) {
fb.dispose();
}
fb = new FrameBuffer(w, h);
}


public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Dibujar();
if (fb != null) {
fb.dispose();
}
}


private void Dibujar() {
if (master == null) {

world = new World();
world.setAmbientLight(100, 100, 100);

sun = new Light(world);
sun.setIntensity(1500, 1500, 1500);

Texture tx_worked_area = new Texture(2, 2, new RGBColor(200, 10, 10));
TextureManager.getInstance().addTexture("track", tx_worked_area);
Texture tx_worked_area2 = new Texture(2, 2, new RGBColor(10, 200, 200));
TextureManager.getInstance().addTexture("track2", tx_worked_area2);
Texture tx_floor = new Texture(2, 2, new RGBColor(6, 120, 58));
TextureManager.getInstance().addTexture("floor", tx_floor);

tractor = Object3D.mergeAll(Loader.loadOBJ(getResources().openRawResource(R.raw.tractor_obj),
getResources().openRawResource(R.raw.tractor_mtl), 1.0f));
sprayer = Object3D.mergeAll(Loader.loadOBJ(getResources().openRawResource(R.raw.fumigadora_de_arrastre_obj),
getResources().openRawResource(R.raw.fumigadora_de_arrastre_mtl),1.0f));

floor = Primitives.getPlane(1, 10000);
floor.rotateX((float) (90 * Math.PI / 180));
floor.setTexture("floor");

//Generate a track for testing propose
Log.i("Generating triangles", "Reserving space");
track = new Object3D(1000);
SimpleVector v1 = new SimpleVector(), v2 = new SimpleVector(), v3 = new SimpleVector(), v4 = new SimpleVector();
Log.i("Generating triangles", "Start populating");
for (i = 0; i < 499; i++) {
v1.set(-working_width / 2, 0, -i * 0.001f);
v2.set( working_width / 2, 0, -i * 0.001f);
v3.set( working_width / 2, 0, -i * 0.001f - 0.001f);
v4.set(-working_width / 2, 0, -i * 0.001f - 0.001f);
track.addTriangle(v2, 1, 0, v1, 1, 0, v3, 1, -1, TextureManager.getInstance().getTextureID("track"));
track.addTriangle(v1, 0, 0, v4, 0, -1, v3, 1, -1, TextureManager.getInstance().getTextureID("track"));
if (i % 100 == 0) {
//MemoryHelper.compact();
Log.i("Generating triangles", "n = " + String.valueOf(2 * i));
}
}
Log.i("Generating triangles", "End generation");

//setup track
track.setTransparency((int)(2^12-1));
track.setTransparencyMode(Object3D.TRANSPARENCY_MODE_DEFAULT);
track.strip();
track.build();
track.translate(0, -0.5f, 0);
track.getMesh().setVertexController(RepositionVertexes_, IVertexController.PRESERVE_SOURCE_MESH);
track.compile(true);
RepositionVertexes_.width = working_width;

/*track2 = new Object3D(200000);
track2.setTransparency((int)(2^12-1));
track2.setTransparencyMode(Object3D.TRANSPARENCY_MODE_DEFAULT);
track2.build();
track2.compile(true, true);
world.addObject(track2);*/
tractor.strip();
tractor.build();
tractor.rotateZ((float) (180 * Math.PI / 180));
tractor.translate(0, -tractor.getCenter().y * 2, 0);
sprayer.build();
sprayer.strip();
sprayer.rotateZ((float) (180 * Math.PI / 180));
sprayer.translate(0, -tractor.getCenter().y * 2, 0);
floor.strip();
floor.build();
floor.translate(0,0,0);

world.addObject(tractor);
world.addObject(sprayer);
world.addObject(floor);
world.addObject(track);

cam = world.getCamera();
cam.setPosition(0, 0, 0);
cam.moveCamera(Camera.CAMERA_MOVEOUT, 10);
cam.moveCamera(Camera.CAMERA_MOVEUP, 3);
cam.lookAt(tractor.getTransformedCenter());

SimpleVector sv = new SimpleVector();

sv.x = 4000;
sv.y = -4000;
sv.z = 4000;
sun.setPosition(sv);
t0 = tractor.getTransformedCenter();
t1 = tractor.getTransformedCenter();

MemoryHelper.compact();

if (master == null) {
Logger.log("Saving master Activity!");
master = MainActivity.this;
}
}
}


Matrix rotationmatrix, transformMatrix;
SimpleVector camera_axis = new SimpleVector();
//SimpleVector v0 = new SimpleVector(), v1 = new SimpleVector(), v2 = new SimpleVector();
int i = 0;
boolean right_triangle = false;

public void onDrawFrame(GL10 gl) {
camera_axis.set(0, 0, mGLView.touchTurnUp);

if (mGLView.touchTurn != 0) {
mGLView.touchTurn = 0;
}
if (mGLView.touchTurnUp != 0) {
mGLView.touchTurnUp = 0;
}
tractor.translate(tractor_direction);


t2 = tractor.getTransformedCenter();
RepositionVertexes_.direction_angle = tractor_direction_angle;

track.getMesh().applyVertexController();
track.touch();
t0.set(t1);
t1.set(t2);

cam.setPositionToCenter(tractor);
cam.align(tractor);
cam.moveCamera(Camera.CAMERA_MOVEOUT, 10);
cam.moveCamera(Camera.CAMERA_MOVEUP, -4);

cam.lookAt(tractor.getTransformedCenter());

fb.clear(back);
world.renderScene(fb);
world.draw(fb);
fb.display();
tv.post(new Runnable() {

@Override
public void run() {
tv.setText("x=" + String.valueOf(t0.x) +
"; y=" + String.valueOf(t0.z) +
"; thita=" + String.valueOf(Math.toDegrees(tractor_direction_angle)));
MemoryHelper.printMemory();
}
});
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}

I think I'm misusing the GenericVertexController, but not know how to use it properly.

Can you post a complete code for using GenericVertexController?
« Last Edit: March 18, 2014, 10:45:36 pm by cnasich »

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Dynamically addTriangles
« Reply #6 on: March 19, 2014, 03:41:43 am »
The fourth float was the normal. Anyway, my arithmetic was wrong: I figured 2 million * 4 instead of 2 million * 4 * 3 (3 bytes per float). So it would've been 24 MB. And you're saying it's closer to 48 MB. 200k, though, should be only 4.8 MB even by Egon's x2 rule.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Dynamically addTriangles
« Reply #7 on: March 19, 2014, 07:43:39 am »
The fourth float was the normal.
A normal is 3-dimensional vector. You can't store it in a single component.

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Dynamically addTriangles
« Reply #8 on: March 19, 2014, 09:39:52 am »
I meant the fourth vector. But there's another 3 I neglected to put in (4*3)*3(3 bytes per float, 3 floats per vector)*number of triangles, more or less x2 (according to you). So, around 14 MB for 200k, right?
« Last Edit: March 19, 2014, 10:16:39 am by AGP »

Offline cnasich

  • byte
  • *
  • Posts: 8
    • View Profile
Re: Dynamically addTriangles
« Reply #9 on: March 19, 2014, 09:37:59 pm »
Thanks Egon and AGP.
I find my problem.
I did not know the order: setVertecController, compile and build.

PD: a float is 4 bytes long in Java. A triangle have:
- 3 vectors -> 3 * 3 * 4 = 36 bytes.
- 1 normal -> 1 * 3 * 4 = 12 bytes.
- 6 texture 2D coordinates (2 each vertex) -> 6 * 4 = 24 bytes.
- 1 texture ID -> 2 bytes (I suppose).
Total for a triangle = 36 + 12 + 24 + 2 = 74
Total size in memory for 200k triangles = 200,000 * 74 = 14,800,000 bytes = 14.1 MB
Missed I some thing?