Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 10 of 10

Thread: Making an arbitrary polygon look darker towards the edges

  1. #1
    Junior Member Newbie
    Join Date
    Jul 2013
    Posts
    4

    Making an arbitrary polygon look darker towards the edges

    I am writing an application which displays 2d polygons. My application is in Java and uses jme3 / LWJGL at the higher levels but I don't think that changes much, my question is at the GL level.

    The 2d polygons have dozens of vertices and the shape of the polygon, including the number and position of vertices, changes a little with each rendered frame. The polygons cannot be assumed to be convex, but they are contiguous, don't have holes, and the path defining each polygon does not ever cross itself.

    Each frame, I'm breaking each polygon down to a set of triangles using a 3rd party java library. Then I'm sending these triangles to OpenGL to be rendered.

    Currently I'm displaying each polygon with just one unshaded color.

    What I want is to smoothly darken that color towards the edge of the polygon. That is, the closer a pixel is to the nearest point on the boundary of the polygon, the darker it should be, according to some formula relating the distance with the darkness.

    I don't know what this kind of effect is called so I've struggled to find any design ideas on the web. I'm looking for any pointers or links to achieving this effect, in general terms. Even "this is known as the XYZ problem". Or any general ideas as to how I would achieve this.

    Thanks

  2. #2
    Junior Member Regular Contributor
    Join Date
    Apr 2012
    Location
    Los Angeles
    Posts
    187
    Have you found a solution to this problem yet?

  3. #3
    Junior Member Newbie
    Join Date
    Jul 2013
    Posts
    4
    Quote Originally Posted by Carmine View Post
    Have you found a solution to this problem yet?
    No. Any suggestions you can think of would be much appreciated!

  4. #4
    Junior Member Regular Contributor
    Join Date
    Mar 2012
    Posts
    129
    I believe what you are looking for is called pillow shading. You could do it by making an alpha-only copy of the polygon, blur it, and then render the original polygon again using a shader that reads the blurred texture intensity and multiplies it by the polygon color.

  5. #5
    Junior Member Newbie yoyonel's Avatar
    Join Date
    Sep 2010
    Location
    Paris
    Posts
    23
    Hello,

    For visual effect, you can:
    - [1] Use a Stencil Buffer (and stencil operations) and render your polygons and mark them (for example 1 for 'inside" polygon)
    - [2] Render in a target your edges
    - [3] Blur this RT [2]
    - [4] Inverse the RT [3]
    - [5] Use the StencilBuffer [1] to apply result of your RT [4] and mix the color result (darker towers the edges)

    you can adjust :
    - [1] : the size width of your rendering edges
    - [3] : the filter size (of your blur filter)

    This rendering can do the trick ... i think ^^

    Good luck,
    YoOOYOOooOO

  6. #6
    Junior Member Newbie
    Join Date
    Jul 2013
    Posts
    4
    Thanks for those quick responses. That's certainly given me some ideas.


    Quote Originally Posted by cireneikual View Post
    I believe what you are looking for is called pillow shading. You could do it by making an alpha-only copy of the polygon, blur it, and then render the original polygon again using a shader that reads the blurred texture intensity and multiplies it by the polygon color.


    Quote Originally Posted by yoyonel View Post
    Hello,

    For visual effect, you can:
    - [1] Use a Stencil Buffer (and stencil operations) and render your polygons and mark them (for example 1 for 'inside" polygon)
    - [2] Render in a target your edges
    - [3] Blur this RT [2]
    - [4] Inverse the RT [3]
    - [5] Use the StencilBuffer [1] to apply result of your RT [4] and mix the color result (darker towers the edges)

    you can adjust :
    - [1] : the size width of your rendering edges
    - [3] : the filter size (of your blur filter)

    This rendering can do the trick ... i think ^^

    Good luck,
    YoOOYOOooOO

  7. #7
    Junior Member Newbie yoyonel's Avatar
    Join Date
    Sep 2010
    Location
    Paris
    Posts
    23
    A simple way =>
    Use a shader (pixel shader, fragment shader) when you're rendering your triangle to compute the distance between the pixel/point and the "base"-edge of your triangle.
    Point-Line distance is a simple computation, you only need to know the "good" edge for each triangle, and use this distance to smooth your render color.

    YoYo

  8. #8
    Junior Member Newbie
    Join Date
    Jul 2013
    Posts
    4
    Quote Originally Posted by yoyonel View Post
    A simple way =>
    Use a shader (pixel shader, fragment shader) when you're rendering your triangle to compute the distance between the pixel/point and the "base"-edge of your triangle.
    Point-Line distance is a simple computation, you only need to know the "good" edge for each triangle, and use this distance to smooth your render color.

    YoYo
    Thanks yoyo!

    This seems like the best method. For each triangle I can pass to the shader a subset of the polygon boundary edges. The shader can then compute the minimum length vector between the current pixel location and one of these polygon boundary edges. It can then use this vector to compute the color / alpha values or look them up in a texture.

    As a potential optimization, in my application (i.e. outside the shader code) I can narrow down the boundary edges to a subset which includes only those edges which are the closest edge to some pixel in the triangle.

  9. #9
    Junior Member Newbie yoyonel's Avatar
    Join Date
    Sep 2010
    Location
    Paris
    Posts
    23
    Sound like a good idea !
    Please send your result :-)

  10. #10
    Junior Member Regular Contributor
    Join Date
    Apr 2012
    Location
    Los Angeles
    Posts
    187
    The code below addresses your problem using Classic GL (fixed pipeline) and some math routines which are included. It carefully extrudes the poly edges inward making quads, then uses simple color interpolation to fade the quads from inner to outer edge. Source code and figure are included. There are some Gouraud shading artifacts. Plus I've only tested it for this fairly simple polygon. I leave it up to you to do more testing. Not sure how contorted your polys are. This algorithm assumes the vertices of a poly are listed in counterclockwise order. To get the effect I think you want, draw the polys twice: 1) use your technique to draw the poly filled with solid color, 2) draw again with my technique to fade the edges. Let me know if it works for you!

    Click image for larger version. 

Name:	Pillow_Fill.jpg 
Views:	78 
Size:	43.3 KB 
ID:	1064

    Code :
     
    //---+----4----+----3----+----2----+----1----+---/\---+----1----+----2----+----3----+----4----+---\\
     
    #include <windows.h>
    #include <stdio.h>
    #include <math.h>
    #include <gl.h>         // The GL Header File  
    #include <glut.h>       // The GL Utility Toolkit (Glut) Header
     
    float hh = 0.1;
     
    //---+----4----+----3----+----2----+----1----+---/\---+----1----+----2----+----3----+----4----+---\\
    //----------------------------------------   vector_sum   ------------------------------------------
     
    void vector_sum (float a[3], float b[3], float c[3])
    {
        c[0] = a[0] + b[0];
        c[1] = a[1] + b[1];
        c[2] = a[2] + b[2];
    }
     
    //---+----4----+----3----+----2----+----1----+---/\---+----1----+----2----+----3----+----4----+---\\
    //----------------------------------------   vector_dif   ------------------------------------------
     
    void vector_dif (float a[3], float b[3], float c[3])
    {
        c[0] = a[0] - b[0];
        c[1] = a[1] - b[1];
        c[2] = a[2] - b[2];
    }
     
    //---+----4----+----3----+----2----+----1----+---/\---+----1----+----2----+----3----+----4----+---\\
    //-----------------------------------------   vec_mag   --------------------------------------------
     
      // Return the magnitude of a 3D vector.
     
    float vec_mag (float v[3])
    {
        return ((float)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]));
    }
     
    //---+----4----+----3----+----2----+----1----+---/\---+----1----+----2----+----3----+----4----+---\\
    //---------------------------------------   vector_angle   -----------------------------------------
     
             //  Return the angle between two vectors in radians.
     
    float vector_angle (float a[3], float b[3])
    {
        float  num, den;
     
        num = a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
        den = vec_mag(a) * vec_mag(b);
     
        return ((float)acos(num/den));
    }
     
    //---+----4----+----3----+----2----+----1----+---/\---+----1----+----2----+----3----+----4----+---\\
    //---------------------------------------   unit_vector   ------------------------------------------
     
    void unit_vector (float v[3])
    {
        float mag;
     
        mag = (float)sqrt (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
     
        v[0] = v[0] / mag;
        v[1] = v[1] / mag;
        v[2] = v[2] / mag;
    }
     
    //---+----4----+----3----+----2----+----1----+---/\---+----1----+----2----+----3----+----4----+---\\
    //----------------------------------------   vec_scale   -------------------------------------------
     
         //  Vector scale function.
     
    void vec_scale (float vec[3], float s)
    {
        vec[0] *= s;
        vec[1] *= s;
        vec[2] *= s;
    }
     
    //---+----4----+----3----+----2----+----1----+---/\---+----1----+----2----+----3----+----4----+---\\
    //----------------------------------------   vec_cross   -------------------------------------------
     
        //   Cross product of two 3D vectors
     
    void vec_cross (float a[3], float b[3], float c[3])
    {
        c[0] = a[1] * b[2]  -  a[2] * b[1];
        c[1] = a[2] * b[0]  -  a[0] * b[2];
        c[2] = a[0] * b[1]  -  a[1] * b[0];
    }
     
    //---+----4----+----3----+----2----+----1----+---/\---+----1----+----2----+----3----+----4----+---\\
    //-----------------------------------------   Keyboard   -------------------------------------------
     
    void Keyboard (unsigned char key, int x, int y)
    {
        switch (key)  {
     
           case 'x':   hh += 0.05;   break;
           case 'z':   hh -= 0.05;   break;
     
           case  27:     exit (0);   break;     // Quit program with 'esc' key.
     
           default :  printf ("   Keyboard -> key = %d, key = %c\n", key, key);   break;
        }
     
        glutPostRedisplay ();
    }
     
    //---+----4----+----3----+----2----+----1----+---/\---+----1----+----2----+----3----+----4----+---\\
    //------------------------------------------   Display   -------------------------------------------
     
    void Display (void)
    {
    	int v, i, j;
    	float a[3], b[3], c[3], goly[5][3], x, alfa;
     
    	static short first = 1, convex[5];
    	static float poly[5][3] = {{-1.0,-2.0},{1.0,-2.0},{0.0,0.5},{0.0,3.0},{-3.0,0.4}};
     
     
    	// Convex = 1 -> convex vertex, convex = 0 -> concave vertex.
     
    	if (first)  {
    	   first = 0;
    	   for (v = 0; v < 6; v++)  {
    	       i = (v - 1) % 5;
    	       j = (v + 1) % 5;
                   vector_dif (poly[v], poly[i], a);
                   vector_dif (poly[j], poly[v], b);
                   vec_cross  (a, b, c);
                   if (c[2] > 0.0)  convex[v] = 1;
                   else             convex[v] = 0;
    	   }
    	}
     
    	glLoadIdentity ();
    	glClear (GL_COLOR_BUFFER_BIT);
     
     
    	// Extrude lines to get quads of thickness 'hh'.
    	// 'hh' can be interactively changed via the 'x' and 'z' keys.
     
    	for (v = 0; v < 5; v++)  {
     
    	   i =  (v + 4) % 5;
    	   j =  (v + 1) % 5;
     
    	   vector_dif (poly[i], poly[v], a);
    	   vector_dif (poly[j], poly[v], b);
     
    	   unit_vector (a);
    	   unit_vector (b);
     
    	   vector_sum (a, b, c);
               unit_vector (c);
    	   alfa = 0.5 * vector_angle (a,b);
    	   x = hh / sin (alfa);
    	   vec_scale (c, x);
    	   if (convex[v]) vector_sum (poly[v], c, goly[v]);
    	   else           vector_dif (poly[v], c, goly[v]);
    	}
     
    	glBegin (GL_QUADS);
               for (v = 0; v < 5; v++)  {
    	      j =  (v + 1) % 5;
    	      glColor3f (0.2, 0.1, 0.2);
                  glVertex3fv (poly[v]); glVertex3fv (poly[j]);
    	      glColor3f (0.4, 0.9, 0.4);
    	      glVertex3fv (goly[j]); glVertex3fv (goly[v]);
    	   }
    	glEnd ();
     
        glutSwapBuffers ();
    }
     
    //---+----4----+----3----+----2----+----1----+---/\---+----1----+----2----+----3----+----4----+---\\
    //------------------------------------------   Init_GL   -------------------------------------------
     
    void Init_GL (void)
    {
        glMatrixMode (GL_PROJECTION);
        glLoadIdentity ();
        glOrtho (-5.0,5.0, -5.0,5.0, -5.0,5.0);
        glMatrixMode (GL_MODELVIEW);
        glLoadIdentity ();
     
        glClearColor (0.2, 0.1, 0.2, 1.0);
    }
     
    //---+----4----+----3----+----2----+----1----+---/\---+----1----+----2----+----3----+----4----+---\\
    //-------------------------------------------   main   ---------------------------------------------
     
    void main (int argc, char** argv) 
    {
        glutInit (&argc, argv);
     
        glutInitDisplayMode    (GLUT_RGB | GLUT_DOUBLE); 
        glutInitWindowSize     (800, 800); 
        glutInitWindowPosition (350, 100);
        glutCreateWindow       ("Pillow Fill - Carmine");
     
        glutKeyboardFunc (Keyboard);
        glutDisplayFunc  ( Display);
     
        Init_GL();
     
        glutMainLoop ();
    }
    Last edited by Carmine; 07-05-2013 at 03:07 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •