Why is lights() not lighting sphere in a class?

GLVGLV
edited January 2018 in Questions about Code

Why is lights() not lighting sphere in a class in this example?

float th_6 = 0; 
Orbital Orb_3;

void setup()
  {
  size(1280, 1024, P3D);

//Class initialization
  Orb_3 = new Orbital();
  }

void draw()
  {   
  background(0); 
  lights();
  noStroke();
  translate(width/2, height/2, 0);
  sphere(20); //lights work on this!
  th_6=th_6+TWO_PI/360;
  seq_D();
  }

class Orbital
  {
  int A = 200; //diameter
  float x, y, z;
  float th = 0;

 void Circle()
    {
    for(th=0;th<TWO_PI;th+=TWO_PI/360)
      {
      x=A*cos(th);  
      y=A*sin(th);
      point(x, y, 0);
      }
    }  

   void Traj()
    {
    x = A*cos(th_6);  
    y = A*sin(th_6);
    translate(x,y);
    }       
  }         

void seq_D()
  {
  strokeWeight(2);
  rotateY(th_6);
  stroke(255, 0, 255);
  Orb_3.Circle();
  Orb_3.Traj();
  sphere(20);       //lights DO NOT work on this!
  } 

Answers

  • Please edit post, highlight code, press Ctrl-o

  • Thanks for tip.

  • GLVGLV
    edited October 2016

    Added a noStroke() to make shading from light work on sphere:

    void seq_D()
      {
      strokeWeight(2);
      rotateY(th_6);
      stroke(255, 0, 255);
      Orb_3.Circle();
      noStroke();       //Added this! 
      Orb_3.Traj();
      sphere(50);       
      }
    
  • @GLV -- good catch -- it doesn't have anything to do with a class, it seems like each sphere() needs there to be noStroke() in order to have default lighting. In order to consistently isolate stroke/noStroke in your sketch try using pushStyle/popStyle.

    A few suggestions:

    1. Set the whole sketch to noStroke() in setup() -- then all your spheres will draw correctly without needing to remember to remove stroke each time.
    2. If you need to change styles (for example, for your purple points of your orbital circle), wrap that pushStyle() / popStyle() so that your later spheres don't all turn purple as well.
    3. Draw your very first central sphere(20) after the rotate -- you can't see a difference now, but if you used a globe of the earth or other textures later, then that would make it spin correctly with the camera.
    4. Right now your Orbital.circle and Orbital.traj both use the same Orbital.x,y as scratch variables for different reasons -- but this could cause nasty bugs in the future. Orbital.x,y should probably be used to store translation offsets if you draw more than one member of the class.

    Other thoughts:

    • If Orbital.circle is going to draw, why not have Orbital.traj draw as well? Consistently of class methods as a sketch grows.
    • Adding arguments for class methods: purple and thick vs. green and thin, for example.
    • Adding an Orbital constructor so that you can set the diameter etc.

    Sketch:

    //// https:// forum.processing.org/two/discussion/18352/why-is-lights-not-lighting-sphere-in-a-class
    
    color purple = color(255, 0, 255);
    color green = color(0, 255, 0);
    float th_6 = 0;
    Orbital Orb_3;
    Orbital Orb_3b;
    
    void setup() {
      size(300, 300, P3D);
      noStroke(); // default so sphere() is lighted
      //Class initialization
      Orb_3 = new Orbital(100);
      Orb_3b = new Orbital(50,0,0,0);
    }
    
    void draw() {   
      background(0);
      lights();
      translate(width/2, height/2, 0);
      sphere(20);
      th_6+=TWO_PI/360;  
      rotateY(th_6);
      Orb_3.center(30);
      Orb_3.circle(3, purple);
      Orb_3.traj(15, th_6);
    
      rotateY(th_6);
      rotateZ(th_6);
      Orb_3b.circle(2, green);
      Orb_3b.traj(5, th_6/2);
    }
    
    class Orbital {
      int diam = 200; //diameter
      float x, y, z;
      float th = 0;
    
      Orbital(int diam_){
        this(diam_, 0.0, 0.0, 0.0);
      }
      Orbital(int diam_, float x_, float y_, float z_){
        diam = diam_;
        x = x_;
        y = y_;
        z = z_;
      }
    
      void center(float size) {
        pushMatrix();
          translate(x, y, z);
          sphere(size);
        popMatrix();
      }
    
      void circle(int weight, color c) {
        float cx, cy;
        for (th=0; th<TWO_PI; th+=TWO_PI/360)
        {
          cx=diam*cos(th);  
          cy=diam*sin(th);
          pushMatrix();
            translate(x,y,z);
            pushStyle();
              strokeWeight(weight);
              stroke(c);
              point(cx, cy, 0);
            popStyle();
          popMatrix();
        }
      }  
    
      void traj(float size, float angle) {
        float tx = diam*cos(angle);  
        float ty = diam*sin(angle);
        pushMatrix();
          translate(tx + x, ty + y, z);
          sphere(size);
        popMatrix();
      }
    }
    

    LightingSphere

  • GLVGLV
    edited October 2016

    Hello, Thanks for taking the time to provide great feedback! My background is embedded C with no object oriented programming. :) and :( ! I have been programming for a couple of months now with Processing and gradually transitioning from "procedural" to "object-oriented" and enjoying the ride. Converting all the code (1000s of lines and dozens of tabs!) I wrote for this and other projects to object-oriented and already seeing the benefits:

    GLV

  • @GLV -- this is really beautiful work! Thank you for sharing the video.

    I hope that the project is still going well.

  • edited October 2016 Answer ✓

    @GLV --

    Later, I found myself wondering if the noStroke() lighting behavior was actually bug and should be reported.

    It looks like it is by-design -- however it can be confusing trying to light a sphere by trial-and-error.

    The problem above was that your stroke weight / sphere distance was creating a mesh that completely covered your fill so that it couldn't interact with the lighting source.


    Essentially:

    1. lighting interacts with non-black fill
    2. stroke covers fill, and does not interact with light.

    Therefor, the only light-able spheres are: - filled - non-black - have no stroke - or have stroke that show fill through the mesh.

    See demo sketch for examples. Out of these eighteen spheres with different settings, only four of them respond to the light source.

    /**
     * Sphere Lighting
     * 2016-10-30 Jeremy Douglass - Processing 3.2.1
     * https:// forum.processing.org/two/discussion/18352/
     **/
    
    float sw, sh, sr; // sphere width, height, radius
    float lightX, lightY;
    
    void setup() {
      size(800, 400, P3D);
      textAlign(CENTER,CENTER);
      textSize(12);
      textMode(SHAPE);
      sw = width/7.0;
      sh = height/3.0;
      sr = width/14.0;
    }  
    void draw() {
      background(64);
      translate(0,0,-70);
    
      styleSphere ( sw * 0, sh * 0, sr, "noStroke", 0,  "noFill");
      styleSphere ( sw * 1, sh * 0, sr, "noStroke", 0,  "0");
      styleSphere ( sw * 2, sh * 0, sr, "noStroke", 0,  "255");
      styleSphere ( sw * 0, sh * 1, sr, "0",        1,  "noFill");
      styleSphere ( sw * 1, sh * 1, sr, "0",        1,  "0");
      styleSphere ( sw * 2, sh * 1, sr, "0",        1,  "255");
      styleSphere ( sw * 0, sh * 2, sr, "255",      1,  "noFill");
      styleSphere ( sw * 1, sh * 2, sr, "255",      1,  "0");
      styleSphere ( sw * 2, sh * 2, sr, "255",      1,  "255");
    
      styleSphere ( sw * 4, sh * 0, sr, "noStroke", 0, "noFill");
      styleSphere ( sw * 5, sh * 0, sr, "noStroke", 0, "0");
      styleSphere ( sw * 6, sh * 0, sr, "noStroke", 0, "255");
      styleSphere ( sw * 4, sh * 1, sr, "0",        10, "noFill");
      styleSphere ( sw * 5, sh * 1, sr, "0",        10, "0");
      styleSphere ( sw * 6, sh * 1, sr, "0",        10, "255");
      styleSphere ( sw * 4, sh * 2, sr, "255",      10, "noFill");
      styleSphere ( sw * 5, sh * 2, sr, "255",      10, "0");
      styleSphere ( sw * 6, sh * 2, sr, "255",      10, "255");
    }
    
    void styleSphere(float x, float y, float r, String strStroke, int strWeight, String strFill){
      pushMatrix();
        translate(x, y, 0);
        translate(r, r, 0);
    
        //// draw sphere
        pushStyle();
          lightControl();
          strokeWeight(strWeight);
          if(strStroke == "noStroke") { noStroke(); }
          else { stroke(int(strStroke)); }
          if(strFill == "noFill") { noFill(); }
          else { fill(int(strFill)); }
          sphere(r);
        popStyle();
    
        //// draw label
        translate(0,0,80);
        pushStyle();
          strokeWeight(1);
          fill(255);
          noLights();
          rect(-36,-24,72,48);
          fill(0);
          text(strStroke + "/" + strWeight + "\n" + strFill, 0,0,0);      
        popStyle();
    
      popMatrix();
    }
    
    void lightControl(){
      // lights();
      directionalLight(255, 204, 204,
        -(mouseX / float(width)  - 0.5) * 2,
        -(mouseY / float(height) - 0.5) * 2,
        -1); 
    }
    

    SphereLighting

  • @jeremydouglass Thanks for the great demo! And excellent formatting as well. Only thing I did was add ortho() to settings to change the view. This was prompted by a friend looking at this and asking about this... which spawned off to another hour of discussion! Have a great new year!

  • Interesting discussion here

    I always use sphere with noStroke();

    But with stroke being active it would depend on the size of the sphere and maybe also on the value of sphereDetail how much actual fill area you see that reacts to light (as has been said)

    I just wanted to mention size and sphereDetail() here as possible factors

    Happy new year!

    Chrisir

  • @GLV -- very glad that it was helpful! Good ortho tip.

    @Chrisir -- great point about sphereDetail() also affecting the mesh and how much surface the stroke covers -- at higher detail, there are more lines per unit of sphere surface. That would be a good thing to add to a revised demo -- possibly with sliders for:

    • stroke weight
    • fill
    • fill color
    • sphere detail
Sign In or Register to comment.