# PDF renderer drawing shapes in different order then the Sketch

**URL:** <https://discourse.processing.org/t/pdf-renderer-drawing-shapes-in-different-order-then-the-sketch/19747>\
**Category:** Coding Questions\
**Created:** [April 13, 2020, 2:41pm UTC](https://discourse.processing.org/t/pdf-renderer-drawing-shapes-in-different-order-then-the-sketch/19747 "2020-04-13T14:41:46Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![LuisFerreira](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/luisferreira/32/9493_2.png) [@LuisFerreira](https://discourse.processing.org/u/LuisFerreira)\
**Post date:** [April 13, 2020, 2:41pm UTC](https://discourse.processing.org/t/pdf-renderer-drawing-shapes-in-different-order-then-the-sketch/19747/1 "2020-04-13T14:41:47Z")

</div>

Hi everyone, i am having a problem exporting my sketch to PDF.

As you can see on the Sketch’s screenshot, everything looks as it should. However the result i get on PDF, the other screenshot, is missing some elements, noticeably part of the building on the left side of the model.

Luckily it’s easy to see that the wall is indeed being drawn to PDF, however it is draw BEFORE the floor and other shapes, so it gets hidden. See the video of the PDF reader rendering the scene presumably by the order it was export.

This city is a single model, so the drawing order should be the same for the renderer and the PDF export, but its not. I am using the _beginRaw() / endRaw()_ and _hint(PConstants.DISABLE\_OPTIMIZED\_STROKE)_ to prevent strokes from being draw over shapes. Is there another hint that solves my problem or can i order the shapes manually before exporting?

Sketch:

 ![Annotation 2020-04-13 160735](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/d/d6e18fed6618d2146cb6ea7bbc2bc8b09ac61ef5.png)

PDF Reader:

 ![Annotation 2020-04-13 162058](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/7/7ab17969fe2b3d53a60ec54ef0ac285ea7b1950c.png)

Video: [https://streamable.com/jtkdwc](https://streamable.com/jtkdwc)

---

<div class="post-metadata">

**Author:** ![behreajj](https://avatars.discourse-cdn.com/v4/letter/b/b5a626/32.png) [@behreajj](https://discourse.processing.org/u/behreajj)\
**Post date:** [April 13, 2020, 10:09pm UTC](https://discourse.processing.org/t/pdf-renderer-drawing-shapes-in-different-order-then-the-sketch/19747/2 "2020-04-13T22:09:57Z")

</div>

> [@LuisFerreira](#):
>
> This city is a single model, so the drawing order should be the same for the renderer and the PDF export, but its not.

Hi @LuisFerreira,

Is the model stored in a `PShape`? How are the faces of the model ordered? Would it be possible to sort them according to distance of a face’s center along the look direction from the camera – in Processing or otherwise? (There’s more than one way to define and calculate the center… or you could use any other criteria you choose with a comparator function.)

Are you using `PGraphics3D` (`P3D`) for the first screen shot? If so, it inherits `hint` from `PGraphicsOpenGL`; the source code is [here](https://github.com/processing/processing/blob/3952f6f7247dba50920662da3276e91166426fb7/core/src/processing/opengl/PGraphicsOpenGL.java#L1845). Specifically, have a look at `ENABLE_DEPTH_SORT` and `DISABLE_DEPTH_SORT`.

---

<div class="post-metadata">

**Author:** ![LuisFerreira](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/luisferreira/32/9493_2.png) [@LuisFerreira](https://discourse.processing.org/u/LuisFerreira)\
**Post date:** [April 14, 2020, 8:11am UTC](https://discourse.processing.org/t/pdf-renderer-drawing-shapes-in-different-order-then-the-sketch/19747/3 "2020-04-14T08:11:40Z")

</div>

> Is the model stored in a `PShape` ?

Yes.

> How are the faces of the model ordered?

The main PShape has no vertexes, just children, about 12000 of them. So it basically has 2 levels, but as for the order of each shape (all triangles) i don’t know, or at least i didn’t change it.

> Would it be possible to sort them according to distance of a face’s center along the look direction from the camera – in Processing or otherwise?

I think it is, but i would prefer a solution that wouldn’t need “model specific” code, since i plan to change the model later and i don’t want to re-code a whole new ordering algorithm for each shape i load. And if it renders correctly in P3D, without any re-ordering or hinting, it should work on PDF as well right?

> Are you using `PGraphics3D` ( `P3D` ) for the first screen shot?

Yes, P3D for the sketch shot, and PDF for the pdf video and shot.

> Specifically, have a look at `ENABLE_DEPTH_SORT` and `DISABLE_DEPTH_SORT`.

i will test this again although i already did. But i didn’t see any change in the PDF export when i turn these on and off. Thanks for the link

---

<div class="post-metadata">

**Author:** ![behreajj](https://avatars.discourse-cdn.com/v4/letter/b/b5a626/32.png) [@behreajj](https://discourse.processing.org/u/behreajj)\
**Post date:** [April 14, 2020, 11:12am UTC](https://discourse.processing.org/t/pdf-renderer-drawing-shapes-in-different-order-then-the-sketch/19747/4 "2020-04-14T11:12:59Z")

</div>

Hi @LuisFerreira ,

I’ll post code – still rather messy – and a picture. If you’re still interested, I’d be happy to explain more. If you’re not interested, or if someone comes up with an easier one, no harm no foul. The model of a heart I used came from [here](https://www.myminifactory.com/object/3d-print-anatomical-heart-34709). I reduced the number of faces in the model in Blender and converted from .stl to .obj.

 ![heartExample.PNG](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/3/3ec9bfa3115154b731c3667c71478ec32c2dd800.jpeg)  
Notice that there are artifacts, or seams, between the faces. So that’s a drawback to this approach.

Best,  
Jeremy

```auto
import processing.pdf.*;
import java.util.*;

boolean recording = true;
PShape original;
ArrayList<PShape> faces;
ArrayList<PShape> projected;
PGraphics3D rndr;

void setup() {
  size(512, 512, P3D);

  rndr = (PGraphics3D)getGraphics();
  rndr.hint(DISABLE_DEPTH_TEST);
  rndr.hint(DISABLE_DEPTH_MASK);
  rndr.hint(DISABLE_DEPTH_SORT);
  rndr.perspective();
  rndr.camera(
    0.0, 0.0, rndr.height * 0.86602,
    0.0, 0.0, 0.0,
    0.0, 1.0, 0.0);

  original = loadShape("heartModel.obj");

  // Extract faces from model.
  int len = original.getChildCount();
  faces = new ArrayList<PShape>(len);
  for (int i = 0; i < len; ++i) {
    PShape face = original.getChild(i);
    faces.add(face);
  }

  // Apply transform to face vertices permanently;
  // do not use shape transform.
  PMatrix3D mat = new PMatrix3D();
  mat.rotate(THIRD_PI * 0.5, 0.0, 1.0, 0.0);
  mat.scale(15.0);

  PVector temp = new PVector();
  PVector transformed = new PVector();
  for (PShape face : faces) {
    int vertCount = face.getVertexCount();
    for (int i = 0; i < vertCount; ++i) {
      PVector vertex = face.getVertex(i, temp);
      mat.mult(vertex, transformed);
      face.setVertex(i, transformed);
    }
  }

  Collections.sort(faces, new FaceComparator());

  // Project from 3D world to 2D screen.
  projected = new ArrayList<PShape>(len);
  PVector projVert = new PVector();
  for (int i = 0; i < len; ++i) {
    PShape face = faces.get(i);
    int c = lerpColor(#ff0000, #00ffff, i / (len - 1.0), HSB);
    face.setFill(c);
    face.setStroke(false);

    int vertCount = face.getVertexCount();
    PShape projectedFace = createShape();
    projectedFace.beginShape();
    for (int j = 0; j < vertCount; ++j) {
      PVector vertex = face.getVertex(j, temp);
      screen(rndr, vertex, projVert);
      projectedFace.vertex(projVert.x, projVert.y);
    }
    projectedFace.endShape();

    projectedFace.setFill(c);
    projectedFace.setStroke(false);

    projected.add(projectedFace);
  }
}

void draw() {
  if (recording) {
    beginRecord(PDF, "foo.pdf");
  }

  background(#fff7d5);

  if (!recording) {
    // DISABLE_DEPTH_TEST does not provide a solution,
    // it helps diagnose the problem.
    if (mousePressed) {
      shape(original);
    } else {
      for (PShape face : faces) {
        shape(face);
      }
    }
  } else {
    for (PShape projFace : projected) {
      shape(projFace);
    }
  }

  if (recording) {
    endRecord();
    recording = false;
  }
}

void keyReleased() {
  recording = true;
}

static class FaceComparator implements Comparator<PShape> {

  int compare(PShape a, PShape b) {

    PVector aVec = new PVector();
    PVector bVec = new PVector();

    PVector aMean = new PVector();
    PVector bMean = new PVector();

    // Find mean center of a.
    int aVertCount = a.getVertexCount();
    for (int i = 0; i < aVertCount; ++i) {
      PVector.add(aMean, a.getVertex(i, aVec), aMean);
    }
    if (aVertCount != 0) {
      PVector.div(aMean, aVertCount, aMean);
    }

    // Find mean center of b.
    int bVertCount = b.getVertexCount();
    for (int i = 0; i < bVertCount; ++i) {
      PVector.add(bMean, b.getVertex(i, bVec), bMean);
    }
    if (bVertCount != 0) {
      PVector.div(bMean, bVertCount, bMean);
    }

    return bMean.z > aMean.z ? -1 :
      aMean.z > bMean.z ? 1 : 0;
  }
}

PVector screen(PGraphicsOpenGL rndr, PVector source, PVector target) {
  return screen(rndr, source.x, source.y, source.z, target);
}

PVector screen (
  PGraphicsOpenGL rndr,
  float xSource,
  float ySource,
  float zSource,
  PVector target ) {

  screen1s(rndr, xSource, ySource, zSource, target);
  return target.set(
    rndr.width * ( 1.0 + target.x ) * 0.5,
    rndr.height * ( 1.0 - ( 1.0 + target.y ) * 0.5 ),
    ( 1.0 + target.z ) * 0.5);
}

PVector screen1s (
  PGraphicsOpenGL rndr,
  float xSource,
  float ySource,
  float zSource,
  PVector target ) {

  float aw = rndr.modelview.m30 * xSource +
    rndr.modelview.m31 * ySource +
    rndr.modelview.m32 * zSource +
    rndr.modelview.m33;

  float ax = rndr.modelview.m00 * xSource +
    rndr.modelview.m01 * ySource +
    rndr.modelview.m02 * zSource +
    rndr.modelview.m03;

  float ay = rndr.modelview.m10 * xSource +
    rndr.modelview.m11 * ySource +
    rndr.modelview.m12 * zSource +
    rndr.modelview.m13;

  float az = rndr.modelview.m20 * xSource +
    rndr.modelview.m21 * ySource +
    rndr.modelview.m22 * zSource +
    rndr.modelview.m23;

  float bw = rndr.projection.m30 * ax +
    rndr.projection.m31 * ay +
    rndr.projection.m32 * az +
    rndr.projection.m33 * aw;

  if ( bw == 0.0 ) {
    return target.set(0.0, 0.0, 0.0);
  }

  float bx = rndr.projection.m00 * ax +
    rndr.projection.m01 * ay +
    rndr.projection.m02 * az +
    rndr.projection.m03 * aw;

  float by = rndr.projection.m10 * ax +
    rndr.projection.m11 * ay +
    rndr.projection.m12 * az +
    rndr.projection.m13 * aw;

  float bz = rndr.projection.m20 * ax +
    rndr.projection.m21 * ay +
    rndr.projection.m22 * az +
    rndr.projection.m23 * aw;

  if ( bw != 1.0 ) {
    float wInv = 1.0 / bw;
    return target.set(
      bx * wInv,
      by * wInv,
      bz * wInv);
  }

  return target.set(bx, by, bz);
}

```

---

<div class="post-metadata">

**Author:** ![behreajj](https://avatars.discourse-cdn.com/v4/letter/b/b5a626/32.png) [@behreajj](https://discourse.processing.org/u/behreajj)\
**Post date:** [April 14, 2020, 1:24pm UTC](https://discourse.processing.org/t/pdf-renderer-drawing-shapes-in-different-order-then-the-sketch/19747/5 "2020-04-14T13:24:23Z")

</div>

Hi again,

Nevermind, I double checked the [reference](https://processing.org/reference/beginRaw_.html) for `beginRaw` (as opposed to `beginRecord` as used above) and read the important part here:

> Using hint(ENABLE\_DEPTH\_SORT) can improve the appearance of 3D geometry drawn to 2D file formats.

I assumed wrongly that depth sorting was enabled by default and that you’d still get improperly sorted faces with it on.

Best,  
Jeremy

---

<div class="post-metadata">

**Author:** ![LuisFerreira](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/luisferreira/32/9493_2.png) [@LuisFerreira](https://discourse.processing.org/u/LuisFerreira)\
**Post date:** [April 15, 2020, 9:57am UTC](https://discourse.processing.org/t/pdf-renderer-drawing-shapes-in-different-order-then-the-sketch/19747/6 "2020-04-15T09:57:06Z")

</div>

Thank you for the help behreajj. I like the idea of your _FaceComparator_ but i haven’t tried it. I did try again with and without hints and I couldn’t find a way to draw the faces in the right order.

I wanted to have this feature in a library i am developing, you can check it at: `https://github.com/LFBFerreira/MediaExport`
