We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpOpenGL and 3D Libraries › quad() with fill() problem
Page Index Toggle Pages: 1
quad() with fill() problem (Read 1073 times)
quad() with fill() problem
Dec 15th, 2007, 10:57pm
 
Hello all;

I'm trying to use quad() with fill(), but without success


/**
quad() does not work properly with fill() under OPENGL

quad () works fine without OPENGL
quad () works without fill, but at corners lines do not meet properly

tested with 'Processing 0135 beta' under linux with java 1.5.0
and under w2k with java 1.6.0

please see code below
*/

import processing.opengl.*;

/*
// for full screen app
static public void main(String args[]) {
 PApplet.main(new String[] {
   "--present", "quaderror"           }
 );
}
*/
int x4;

void setup()
{
//  size(300, 300);
//  size(screen.width, screen.height);

 size(300, 300, OPENGL);
// for full screen app
//  size(screen.width, screen.height, OPENGL);

 strokeWeight (10);

 x4 = 0;
}

void draw()
{
 background(0);
 noCursor ();
 strokeWeight(10);

 x4 += 4;

 if (x4 > (height>>1))
   x4 = 0;

 fill (222);
 quad (0, 0, width/6, 3*height/4, x4, height, 0, height);

 delay (20);
}

does anyone know a workaround?
thanks in advance.

fid
Re: quad() with fill() problem
Reply #1 - Dec 17th, 2007, 5:03pm
 
quad() is a "shortcut" for drawing two triangles through the diagonal - this works fine if your quads are simple, convex and non-degenerate, but yours is complex, concave, and even degenerate in one case. (when x4==0)  

you could fix it for this sketch by reordering your vertices so that the diagonal is from lower-left to the concave cusp, like so:
 quad (0, height, 0, 0, width/6, 3*height/4, x4, height);

the more general solution would be to think of it as a 4-sided polygon rather than a quad, using beginShape(), vertex() and endShape() to build it, then it'll be properly tesselated into triangles when drawn.
Re: quad() with fill() problem
Reply #2 - Dec 17th, 2007, 10:00pm
 
davbol wrote on Dec 17th, 2007, 5:03pm:
quad() is a "shortcut" for drawing two triangles through the diagonal - this works fine if your quads are simple, convex and non-degenerate, but yours is complex, concave, and even degenerate in one case. (when x4==0)  

you could fix it for this sketch by reordering your vertices so that the diagonal is from lower-left to the concave cusp, like so:
 quad (0, height, 0, 0, width/6, 3*height/4, x4, height);

the more general solution would be to think of it as a 4-sided polygon rather than a quad, using beginShape(), vertex() and endShape() to build it, then it'll be properly tesselated into triangles when drawn.



thx davbol;

yes, beginShape(), vertex() and endShape() is the right way but much too slow Sad
I'm working on moving quads and their corners are calculated randomly,
so concave quads cannot be avoided, furthermore they are needed.
it all works fine as long as no opengl is used, but then everything is getting very, very slow (definitely in full screen mode)
so, I guess the implementation of quad() under opengl is different from the implementation under 2D ?
Re: quad() with fill() problem
Reply #3 - Dec 19th, 2007, 6:37pm
 
fid wrote on Dec 17th, 2007, 10:00pm:
so, I guess the implementation of quad() under opengl is different from the implementation under 2D ?


Quite.  With Java2D a quad is drawn as a 4-vertex polygon and rendering is much simpler since it's just flat pixel rasterization, and even degenerate complex polygons where segments intersect will often (though not always) render "reasonably".  With 3D every surface eventually has to be represented by triangles, and degenerate polys rarely triangulate properly.

Here's a test, what shape SHOULD this be:
 quad(0,0, 100,100, 0,100, 100,0);
If you draw those vertices in the order listed it's degenerate, an hourglass.  If you draw the "shell" of those vertices, it's a square.  But it can't be both! (so you're likely to get jibberish when it's triangulated)

But *something* has to triangulate it, whether it's a "split the quad in half along the diagonal" rule, or a generic triangulation of a 4-sided polygon, or you doing it manually.  If the built-in solutions don't work for you, then you'll have to do it yourself - either by reordering the vertices of your random quad so that the diagonal doesn't intersect another segment as above (to get the square), or by manually drawing the two triangles that your concave "quad" implies (to get the hourglass).

Lesson:  If you don't want to draw invalid geometry, then don't create invalid geometry.  Cheesy
Re: quad() with fill() problem
Reply #4 - Dec 19th, 2007, 8:28pm
 
davbol wrote on Dec 19th, 2007, 6:37pm:
Lesson:  If you don't want to draw invalid geometry, then don't create invalid geometry.  Cheesy



Lesson: Valid geometry under 2D is invalid geometry under OPENGL. Sad
Re: quad() with fill() problem
Reply #5 - Dec 20th, 2007, 11:11pm
 
No matter how you look at it, an hourglass is a pretty weird polygon -- much too weird to take it as is for a 3D surface. :D

You seem to be worried about the speed of beginShape(),vertex(),endShape(), but unfortunately you can't have it both ways -- if you make degenerate polys then *something* has to fix it for you, which takes time.  The fastest method of drawing 3d surfaces is to just draw valid triangles directly. (ignoring display lists and other advanced stuff)  For simple polygons the built-in triangulator is pretty fast, but as you've seen will fail on degenerate polys.

Here's what's necessary to draw that hourglass with OpenGL, adapt and reuse for your own sketch, though it's not likely to be fast:

Quote:


import processing.opengl.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;

GL gl;
GLU glu;
GLUtessellator tess;
TessCallback tessCallback;

void setup() {
 size(400,400,OPENGL);
 // setup the tesselator
 gl = ((PGraphicsOpenGL)g).gl;
 glu = ((PGraphicsOpenGL)g).glu;
 tess = glu.gluNewTess();
 tessCallback = new TessCallback();
 glu.gluTessCallback(tess, GLU.GLU_TESS_BEGIN, tessCallback);
 glu.gluTessCallback(tess, GLU.GLU_TESS_END, tessCallback);
 glu.gluTessCallback(tess, GLU.GLU_TESS_VERTEX, tessCallback);
 glu.gluTessCallback(tess, GLU.GLU_TESS_COMBINE, tessCallback);
 glu.gluTessCallback(tess, GLU.GLU_TESS_ERROR, tessCallback);
}

void draw() {
 background(255);
 stroke(0);
 fill(128);
 /*
 // this degenerate "hourglass" poly won't triangulate properly:
 beginShape();
 vertex(100,100);
 vertex(300,300);
 vertex(100,300);
 vertex(300,100);
 endShape(CLOSE);
 */  
 // so have to do it the hard way:
 glu.gluTessBeginPolygon(tess, null);
 glu.gluTessBeginContour(tess);
 double [] vertex1 = { 100, 100, 0 };
 glu.gluTessVertex(tess, vertex1, 0, vertex1);
 double [] vertex2 = { 300, 300, 0 };
 glu.gluTessVertex(tess, vertex2, 0, vertex2);
 double [] vertex3 = { 100, 300, 0 };
 glu.gluTessVertex(tess, vertex3, 0, vertex3);
 double [] vertex4 = { 300, 100, 0 };
 glu.gluTessVertex(tess, vertex4, 0, vertex4);
 glu.gluTessEndContour(tess);
 glu.gluTessEndPolygon(tess);
}

class TessCallback extends GLUtessellatorCallbackAdapter {
 public void begin(int type) {
   switch (type) {
     case GL.GL_TRIANGLE_FAN: beginShape(TRIANGLE_FAN); break;
     case GL.GL_TRIANGLE_STRIP: beginShape(TRIANGLE_STRIP); break;
     case GL.GL_TRIANGLES: beginShape(TRIANGLES); break;
   }
 }
 public void end() {
   endShape();
 }
 public void vertex(Object data) {
    if (data instanceof double[]) {
     double[] d = (double[]) data;
     if (d.length != 3) {
         throw new RuntimeException("TessCallback vertex() data isn't length 3");
     }
     g.vertex((float) d[0], (float) d[1], (float) d[2]);
   } else {
     throw new RuntimeException("TessCallback vertex() data not understood");
   }
 }
 public void error(int errnum) {
   String estring = glu.gluErrorString(errnum);
   throw new RuntimeException("Tessellation Error: " + estring);
 }
 public void combine(double[] coords, Object[] data, float[] weight, Object[] outData) {
   double[] vert = new double[coords.length];
   vert[0] = coords[0];
   vert[1] = coords[1];
   vert[2] = coords[2];
   outData[0] = vert;
 }
}


Re: quad() with fill() problem
Reply #6 - Dec 22nd, 2007, 11:58pm
 
thx;

i'll integrate it with my algorithm.

merry x-mas
Page Index Toggle Pages: 1