Bn'R
Bn'R

Reputation: 43

Visible grey edges inside Html-canvas

Hello i am trying to export a uvmap for a model and i am filling triangles(meshes) with color, it works but i always see grey mesh lines. i tried to draw lines if i draw the lines with different color i can see lines but if i chose same color its always grey Any idea how to accomplish that thanks

    const { Scene } = tshirtNodes; // Access Three.js state
    const geometry = Scene.children[0].geometry; // Access geometry of the 3D model
    const uvAttribute = geometry.attributes.uv; // UV data
    const indexAttribute = geometry.index; // Triangle indices
    const canvasSize = 10000; // Canvas size
    const uvArray = uvAttribute.array; // UV coordinates
    const indexArray = indexAttribute.array; // Triangle indices
    const renderUVMap = () => {
              console.log("render uvmap");
              for (let i = 0; i < indexArray.length; i += 3) {
                const i1 = indexArray[i] * 2;
                const i2 = indexArray[i + 1] * 2;
                const i3 = indexArray[i + 2] * 2;
        
                const uv1 = { x: uvArray[i1], y: uvArray[i1 + 1] };
                const uv2 = { x: uvArray[i2], y: uvArray[i2 + 1] };
                const uv3 = { x: uvArray[i3], y: uvArray[i3 + 1] };
        
                let part = null;
                for (const [key, condition] of Object.entries(uvConditions)) {
                  if (
                    isWithinCondition(uv1, condition) ||
                    isWithinCondition(uv2, condition) ||
                    isWithinCondition(uv3, condition)
                  ) {
                    part = key;
                    break; // Stop once the part is determined
                  }
                }
        
                if (!part) continue; 
                if (partColorType[part] === "single") {
                  const color = colorsForparts[part];
                  if (!color) continue;
        
                  const [r, g, b] = color.map((c) => Math.floor(c * 255));
                  ctx.fillStyle = `rgb(${r}, ${g}, ${b})`;
        
                  ctx.beginPath();
        
                  ctx.moveTo(uv1.x * canvasSize, uv1.y * canvasSize);
                  ctx.lineTo(uv2.x * canvasSize, uv2.y * canvasSize);
                  ctx.lineTo(uv3.x * canvasSize, uv3.y * canvasSize);
                  ctx.closePath();
                  ctx.fill();
        
                  // ctx.strokeStyle = `rgb(${r}, ${g}, ${b})`;
                  // ctx.beginPath();
                  // ctx.moveTo(uv1.x * canvasSize, uv1.y * canvasSize);
                  // ctx.lineTo(uv2.x * canvasSize, uv2.y * canvasSize);
                  // ctx.lineTo(uv3.x * canvasSize, uv3.y * canvasSize);
                  // ctx.lineWidth = 0.05; 
                  // ctx.stroke();
                } 
              }
            };

an example image

At the left side you can see meshes as grey and right side green when i chose different color than the triangles

Upvotes: 2

Views: 65

Answers (1)

A_____ A_______
A_____ A_______

Reputation: 376

ctx.stroke() was correct idea but you set ctx.lineWidth = 0.05; and this is the reason so try to use ctx.fill() and ctx.stroke() but with ctx.lineWidth = 1 (default value for this parameter) like:

ctx.lineWidth = 1;

for (let i = 0; i < indexArray.length; i += 3) {
    ...
    if (partColorType[part] === "single") {
        const color = colorsForparts[part];
        if (!color) continue;

        const [r, g, b] = color.map((c) => Math.floor(c * 255));
        ctx.fillStyle = `rgb(${r}, ${g}, ${b})`;
        ctx.strokeStyle = ctx.fillStyle;

        ctx.beginPath();
        ctx.moveTo(uv1.x * canvasSize, uv1.y * canvasSize);
        ctx.lineTo(uv2.x * canvasSize, uv2.y * canvasSize);
        ctx.lineTo(uv3.x * canvasSize, uv3.y * canvasSize);
        ctx.closePath();

        ctx.fill();
        ctx.stroke();

    }
}

here is small example with canvas 100x100px: small image exampl

const uvDots = [
   5,  5,
  75, 25,
  25, 75,
  95, 95,
  95,  5,
].map(a=>a+(Math.random()*2-1)*3 );

const Index = [
  0, 1, 2,
  1, 3, 2,
  0, 4, 1,
  1, 4, 3,
];

function draw(ctx, fill, stroke, lineWidth) {
    ctx.fillStyle = "#000";
    ctx.fillRect(0, 0, 100, 100);
    
    ctx.fillStyle = "#f00";
    ctx.strokeStyle = ctx.fillStyle;
    ctx.lineWidth = lineWidth;
  
    for (let i = 0; i < Index.length; i+=3) {
        ctx.beginPath();
        ctx.moveTo(uvDots[ Index[i  ]*2 ], uvDots[ Index[i  ]*2+1 ]);
        ctx.lineTo(uvDots[ Index[i+1]*2 ], uvDots[ Index[i+1]*2+1 ]);
        ctx.lineTo(uvDots[ Index[i+2]*2 ], uvDots[ Index[i+2]*2+1 ]);
        ctx.closePath()
        
        if (fill  ) {ctx.fill  ()}
        if (stroke) {ctx.stroke()}
    }
}

const getCtxBySelector = s=>document.querySelector(s).getContext('2d');

draw(getCtxBySelector('#canvas1'),  true, false, 1)
draw(getCtxBySelector('#canvas2'), false,  true, 1)
draw(getCtxBySelector('#canvas3'),  true,  true, 1)
draw(getCtxBySelector('#canvas4'),  true,  true, 0.05)
body {
  display: grid;
  grid-template-columns: repeat(2, auto);
  column-gap: 10px;
  row-gap: 10px;
  width: fit-content;
}

canvas {
  width: 300px;
  height: 300px;
  image-rendering: pixelated;
}

span {
  text-align: center;
}
  <body>
    <span>only fill</span>
    <span>only stroke (lineWidth = 1)</span>
    <canvas id="canvas1" width="100" height="100"></canvas>
    <canvas id="canvas2" width="100" height="100"></canvas>
    <span>fill + stroke (lineWidth = 1)</span>
    <span>fill + stroke (lineWidth = 0.05)</span>
    <canvas id="canvas3" width="100" height="100"></canvas>
    <canvas id="canvas4" width="100" height="100"></canvas>
  </body>

also you can make this work much faster if you use UV as geometry for mesh and render it with shader which will define how to fill polygons. Also in that case there will be no such problem with lines.

Upvotes: 1

Related Questions