Using PShapes as a canvas for images

Hello Everyone,

I’m just getting started with P3D, although I’ve used Processing in the past, and have run into an issue: I can’t figure out how to place images on a PShape. I have looked at the Texture Cube example provided by Dave Bollinger and have managed to get it to work for me but the next step would be to place an image not as a texture but as an image that can be modified by the user by being translated, rotated and scaled on the box. Something like this:

3

You can see how the image has been scaled and transformed to look as if the face of the cube is its “regular” canvas. I haven’t been able to find any information on how to address the faces individually, other than by using the texture command, which unfortunately does not allow me to then translate the image, and furthermore does not allow for multiple images to be placed and overlapped.

If I get this to work, my ultimate goal would then be to upload an obj file with a uv map created in Blender where images can be placed and moved by the user.

Does anyone have any experience with this? Is this even possible in Processing? Would I be better off considering a different environment to tackle this problem?

Thanks in advance for the help!

1 Like

I was able to get an image on faces of a cube and sharing example.

Started with these:
https://processing.org/examples/texturecube.html
https://processing.org/examples/texturecylinder.html
https://processing.org/reference/vertex_.html

PImage tex;

float rotx;
float roty;

void setup() 
  {
  size(800, 800, P3D);
  tex = loadImage("download.jpg");
  textureMode(NORMAL);
  }

void draw() 
  {
  background(0);
  noStroke();
  translate(width/2.0, height/2.0, 0);
  rotx += TAU/500;
  roty += TAU/500;
  rotateX(rotx);
  rotateY(roty);
  scale(100);
  TexturedCube(tex);
  }

void TexturedCube(PImage tex) 
  {
  beginShape(QUADS);
  texture(tex); 
  // +Z "front" face
  vertex(-1, -1,  1, 0, 0);
  vertex( 1, -1,  1, 1, 0);
  vertex( 1,  1,  1, 1, 1);
  vertex(-1,  1,  1, 0, 1);
  endShape();

  beginShape(QUADS);
  texture(tex);
  // +Y "bottom" face
  vertex(-1,  1,  1, 0, 0);
  vertex( 1,  1,  1, 1, 0);
  vertex( 1,  1, -1, 1, 1);
  vertex(-1,  1, -1, 0, 1);
  endShape();
  
  beginShape(QUADS);
//  texture(tex);
  fill(255, 255, 0);
  // +X "right" face
  vertex( 1, -1,  1, 0, 0);
  vertex( 1, -1, -1, 1, 0);
  vertex( 1,  1, -1, 1, 1);
  vertex( 1,  1,  1, 0, 1);
  endShape();
  }

download

:slight_smile:

1 Like

Hi glv,

Thank you for taking the time to look at my query. Unfortunately the approach you’ve suggested relies on the texture call. As I understand it calling texture() does not allow for multiple images to be placed one on top of the other, nor does it allow for the image to be translated within the plane (at least not without modifying the UV map).

Have I misunderstood how to use texture() and is it possible to have multiple overlapping textures or is there another approach where this would be possible?

Thanks again!

Experimenting…

Created an image, rotated it, grabbed it (get()) and put it on the face of cube.
Rotations and translations a bit messy… I was manipulated code I was working on at the moment.

PImage tex;
PImage img = createImage(50, 50, RGB);

float rotx, roty, rotz;
float size;

void setup() 
  {
  size(600, 600, P3D);
  textureMode(NORMAL);
  }

void draw() 
  {
  background(128);
  noStroke();

  rotx += TAU/500;
  roty += TAU/500;

pushMatrix();
  translate(100, 100);
 pushMatrix();
  rotate(rotx*2);
  translate(-100, -100);
 
  strokeWeight(5);
  stroke(0);
  fill(255, 255, 0);
  circle(100, 100, 190);
  rectMode(CENTER);
  fill(0, 255, 0);
  rect(100, 100, 50, 50);
 
 popMatrix(); 
popMatrix();
  img = get(0, 0, 200, 200);
  
  image(img, 400, 400); 
  
 pushMatrix();
  translate(width/2.0, height/2.0, -500);
  rotateX(rotx);
  rotateY(roty);
  size = 100;
  noStroke();
  TexturedCube(img);
 popMatrix();
  }

void TexturedCube(PImage tex) 
  {
  beginShape(QUADS);
  texture(tex); 
  // +Z "front" face
  vertex(-size, -size,  size, 0, 0);
  vertex( size, -size,  size, 1, 0);
  vertex( size,  size,  size, 1, 1);
  vertex(-size,  size,  size, 0, 1);
  endShape();

  beginShape(QUADS);
  texture(tex);
  // +Y "bottom" face
  vertex(-size,  size,  size, 0, 0);
  vertex( size,  size,  size, 1, 0);
  vertex( size,  size, -size, 1, 1);
  vertex(-size,  size, -size, 0, 1);
  endShape();
  
  beginShape(QUADS);
  texture(tex);
//  fill(255, 255, 0);
  // +X "right" face
  vertex( size, -size,  size, 0, 0);
  vertex( size, -size, -size, 1, 0);
  vertex( size,  size, -size, 1, 1);
  vertex( size,  size,  size, 0, 1);
  endShape();
  }

:slight_smile:

1 Like

Hi glv,

Again thanks for taking the time to look into the code. I had not thought about using popmatrix() to address the image being loaded directly. In addition I had completely not considered manipulating the images separately and then using get() to place them on the face of the cube. I don’t think I would have ever come up with something like that so thank you for helping me, it would have taken forever for me to sort this out myself. This way I can definitely overlap images. Just one last thing: for the application I want to have I can’t really show the images in the top right corner or in any other place of the screen. I was thinking of using createGraphics() as a way to create a separate canvas and then loading the images onto the cube. Do you think this will work? I will give it a try regardless and if it does I’ll make sure to post the code I get here but I feel I should ask since this is one of the many elements of Processing I have less experience in.

Again thank you so much for your help!

1 Like

Hey There !

What about like making a custom shape and just applying a PImage on each ‘face’ ?

Have a look at this link

Hey InferNova,

Thanks for the tip! The one issue with this approach is that its not possible to draw multiple images on top of one another, since texture() only allows one image to be drawn at any point in time. This was my major hang up.

I have actually started to look into the solution I proposed of using PGraphics to solve the problem, but I’ve run into some issue since seemingly the code is not updating the positions of the drawn images at all. That and I’m getting the error “The pixels array is null.”

I’ll attach the code I have so everyone can see.

1 Like
PImage tex;
PImage tex2;

PGraphics pg;

PImage img = createImage(50, 50, RGB);
PImage img2 = createImage(50, 50, RGB);

int psX, psY = 200;

float rotx, roty, rotz;
float size;

void setup() 
{
  size(600, 600, P3D);
  textureMode(NORMAL);

  pg = createGraphics(200, 200);
}

void draw() 
{
  background(128);
  noStroke();

  //rotx += TAU/500;
  //roty += TAU/500;

  pg.beginDraw();
  pg.pushMatrix();
  pg.translate(100, 100);
  pg.pushMatrix();
  pg.rotate(radians(mouseX));
  pg.translate(-100, -100);

  pg.strokeWeight(5);
  pg.stroke(0);
  pg.fill(255, 255, 0);
  pg.circle(100, 100, 190);
  pg.rectMode(CENTER);
  pg.fill(0, 255, 0);
  pg.rect(100, 100, 50, 50);

  pg.popMatrix(); 
  pg.popMatrix();

  pg.pushMatrix();
  pg.translate(psX, psY);
  pg.pushMatrix();
  pg.rotate(rotx*2);
  pg.translate(-100, -100);

  pg.strokeWeight(5);
  pg.stroke(0);
  pg.fill(0, 255, 255);
  pg.circle(100, 100, 190);
  pg.rectMode(CENTER);
  pg.fill(255, 0, 0);
  pg.rect(100, 100, 50, 50);

  pg.popMatrix(); 
  pg.popMatrix();

  pg.endDraw();

  //img = get(0, 0, 200, 200);

  //image(pg, 400, 400); 

  pushMatrix();
  translate(width/2.0, height/2.0, -500);
  //rotateX(radians(mouseX));
  //rotateY(radians(mouseY));
  size = 100;
  noStroke();
  TexturedCube(img);
  popMatrix();
}

void keyPressed()
{
  if (keyCode == UP)
  {
    psY--;
  }

  if (keyCode == DOWN)
  {
    psY++;
  }

  if (keyCode == LEFT)
  {
    psX--;
  }

  if (keyCode == RIGHT)
  {
    psX++;
  }
}

void TexturedCube(PImage tex) 
{
  beginShape(QUADS);
  texture(pg); 
  // +Z "front" face
  vertex(-size, -size, size, 0, 0);
  vertex( size, -size, size, 1, 0);
  vertex( size, size, size, 1, 1);
  vertex(-size, size, size, 0, 1);
  endShape();

  beginShape(QUADS);
  texture(pg);
  // +Y "bottom" face
  vertex(-size, size, size, 0, 0);
  vertex( size, size, size, 1, 0);
  vertex( size, size, -size, 1, 1);
  vertex(-size, size, -size, 0, 1);
  endShape();

  beginShape(QUADS);
  texture(pg);
  //  fill(255, 255, 0);
  // +X "right" face
  vertex( size, -size, size, 0, 0);
  vertex( size, -size, -size, 1, 0);
  vertex( size, size, -size, 1, 1);
  vertex( size, size, size, 0, 1);
  endShape();
}

… I figured it out… I missed the endDraw. This was causing the problem. Edited to fix.

1 Like

I may be mistaken but doesn’t PGraphics require a .draw() and a .end() ?

Yes you are very right. I corrected the code to reflect it. This is what you get when you code when tired… :dizzy_face:

1 Like