TRIANGLE_FAN not behaving as expected on WEBGL?

Hi all,
I just noticed that when trying to draw a Triangle Fan on WEBGL, I don’t get the expected behavior ie. ALL lines stroked.
On WEBGL only the outlines + last radial line (point1 to center) appear stroked, while all the other radial lines disappear(!?)

Is it a problem w/stroking or actually the way the triangles are built?

Thanks in advance

(I used the default reference code for clarity. Just comment/uncomment 2nd line to see)

Screen Shot 2022-12-15 at 19.53.36
Screen Shot 2022-12-15 at 20.20.49

let Webgl = true
// Webgl = false //uncomment to see difference

function setup() {
  if (Webgl){
    createCanvas(400, 400, WEBGL);
  } else {
    createCanvas(400, 400);
  }
}

function draw() {
  if (Webgl){
    orbitControl();
  } else {
    translate(width/2, height/2)
  }
  
  background(220);
  beginShape(TRIANGLE_FAN);
  vertex(57.5, 50, 0);
  vertex(57.5, 15, 0);
  vertex(92, 50, 0);
  vertex(57.5, 85, 0);
  vertex(22, 50, 0);
  vertex(57.5, 15, 0);
  endShape();
}
1 Like

Hi @wageDu,

Thanks for reporting that! :wink:

From what I saw on previous issues, it may be related to how p5.js handles vertices and edges in WebGL:

And how the edges are computed:

Maybe someone has a better understanding on the subject?

2 Likes

Hi @josephh and thanks for the reply.

I had a look on p5 issues (and StackO) and found nothing. But you confirmed it’s part of existing issues, not a mistake of mine so, should I open a new issue?

Thanks again! Cheers

I didn’t find anything related to the specific problem you are having so I would open an issue :nerd_face: (except if anyone knows the reason of that behavior)

2 Likes
3 Likes

I have experienced the same problem with TRIANGLE_FAN and TRIANGLE_STRIP it only seems to occur when stroke and fill are applied together.

If you use WEBGL with stroke(...) and noFill() you get an open wire frame.

1 Like

I just tried in the code above( original post) and it doesn’t change a bit.
Added stroke(0); noFill(); right below createCanvas(400,400,WEBGL)
I also tried adding both commands right before beginShape
still same result
Could you share a bit of your code, please?
Thanks a lot

I owe you an apology this issue does not apply to triangle strips. I don’t have any small code examples to show you but this video shows an animated 3D model. Those areas in purple were drawn using TRIANGLE_STRIP and the yellow areas using TRIANGLE_FAN. You can clearly see that the triangle borders are clear when using TRIANGLE_STRIP but not the TRIANGLE_FAN.

When creating the video and looking at my code it dawned on me that the stroke simply links the vertices as they are processed and that for a fan there is only one radial connection - that between the first vertex and the second one. So this might not be a bug it might just be the way WEBGL works.

I have added the rendering code below for the sake of completeness.

    /**
     * Render this model using as an open wireframe
     * @param p drawing context
     */
    renderWireframe(p = p5.instance) {
        p.push();
        let vpos = 0;
        let cfIdx = this.cFrame * this.num_xyz;
        let nfIdx = this.nFrame * this.num_xyz;
        p.noFill();
        p.stroke(0);
        p.strokeWeight(1.1);
        for (let i = 0; i < this.cmds.length; i++) {
            let cmd = this.cmds[i];
            p.beginShape(cmd < 0 ? p.TRIANGLE_FAN : p.TRIANGLE_STRIP);
            // =================================================================
            // The next line helps differentiate strips and fans
            p.fill(cmd < 0 ? p.color(255, 255, 200) : p.color(255, 200, 255));
            // =================================================================
            cmd = Math.abs(cmd);
            for (let j = 0; j < cmd; j++) {
                let gl_vertex = this.gl_verts[vpos];
                let cp = this.points[cfIdx + gl_vertex.idx];
                let np = this.points[nfIdx + gl_vertex.idx];
                let x = cp.getX() + this.interpol * (np.getX() - cp.getX());
                let y = cp.getY() + this.interpol * (np.getY() - cp.getY());
                let z = cp.getZ() + this.interpol * (np.getZ() - cp.getZ());
                p.vertex(this.scale * x, this.scale * y, this.scale * z);
                vpos++;
            }
            p.endShape();
        }
        p.pop();
    }
2 Likes

Here is a workaround that uses indexed triangles with the OpenGL TRIANGLES mode.

let Webgl = true;
  // Webgl = false; //uncomment to see difference

function setup() {
  if (Webgl) {
    createCanvas(400, 400, WEBGL);
  } else {
    createCanvas(400, 400);
  }
  fan = new Array(
    createVector(57.5, 50, 0),
    createVector(57.5, 15, 0),
    createVector(92, 50, 0),
    createVector(57.5, 85, 0),
    createVector(22, 50, 0),
    createVector(57.5, 15, 0)
  );
}

function draw() {
  if (Webgl) {
    orbitControl();
  } else {
    translate(width/2, height/2)
  }
  background(220);
  drawFan(fan);
}

// Using indexed triangles instead of TRIANGLE_FAN
function drawFan(f) {
  let c = f[0];
  console.log('Length', f.length);
  beginShape(TRIANGLES);
  for (let i = 1; i < f.length - 1; i++) {
    vertex(c.x, c.y, c.z);
    vertex(f[i].x, f[i].y, f[i].z);
    vertex(f[i+1].x, f[i+1].y, f[i+1].z);
  }
  endShape(CLOSE);
}
3 Likes

Regarding the topic, there’s a workaround: using TRIANGLE_STRIP and picking the center every 3 vertices. But that’s more of a proof of concept than a real/valid/efficient solution. Thankfully Dave has fixed it for a next release.

Now, your troglodyte/Troll… WOW! That is insane! O_O
:clap:

1 Like

IMPORTANT - I can’t take credit for the actual model. It is one of two models abandoned / discarded by their creator.

The creature is called an Ogro and it is stored in Quake MD2 file format. Originally a proprietary format it is now an open format. My interest started many years ago when I created a MD2 file loader in Java and a week ago I decided to create a Javascript MD2 file loader.

In the video you see a wireframe image of the Ogro but I will be publishing the skinned version of this and the second model on my website and Open Processing in the next few days. When that happens I will announce it on this forum.

Glad to know there is a fix for the next release. :smile:

2 Likes