Skip to content

implementing beginContour and endContour in WEBGL mode #6042

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

aditya-shrivastavv
Copy link
Contributor

Resolves #5946

Changes:

Added beginContour() and endContour() in WEBGL renderer file and refactored some code for it.
It is not complete yet I there are many bugs left to be solved, please suggest me if I am working in right direction or not ?

Progress:

Still working on it
Any guidance is really appreciated.

PR Checklist

Copy link
Contributor

@davepagurek davepagurek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your work on this so far! I've tried to explain a bit what further changes we'll have to do. Let me know if those make sense or if I can help explain anything some more!

@@ -101,7 +112,11 @@ p5.RendererGL.prototype.vertex = function(x, y) {
v = arguments[4];
}
const vert = new p5.Vector(x, y, z);
this.immediateMode.geometry.vertices.push(vert);
if (this.immediateMode.isContour) {
this.immediateMode.geometry.contourVertices.push(vert);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, I think this is generally the right approach! The one difference is that we might have multiple beginContour/endContour calls within one shape. So we probably need contourVertices to be an array of arrays in WebGL mode, instead of just a single array.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually, we'll need to pass all the contours into this array in _tesselateShape here:

const contours = [

This probably means we'll need to store vertexNormals, vertexColors, vertexStrokeColors, and uvs for each contour as well as just the position.

p5.RendererGL.prototype.beginContour = function() {
this.immediateMode.isContour = true;
this.immediateMode.isFirstContour = true;
this.immediateMode.geometry.contourVertices = [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think we can store this on this.immediateMode instead of this.immediateMode.geometry? We use the same geometry class for 3D models loaded with loadModel(), which won't have this notion of contours, so this should probably just be internal to p5.RendererGL.

if (shouldClose) {
part.push([verts[j].length - 1, 0]);
}
res.push(part);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the main branch, the expected output of this function is an array of [index1, index2] tuples, basically saying "connect the vertex at geometry.vertices[index1] with the vertex at geometry.vertices[index2] with a line." This starts to get a little tricky now that not all the vertices are in the same geometry.vertices array.

With your change, this now returns an array of arrays of those tuples. That could be helpful, since now we know that the first array element is the pairs for the main shape vertices, the second array element is the pairs for the first contour, the third array element is the pairs for the second contour, etc. It just means we'll have to update the _edgesToVertices function, which takes this output and makes all the lines, to handle this new format.

e.g. over here, it directly accesses this.vertices[index]. We'll have to update this to loop over each array of edges, and determine which set of vertices/vertex stroke colors it should be reading from:

const begin = this.vertices[currEdge[0]];

@aditya-shrivastavv aditya-shrivastavv changed the title making path for beginContour in WEBGL implementing beginContour and endContour in WEBGL mode Mar 6, 2023
@aditya-shrivastavv
Copy link
Contributor Author

thanks @davepagurek these suggestions will be very helpful 😊

@aditya-shrivastavv
Copy link
Contributor Author

Hello @davepagurek sir, I have some questions can you please explain them, It would be beneficial to better my understanding.

  1. why is there a difference in the number of parameters the vertex function takes in p5.RendererGL.Immediate and in vertex

    p5.prototype.vertex = function(x, y, moveTo, u, v) {

    p5.RendererGL.prototype.vertex = function(x, y) {

    I know that the remaining parameters are later handled in RendererGL.Immediate (like below) but why is there a difference?
    if (arguments.length === 3) {
    // (x, y, z) mode: (u, v) assumed to be 0.
    z = arguments[2];
    } else if (arguments.length === 4) {
    // (x, y, u, v) mode: z assumed to be 0.
    u = arguments[2];
    v = arguments[3];
    } else if (arguments.length === 5) {
    // (x, y, z, u, v) mode
    z = arguments[2];
    u = arguments[3];
    v = arguments[4];
    }

  2. Please explain the role of moveTo in here, In a stack trace I have noticed that the first vertex after the beginContour is called has this property of moveTo = true. Is that responsible for detaching the contourVertices form simple vertices? should this type of strategy be used in WebGL mode?

    if (moveTo) {
    vert.moveTo = moveTo;
    }
    if (isContour) {
    if (contourVertices.length === 0) {
    vert.moveTo = true;
    }

@davepagurek
Copy link
Contributor

  1. I don't think there's any particular reason for making the arguments different, since as you noted, any other arguments that aren't in the regular function signature can be accessed via the arguments array. Probably it just made the code a little less complex at the time to make the commonly used parameters be the ones directly in the function signature. But not much depends on this, it can be easily changed if we have a reason for it.

  2. This comes down to how the different rendering engines work:

    In 2D mode, you can cut out regions of a shape by using the evenodd fill rule and then drawing a second shape on top of the first shape. This is the behaviour p5's contours are using. The moveTo flag indicates that the vertex shouldn't be connected to the previous vertex with a line as part of the same shape, but rather, that the canvas should "lift up the pen", move it to that vertex, then put it down, starting the next shape.

    In WebGL, there isn't a native JS canvas system for clipping like that to work with. Instead, we use libtess, which provides a similar evenodd fill rule system, but its API is a little different: rather than being part of one big shape and moving a pen without drawing a line to make a contour, in libtess, each contour is delineated with a gluTessBeginContour() and the front and gluTessEndContour at the end:

    this._tessy.gluTessBeginContour();
    const contour = contours[i];
    for (
    let j = 0;
    j < contour.length;
    j += p5.RendererGL.prototype.tessyVertexSize
    ) {
    const coords = contour.slice(
    j,
    j + p5.RendererGL.prototype.tessyVertexSize
    );
    this._tessy.gluTessVertex(coords, coords);
    }
    this._tessy.gluTessEndContour();
    The API doesn't care how we store that information as long as we can make those function calls sandwiching the vertex calls. Currently, we don't have multiple contours, but we preemptively are storing them as an array of arrays, so that we can loop over each one and make those begin/end contour calls in each loop:
    for (let i = 0; i < contours.length; i++) {
    One could also pass in a single flat array of vertices with a moveTo flag to delineate where each separate contour begins, but right now the system has started to be set up to pass in an array of arrays.

@davepagurek
Copy link
Contributor

Thanks for your initial work on this! With #6297 merged in, I'm going to close this draft as the initial feature is now implemented, but feel free to open new issues if you notice any bugs or have follow-up feature requests!

@aditya-shrivastavv aditya-shrivastavv deleted the contour-support branch October 31, 2023 10:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

endContour() throws error in WEBGL mode
2 participants