4
$\begingroup$

I am building an algorithm which takes a bitmap image as input and render the image as an embroidery design.

The different steps are :

  • Vectorize the image, I keep only 5 colors (Done)
  • Generate stitches lines (Done)
  • Apply wire embroidery texture to the lines, add lights and show a realistic rendering ( It's this step that I am having trouble with)

Let's take an example. The original image is :

Original image

From there, I vectorize the image and obtain an SVG file.

After that, I generate stitches lines automatically which you can find here (svg file): https://www.dropbox.com/s/jmi6rz1ixgkjjpb/flowers_fill_0.7_vLongShort_space_randomLength.svg?dl=0

When you zoom in, it looks like this :

stitches

If I export the svg as png, I get :

ExportPng

As you can see; having this result is not enough to render realistically the embroidery design.

I am looking to have a texture more like this :

Real

I tried generating a normal map and the use it adds some depth, but again, the result looks very plastic ... :

Rendering with normal map

I don't know what I should do now to have a realistic rendering ... At first, it wasn't supposed to be a computer graphic problem so I am not a specialist in the area, but I think using webgl or opengl is the best choice.

However, I don't know how to give the rights textures to the lines ...

$\endgroup$
3
$\begingroup$

Picking up from step 2, where you generated line segments to represent individual stitches, I would first suggest that you apply rounded ends to each segment, rather than square ends.

I would then convert each segment to an outline, (i.e. each rounded stitch becomes an separate poly-line representing the outer boundary.)

For example, suppose you start with point A & point B, representing a single stitch in line segment form. We can derive the rounded outline of this segment with the following Javascript code using THREE.js:

    function outlineSegment (Ax, Ay, Bx, By, radius){
        var radius = radius || 0.5; //millimeters?
        var A = new THREE.Vector2(Ax, Ay);
        var B = new THREE.Vector2(Bx, By);
        var C = B.clone().sub(A).normalize().multiplyScalar(radius);
        var angle = C.angle();
        var outline = new THREE.Shape();
        outline.moveTo( B.x + C.y, B.y - C.x );
        outline.absarc(B.x, B.y, radius, angle-Math.PI/2, angle+Math.PI/2);
        outline.lineTo(A.x - C.y, A.y + C.x);
        outline.absarc(A.x, A.y, radius, angle+Math.PI/2, angle+Math.PI*3/2);
        outline.autoClose = true;
        return new THREE.ShapeGeometry(outline);
    }

The above function finishes by triangulating the polyline into faces, (See the orange area in the included picture.)

Next, send these faces to be rendered by the GPU, applying a vertex shader which sets a vec2 varying variable (sounds redundant, but it's not) indicating the vertex position relative to the original line segment (which we have included as vertex attributes)

Now, we move on to the fragment shader, where we use the varying variable created in the vertex shader to derive a normal.

Let's say that "linePos" is the position along the line segment, (i.e. the x-value, if the line is horizontal. y-value if it is vertical, etc.)

Furthermore, let's say "lineDist" is the distance from the central line segment, e.g. -2 if it's 2 units to the left of the line (purple arrows) or +5 if it's on the right (blue arrows).

We can use these two values, derived from the varying variable, to create a normal for the point on the thread.

A bit of this code might be:

abs(sin(linePos+lineDist))

but there's a fair bit more than that to write. I can't go through and write the entire program for you here & now, but hopefully these ideas & diagram will shine some light in the right direction.

Best of luck.

embroidery geometry diagram

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.