vladdeSV / me-generator

Generate an image with random pieces of clothing / cosmetics. Not for NFTs.
https://generator.vladde.me/?seed=
MIT License
3 stars 1 forks source link

Z-index of part element #4

Closed vladdeSV closed 3 years ago

vladdeSV commented 3 years ago
shirt with empty space

Currently, all parts are drawn from bottom to top, where each new part is drawn on-top of every other part. This causes some problems where, for instance, an arm should appear both under a shirt's arm, but in front of a shirts torso.

The solution to this was to draw "empty space" in the shirt where the the arm should be visible through. This is fairly limiting sometimes, but most of all undesirable.


shirt with layered parts

In order to combat this, one solution is to separate the shirt arms from the shirt torso and putting them at different z-levels. For instance, in this image the shirt arms are separated from the shirt torso in the SVG. Each part is also separated internally even further, which would allow for an human arm to be "sandwiched" between the arm parts, while still being separated from the torso completely. The only relation the arm has to the torso is that it is drawn in front of the torso.

The relation between different parts need to be addressed somewhere, and I believe that the rulebook.json is the best place for this.


As of right now there are two major issues:

vladdeSV commented 3 years ago

An example demonstrating how the new layered version of the shirt is built up, and how body parts would relate to it.

ltt crewneck

vladdeSV commented 3 years ago

Although differently layered parts of pieces are not currently usable, all new items will be split into multiple parts in me-generator-images. No background layers will be added for new parts.

In general:

vladdeSV commented 3 years ago

I am thinking that a for a SVG, the top-level elements will be addressable and rearrangeable.

For instance, take this image which consists of a total of 3 elements in the following structure:

svg
├─ rect
│  └─ circle
└─ rect

layered svg

I suggest a solution where only the rects will be able to have their Z-index modified, and the only other permutation would be: layered svg modified z-index


For the example with the shirt, the structure would become:

svg
├─ "left arm (frontside)"
├─ "left arm (backside)"
├─ "right arm (frontside)"
├─ "right arm (backside)"
├─ "torso (frontside)"
└─ "torso (backside)"
vladdeSV commented 3 years ago

To further expand on my previous comment.

All addressable elements would be in a flat list. I believe combining multiple SVG's elements into one long list will make rearranging them much easier than any other approach I have managed to come up with.

svg-1
├─ rect
└─ circle

svg-2
└─ g

  ↓

svg-combined
├─ rect
├─ circle
└─ g

Because of a flat list, the following should be easy to write rules for, as well as implementing in code. One permutation of the above could be:

svg-combined-modified
├─ rect
├─ g
└─ circle

(this is representative of putting an arm between two layers of clothing, where the arm and clothing are in different SVG files)


I am not entirely sure how the elements should be addressed yet.

vladdeSV commented 3 years ago

I believe the proper way to handle ordering elements would be a list of instructions, similar to how rules function (when disallowing). The idea is pretty simple. Iterate all "index rules", and if that rule references a part which is present, move it.

Moving a part must be directly in front or behind another part. This is to remove complexity.

Although not fully fledged syntax for referencing a part's element, I believe a good start for the syntax would be <part>#<element id>. Possibly, if the entire part is to be moved, the trailing #<element id> would not be necessary.

To "sandwich" an arm between two layers of clothing, the rules would be structured as:

["left arm", "in front of", "ltt crewneck#left backside"]

Reads as: place the part with id left arm above the element left backside, which belongs to part ltt crewneck.

vladdeSV commented 3 years ago

To give a simplified example of what happens.

ltt crewneck
├─ right frontside
├─ right backside
├─ … (additional parts parts hidden in this example)

right arm
└─ arm

The combined SVG would then look like

combined-svg
├─ right frontside   // id: ltt crewneck#right frontside
├─ right backside    // id: ltt crewneck#right backside
├─ …
└─ arm               // id: right arm#arm

The "index rules" would be in the rulebook.json.

// rulebook.json
{
  "index": [
    ["foo#abc", "behind", "bar#abc"],
    ["right arm", "in front of", "ltt crewneck#right backside"],
    // …
  ],
  // …
}

After parsing these rules, the following happens

The final result would become

output
├─ right frontside   // id: ltt crewneck#right frontside
├─ arm               // id: right arm#arm
├─ right backside    // id: ltt crewneck#right backside
└─ …
vladdeSV commented 3 years ago

I just realized that the "index rules" actually allows for rearranging individual elements in the same part.

If this syntax for selecting elements is implemented for "allow/disallow rules", I could theoretically generate an entire image from a single SVG…?

vladdeSV commented 3 years ago

The current implementation adds multiple SVGs together in one SVG, meaning the SVGs are nested. Because a SVG has a width and a height, any element reaching outside of the SVG border will be cropped.

With the proposed implementation, each SVG's width and height will be removed, and thus the cropping will not happen. I do not believe this is an issue, but definitely something that might come as unexpected.

vladdeSV commented 3 years ago

As of 77b492d61b4bf14f7844ac7e8903312c412d9a36, a working version of rearranging elements of parts is possible.

I am going to celebrate this with an emoji.