Rendering polynomial surfaces in OpenGL

I need to be able to draw polynomial surfaces but I have
not found a way to do it with OpenGL. The problem is as
follows:

Given the polynomial: f(x,y) = sum(a_ijx^iy^j) i,j = 1,2,…,n
example: f(x,y) = 2.0x^2 + y^2 +3xy + x + 2.0y + 1.0

I want to be able to draw the 3D surface over a triangular domain:
example: I have the 2D triangle T2=(x1,y1, x2,y2, x3,y3).
If I say something like:

glBegin(GL_TRIANGLES)
glVertex3f(x1,y1,f(x1,y1));
glVertex3f(x2,y2,f(x2,y2));
glVertex3f(x3,y3,f(x3,y3));
glEnd();

I will see the the 3D triangle T3 whose vertices are
(xi,yi,f(xi,yi)) i=1,2,3 and all the points in the
2D triangle T2 have z coordinate such that it
lies inside the plane of the the triangle T3.

What I want to change is that each point P2(xp,zp) inside the
triangle T2 is mapped to a point P3(xp,yp,zp) where zp is given
by: zp = f(xp,yp).

How can I achieve that with OpenGL?

Thanks in advance!

Archonda, what you are asking is simple in principle.
It is simply an issue of discretization.

If the function does NOT vary much within the triaangular
domain T2 (the 2D triangle), you should be able to
plot a single triangle (T3) by generating vertices
as you would normally do. So, suppose you want to
plot 100 T2-type triangles. If you have a way of
generating their x and y components, simply feed
those to your f(x,y) and spit out a z variable
to give to the glVertex() call. If you have a way
to systematically generate T2 triangles, you are
set.

Now, if the function varies “quickly” within each
of these T2 triangles, then you might have to re-
descritize within that T2 triangle… just generate
more T2-type subtriangles and keep rendering.

If, by chance, you do not have any ideas on how to
systematically generate T2 triangles, then just
make a 2D grid, looping over i and j, and generate
two triangles for each i,j pair. Use clip planes
to trim that down to a large triangle if you have
to.

I hope this helps. But I am certain that what you
are asking is really easy. Send me a private message
if you need some more pointers or clearifications.

Hmm, it seems that you didn’t understand!
I have not problem rendering the T2 or T3
triangles. What I do need to know is whether
OpenGL supports drawing a surface given
by a specific polynomial z = f(x,y).
I know that GLU extends OpenGL by allowing it
to draw Bezier surfaces. But those people who
implemented that didn’t make a wise choise.
Drawing polynomial surfaces is more general
than Bezier surfaces. So If they had implementd
the former hey would ne able to render the later.
So My questions is: Can we Render such a surface?
Suppose you have the T2 triangle then you should find a way to render the T3 surface (not a triangle any more) but its projections is the T2, in which all z points are given buy z=f(x,y).

So this is the problem. I See that the only
solution we have from what you have described is
recursively refine each triangle to 4 or 16 …
and draw the T3 triangles instead! Yes this is an
options but this is tricky. The real question is

“Is it possible for OpenGL to do the right thing?”

I think that you know that this is a hole in OpenGL’s functionality or perhaps in GLU’s functionality. Do you think that there is a way to do it properly by examining GLU source code?

Thanks again!

A clearification. The rendering pipeline is the GL
alone. GLU is a different story. It is a utility
toolkit, and works over the underlying GL API. I
could be wrong, of course.

I disagree with you with regard to the Bezier patches
implementation being a hole in the GL and that
polynomial surfaces is better. A bezier curve is
parametrized by its arclength, in some sense – you
can think about a mapping, but it is generally one-
to-one with the arclength parameter – which is NOT
the case for a polynomial surface. We can argue this
forever, but I believe that you are not seeing the
full picture. For example, what if your Bezier
curve is folding over itself in the z coordinate,
and by this I mean having multiple z values for
the same x and y values. This cannot be done with
a polynomial surface (sorry!).

I might still be failing to see what you are saying. I will be away on vacation for a week so
I am not going to follow up on this discussion for
a while.

I am not very sure, but the OpenGL Shading language may be what you’r looking for.

I See that the only
solution we have from what you have described is
recursively refine each triangle to 4 or 16 …
and draw the T3 triangles instead! Yes this is an
options but this is tricky
Just guessing here, but I think you are looking for something like this:

void DrawPolynomialSurface(
	float P[3],
	float DirX[3],
	float DirY[3],
	float DirZ[3],
	float x,
	float y,
	float dx,
	float dy,
	float (*f)(float x,float y),
	int SubdivisionDepth)
{
	int i,j,k;
	glBegin(GL_TRIANGLES);
	for(i=0;i<SubdivisionDepth;i++)
	for(j=0;j<SubdivisionDepth;j++)
	{
		float a0=i/(float)SubdivisionDepth;
		float b0=j/(float)SubdivisionDepth;
		float a1=(i+1)/(float)SubdivisionDepth;
		float b1=(j+1)/(float)SubdivisionDepth;

		float x0=x+a0*dx;
		float y0=y+b0*dy;
		float x1=x+a1*dx;
		float y1=y+b1*dy;

		float Disp00[3];//Disp00=P+a0*DirX+b0*DirY+f(x00,y00)*DirZ;
		float Disp01[3];//Disp01=P+a0*DirX+b1*DirY+f(x01,y01)*DirZ;
		float Disp10[3];//Disp10=P+a1*DirX+b0*DirY+f(x10,y10)*DirZ;
		float Disp11[3];//Disp11=P+a1*DirX+b1*DirY+f(x11,y11)*DirZ;

		for(k=0;k<3;k++)
		{
			Disp00[k]=P[k]+a0*DirX[k]+b0*DirY[k]+f(x0,y0)*DirZ[k];
			Disp01[k]=P[k]+a0*DirX[k]+b1*DirY[k]+f(x0,y1)*DirZ[k];
			Disp10[k]=P[k]+a1*DirX[k]+b0*DirY[k]+f(x1,y0)*DirZ[k];
			Disp11[k]=P[k]+a1*DirX[k]+b1*DirY[k]+f(x1,y1)*DirZ[k];
		}

		glVertex3fv(Disp00);
		glVertex3fv(Disp01);
		glVertex3fv(Disp10);

		glVertex3fv(Disp01);
		glVertex3fv(Disp11);
		glVertex3fv(Disp10);
	}
	glEnd();
}

// Calling it like this should give you a nice surface.
float f(float x,float y)
{
	return x*x*x+y*y;
}
//...
glMatrixMode(GL_PROJECTION);
glOrtho(-5.0f,5.0f,-5.0f,5.0f,-20.0f,20.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//...
float P[3]={0.0f,0.0f,0.0f};
float DirX[3]={+1.0f,1.0f,1.0f};
float DirY[3]={-1.0f,1.0f,1.0f};
float DirZ[3]={0.0f,1.0f,-1.0f};
DrawPolynomialSurface(P,DirX,DirY,DirZ,-1.0f,-1.0f,2.0f,2.0f,f,10);

Note: this is illustrative (read: really slow) code.

Originally posted by archondas:
“Is it possible for OpenGL to do the right thing?”
It depends on what you think “the right thing” is…

If you expect OpenGL to draw a real curved surface, this is not possible, you can only draw flat polygons. GLU does the same thing for Bezier surfaces. But after all, a computer screen is “just” a regular array of square pixels, so you can’t draw something really round anyways…

But the subdivision method described by iznogoud and samv is not as bad as it seems. You just have to subdivide enough so that the resulting triangles are smaller than 1 pixel, and generate the “real” normals at each triangle vertex (derivative of the original function, not the triangle normal). Then you get an image that is identical to “the real thing” after displaying on a raster monitor.

In reality, you will find that for most functions you won’t have to subdivide anywhere near pixel resolution to get an image with good quality, but if it is not enough, you can just subdivide further and get arbitrary near to the “real” image until you hit the resolution of your monitor. It’s always a tradeof between quality and performance.