PDA

View Full Version : Custom color interpolation inside of a circle



hsencan
03-03-2012, 02:18 PM
Let's say I have a triangle. Each vertex of that triangle has a color value, inside of that triangle the colors were interpolated.
a well known example:
http://www.packtpub.com/sites/default/files/Article-Images/4767OS_01_04.png

I wanna a draw a circle or ellipse outside of this triangle and paint the unpainted portion of this ellipse by interpolating the colors of the triangle.
What I mean is FROM the borders of the circle TO the borders of triangle there needs to be an interpolation logic. We can assume the borders of the ellipse has a color value equal to the blue.

To Be more clear, at the lower left corner of the circle I have a blue value. And inside of the circle is colorless until I meet the lower left corner of the triangle which is red. From that blue to red there needs to be an interpolation. This process needs to be done for every pixel of the circle.

Here is the code for how I draw the circle and triangle:

glBegin(GL_TRIANGLES);
glColor3f(1.0, 0.0, 0.0);
glVertex3f( 0.0f, 1.0f, 0.0f);
glColor3f(0.0, 1.0, 0.0);
glVertex3f(-1.0f,-1.0f, 0.0f);
glColor3f(0.0, 0.0, 1.0);
glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();

const float DEG2RAD = 3.14159/180;
glBegin(GL_LINE_LOOP);

for (int i=0; i < 360; i++)
{
float degInRad = i*DEG2RAD;
glVertex2f(cos(degInRad)*2.0f,sin(degInRad)*2.0f);
}
glEnd();

Any ideas?

menzel
03-03-2012, 04:47 PM
As you are drawing just a line loop, OpenGL does not generate fragments for the space between the circle and the triangle so it has to stay black. Try drawing a filled circle (maybe as a triangle fan) and see if the interpolation between the outer vertices and the center matches your taste. As the interpolation will always be linear, you might have to tessellate your mesh to get a different appearance. You can also do more complicated fragment accurate interpolation with a fragment shader...

hsencan
03-03-2012, 05:27 PM
When I draw a filled circle using the code below it just draws a yellow circle and does not interpolate anything. Is there a keyword GL_?? that I can use for interpolation?


void FilledCircle()
{
float x1,y1,x2,y2;
float angle;
double radius=4;

x1=0,y1=0;
glColor3f(0.0,0.0,1.0);

glBegin(GL_TRIANGLE_FAN);
glVertex2f(x1,y1);

for (angle=1.0f;angle<361.0f;angle+=0.2)
{
x2 = x1+sin(angle)*radius;
y2 = y1+cos(angle)*radius;
glVertex2f(x2,y2);
}

glEnd();
}

tonyo_au
03-03-2012, 10:32 PM
I think you really should look at shaders for this sort of thing. It will be a lot simpler since each rendered fragment comes with a screen coordinate in glFragCoord. You can then interpolate the colour of the fragment from any set of coordinates/colours supplied in uniforms with any function you like.

This is not tested code but gives you an idea



uniform vec2 loc1; // screen coord
uniform vec2 loc2; // screen coord
uniform vec3 colour1; // rgb
uniform vec3 colour2;

layout(location = 0, index = 0) out vec4 fFragColour;

void main()
{
vec2 d1 = loc1 - glFragCoord.xy;
vec2 d2 = loc2 - glFragCoord.xy;

float l1 = d1.length();
float l2 = d2.length();

float w1 = l1/(l1+L2);
float w2 = l2/(l1+l2);

vec3 c = colour1 * vec3(w1,w1,w1) + colour2 * vec3(w2,w2,w2);

fFragColour = vec3(c.xyz,1.0f);
}

hsencan
03-03-2012, 11:28 PM
Although what you suggest might be better way to do this. I am trying to implement a different logic.

What I am trying yo do is
1. Draw the triangle
2. Start drawing the circle
3. For every pixel of the circle
3.a. Create an imaginary line between that pixel and the center of the triangle
3.b. Find the intersection of that line with the triangle border
3.b. Find the the color of the intersection at that point
3.c. Draw a real line from that pixel to that point on the triangle border.

With this logic I think I will be able to create the figure I want because from the circle boundary to triangle boundary, the lines I will draw will be interpolated.

However my problem is about 3a and 3b now, how can I find the intersection of a line to a plane (triangular or polygonal) and can I have the color of that point on the screen?

tonyo_au
03-04-2012, 05:06 AM
You realise the method you propose will generate massive overdraw;but I assume you are doing this as an exercise.

One method is to render the screen with the triangle to a texture.

You can now use maths to find the intersection point of the pixel-centre and vertex-vertex line segments (all on cpu). This gives a coordinate to read the colour from the rendered texture.

You can now do a line draw from pixel to intersection point.

I can't think of a simple way of finding all the circle pixels because it is dependant on the window size.

menzel
03-04-2012, 01:24 PM
I also think you will have to do this by yourself without help of the GL API, so either in a shader or on the CPU: software resterization of the circle to find the startingpoint of the lines, line-line intersection to find the other point, calculatind the interpolated color as the color for the endpoint and then you can draw the lines (with massive overdraw) via GL.

hsencan
03-04-2012, 05:36 PM
Hi I followed your advice and use the OpenGl interpolation with triangle fan,

I can add my code for more advice.

I added three pictures.

The first picture is the original pentagon. I draw that using 9 triangles composed by 8 vertices. Each vertex has a color power value from blue to red.

In the second picture. What I am trying to accomplish adding a circle outside of that triangle and create a natural smooth looking picture.

In the third picture I am showing how I have drawn the circles using the outer triangle vertices. For each portion of the circle I make a loop (i.e. from PI/2 to PI) and for ever pixel on the circle boundary I use the corresponding triangle's out 2 vertices and draw a triangle between those three points



for (float angle=-M_PI/5;angle<M_PI/5;angle+=0.002)
{
glColor3f(vertexColors[triangle[t][0]][0], 0.0, vertexColors[triangle[t][0]][1]);
glVertex3f((float)coords[triangle[t][0]][0], (float)coords[triangle[t][0]][1], 0.0);
glColor3f(vertexColors[triangle[t][1]][0], 0.0, vertexColors[triangle[t][1]][1]);
glVertex3f((float)coords[triangle[t][1]][0], (float)coords[triangle[t][1]][1], 0.0);
glColor3f(0.0, 0.0, 1.0);
float x2 = sin(angle)*CIRCLE_RADIUS;
float y2 = cos(angle)*CIRCLE_RADIUS;
glVertex3f(x2,y2,0);
}



However even though this is basically what I want, the final result is not satisfactory.
1. you see the triangle boundaries inside of the pentagon.
2. You can also see the uneven distribution of colors at the corners of the pentagon. But this is understandable because of the way that I draw the circle using 5 different surfaces.

Thanks for all the comments to finish this initial task. However I am open to new comments to have a better looking, smoother result and how I can achieve that.