Draw order in 3D

I’m getting into 3d for the first time and I’m not quite sure how I’m supposed to handle draw order.

The easiest way to explain my question is probably with an image and code.
Screenshot%20from%202018-10-24%2009-58-23

void setup() {
  size(1280, 720, P3D);
  camera = new PeasyCam(this, 500);
}

void draw() {
  background(0);

  // grey sphere
  stroke(150);
  fill(255);
  sphere(50);
  
  // blue sphere
  translate(150, 150, 150);
  stroke(0, 0, 255);
  sphere(50);
}

In this image, the camera is positioned on the side of the grey sphere, with the blue sphere in the back (that’s why it appears smaller, even though both spheres have a radius of 50). Despite that, the blue sphere is rendered overtop of the grey one.

Intuitively, I would expect that, given this camera angle, the grey sphere should block the view of the blue one, even though the blue one was rendered last. What am I missing here?

1 Like

Try this. Blue sphere behind grey sphere. Works fine.

void setup() {
  size(1280, 720, P3D);
 // camera = new PeasyCam(this, 500);
}

void draw() {
  background(0);
  translate(width/2,height/2);

  // grey sphere
  stroke(150);
  fill(255);
  sphere(50);
  
  // blue sphere
  translate(50,50,-50);
  stroke(0, 0, 255);
  sphere(50);
}
1 Like

The Processing compiler renders the shapes in the order you write it in. Since the gray sphere is after the blue sphere, the blue sphere would be first.

If it was the opposite, that means everything would be covered by the background! :slight_smile:

This might be true in 2D mode. It is not true in 3D mode! Consider the code in my post, above. The blue sphere is drawn in draw() after the grey one, yet it appears behind it!

I never knew! You can ignore my post then :slight_smile:

Or if you think about it like Reality, if you draw a picture you can Cover up other colors by Drawing after the first, But if you take 3D it’s like placing Blocks. You can place things behind another Block that is already there, then it still wouldn‘t Show, since the 1st one Blocks the view. You can also use this method to draw a 2D picture with 3D Planes/points and modify it, just by changing the z Position of the planes/points, no matter in what Order you draw them.

As it has been said:

  • In 2D the draw order determines which shape is before another (and covers it). Like on a canvas, the shape which gets drawn first is painted over by shapes that are drawn later.

  • In 3D the draw order does not matter. Instead, processing calculates which shape is in front and which shape in the back. This determines what shape is before another shape (and covers it). This is determined by the Z-Position of a shape.

You are not drawing on a canvas but placing shapes in a 3D room. Think of the surface of a table, with translate(), the x parameter places left/right, the y parameter places above the table (up/down), and the last Parameter, the z parameter moves the shape towards you or away from you parallel to the table surface (back / forth).
If you rotate the entire scene, you can see the placement of the shapes.

This sketch shows a better handling of the spheres in a function sphereAt.

Chrisir



final color RED   = color(255, 0, 0);
final color GREEN = color(0, 255, 0);
final color BLUE  = color(0, 0, 255);
final color GRAY  = color(150);

void setup() {
  size(1280, 720, P3D);
  // camera = new PeasyCam(this, 500);
}//setup

void draw() {
  background(0);
  lights(); // everything looks better with lights()
  sphereAt (width/2, height/2, 0, GRAY);
  sphereAt (width/2+50, height/2+50, -50, BLUE);
} // draw 

void sphereAt ( float x, float y, float z, 
  color colorSphere) {

  pushMatrix();       // store Matrix 
  translate(x, y, z); // position
  noStroke();         // no lines on the sphere  
  fill(colorSphere);  // fill color of the sphere 
  sphere(50);         // size of the sphere = 50 
  popMatrix();        // restore Matrix 
  //
}//sphereAt
//
1 Like

Hey all, thanks for the responses! I haven’t had a chance to go through and try them yet, but I’m still working on this and will let you know if the problem was solved soon.

1 Like

The issue above was with translateZ(-150) vs translateZ(150). So a question of which direction is forward / back.

Also notice that coordinates when using PeasyCam work differently than the default 3D cam.

Even once this is worked out:

Note however, with transparent object 3D CAN still sometimes have problems with drawing behind-things in front of in-front things. For fixing that, use hint().

This can also apply to strokes – so if you are rendering a sphere with strokes, that can be the issue. See hamoids demo sketch and try clicking settings on and off to get a sense of how strokes can pop-through in surprising ways.

1 Like

Hmm, is there a specific way to make objects be non-transparent? I’ve played around with the hint() settings, but they don’t seem to be affecting the way my sketches are being rendered.

Here’s a longer example that gets a bit closer to what I’m actually trying to do.

By clicking the mouse I can alter which shape gets drawn first, and this changes the way they are displayed in the sketch, regardless of camera position.
Screenshot%20from%202018-10-25%2011-44-03

boolean sphereFirst = true;

void setup() {
  size(1280, 720, P3D);
  hint(ENABLE_DEPTH_TEST);
  hint(ENABLE_DEPTH_SORT);
}

void draw() {
  background(55);
  lights();
  rotateCam();

  // Clicking the mouse button changes which shape gets rendered first.
  if (sphereFirst)
  {
    makesphere();
    makerect();
  }
  else
  {
    makerect();
    makesphere();
  }
}

void rotateCam()
{
  translate(width/2, height/2);
  rotateX(frameCount * 0.002);
  rotateY(frameCount * 0.005);
}

void makerect()
{
  pushMatrix();
  fill(100);
  rotateX(HALF_PI);
  rect(-10, -10, 100, 100);
  popMatrix();
}

void makesphere()
{
  pushMatrix();
  translate(0, -25, 0);
  stroke(50, 255, 50);
  fill(0, 0, 255);
  PShape globe = createShape(SPHERE, 25);
  shape(globe);
  popMatrix();
}

void mousePressed() {
  sphereFirst = !sphereFirst;
}

i see some results regarding tranparency

void makerect()
{
  pushMatrix();
  stroke(50, 255, 50,mouseY/3);
  fill(100,100,100,mouseX/5);
  rotateX(HALF_PI);
  rect(-10, -10, 100, 100);
  popMatrix();
}

void makesphere()
{
  pushMatrix();
  translate(0, -25, 0);
  stroke(50, 255, 50,mouseY/3);
  fill(0, 255, 255,mouseX/5);
  sphere(25);
  popMatrix();
}

the

hint()

is from processing.js ?? should that work here? well it does not give a error?

//______________________________________________
when you use P3D a operation would be nice, here a working example
for mouse or keyboard

PImage earth;
PShape globe;

//_________________________________________________________________ SETUP
void setup() {
  size(640, 360, P3D);
  earth = loadImage("earth.jpg");
  globe = createShape(SPHERE, 1);
  globe.setStroke(false);
  globe.setTexture(earth);
  info_print();
}//setup

//_________________________________________________________________ DRAW
void draw() {
  background(0);
  lights(); // everything looks better with lights()
  PTZ();
} // draw 

//_________________________________________________________________ DRAW_OBJECT
void draw_object() { //_________________called by / from inside PTZ
  noStroke();        //directionalLight(250, 250, 250, 0, 0, -1); //ambientLight(100,100,100); // light and texture not work together
  shape(globe,0, 0);
  sphereAt (3, 0, 0, 0.3, color(140,140,140));
}

//_________________________________________________________________ SPHEREAT
void sphereAt( float x, float y, float z, float r, color colorSphere) {
  translate(x,y,z);
  fill(colorSphere);  // fill color of the sphere 
  sphere(r);          // size of the sphere
  translate(-x,-y,-z);
}//sphereAt

//_________________________________________________________________
// PTZ tab

int mode = 0;
float Zmag = 21.1;
int Zaxis=-160;                                                       
float Xmag, Ymag = 0;
float newXmag, newYmag = 0; 
int newZmag = 0;
int zoomf = 3;
float newxpos, newypos = 0;       // for PAN
float xposd, yposd = 0;           // for PAN

//_________________________________________________________________ ROTATE / TILDE and MOVE / PAN
void mousePressed() {
  if      (mouseButton == LEFT)   { mode=1; }  // ORBIT
  else if (mouseButton == RIGHT)  { mode=2; }  // PAN
  // else if (mouseButton == CENTER) { mode=3; }  // zoom mouse wheel
}

//_________________________________________________________________ mouse PT end
void mouseReleased() { 
  mode = 0;
}

//_________________________________________________________________ mouseWheel ZOOM
void mouseWheel(MouseEvent event) {
  int newZmag = event.getCount();                                     // +- 1
  if (Zmag > 10) { Zmag += newZmag * 5; } else { Zmag += newZmag; }   // from 1 to 11 go in step 1 else in step 5 
}

void keyPressed(){
 if ( keyCode == UP   ) {Ymag -= 0.1 ;} 
 if ( keyCode == DOWN ) {Ymag += 0.1 ;} 
 if ( keyCode == RIGHT) {Xmag -= 0.1 ;} 
 if ( keyCode == LEFT ) {Xmag += 0.1 ;}
 
 if ( keyCode == 16 )   {Zmag -= 1 ;} // [PageUP]
 if ( keyCode == 11 )   {Zmag += 1 ;} // [PageDOWN]
 //println("key: "+key); println("keyCode: "+keyCode);
 
}
//_________________________________________________________________ Pan Tilde Zoom
void PTZ() {
  pushMatrix(); 
  translate(width/2, height/2, Zaxis);
  // get new mouse operation  
  if ( mode == 2 ) {                              // PAN ( right mouse button pressed)
    xposd = (mouseX-float(width/2));
    yposd = (mouseY-float(height/2));  
  }  
  newxpos = xposd;// xposd=0;
  newypos = yposd;// yposd = 0; 
  translate(newxpos,newypos, 0);          // move object
  if ( mode == 1 ) {  // ORBIT ( left mouse button pressed)
  newXmag = mouseX/float(width) * TWO_PI;
  newYmag = mouseY/float(height) * TWO_PI;
  
  float diff = Xmag-newXmag;
  if (abs(diff) >  0.01) {   Xmag -= diff/4.0; }
  diff = Ymag-newYmag;
  if (abs(diff) >  0.01) {   Ymag -= diff/4.0; }
  }
  rotateX(-Ymag);   rotateY(-Xmag);   
  scale(Zmag);
  
  draw_object();                                // see MAIN: THE OBJECT
  
  popMatrix();   
}

//_______________________________________________ SETUP PRINT INFO
void info_print() {
 println("PTZ info:");
 println("mouse LEFT press drag up down right left || key arrow UP DOWN RIGHT LEFT -> rotate");
 println("mouse RIGHT press -> move ");
 println("mouse WHEEL turn || key PAGE UP DOWN -> zoom");
}

you need the earth image in
/data/earth.jpg
earth

The only thing missing in your program is replacing the two hints by this one

hint(DISABLE_DEPTH_TEST);

@kll

the hint() is from processing.js ?? should that work here? well it does not give a error?

Yeah, it works fine. It also works fine with @jeremydouglass 's example, so I don’t think it’s only for processing.js.

@hamoid

The only thing missing in your program is replacing the two hints by this one hint(DISABLE_DEPTH_TEST);

I tried that, but it didn’t change anything on my machine. The shape that I draw last is always rendered in front, regardless of how they are actually positioned in the space.

Weird… for me with

hint(DISABLE_DEPTH_TEST);

does sorted-by-code and

hint(ENABLE_DEPTH_TEST);

does sorted-by-depth.

Referring to your makeRect example:

rect is a 2D shape. Try box instead.

When using rect in 3D space or using box you need to use translate () with 3 parameters.

Without translate it’s at Z = 0 I guess or just drawn above the scene