kramann.info
© Guido Kramann

Login: Passwort:










kramann.info
© Guido Kramann

Login: Passwort:




Getting started with Android-Processing VR

(EN google-translate)

(PL google-translate)

The strategy here is: Keeping the code short by making an intensive use of the available libraries.

vr002_richtungen

vr002_richtungen.zip
import processing.vr.*;

PShape spheres;

//Resultat zu Koordinatenrichtungen:

// x-Achse zeigt nach rechts 
// y-Achse zeigt nach oben
// z-Achse zeigt nach hinten
// eigene Position: z>0, also leicht nach hinten versetzt

//Auslesen der Objektmatrix:
//Spalten 1..3: Einheitsvektoren des Blick-Koordinatensystems, 4. Spalte Position des Viewers.
PMatrix3D eyeMat = new PMatrix3D();
void setup() 
{
  fullScreen(STEREO);
  spheres = createShape(GROUP);
  float[][] orte = {
                       {1000,0,0},  //rot links von mir
                       {-1000,0,0}, //grün rechts von mir
                       {0,1000,0},  //gelb unter mir
                       {0,-1000,0}, //blau über mir
                       {0,0,1000},  //türkis hinter mir
                       {0,0,-1000}  //violett weit vor mir durch weiss verdeckt!
                   };
  int[][] farben = {
                        {255,0,0},//rot
                        {0,255,0},//gruen
                        {255,255,0},//gelb
                        {0,0,255},  //blau
                        {0,255,255},//türkis
                        {255,0,255}  //violett
                   };                   
  for(int i=0;i<orte.length;i++)
  {
      PShape sphere = createShape(SPHERE, 50);
      sphere.setStroke(false);
      sphere.setFill(color(farben[i][0],farben[i][1],farben[i][2]));
      sphere.translate(orte[i][0],orte[i][1],orte[i][2]);
      spheres.addChild(sphere);
  }
  textAlign(CENTER, CENTER);
  textSize(displayDensity * 36);  
  frameRate(30);
}
int zzz=0;
void draw() 
{
  background(0);
  getEyeMatrix(eyeMat); //Kameramatrix auslesen
  
  translate(eyeMat.m03, eyeMat.m13, eyeMat.m23); //Welt in Koordinatenursprung von Kamera setzen.
  lights();
  shape(spheres);

  eye(); //Transformation realtiv zur Kamera
  translate(0, 0, 500); //Zielkreis relativ zur Kamera zeichnen
  noFill();
  stroke(255,0,0);
  ellipse(0, 0, 50, 50);
  
  if(zzz%90==0)
  {
      println(zzz);
      //Einheitsvektoren des Kamerasystems in Koordinaten des Inertialsystems ex, ey , ez
      println("ex=["+nfp(eyeMat.m00,1,3)+","+nfp(eyeMat.m10,1,3)+","+nfp(eyeMat.m20,1,3)+"]");
      println("ey=["+nfp(eyeMat.m01,1,3)+","+nfp(eyeMat.m11,1,3)+","+nfp(eyeMat.m21,1,3)+"]");
      //ez zeigt in die Blickrichtung!
      //In Startrichtung nach vorne blicken: ez=[0,0,-1]
      //nach links blicken:                  ez=[-1,0,0]
      //nach rechts blicken:                 ez=[ 1,0,0]
      //nach hinten blicken:                 ez=[ 0,0,1]
      //nach oben   blicken:                 ez=[ 0,-1,0]
      //nach unten  blicken:                 ez=[ 0, 1,0]
      println("ez=["+nfp(eyeMat.m02,1,3)+","+nfp(eyeMat.m12,1,3)+","+nfp(eyeMat.m22,1,3)+"]");
      println("pos=["+nfp(eyeMat.m03,1,3)+","+nfp(eyeMat.m13,1,3)+","+nfp(eyeMat.m23,1,3)+"]");
      println("ez so anpassen, dass dessn Norm mit den Koordinaten der Spheren übereinstimmt:");
      println("ez=["+nfp(eyeMat.m02,1,3)+","+nfp(-eyeMat.m12,1,3)+","+nfp(eyeMat.m22,1,3)+"]");
  }    
  zzz++;
}

Code 0-1: vr002_richtungen - Positionierung farbiger Bälle auf den Koordinatenachsen zur Orientierung und Ausgabe der Blickrichtung

Orientierung des VR-Koordinatensystems.

Bild 0-1: Orientierung des VR-Koordinatensystems.

Die eye-Matrix liefert in den ersten drei Spalten die Einheitsvektoren des "Blickrichtungs-Koordinatensystems".

vr002_puls

vr002_puls.zip
  • Die Lautstärke von Tönen wird mit der Fokussierung der vorderen, linken und unteren Sphäre gekoppelt.
import processing.vr.*;

import android.media.AudioTrack;
import android.media.AudioFormat;
import android.media.AudioManager;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

Piano piano;
//Idee:
//Die Sphären geben pulsierende Töne von sich.
//Je besser man eine Sphäre fokussiert hat, desto höher die Pulsfrequenz.

PShape spheres;

PMatrix3D eyeMat = new PMatrix3D();

//Übereinstimmungsgrad zwischen der Blickrichtung und den 6 Sphären:
//                           VORN  HINTEN  LINKS  RECHTS   OBEN   UNTEN
//                           00-    00+    -00    +00      0+0    0-0 
double[] uebereinstimmung = {0.0,   0.0,   0.0,   0.0,     0.0,   0.0};
double ez_x = 0.0; 
double ez_y = 0.0;
double ez_z = 0.0;
public void aktualisiereUebereinstimmung()
{
      uebereinstimmung[0] = ez_x*0.0 + ez_y*0.0 + ez_z*(-1.0); 
      uebereinstimmung[1] = ez_x*0.0 + ez_y*0.0 + ez_z*(1.0); 
      uebereinstimmung[2] = ez_x*(-1.0) + ez_y*0.0 + ez_z*0.0; 
      uebereinstimmung[3] = ez_x*1.0 + ez_y*0.0 + ez_z*0.0; 
      uebereinstimmung[4] = ez_x*0.0 + ez_y*1.0 + ez_z*0.0; 
      uebereinstimmung[5] = ez_x*0.0 + ez_y*(-1.0) + ez_z*0.0;
      
      for(int i=0;i<uebereinstimmung.length;i++)
          if(uebereinstimmung[i]<0.0)
              uebereinstimmung[i]=0.0;
}

void setup() 
{
  piano = new Piano();
  fullScreen(STEREO);
  spheres = createShape(GROUP);
  float[][] orte = {
                       {1000,0,0},  //rot links von mir
                       {-1000,0,0}, //grün rechts von mir
                       {0,1000,0},  //gelb unter mir
                       {0,-1000,0}, //blau über mir
                       {0,0,1000},  //türkis hinter mir
                       {0,0,-1000}  //violett weit vor mir durch weiss verdeckt!
                   };
  int[][] farben = {
                        {255,0,0},//rot
                        {0,255,0},//gruen
                        {255,255,0},//gelb
                        {0,0,255},  //blau
                        {0,255,255},//türkis
                        {255,0,255}  //violett
                   };                   
  for(int i=0;i<orte.length;i++)
  {
      PShape sphere = createShape(SPHERE, 50);
      sphere.setStroke(false);
      sphere.setFill(color(farben[i][0],farben[i][1],farben[i][2]));
      sphere.translate(orte[i][0],orte[i][1],orte[i][2]);
      spheres.addChild(sphere);
  }
  textAlign(CENTER, CENTER);
  textSize(displayDensity * 36);  
  frameRate(30);
}
int zzz=0;
void draw() 
{
  background(0);
  getEyeMatrix(eyeMat); //Kameramatrix auslesen
  
  translate(eyeMat.m03, eyeMat.m13, eyeMat.m23); //Welt in Koordinatenursprung von Kamera setzen.
  lights();
  shape(spheres);

  eye(); //Transformation realtiv zur Kamera
  translate(0, 0, 500); //Zielkreis relativ zur Kamera zeichnen
  noFill();
  stroke(255,0,0);
  ellipse(0, 0, 50, 50);

  ez_x =  eyeMat.m02;
  ez_y = -eyeMat.m12;
  ez_z =  eyeMat.m22;
  aktualisiereUebereinstimmung();
  if(zzz%90==0)
  {
      println("ez=["+nfp(eyeMat.m02,1,3)+","+nfp(-eyeMat.m12,1,3)+","+nfp(eyeMat.m22,1,3)+"]");
  }    
  zzz++;
}

Code 0-2: vr002_puls (Haupttab)

double dreieck(double a, double freq, double t)
{
    double tt = t*freq - Math.floor(t*freq);  //weitere Verbesserung: Lookup-Table im Bereich 0..1 sehr sehr fein (10000 Werte z.B.)
    if(t>=0.0)
    {
      if(tt<0.25)
          return 4.0*a*tt;
      else if(tt<0.75)
          return 4.0*a*(0.25 - (tt-0.25));
      else
          return 4.0*a*(-0.25+(tt-0.75));
    }
    else
    {
      tt=-tt;
      if(tt<0.25)
          return -4.0*a*tt;
      else if(tt<0.75)
          return -4.0*a*(0.25 - (tt-0.25));
      else
          return -4.0*a*(-0.25+(tt-0.75));
    }
}

public class Piano implements Runnable
{
     AudioTrack audioTrack;
     int sr = 44100;
     int buffsize = 8820;
     double t=0.0;
  
     double dt = 1.0/(double)sr;
     protected ScheduledExecutorService schedExecService;  
     short[] puffer = new short[buffsize*2]; //4 Byte pro Sample == 16Bit Stereo  //2 * bei short
  
     public Piano()     
     {
        try
        {
            audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sr, 
                                    AudioFormat.CHANNEL_OUT_STEREO, 
                                    AudioFormat.ENCODING_PCM_16BIT, 
                                    buffsize*4, 
                                    AudioTrack.MODE_STREAM);
            audioTrack.setStereoVolume(1.0f, 1.0f);
            audioTrack.play();
            
            schedExecService = Executors.newSingleThreadScheduledExecutor();
            long period = (buffsize*1000)/sr; //Seconds per Beat==60/BPM, die Hälfte weil 8tel, mal 1000 weil Millisekunden.
            schedExecService.scheduleAtFixedRate(this, 0, period, TimeUnit.MILLISECONDS);                
        }
        catch(Exception ee)
        {
            System.out.println("FEHLER: "+ee);
        }              
     }
    
     public void run()
     {
                for(int i=0;i<buffsize;i++)
                {
                      puffer[i*2+0] = (short)dreieck(uebereinstimmung[0]*15000.0,440.0,t);  //VORN
                      puffer[i*2+1] = (short)dreieck(uebereinstimmung[2]*15000.0,770.0,t);  //LINKS
                      
                      //UNTEN
                      puffer[i*2+0] += (short)dreieck(uebereinstimmung[5]*15000.0,330.0,t); 
                      puffer[i*2+1] += (short)dreieck(uebereinstimmung[5]*15000.0,330.0,t);  
                      
                      
                      
                      t+=dt;
                }
          
                audioTrack.write(puffer, 0,buffsize*2);
     }
}

Code 0-3: vr002_puls (toene-Tab)

Dreht man den Kopf nach rechts und fokussiert die rechte Sphäre verstummen alle Töne.