Plane, Texture... Probleme.. Oder andere Idee?

Started by Netski, October 26, 2012, 04:07:23 PM

Previous topic - Next topic

Netski

Hallo!
Ich entwickel derzeit ein Teil für eine AR-Navigation, welche je nach Neigungswinkel (Handy im Horizontalen) nach vorne (also Kamera schaut auf den Boden (90°), oder gerade aus vom Benutzer weg: 0°) ein Kreis auf dem Bildschirm anzeigt.
Der Kreisradius definiert sich theoretisch aus: r(phi)=(90-x)/x - daraus ergibt sich: Bei phi=0 sieht man eine gerade Linie auf dem Bildschirm, bei phi=90 (blick nach unten) sieht man den gesamten Kreis.
Anders ausgedrückt: Man schwebt sozusagen in den Mittelpunkt des Kreises und schaut auf die Kreislinie oder man schwebt über den Kreis und sieht auf den gesamtem Kreis.

Soweit zur Thematik.
Nun zum Problem:
Meine erste Lösung wurde relativ gut mit Paint() gelöst. Kreis zeichnen usw. funktioniert super, sobald jedoch phi=0 wird, wird der Radius beliebig groß, was zu Ungenauigkeiten bei weiteren Berechnungen führt.
Vielleicht hat jemand dazu schon eine passende Lösung parat.

Mein zweiter Lösungsansatz: mit 3D-API
Da bin ich auf die JPCT Api gestoßen und konnte alles recht einfach implementieren. Problem jetzt: Ich kann kein Kreis zeichnen. Nach langem suchen im Forum / Google etc. bin ich auf Beiträge gestoßen wie "Plane machen und Textur eines Kreises drauf". Gut - Habe mir eine Textur gemacht bzw. einen Kreis 512x512 (bzw. beliebig 2^x*2^x) mit einem Roten Kreis drin der bis zu den Kanten des Images geht.

Erstelle mir eine Plane, weise die Textur zu und stelle fest, dass die Plane irgendwie immer nur einen kleineren Ausschnitt anzeigt (geschätzt schneidet die Plane die äußeren 10-20pixel des Bildrandes ab: also fügt er eine 490x490 pixel Datei ein..)

Code: (cube heißt nur noch cube, bedeutet aber natürlich nicht cube)

Texture texture = new Texture(BitmapHelper.rescale(
BitmapHelper.convert(parent.getResources().getDrawable(R.drawable.circle))
, 512,512));
TextureManager.getInstance().addTexture("circle", texture);
cube = Primitives.getPlane(1, 10);
cube.calcTextureWrapSpherical();
          cube.setTexture("circle");
...
7


Wäre super wenn mir jemand weiterhelfen kann. Vielleicht hab ich auch zweimal den falschen Lösungsansatz verwendet.
Danke!

EgonOlsen

Nimm einfach das calcTextureWrap...da raus. Das dient in den Beispielen dazu, irgendwelche Texturkoordinaten zu erzeugen wo man gar keine hat. Auf eine Plane angewandt macht es die richtigen Koordinaten aber kaputt.

Netski

Jap, das funktioniert. Danke schonmal.

Problem jetzt: Ist man im Kreis (phi=0) sieht man genau auf die Kante vom Kreis (Wie im Flächenland :)). Aber leider verschwindet dann ja die Kante, da die Höhe des planes = 0 ist. Auch unterhalb des Planes fehlt dann die Fläche. Was nun? :(

EgonOlsen

Naja, Polygone haben halt keine Dicke...da kann man im Prinzip nur die Plane durch ein 3D-Model eines Kreises ersetzen. Das sollte sich mit den gängigen Editoren relativ einfach erstellen lassen.

Netski

Okay... gibt es irgendwo gescheite Beispiele/Dokus für die Implementierung von .3ds/.obj in jpct? Habe mit blender/sketchup/3dsmax jeweils .3ds/.obj erstellt, jedoch ohne erfolg geladen. Auch verschiedenste Artikel im Forum/Wiki helfen nicht sonderlich weiter.

EgonOlsen

#5
"Ohne Erfolg geladen" ist jetzt etwas sehr unspezifisch. Eigentlich ist das Laden sehr simpel. Wenn man danach nichts sieht, dann liegt das meist daran, dass man nicht auf das Objekt guckt, weil es gemäß den Angaben in der Datei sonstwo im Objectspace liegt oder es ist viel zu klein oder zu groß. Das kann die Engine nicht wissen, da hilft manchmal nur probieren. Ein Blick ins Log ist auch oft hilfreich.
Auch nicht vergessen, dass der Loader ein Array liefert. Je nach Struktur des Objektes ist es mit dem ersten Element nicht getan.

Netski

#6
Okay, war ein eher dummer Fehler von mir. Habe nur immer in den falschen Logcat filter geschaut.

Nächstes: Wechselt die Kamera ihren "Up" Vektor sobald sie den z-0 Punkt überschreitet?
Ich hoffe ich kann Beschreiben was ich beobachte:

Mein Kreis liegt im 0-Punkt. Kamera startet "über" ihr: also mit den Koordinaten 0/0/50 und bewegt sich dann circa in Richtung 0/10/0 und schaue mit der Kamera immer in Richtung Kreismittelpunkt. Dabei beobachte ich den Kreis anfangs von Oben, beleuchtet wird der Kreis derzeit von unten. Also sehe ich einen dunklen Kreis. Nahe dem z=0(also ich bin noch z>0) sehe ich, dass der Kreis von unten beleuchtet wird. Also: obere Kante Dunkel, untere Kante hell! Sobald kamera-z<0 wird, dreht sich anscheinend die Kamera. Erwarten würde ich folgendes: Die Kante oben bleibt dunkel und untere Kante bleibt hell. Jedoch vertauscht sich dies. Zudem ist das erwartete Bild nicht jenes, in welchem sich der Kreis bei z<0 nach oben hin "wegbiegt" - also die Kante die mir näher ist, sollte nach oben hin verschwinden (gekommen von unten). Man beobachtet als Benutzersicht nur, dass sich die Kamera auf z=0 bewegt, sich um 180° auf der y-achse dreht (ich bewege die kamera in Richtung z zum Kreismittelpunkt und x zum Kreisrand).

Also was ist mit der Kamera los? Oder bin ich wieder aufm Denkfehlertripp?



edit: Kamera rotation um Z um 135° hat es fast gefixxt. Aber scheint mir irgendwie unlogisch. Da z doch die Vertikale-achse ist...

EgonOlsen

Ich vermute mal, du benutzt lookAt(), um auf den Mittelpunkt zu schauen? Wenn ja, dann ist dieses Verhalten normal. lookAt() macht keine Annahmen darüber, wie die Kamera gedreht ist. Die Method stellt nur sicher, dass man auf den Punkt schaut...nicht in welchem Winkel die Kamera bezogen auf den Sichtvektor steht. Wenn du sowas brauchst, ist setOrientation() vermutlich besser. Allerdings musst du da selber dafür sorgen, dass die beiden Vektoren senkrecht aufeinander stehen.

Netski

#8
Jap, funktioniert nun alles soweit.
Das einzige was mich stört ist, dass es sehr ruckelig läuft. Die Bewegung der Kamera erfolgt ja auf der Grundlage eines SensorEvents (Sensordaten ändern sich -> onDraw ändert Position der Kamera).
Bei dieser Art der Translation (Kamera bewegt sich) verhält sich das Programm sehr ruckelig.
Allerdings kann ich gleichzeitig über Touch meinen Kreis drehen (ist noch zu Testzwecken drin) und dabei rotiert der Kreis sehr flüssig.
Gleiches Schema bei beiden: Sensor registriert etwas, ändert Werte, draw zeichnet etwas anhand der Werte. Bei Touch flüssig, bei Motion schlecht.

Idee: Motionsensor bekommt eine ziemlich inhomogene Werteverteilung "10, 15, 30, 44, 60" und genau daran wird die Position in jedem Frame angepasst -> Sprünge von 10 auf 15 sehen wie Ruckeln aus?
Lösung: "MoveTo" für die Kamera, Kamera mit einer Geschwindigkeit x in die Richtung bewegen in kleinen Schritten.
Frage: Logisch oder eher Unfug und ich beachte wieder etwas der jpct-api nicht?


Problem gelöst soweit.
moveCamera verflüssigt das ganze.
Danke für die Hilfe. Wird aber sicherlich nicht das letzte Mal sein, dass ich mich melde :)

Netski

#9
Okay ich stoße wohl doch wieder auf Grenzen. Aber programmierer auch das erste Mal für Android Systeme.

Hier mein Problem bzw. erst mein Systemaufbau:

Aus einer Activity A starte ich über startActivity per Knopfdruck eine Activity B oder wir nennen sie FView.
Diese FView hat im Hintergrund zum einen eine Kamera, die im Layout an ein CamViewFrame (Framelayout) gehängt wird und funktioniert ohne Probleme.
Desweiteren wird in der FView ein "private GLSurfaceView mGLView;" angelegt und dies in der onCreate instantiiert (mGLView = new GLSurfaceView(getApplication());)
Dazu habe ich ein weiteres FrameLayout (camDrawFrame), welchem ich 1) per addView die mGLView anhänge und 2) erstelle ich ein "drawBoard" aus einer Klasse Drawing und übergebe diesem ebenfalls das mGLView (und mache auch camDrawFrame.addView(drawBoard).
Die Drawing Klasse erzeugt den Renderer und gleichzeitig eine onDraw.
Des weiteren hat die FView noch Sensoren implementiert.

Problem: Erwartet wird ein 3D Objekt welches sich bewegt anhand der Sensoren, Kamera, div. 2D Text der div. Werte des Sensors/3D Objektes anzeigt.
Es kommt beim ersten mal aufrufen: Kein 3D Objekt (drawFrame wird aber aufgerufen), Sensorwerte werden angezeigt (auch immer aktualisiert) und Kamera läuft.
Also fehlt mir jetzt das 3D-Objekt, welches sich eigentlich nach den Sensoren bewegen sollte.
Dann drücke ich auf zurück, und starte FView ein zweites mal direkt: Diesmal gibt es ein 3D-Objekt, welches sich aber nicht bewegt. Zudem werden die Werte nicht mehr aktualisiert auf dem Bildschirm. Jedoch zeigt mit Logcat noch an, dass sich der Sensor ändert(in der FView) und auch drawFrame aufgerufen wird - in der drawFrame ändert sich jetzt aber der Sensor angeblich nicht mehr (immer gleicher Wert).

Also ich bin seit Stunden am suchen und finde nicht mehr meinen Fehler. Wahrscheinlich sehr ich den Wald vor lauter Bäumen nicht mehr und der Fehler liegt irgendwo da wo ich ihn nicht erahne. Hoffe hier kann mir wer helfen. Vielleicht ist mein gesamter Aufbau schon hinfällig. Ich wüsste aber nicht wie ich es sons machen soll.


//Habe jetzt einiges geändert. FView ist eine Activity und implementiert LocationListener und SensorEventListener; Das Layout besteht aus einem GLSurfaceView und einem SurfaceView. Problem ist nun, Camera geht aufs SurfaceView, aber wie/wo den Renderer anhängen?

EgonOlsen

Keine Ahnung, ehrlich gesagt. Dieses Gemixe von Activities habe ich gefühlt nie wirklich durchdrungen. Ich habe immer eine Activity, da drin läuft alles ab und fertig. Die ganzen Möglichkeiten von Android an dieser Stelle habe ich bisher nicht genutzt bzw. nicht nutzen müssen.

Netski

#11
Ja ich Blicke durch diesen Urwald derzeit auch noch nicht durch.
Habe das Programm nun umgeformt:
FView beinhaltet direkt glsurface & renderer.
Das ganze läuft nun erheblich schneller. Dennoch habe ich immer noch ein Problem: Das Modell wird nicht immer geladen. Manchmal wird es erst geladen, wenn ich die Activity neu aufrufe.
Ich lade folgendermaßen:

modelLoadingStream = getResources().openRawResource(
R.raw.compasscone);
circle = Object3D.mergeAll(Loader.load3DS(modelLoadingStream,
10));

Es kommt mir so vor, als wenn er onDrawFrame früher erreicht, als das er das Objekt geladen hat. Erst mit dem Objekt arbeitet (translationen rotationen etc) und während dessen es nicht mehr richtig läd. Ich möchte nicht anfangen mit Semaphoren oder sonstigen nun anzufangen...


//edit
Also, wenn ich die Activity neu aufrufe, bezieht er sich auf das static Objekt, initialisiert den renderer, läd dort aber die Modelle nicht neu. Woher bezieht er dann die Objekte nach dem Activity-Neustart, wenn onSurfaceChanged(wo die Objekte geladen werden) nicht mehr vollständig durchlaufen wird aufgrund von if(master==null)... ??

Wenn ich das mit dem master==null weglasse, durchläuft er ja sicher onSurfaceChanged und sollte die Objekte laden. Laut Logcat tut er dies auch. Dennoch werden die Objekte nich angezeigt... bin ratlos.!

EgonOlsen

Die static-Geschichte funktioniert, weil er die VM nicht beendet. Und solange das nicht passiert, bleibt die statische Referenz erhalten. In der müssen natürlich Referenzen auf die Objekte bestehen. Andernfalls räumt die Garbage Collection ist einfach ab.

Ansonsten blicke ich nicht mehr durch, was du da so tust... ;) Also er kann onDrawFrame nicht vor dem Durchlauf von onSurfaceChanged erreichen. Und falls du dennoch unsicher bist, setz doch einfach ein Flag am Ende von onSurfaceChanged.

Ich würde den ganzen Kram mal auf eine Activity und ohne irgendwelchen Camera-Zampano eindampfen und wenn das vernünftig läuft, darauf aufbauend die fehlenden Dinge ergänzen. Dann sieht man besser, wo das Problem liegt.

Netski

Die meisten Dinge sind nun erledigt. Danke soweit.

Ich suche jetzt nach einer Möglichkeit mit Paint quasi im dreidimensionalem Raum zeichnen zu können. D.h. ich habe irgendwo ein Objekt und möchte an diesem Objekt z.B. ein Text anzeigen lassen, welcher immer wie ein Billboard zum Benutzer hinzeigt. Hierbei würde der Text folglicherweise kleiner/größer werden je nach Entfernung.

Oder gibt es eine Möglichkeit, die Koordinaten der Objekte im 3D-Raum auf die Bildschirm-Koordinaten zu transformieren?
Z.B. Objekt A liegt bei (0,0,0); Camera bei (1,0,0) und Camera schaut in Richtung (-1,0,0). Frage nun das Objekt nach den Bildschirm koordinaten und müsste in diesem Falle etwas wie (200,150) bekommen bei einem Bildschirm mit 400px Breite und 300px Höhe.
Würde die Kamera nun bei (1,1,0) liegen, käme vllt etwas heraus wie (200, 290).

EgonOlsen

In Interact2D findest du einige Methoden zur Transformation von 2D nach 3D und zurück. Damit sollte es gehen.