Placing a texture on a pshape

Hello, I am making a game and I have a pshape planet with 360 vertices placed in a circle.

PVector circ = new PVector(rad,0);
    tar = createShape();
    tar.beginShape();
    //loops 359 times to enable rotation in 1° increments
    for(int i = 1; i<360; i++)
    {
      //Creates a vertex at circ.x and circ.y
      tar.vertex(circ.x,circ.y);
      //Rotates circ by 1° converted to radians
      circ.rotate(PI/180);
    }
    //Ends the shape
    tar.endShape(CLOSE);

You throw meteors which hit the planet and move the vertices to make a crater. The meteors are objects of the class projectile which has float x,y,dim. The class also has velocity pvector and it shows an ellipse at x,y with diameter dim which is moved by the vel vector.

boolean collision(Projectile k)
  {
    //b gets the vertex information for optimization
    PVector b;
    //if collision is detected hit is set to true
    boolean hit=false;
    //Loops through the vertices to check which if any are hit
    for(int i = 0;i<tar.getVertexCount();i++)
    {
      //The unfinished crater algorithm
      b = tar.getVertex(i);
      //Checks if the vertex is in contact with the projectile
      if(dist(x + b.x,y + b.y,k.x,k.y)<k.dim/2)
      {
        //adds the projectiles velocity to any vertex in contact with the projectile
        b.add(k.vel);
        //sets the new vertex
        tar.setVertex(i,b);
        hit = true;
      }
    }
    //if a collision occurred a hole is made where the projectile hit
    return hit;
  }

So the craters are a part of the pshape itself. In the end it looks like this

I would like to place an image on the planet in a way that the image is not warped in any way, and when the vertices are moved the crater part of the image disappears and the rest is still unchanged. I thought about using the texture function but I don’t know how I would do that. I also thought about going through the pixel array and changing all white pixels on the planet to corresponding pixels from the image of the planet, but the problem is the planet rotates using a rotate function I wrote that actually sets new location for all vertices using trigonometry. Any suggestion or idea would be appriciated

1 Like

This sounds like you want a mask.

  1. plot your shape
  2. draw your shape onto a PGraphics mask.
  3. apply the mask image to your texture / fill image
  4. display the (masked) texture/fill image.
/**
 * ShapeMask
 * draw a Mask example with createShape
 * 2019-08 Processing 3.4
 * see https://discourse.processing.org/t/placing-a-texture-on-a-pshape/13561
 **/
PImage photo;
PShape tar;
PGraphics maskImage;
void setup() {
  size(512, 512);
  photo = loadImage("https://forum.processing.org/processing-org.jpg");
  
  tar = createShape();
  tar.setStroke(false);
  tar.beginShape();
  //loops 359 times to enable rotation in 1° increments
  PVector rad = new PVector(200,0);
  for(int i = 1; i<360; i++)
  {
    //Creates a vertex at circ.x and circ.y
    rad.setMag(random(190,210));
    tar.vertex(rad.x, rad.y);
    //Rotates circ by 1° converted to radians
    rad.rotate(PI/180);
  }
  //Ends the shape
  tar.endShape(CLOSE);

  // create mask
  maskImage = createGraphics(512,512);
  maskImage.beginDraw();
  maskImage.shape(tar, width/2, height/2);
  maskImage.endDraw();
  // apply mask
  photo.mask(maskImage);

  noLoop();
}

void draw() {
  //shape
  //shape(tar, width/2, height/2);

  //mask from shape
  //image(maskImage,0,0);

  //masked image
  image(photo, 0, 0);
  saveFrame("ShapeMask.png");
}

Each time the vertices in your shape change, regenerate the mask and re-apply it – no need to generate the mask every single frame if the shape isn’t changing.


For a simpler approach that uses primitives directly on the PGraphics rather than PShape, see: How to copy a triangle out of an image - Processing 2.x and 3.x Forum

2 Likes

Thanks, this is a great solution, but how could I rotate it. Is there maybe a rotate function in the PImage class that I could use?

Rotate what? The vector shape, or the image, or both?

The vertices of the planet rotate constantly so I would want to rotate the pimage photo by a certain amount and then apply the mask

The most efficient thing is to rotate neither the vector shape nor the image – just rotate the output only to create a spinning planet.

void draw() {
  background(255);
  translate(256,256);
  float rval = (0.0005*millis())
  rotate(rval);
  translate(-256,-256);
  image(photo, 0, 0);
}

That means you don’t need to constantly regenerate your mask – or your PShape. When you do your collision detection, rotate your meteor (!) into the planet’s frame of reference and compute the collision that way. So instead of recomputing the rotation of 360 vertices every single frame and generating a new mask, you are only rotating e.g. 1 vertex whenever there is a meteor in motion, and your mask only changes during impact.

This approach will also help you avoid accumulating float errors over long periods of rotation