Code generated pattern wrap on 3D

Hello, I have been to trying to program a cuboid with surfaces rendered in code generated patterns (image attached). While there is a texture function for wrapping images, I couldn’t find anything for SVG’s or code generated patterns. Also, it seems texture wrap doesn’t export for pdf/svg on renderers like P3D or OpenGL. I would like to render the final output as PDF or SVG. Does anyone know how to do this?

Thanks.

1 Like

Hi! What about drawing 6 planes with 6 textures? Maybe create your own function like mycube(x, y, z, w, h, d, tex1, tex2, tex3, tex4, tex5, tex6)? Would that work?

1 Like

@hamoid I was thinking of that as the last option, but may be I shall give it a try. To reduce some complexity, is there a way to vector mask/map procedural textures onto a 3d plane?

I think there are two ways to get what you want:

  1. With textures. You draw 3 shapes with 4 vertices each, like in https://processing.org/reference/texture_.html Each vertex has the screen space coordinates and the texture coordinates. I find it easier to work with textureMode(NORMAL);, so the texture coordinates are normalized (between 0.0 and 1.0 instead of using pixel sizes, which change depending on the specific texture you use).

Since you want to generate your texture, you can create a PGraphics, draw into it and later use it as a texture for your planes.

This works, but if you want to print the result large it’s not ideal, because the pattern on each side is a bitmap and it may look pixelated if your texture is not high res enough.

  1. Deforming the coordinate system with shearX(), shearY(), rotate etc. to simulate the perspective. It may be tricky to position each plane on the right location, but once done, you could call any function including ellipse() to draw on the planes directly as if they were 3 displays, without using any temporary PGraphics. This should produce a completely vector based result, so if you created an SVG or PDF you can print them as large as you want.

An example of this second approach:

void setup() {
  size(400, 400, P3D);
  noStroke();
}
void drawCircles(float x, float y) {
  for(int sz=80; sz>0; sz-=10) {
    fill(random(255));
    ellipse(x, y, sz, sz);
  }
}
void draw() {
  background(255);
  translate(width/2, height/2);

  fill(60);
  pushMatrix();
  shearX(PI/4);
  scale(1.0, 0.5);
  rect(0, 0, 100, -100);
  drawCircles(50, -50);
  popMatrix();

  fill(100);
  rect(0, 0, 100, 100);
  drawCircles(50, 50);

  fill(160);
  pushMatrix();
  shearY(PI/4);
  scale(0.5, 1.0);
  rect(0, 100, -100, -100);
  drawCircles(-50, 50);
  popMatrix();
}

2018-09-10-155519_400x400_scrot

3 Likes

A variation of 2, where you rotate the axes so you can draw in a known safe area, in this case it’s a rectangle located at 0, 0 and with dimensions 100, 100. There you could draw a grid like in your example, knowing that you stick to that safe area if you want to stay within the rectangle.

void setup() {
  size(400, 400, P3D);
  noStroke();
  rectMode(CENTER);
  hint(DISABLE_DEPTH_TEST);
}
void drawCircles(float x, float y) {
  for(int sz=80; sz>0; sz-=10) {
    fill(random(255));
    ellipse(x, y, sz, sz);
  }
}
void draw() {
  background(255);
  translate(width/2, height/2);
  rotateX(-0.5);
  scale(2.0);

  // right plane
  fill(60);
  pushMatrix();
  rotateY(PI/4);
  translate(0, 0, 50);
  rect(0, 0, 100, 100);
  drawCircles(0, 0);
  popMatrix();

  // left plane
  fill(100);
  pushMatrix();
  rotateY(-PI/4);
  translate(0, 0, 50);
  rect(0, 0, 100, 100);
  drawCircles(0, 0);
  popMatrix();

  // top plane
  fill(140);
  pushMatrix();
  rotateY(PI/4);
  rotateX(PI/2);
  translate(0, 0, 50);
  rect(0, 0, 100, 100);
  drawCircles(0, 0);
  popMatrix();
}

2018-09-10-160408_400x400_scrot

With this approach the result is still vector data. I hope this works with PDF / SVG, I haven’t tried.

The hint I used forces things to be drawn to the screen in the same order as your instructions get executed. Without it I get this unwanted but nice glitch due to z-fighting:
2018-09-10-160832_400x400_scrot

2 Likes

Thanks @hamoid, this approach seems interesting, will try to render a pdf from this and let you know.

It almost worked in achieving the vector output, but unfortunately it is rendering pdf/svg in triangles. I’m looking for vectors with clean paths. I would be using the vector output on a xy plotter. Im assuming there should be another way of rendering the pdf/svg output.

import processing.pdf.*;
import processing.svg.*;
float rotx = PI/4;
float roty = PI/4;
boolean record;

void setup() {
  size(400, 400, OPENGL);
  noStroke();
  rectMode(CENTER);
  hint(DISABLE_DEPTH_TEST);
  pixelDensity(2);
  ortho();
  smooth();
}
void drawCircles(float x, float y) {
  for (int sz=80; sz>0; sz-=10) {
    fill(random(255));
    ellipse(x, y, sz, sz);
  }
}
void draw() {
  background(255);

  if (record) {
    beginRaw(PDF, "output.pdf");
    //beginRaw(SVG, "output.svg");
  }

  translate(width/2, height/2);
  rotateX(rotx);
  rotateY(roty);  
  scale(2.0);

  // right plane
  fill(255, 0, 0);
  pushMatrix();
  rotateY(PI/4);
  translate(0, 0, 50);
  rect(0, 0, 100, 100);
  drawCircles(0, 0);
  popMatrix();

  // left plane
  fill(0, 100, 255);
  pushMatrix();
  rotateY(-PI/4);
  translate(0, 0, 50);
  rect(0, 0, 100, 100);
  drawCircles(0, 0);
  popMatrix();

  // top plane
  fill(255, 200, 0);
  pushMatrix();
  rotateY(PI/4);
  rotateX(PI/2);
  translate(0, 0, 50);
  rect(0, 0, 100, 100);
  drawCircles(0, 0);
  popMatrix();
  if (record) {
    endRaw();
    record = false;
  }
}

void keyPressed() {
  // Use a key press so that it doesn't make a million files
  if (key == 's') {
    record = true;
  }
}

void mouseDragged() {
  float rate = 0.01;
  rotx += (pmouseY-mouseY) * rate;
  roty += (mouseX-pmouseX) * rate;
}

1 Like

It’s expected that it uses triangles, since the program uses filled shapes.

What if you replace noStroke() by noFill() and every mention of fill(...) by stroke(...)?

@hamoid Finally I managed to get the positioning of the planes and pattern mapping right. Also the issue of triangulation doesn’t appear when using strokes alone as the shapes are broken into disjointed lines - but then it gets chaotic since there is no fill. Since there are only 6 surfaces, I should be able to easily fix this in a vector editing tool as long as I’m only generating one or few cuboids.

The bigger problem starts to appear when having fills. The appearance of rendered pdf seems to be based on the actual sequence of the functions in code. While there is a function for depth sorting for 3D renders/PDF. The depth sorting seems to work only for fills - all the stroke data is pushed behind the fills if I enable hint(ENABLE_DEPTH_SORT); (attached).

So I added the hint(DISABLE_OPTIMIZED_STROKE); function to get the stroke data on top, but now its not sorted as it appears on run preview (attached).
12%20PM

2 Likes

Cool, you’re getting closer :slight_smile:

What if you draw only the three faces you care about. Is that an option?

The problem is I would like to have all 6 faces since the object would be rotated dynamically. But I would only need the 3 surfaces with textures that are visible, so it would definitely help I can eliminate the rest of hidden 3 surfaces during the process of generating the PDF - That way I don’t have to edit this further in illustrator or Inkscape. Is there a way to convert the 3D visual into a 2D visual and then render as 2D output - so there would be no depth issues or hidden surfaces?

Not that I know of.

I was taking a look at the exported svg / pdf files and it seems like the current implementation of those exporters in Processing is very simple and not optimized. Ellipse borders become tons of segments and the fills become many triangles, when the border could be just one segment with many points, same for the fill.
The issue with that is that the resulting file is not easily editable in something like Inkscape.

I also took a look at doing the same in openFrameworks. The exporter is better (paths with many vertices are ok, circles are not made out of triangles) but I could not get 3D shapes exported correctly (in my brief tests).

I don’t know if it helps, but you could calculate which plane of each pair is closer to you and render that, skipping the one that is farther.

Update: one more option would be using three.js. It has an SVG renderer. three.js svg - sandbox An example: Using Three.js to Create Vector-Graphics from 3D-Visualizations Right in Your Browser - Felix Breuer's Blog

2 Likes

Will try to work around this, seems like the only option i have since I don’t know any other programming language. Thanks for the help so far @hamoid

@vallu you might also be interested in @WakeMeAtThree 's morph explorations – see in particular the comment about ortho() mode when working in 3D.

2 Likes