Search code examples
javascriptcanvaspolygonwireframe

JavaScript - Gap between triangles when wire-frame is removed


I'm relatively new to JavaScript and to get a grip on it I've been working on a 3D engine and I stumbled on something odd. When I render a filled mesh with wire-frame disabled, a gap shows up between my triangles.

Here's an example:

// vertices
var v1 = [40,20];
var v2 = [125,35];
var v3 = [165,105];
var v4 = [35,95];

// draw on screen 1
var canvas = document.getElementById("screen");
var context = canvas.getContext("2d");
triangle(v1,v2,v3,context,true);
triangle(v3,v4,v1,context,true);

// draw on screen 2
var canvas = document.getElementById("screen2");
var context = canvas.getContext("2d");
triangle(v1,v2,v3,context,false);
triangle(v3,v4,v1,context,false);

// draw triangle method
function triangle(v1,v2,v3, context,wireframe)
{
  context.beginPath();
  context.moveTo(v1[0],v1[1]);
  context.lineTo(v2[0],v2[1]);
  context.lineTo(v3[0],v3[1]);
  context.lineTo(v1[0],v1[1]);
  context.closePath();
  context.fillStyle = "#333";
  context.fill();
  if (wireframe)
  {
    context.strokeStyle = "#0f3";
    context.stroke();
  }
}
body
{
	background-color: #ddd;
}
canvas 
{
  border:2px solid #000;
}
<canvas id="screen" width="200" height="150" ></canvas>
<canvas id="screen2" width="200" height="150"></canvas>

In essence, the two polygons don't seem to connect properly.

  • Making the wire-frame the same colour as triangle is not a solution. I want to apply a texture without seeing the edge.
  • Drawing connected polygons isn't a solution, each triangle may have its own texture transformation.
  • Should I overdraw triangles to close the gaps?
  • Is this an Anti-Aliasing issue?

Thanks in advance.

enter image description here Above: Shows gap between triangles when the wire-frame has been disabled

UPDATE 9-apr-2017

I've considered various options to solve my issue, including writing a triangle routine. Picture down below. However, drawing two triangles tanks my FPS quite a lot. I need a faster way to put pixels on the canvas, but that's for another post since it's off topic.

However, I think that expanding the triangle half a pixel is a better/faster solution since the fill() method is executed by the browser internally instead of JavaScript.

enter image description here


Solution

  • One solution would be to inflate the triangles by a little bit to fill the gaps. This code inflates by 1%.

    I think more ideal would be code that inflates by 0.5 pixels, however, that code would be a little more expensive as it would involve calculating vector lenghts...

    // vertices
    var v1 = [80,40];
    var v2 = [250,70];
    var v3 = [230,210];
    var v4 = [70,190];
    
    // draw on screen 1
    var canvas = document.getElementById("screen");
    var context = canvas.getContext("2d");
    triangle(v1,v2,v3,context,true);
    triangle(v3,v4,v1,context,true);
    
    // draw on screen 2
    var canvas = document.getElementById("screen2");
    var context = canvas.getContext("2d");
    inflateTriangle(v1,v2,v3,context,false);
    inflateTriangle(v3,v4,v1,context,false);
    
    // draw triangle method
    function inflateTriangle(v1,v2,v3, context,wireframe)
    {
    	//centre of tri
      xc=(v1[0]+v2[0]+v3[0])/3;
      yc=(v1[1]+v2[1]+v3[1])/3;
      
      //inflate tri by 1%
      x1= xc+(v1[0]-xc)*1.01;
      x2= xc+(v2[0]-xc)*1.01;
      x3= xc+(v3[0]-xc)*1.01;
      y1= yc+(v1[1]-yc)*1.01;
      y2= yc+(v2[1]-yc)*1.01;
      y3= yc+(v3[1]-yc)*1.01;
      
    
    
      context.beginPath();
      context.moveTo(x1,y1);
      context.lineTo(x2,y2);
      context.lineTo(x3,y3);
      
      context.closePath();
      context.fillStyle = "#333";
      context.fill();
      if (wireframe)
      {
        context.strokeStyle = "#0f3";
        context.stroke();
      }
    }
    <body>
    
    <canvas id="screen" width="400" height="300" style="border:2px solid #000;"></canvas>
    <canvas id="screen2" width="400" height="300" style="border:2px solid #000;"></canvas>
    
    </body>