Rotate a 2d circle around my Object3D

Started by shailevy, February 24, 2014, 05:04:49 PM

Previous topic - Next topic

shailevy

Hi,

I'm working on an app that uses gesture to manipulate a 3d model using JPCT-AE. I want to wrap around the model (Object3D) 3 circles representing each axis that will move and rotate with the object.

It should look similar to this (Circles around the model):


I'm assuming the best approach will be to draw the circles using PolyLines so I wrote a small function that accepts a radius, number of points in the circle, center.
Or:
   SimpleVector[] MakeCircle2d(float rad, int points,
         SimpleVector center) {..}

I create and Polyline from those points I got.
The next steps will be to modify (rotate) the list of points so I can create 2 more polylines that will 2 more circles (rotates on X,Y,Z).
I can't attach a polyline as a child object so on every transformation I will need to recalculate and display the new circles.

I'm kind of struggling here so I'm start to doubt my approach:
1. Do you feel I'm taking the correct approach ? if not what do you suggest ?
2. What would be the correct/efficient  way to rotate the array of SimpleVector around my model ?
3.  What would be the correct/efficient way to create 2 more circles from the original array of SimpleVector (or should I modify my function to return 3 array's .. 1 for each circle)


EgonOlsen

Polyline come closest to what you have in mind. If you don't to recreate them all the time, why don't you rotate the camera instead? That will keep the Polyline definition fixed and the visual result will look the same (except for lighting, which will of course rotate together with the camera).

shailevy

I might have more than one object on the screen so rotating the camera isn't a good option for me unless I'm missing something
The circles will be drawn to the object as long at is being rotated by a touch event.

I'm kind of glad I chose on the right direction but a bit sad that I can't attach a polyline as a child of an object.
Either way, I'm still a bit confused about how I should rotated the circles since it just an array of SimpleVector I need to manipulate them directly and then update the polyline.

(My next question is rather "noobish")
I guess I should loop over the array of SimpleVector and call some kind of rotate function on each. I need it to be in sync with my objects (the object won't move during the rotation).
Which rotate function you think I should use to do that ?

(btw, Is there any plan to some some kind of transformation on Polyline ?)


EgonOlsen

I can look at it tomorrow to see if adding somekind of basic rotation support is easy to do. The reason why Polyline is lacking some features that Object3D has, is because it's "just" some little helper to get some lines drawn. It was never supposed to be heavily used. However, i'll look into it...

shailevy

Thanks !! It will really help us. (I didn't find a donate button so your next beer won't be on me just yet)

I hope you will do decide to quickly enrich the Polyline class. It just doesn't feel right manually re-calculate all the x-y-z of 40-100 points * 3 circle (and then rebuild the array and update the line).

Keep me posted please

EgonOlsen

Ok, i've added the option to set a parent Object3D to a Polyline. That way, it will inherit the transformations of that object. Keep in mind that when doing that, you have to think in object space of that object instead of world space when creating the Polyline.

Here's the jar: http://jpct.de/download/beta/jpct_ae.jar

And here's a hacky example that uses it:


package com.example.polylinetest;

import java.lang.reflect.Field;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.MotionEvent;

import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Light;
import com.threed.jpct.Logger;
import com.threed.jpct.Object3D;
import com.threed.jpct.Polyline;
import com.threed.jpct.RGBColor;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;
import com.threed.jpct.util.ExtendedPrimitives;
import com.threed.jpct.util.MemoryHelper;

public class PolylineTest extends Activity {

private static PolylineTest master = null;

private GLSurfaceView mGLView;
private MyRenderer renderer = null;
private FrameBuffer fb = null;
private World world = null;
private RGBColor back = new RGBColor(50, 50, 100);

private float touchTurn = 0;
private float touchTurnUp = 0;

private float xpos = -1;
private float ypos = -1;

private Object3D obj = null;
private int fps = 0;

protected void onCreate(Bundle savedInstanceState) {

Logger.log("onCreate");

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

super.onCreate(savedInstanceState);
mGLView = new GLSurfaceView(getApplication());
mGLView.setEGLContextClientVersion(2);

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

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

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

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

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);
}
}

public boolean onTouchEvent(MotionEvent me) {

if (me.getAction() == MotionEvent.ACTION_DOWN) {
xpos = me.getX();
ypos = me.getY();
return true;
}

if (me.getAction() == MotionEvent.ACTION_UP) {
xpos = -1;
ypos = -1;
touchTurn = 0;
touchTurnUp = 0;
return true;
}

if (me.getAction() == MotionEvent.ACTION_MOVE) {
float xd = me.getX() - xpos;
float yd = me.getY() - ypos;

xpos = me.getX();
ypos = me.getY();

touchTurn = xd / -100f;
touchTurnUp = yd / -100f;
return true;
}

try {
Thread.sleep(15);
} catch (Exception e) {
// No need for this...
}

return super.onTouchEvent(me);
}

protected boolean isFullscreenOpaque() {
return true;
}

class MyRenderer implements GLSurfaceView.Renderer {

private long time = System.currentTimeMillis();

public MyRenderer() {
}

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

if (master == null) {
world = new World();
obj = ExtendedPrimitives.createCube(10);
world.addObject(obj);

Light light = new Light(world);
light.setAttenuation(-1);
light.setPosition(new SimpleVector(100, 100, 0));
light.setIntensity(255, 0, 0);
obj.build();
obj.compile();

float d = 7f;

SimpleVector[] sv = new SimpleVector[5];
sv[0] = new SimpleVector(-d, -d, d);
sv[1] = new SimpleVector(d, -d, d);
sv[2] = new SimpleVector(d, d, d);
sv[3] = new SimpleVector(-d, d, d);
sv[4] = new SimpleVector(-d, -d, d);

Polyline lines = new Polyline(sv, RGBColor.WHITE);
lines.setParent(obj);
world.addPolyline(lines);

sv = new SimpleVector[5];
sv[0] = new SimpleVector(-d, -d, -d);
sv[1] = new SimpleVector(d, -d, -d);
sv[2] = new SimpleVector(d, d, -d);
sv[3] = new SimpleVector(-d, d, -d);
sv[4] = new SimpleVector(-d, -d, -d);

lines = new Polyline(sv, RGBColor.WHITE);
lines.setParent(obj);
world.addPolyline(lines);

sv = new SimpleVector[5];
sv[0] = new SimpleVector(-d, -d, d);
sv[1] = new SimpleVector(-d, -d, -d);
sv[2] = new SimpleVector(-d, d, -d);
sv[3] = new SimpleVector(-d, d, d);
sv[4] = new SimpleVector(-d, -d, d);

lines = new Polyline(sv, RGBColor.WHITE);
lines.setParent(obj);
world.addPolyline(lines);

sv = new SimpleVector[5];
sv[0] = new SimpleVector(d, -d, d);
sv[1] = new SimpleVector(d, -d, -d);
sv[2] = new SimpleVector(d, d, -d);
sv[3] = new SimpleVector(d, d, d);
sv[4] = new SimpleVector(d, -d, d);

lines = new Polyline(sv, RGBColor.WHITE);
lines.setParent(obj);
world.addPolyline(lines);

world.getCamera().moveCamera(Camera.CAMERA_MOVEOUT, 50);
MemoryHelper.compact();

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

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}

public void onDrawFrame(GL10 gl) {
if (touchTurn != 0) {
obj.rotateY(touchTurn);
touchTurn = 0;
}

if (touchTurnUp != 0) {
obj.rotateX(touchTurnUp);
touchTurnUp = 0;
}

fb.clear(back);
world.renderScene(fb);
world.draw(fb);
fb.display();

if (System.currentTimeMillis() - time >= 1000) {
Logger.log(fps + "fps");
fps = 0;
time = System.currentTimeMillis();
}
fps++;
}
}

}


shailevy


shailevy

Doesn't seem connected (removed all calls to polylines.setParent) but this version suddenly crashes in a different place:
"The matrix to be filled can't be the same instance as the matrix to invert!"

Should I open a separate thread ?

02-28 18:00:45.344: E/AndroidRuntime(6048): java.lang.RuntimeException: [ 1393603245338 ] - ERROR: The matrix to be filled can't be the same instance as the matrix to invert!
02-28 18:00:45.344: E/AndroidRuntime(6048):    at com.threed.jpct.Logger.log(Logger.java:193)
02-28 18:00:45.344: E/AndroidRuntime(6048):    at com.threed.jpct.Matrix.invert(Matrix.java:730)
02-28 18:00:45.344: E/AndroidRuntime(6048):    at com.threed.jpct.Object3D.getInverseWorldTransformation(Object3D.java:6265)
02-28 18:00:45.344: E/AndroidRuntime(6048):    at com.threed.jpct.Object3D.rayIntersectsAABB(Object3D.java:3673)
02-28 18:00:45.344: E/AndroidRuntime(6048):    at com.threed.jpct.Object3D.rayIntersectsAABB(Object3D.java:3635)
02-28 18:00:45.344: E/AndroidRuntime(6048):    at com.threed.jpct.World.calcMinDistanceAndObject3D(World.java:741)


EgonOlsen

Yes, that check has been added in this version. I wasn't aware  that the engine itself seems to trigger it. It doesn't do this in my tests...i'll look into it.

EgonOlsen

Ok, please redownload the beta jar and try again. The problem should be fixed now. My trigger was bit trigger happy...