3D renderer not recognized in secondApplet

edited July 2016 in Questions about Code

the P3D renderer in the following sketch with 2 windows in PS3 is not recognized. I get the error:

vertex() with x, y, and z coordinates can only be used with a renderer that supports 3D, such as P3D... .

if I put the content of the class Tetra inside a function and call it in draw() the problem does not appear?

a hint to solve this would be great. :)

float ballX;
float ballY;

float theta = 0.0;

Tetra tetra;

public void setup() {
  size(900, 900, JAVA2D);

  String[] args = {"SecondApplet"};
  SecondApplet sa = new SecondApplet();
  PApplet.runSketch(args, sa);
}

void draw() {
  ballX = mouseX;
  ballY = mouseY;
  background(0);
  ellipse(ballX, ballY, 10, 10);
}   

public class SecondApplet extends PApplet {

  public void settings() {
    size(900, 900, P3D);
    tetra = new Tetra(10); 
  }

 public void setup() {
    frameRate(30);   
  } 

  public void draw() {
   background(255);
  theta += 0.01;

  translate(width/2, height/2, 0);
  rotateX(theta);
  rotateY(theta);  

  // translate the scene again
  translate(100, 100, 20);
  shape(tetra.gr); 
  }
}

public class Tetra {

  // The PShape object
 PShape gr;
  int t;

  Tetra(int t_) {
    t = t_;

    gr = createShape();

    beginShape();
    fill(150, 0, 0, 127);
    vertex(-t, -t, -t);
    vertex( t, -t, -t);
    vertex( 0, 0, t);

    fill(0, 150, 0, 127);
    vertex( t, -t, -t);
    vertex( t, t, -t);
    vertex( 0, 0, t);

    fill(0, 0, 150, 127);
    vertex( t, t, -t);
    vertex(-t, t, -t);
    vertex( 0, 0, t);

    fill(150, 0, 150, 127);
    vertex(-t, t, -t);
    vertex(-t, -t, -t);
    vertex( 0, 0, t);

    endShape();
  }
}

Answers

  • edited July 2016

    What you're asking for us to explain is an advanced & not-so-known topic about how nested classes & closures work in Java! ~O)

    You can "fix" it by simply moving your class Tetra into class SecondApplet; thus turning the former a nested class of the already nested class SecondApplet: 8-}

    static class SecondApplet extends PApplet {
      Tetra tetra;
      float theta;
    
      void settings() {
        size(displayWidth>>1, displayHeight>>1, P3D);
      }
    
      void setup() {
        tetra = new Tetra(10);
        frameRate(30);
      } 
    
      void draw() {
        background(-1);
        theta += 0.01;
    
        translate(width>>1, height>>1, 0);
        rotateX(theta);
        rotateY(theta);  
    
        translate(100, 100, 20);
        shape(tetra.gr);
      }
    
      class Tetra {
        PShape gr;
        int t;
    
        Tetra(int t_) {
          t = t_;
    
          gr = createShape();
    
          beginShape();
          fill(150, 0, 0, 127);
          vertex(-t, -t, -t);
          vertex( t, -t, -t);
          vertex( 0, 0, t);
    
          fill(0, 150, 0, 127);
          vertex( t, -t, -t);
          vertex( t, t, -t);
          vertex( 0, 0, t);
    
          fill(0, 0, 150, 127);
          vertex( t, t, -t);
          vertex(-t, t, -t);
          vertex( 0, 0, t);
    
          fill(150, 0, 150, 127);
          vertex(-t, t, -t);
          vertex(-t, -t, -t);
          vertex( 0, 0, t);
    
          endShape();
        }
      }
    }
    

    An even easier "fix" is get rid of class Tetra and turn it a method of class SecondApplet.
    After all, you just create 1 instance of it. :>

  • thanks a lot go2Loop and sorry if my request is unawarely demanding a lot. I extracted this simpel sketch to illustrate my problem. but the sketch I am working on contains 19 classes with altogether some 1.000 lines of code which I work on the last 3 years. At least 2 classes (more will coming for sure) I need for drawing with the P3D Applet and one of it has potentially 37 instances. But your suggested solution is a way I will try: putting all 3D relevant code inside the class SecondApplet. Thanks!

  • edited July 2016

    ... putting all 3D relevant code inside the class SecondApplet.

    That sounds too big to fit everything in! May I suggest another approach? :-\"

    • Regular sketches only got 1 canvas where we draw stuff.
    • But w/ more than 1 PApplet, the question arises:
    • Which canvas is acted upon when we invoke something as simple as rect() or fill()?
    • In order to make sure which canvas we're currently targeting, we need to prefix the commands w/ the target PApplet instance.
    • So rather than just fill(#FF0000); we type in p.fill(#FF0000);.
    • Where p is the PApplet's reference of the canvas we're targeting. :>
    • Most practical way to get the p is requesting it as a constructor's parameter. *-:)
    • Take a look at the following sample w/ nested static class MyCircle: B-)

    // forum.Processing.org/two/discussion/17585/
    // 3d-renderer-not-recognized-in-secondapplet#Item_3
    
    // GoToLoop (2016-Jul-19)
    
    MyCircle circle;
    
    void settings() {
      size(400, 300);
      smooth(3);
      noLoop();
    }
    
    void setup() {
      ellipseMode(CENTER);
      strokeWeight(2.5);
      stroke(0);
    
      PVector myVec = new PVector(width>>1, height>>1, 0300);
      circle = new MyCircle(this, myVec, #FFFF00);
    }
    
    void draw() {
      background(0100);
      circle.display();
    }
    
    static class MyCircle {
      final PApplet p;
      final PVector circle = new PVector();
      final color c;
    
      MyCircle(PApplet pa, float x, float y, float diam, color cc) {
        p = pa;
        circle.set(x, y, diam);
        c = cc;
      }
    
      MyCircle(PApplet pa, PVector vec, color cc) {
        p = pa;
        circle.set(vec);
        c = cc;
      }
    
      MyCircle display() {
        p.fill(c);
        p.ellipse(circle.x, circle.y, circle.z, circle.z);
        return this;
      }
    }
    
  • your suggestion is very welcome GoToLoop! I try this now. Thanks!

  • edited July 2016

    Thanks again for this great help GoToLoop! :) :) :)

    In the following example I applied your code to my problem for notice: 2 windows, one Java2D, one P3D, 2 classes for each PApplet one.

     // forum.Processing.org/two/discussion/17585/
    // 3d-renderer-not-recognized-in-secondapplet#Item_4
    
    // after GoToLoop (2016-Jul-20) 
    
    MyCircle circle;    
    
    Tetra tetra;
    
    float theta = 0.0;
    
    void settings() {
      size(400, 300, JAVA2D);
      smooth(3);
      noLoop();
    
      String[] args = {"SecondApplet"};
      SecondApplet sa = new SecondApplet();
      PApplet.runSketch(args, sa);
    }
    
    void setup() {
      ellipseMode(CENTER);
      strokeWeight(2.5);
      stroke(0);
    
      PVector myVec = new PVector(width>>1, height>>1, 0300);
      circle = new MyCircle(myVec, #FFFF00);
    }
    
    void draw() {
      background(255);
      background(0100);
      circle.display();
    }
    
    public class SecondApplet extends PApplet {
      public void settings() {
        size(400, 300, P3D);
      }
    
      public void setup() {
        frameRate(30);  
        //PVector myVec = new PVector(width>>1, height>>1, 0300);
        //circle = new MyCircle(this, myVec, #FFFF00);
        tetra = new Tetra(this, 10);
      } 
    
      public void draw() {
         background(255);
         theta += 0.01;
         translate(width/2, height/2, 0);
         rotateX(theta);
         rotateY(theta);
    
         // translate the scene again
         translate(100, 100, 20);
    
        background(0100);
        //translate(mouseX, mouseY, 20);
        //circle.display();
        //translate(mouseX, mouseY, 0);
         tetra.display();
        //box(100);
      }
    }
    
    public class MyCircle {  
      final PVector circle = new PVector();
      final color c;
    
      MyCircle(float x, float y, float diam, color cc) {    
        circle.set(x, y, diam);
        c = cc;
      }
    
      MyCircle(PVector vec, color cc) {    
        circle.set(vec);
        c = cc;
      }
    
      void display() {
        fill(c);
        ellipse(circle.x, circle.y, circle.z, circle.z);    
      }
    }
    
    
    public class Tetra {
    
      final PApplet p;
    
      // The PShape object
      final PShape gr;
      int t;  
      float speed;
    
      Tetra(PApplet pa, int t_) {
        p = pa;
    
        t = t_;
    
        gr = p.createShape();
    
        gr.beginShape(TRIANGLES);
        gr.fill(150, 0, 0, 127);
        gr.vertex(-t, -t, -t);
        gr.vertex( t, -t, -t);
        gr.vertex( 0, 0, t);
    
        gr.fill(0, 150, 0, 127);
        gr.vertex( t, -t, -t);
        gr.vertex( t, t, -t);
        gr.vertex( 0, 0, t);
    
        gr.fill(0, 0, 150, 127);
        gr.vertex( t, t, -t);
        gr.vertex(-t, t, -t);
        gr.vertex( 0, 0, t);
    
        gr.fill(150, 0, 150, 127);
        gr.vertex(-t, t, -t);
        gr.vertex(-t, -t, -t);
        gr.vertex( 0, 0, t);
    
        gr.endShape();
      }
    
      Tetra display() {
        //p.box(100);
        p.shape(gr);
        return this;
      }
    }
    
  • edited July 2016

    Very good! <:-P Just some extra "silly" tips: B-)

    You can replace the 3 statements below:

    String[] args = {"SecondApplet"};
    SecondApplet sa = new SecondApplet();
    PApplet.runSketch(args, sa);
    

    W/ just 1: runSketch(platformNames, new SecondApplet());

    It's advisable to declare those classes w/ static so it won't compile if we forget the p.. *-:)

    Remember if you wish to make class MyCircle available for any PApplet, you're gonna need to use p. there too. L-)

  • edited July 2016

    thanks for all the info! one question arises from this tip:

    Remember if you wish to make class MyCircle available for any PApplet, you're gonna need to use p. there too.

    there is lots of code already running in my big sketch and if possible I would like to avoid changing it. So in the example I tried to let the "p." for the Java2D (main window) away to verify if it is possible and it seemes to work. I thougt that it is so because it is the "first PApplet" then using the "p." for all the code in the second PApplet (P3D) which I am writing now? Would this work?

  • edited July 2016

    Those were just tips. Having the p. in a class makes it available for any PApplet, be it the main 1 or the others.
    However, if it's been decided that some inner class is gonna to be used exclusively for the main PApplet, you don't need the p. of course. :-\"

  • edited July 2016

    a further question concerning the communication between classes:

    I have one class physModel which takes some data from an external input and computes some analysis data,

    then different classes for each of both PApplets which use these data for visualization once in 2D, once in 3D.

    I intend to make the analysis data of physModel available for different classes of both PApplets: If I want to access data from physModel (a class inside the first PApplet) inside class vis3D of the second PApplet can I just say: physModel.anyArray[x]? And I suppose if vis3D inherits from physModel then I write just anyArray[x]?

  • edited July 2016

    or to relate this question more closely to our discussion examples: how to access e.g. the value of color c of class MyCircle inside class Tetra. I put some println() inside the classes to show the data in the console. I can ask data from Tetra inside MyCircle but not from MyCircle inside a Tetra instance.

    // forum.Processing.org/two/discussion/17585/
    // 3d-renderer-not-recognized-in-secondapplet#Item_5
    
    // after GoToLoop (2016-Jul-21)
    
    PApplet p;
    SecondApplet sa;
    
    MyCircle circle;
    
    Tetra tetra;
    
    float theta = 0.0;
    
    void settings() {
    
      size(400, 300, JAVA2D);
      smooth(3);
      noLoop();
    
    //runSketch(platformNames, new SecondApplet());
    String[] args = {"SecondApplet"};
    SecondApplet sa = new SecondApplet();
    PApplet.runSketch(args, sa);
    }
    
    void setup() {
      ellipseMode(CENTER);
      strokeWeight(2.5);
      stroke(0);
    
      PVector myVec = new PVector(width>>1, height>>1, 0300);
      circle = new MyCircle(this, myVec, #FFFF00);
    }
    
    void draw() {
      //background(255);
      background(0100);
      circle.display();
    }
    
    public class SecondApplet extends PApplet {
      public void settings() {
        size(400, 300, P3D);
      }
    
      public void setup() {
        frameRate(30);  
        //PVector myVec = new PVector(width>>1, height>>1, 0300);
        //circle = new MyCircle(this, myVec, #FFFF00);
        tetra = new Tetra(this, 10);    
      } 
    
      public void draw() {
         background(255);
         theta += 0.01;
         translate(width/2, height/2, 0);
         rotateX(theta);
         rotateY(theta);
    
         // translate the scene again
         translate(100, 100, 20);
    
        background(0100);    
         tetra.display();
    
      }
    }
    
    public class MyCircle { 
      final PApplet p;
      final PVector circle = new PVector();
      final color c;
    
      MyCircle(PApplet pa, float x, float y, float diam, color cc) {
        p = pa;
        circle.set(x, y, diam);
        c = cc;
      }
    
      MyCircle(PApplet pa, PVector vec, color cc) { 
        p = pa;
        circle.set(vec);
        c = cc;
        println("myCircle, color c: "+c);
        println("myCircle, tetra t: "+tetra.t);
        //platformNames
      }
    
      void display() {
        p.fill(c);
        p.ellipse(circle.x, circle.y, circle.z, circle.z);    
      }
    }
    
    
    public class Tetra {
    
      final PApplet p;
    
      // The PShape object
      final PShape gr;
      int t;  
      float speed;
    
      Tetra(PApplet pa, int t_) {
        p = pa;
    
        println("asking inside tetra for color c of myCircle: "+circle.c);
    
        t = t_;
    
        gr = p.createShape();
    
        gr.beginShape(TRIANGLES);
        gr.fill(150, 0, 0, 127);
        gr.vertex(-t, -t, -t);
        gr.vertex( t, -t, -t);
        gr.vertex( 0, 0, t);
    
        gr.fill(0, 150, 0, 127);
        gr.vertex( t, -t, -t);
        gr.vertex( t, t, -t);
        gr.vertex( 0, 0, t);
    
        gr.fill(0, 0, 150, 127);
        gr.vertex( t, t, -t);
        gr.vertex(-t, t, -t);
        gr.vertex( 0, 0, t);
    
        gr.fill(150, 0, 150, 127);
        gr.vertex(-t, t, -t);
        gr.vertex(-t, -t, -t);
        gr.vertex( 0, 0, t);
    
        gr.endShape();
      }
    
      Tetra display() {
        //p.box(100);
        p.shape(gr);
        return this;
      }
    }
    
  • edited July 2016

    a workaround to send data from circle to tetra by a function e.g. keyPressed():

    // forum.Processing.org/two/discussion/17585/
    // 3d-renderer-not-recognized-in-secondapplet#Item_5
    
    // after GoToLoop (2016-Jul-21)
    
    MyCircle circle;
    
    Tetra tetra;
    
    float theta = 0.0;
    
    void settings() {
    
      size(400, 300, JAVA2D);
      smooth(3);
      noLoop();
    
    runSketch(platformNames, new SecondApplet());
    }
    
    void setup() {
      frameRate(1);
      ellipseMode(CENTER);
      strokeWeight(2.5);
      stroke(0);
    
      PVector myVec = new PVector(width>>1, height>>1, 0300);
      circle = new MyCircle(this, myVec, #FFFF00);
    }
    
    void draw() {
      //background(255);
      background(0100);
      circle.display();
    }
    
    //void keyPressed() {
    //    println("data from MyCircle send to Tetra!");
    //    tetra.trial = circle.c;  
    //  } 
    
    public class SecondApplet extends PApplet {
      public void settings() {
        size(400, 300, P3D);
      }
    
      public void setup() {
        frameRate(1);  
        //PVector myVec = new PVector(width>>1, height>>1, 0300);
        //circle = new MyCircle(this, myVec, #FFFF00);
        tetra = new Tetra(this, 10);    
      } 
    
      public void draw() {
         background(255);
         theta += 0.01;
         translate(width/2, height/2, 0);
         rotateX(theta);
         rotateY(theta);
    
         // translate the scene again
         translate(100, 100, 20);
    
        background(0100);    
         tetra.display();
         println("tetra.trial: "+tetra.trial);    
      }
    
    //works:
      public void keyPressed() {    
      tetra.trial = circle.c;
      println("data from MyCircle send to Tetra!");
      } 
    }
    
    public class MyCircle { 
      final PApplet p;
      final PVector circle = new PVector();
      final color c;
    
      MyCircle(PApplet pa, float x, float y, float diam, color cc) {
        p = pa;
        circle.set(x, y, diam);
        c = cc;
      }
    
      MyCircle(PApplet pa, PVector vec, color cc) { 
        p = pa;
        circle.set(vec);
        c = cc;
        //das funktioniert:
        println("myCircle, color c: "+c);
        println("myCircle, tetra t: "+tetra.t);
    
        //platformNames
      }
    
      void display() {
        p.fill(c);
        p.ellipse(circle.x, circle.y, circle.z, circle.z);    
      }
    
    
    }
    
    
    public class Tetra {
    
      final PApplet p;
    
      // The PShape object
      final PShape gr;
      int t;  
      float speed;
      int trial;
    
      Tetra(PApplet pa, int t_) {
        p = pa;
        t = t_;
        trial = 0;
    
        gr = p.createShape();
    
        gr.beginShape(TRIANGLES);
        gr.fill(150, 0, 0, 127);
        gr.vertex(-t, -t, -t);
        gr.vertex( t, -t, -t);
        gr.vertex( 0, 0, t);
    
        gr.fill(0, 150, 0, 127);
        gr.vertex( t, -t, -t);
        gr.vertex( t, t, -t);
        gr.vertex( 0, 0, t);
    
        gr.fill(0, 0, 150, 127);
        gr.vertex( t, t, -t);
        gr.vertex(-t, t, -t);
        gr.vertex( 0, 0, t);
    
        gr.fill(150, 0, 150, 127);
        gr.vertex(-t, t, -t);
        gr.vertex(-t, -t, -t);
        gr.vertex( 0, 0, t);
    
        gr.endShape();
    
        //man kommt innerhalb der Klasse der 2. PAPplet nicht mehr an die Daten der ersten ran:
        //println("asking inside tetra for color c of myCircle: "+circle.c);
    
        //but after sending data from the forst PApplet to the second then I can access these data:
        println("trial: "+trial);
      }
    
      Tetra display() {
        //p.box(100);
        p.shape(gr);    
        return this;
      } 
    }
    
  • Before any further explanation an important observation about naming conventions in Java:

    Variables & methods use lowerCase names, while classes & interfaces go w/ UpperCase names.

    Therefore physModel should be class PhysModel.
    And vis3D should be class Vis3D instead.

  • yes i know, I was negligent mixing class with instance names

  • edited July 2016

    Your workaround based on declaring "global" variables so they can be accessed everywhere is valid.
    Although it breaks some "snob" principles about separation of concerns.

    If field tetra is initialized in class SecondApplet, it should be declared there as well, not globally.

    Well, I've fixed your last example by transferring field tetra inside SecondApplet.

    In its place I've declared a "global" variable to hold the reference for SecondApplet:
    final SecondApplet sa = new SecondApplet();

    Now in order for any class outside SecondApplet to access its members, just prefix them w/ sa.: sa.tetra

    We can't use p. in those cases b/c, for example, member tetra doesn't originally exists in class PApplet.

    That is, tetra wasn't inherited from PApplet, but it's exclusively from SecondApplet.

    // forum.Processing.org/two/discussion/17585/
    // 3d-renderer-not-recognized-in-secondapplet#Item_14
    
    // after GoToLoop (2016-Jul-21)
    
    final SecondApplet sa = new SecondApplet();
    
    MyCircle circle;
    float theta;
    
    void settings() {
      size(400, 300, JAVA2D);
      smooth(3);
      noLoop();
    
      runSketch(platformNames, sa);
    }
    
    void setup() {
      frameRate(1);
      ellipseMode(CENTER);
      strokeWeight(2.5);
      stroke(0);
    
      PVector myVec = new PVector(width>>1, height>>1, 0300);
      circle = new MyCircle(this, myVec, #FFFF00, sa.tetra);
    }
    
    void draw() {
      background(0100);
      circle.display();
    }
    
    class SecondApplet extends PApplet {
      Tetra tetra;
    
      void settings() {
        size(400, 300, P3D);
      }
    
      void setup() {
        frameRate(1);
        tetra = new Tetra(this, 10);
      } 
    
      void draw() {
        background(-1);
        translate(width>>1, height>>1, 0);
        rotateX(theta += .01);
        rotateY(theta);
    
        // translate the scene again
        translate(100, 100, 20);
    
        background(0100);    
        tetra.display();
        println("tetra.trial:", tetra.trial);
      }
    
      void keyPressed() {    
        tetra.trial = circle.c;
        println("data from MyCircle sent to Tetra!");
      }
    }
    
    class MyCircle { 
      final PApplet p;
      final PVector circle = new PVector();
      final color c;
    
      MyCircle(PApplet pa, float x, float y, float diam, color cc) {
        p = pa;
        circle.set(x, y, diam);
        c = cc;
      }
    
      MyCircle(PApplet pa, PVector vec, color cc, Tetra t) { 
        p = pa;
        circle.set(vec);
        c = cc;
    
        println("myCircle, color c: " + c);
        println("myCircle, tetra t: " + t);
      }
    
      void display() {
        p.fill(c);
        p.ellipse(circle.x, circle.y, circle.z, circle.z);
      }
    }
    
    static class Tetra {
      final PApplet p;
      final PShape gr;
    
      int t, trial;  
      float speed;
    
      Tetra(PApplet pa, int tt) {
        p = pa;
        t = tt;
    
        gr = p.createShape();
        gr.beginShape(TRIANGLES);
    
        gr.fill(150, 0, 0, 127);
        gr.vertex(-t, -t, -t);
        gr.vertex( t, -t, -t);
        gr.vertex( 0, 0, t);
    
        gr.fill(0, 150, 0, 127);
        gr.vertex( t, -t, -t);
        gr.vertex( t, t, -t);
        gr.vertex( 0, 0, t);
    
        gr.fill(0, 0, 150, 127);
        gr.vertex( t, t, -t);
        gr.vertex(-t, t, -t);
        gr.vertex( 0, 0, t);
    
        gr.fill(150, 0, 150, 127);
        gr.vertex(-t, t, -t);
        gr.vertex(-t, -t, -t);
        gr.vertex( 0, 0, t);
    
        gr.endShape();
        println("trial:", trial);
      }
    
      Tetra display() {
        p.shape(gr);    
        return this;
      }
    }
    
  • edited July 2016

    There's a 2nd issue there as well: Is global field circle also supposed to be shared among classes?
    Or should main PApplet got its own Circle instance and SecondApplet its own too? :-/

  • edited July 2016

    Is global field circle also supposed to be shared among classes?

    yes, there should be one class Circle shared with both PApplets.

    Or should main PApplet got its own Circle instance and SecondApplet its own too?

    No. In my sketch this class Circle get the external input and does some calculations which I would like to avoid doing twice.

  • edited July 2016 Answer ✓

    Oki doki! Just 1 more detail: "global" variable circle is null until:
    circle = new MyCircle(this, myVec, #FFFF00, sa.tetra);

    And tetra is null until: tetra = new Tetra(this, 10);

    If any Thread tries to access either of them while they're still null the whole program is gonna crash!

    I believe you're aware that each PApplet got its own "Animation" Thread, right?

    You may try to delay runSketch() only after circle is initialized.
    Problem is that doing so, tetra is still null @ circle = new MyCircle(this, myVec, #FFFF00, sa.tetra);

    Therefore you're gonna need to plan out your program more carefully. Good luck! >-)

  • thank you for these insights. quite a double bind with Circle and Tetra communicating with each other >:). but this helps a lot. considering this I tend to make Circle (main PApplet) to the "operator" of the whole programm which sets and gets data from tetra. So hopefully I will work around the need to access Circle from tetra. :)

Sign In or Register to comment.