OpenGL - Render Plane equation

Started by
3 comments, last by mathematical 7 years, 11 months ago

Hi guys, i'm trying to figure out how to render a plane. My internal plane representation consists of a normal, and distance from origin


Vector3 Normal;
float Distance;

Given this, i've tried the following to render the plane:


GL.PushMatrix();

GL.Translate(Normal.X * Distance, Normal.Y * Distance, Normal.Z * Distance);
GL.Rotate(Normal.Y * 360f, 0f, 1f, 0f);
GL.Rotate(Normal.X * 360f, 1f, 0f, 0f);
GL.Rotate(Normal.Z * 360f, 0f, 0f, 1f);

GL.Begin(PrimitiveType.Quads);
    GL.Vertex3(-1, 1, 0);
    GL.Vertex3(-1, -1, 0);
    GL.Vertex3(1, -1, 0);
    GL.Vertex3(1, 1, 0);
GL.End();

GL.PopMatrix();

While this seems to work, i have doubts that it will with all angles... (Reason being the rotation order).

So, my question, is there a better way to derive a plane to be rendered?

I'm using C# and OpenTK to render this.

Please don't comment that i should be using more modern OpenGL, that is not constructive to the question i'm asking.

Advertisement

Your doubts are valid, but the reason is wrong. The vertices are placed onto the local x/y plane, hence the normal is along the direction of the local z axis. Putting (0,0,1) into your rotation code and considering that rotation by 360° is identical to rotation by 0°, you correctly see the front of your plane. However, just using normals along x (1,0,0) or y (0,1,0) or so with your rotation code still give you the same vertices, since all transformations are the same. Changing the order of rotation does not make any difference then.

Actually, using a normal and a distance lets several degrees of freedom in an open state. Rendering a plane with vertices need those degree of freedom to be fixed. What I mean is that you need a definition of

a) an origin of the plane, so that there is a point with local co-ordinates (0,0,0),

b) an orientation angle around the normal (think of the rolling angle of a camera; the normal gives you just 2 of the 3 angles).

You solved a) by using the point

origin := (0,0,0) + distance * normal

You solve b) by just picking an angle, i.e. so that rolling is zero.

So with these fixes you have a position and an orientation as a direction and "no rolling". Let's express "no rolling" as

up_vector := (0,1,0)
And instead of a pure direction, let's use it as difference vector from the origin to a tip point

center_point := origin + normal * 1

Now (with the origin and the center point and the up vector), what we have here are the ingredients for the gluLookAt function! Although being described as a function to compute a view matrix, the function actually just builds a transformation matrix with a translation and rotations so that the z axis points in a specific direction.

The math behind the gluLookAt function isn't complicated and leaving OpenGL's matrix stack behind is ever a Good Thing TM, but I assume you may be happy with the sketched solution. Otherwise feel free to ask :)

I think this is what you are describing:


Vector3 forward = new Vector3(Normal.X, Normal.Y, Normal.Z);
Vector3 up = new Vector3(0f, 1f, 0f);
Vector3 right = Vector3.Cross(forward, up);
up = Vector3.Cross(right, forward);

Matrix4 rot = new Matrix4(right.X, up.X, -forward.X, 0.0f,
    right.Y, up.Y, -forward.Y, 0.0f,
    right.Z, up.Z, -forward.Z, 0.0f,
    0.0f, 0.0f, 0.0f, 1.0f);
Matrix4 trans = Matrix4.Translate(Normal * Distance);

Matrix4 result = rot * trans;

GL.PushMatrix();
GL.LoadMatrix(result.OpenGL);

GL.Begin(PrimitiveType.Quads);
GL.Vertex3(-1, 1, 0);
GL.Vertex3(-1, -1, 0);
GL.Vertex3(1, -1, 0);
GL.Vertex3(1, 1, 0);
GL.End();

GL.Begin(PrimitiveType.Points);
GL.Color3(1f, 1f, 0f);
GL.Vertex3(0f, 0f, 0f);
GL.Color3(1f, 0f, 1f);
GL.Vertex3(Normal.X * Distance, Normal.Y * Distance, Normal.Z * Distance);
GL.End();

GL.PopMatrix();

This however does not seem to work either. I can't even get the reference points rendering once i load the matrix generated above :(

Am i missing a step in this?

I don't know how your framework linearizes matrices, so this code snippet
Matrix4 rot = new Matrix4(...)

may or may not be correct.

But there is a noticeable difference in transformation computation between your 1st and your 2nd post. In the 1st post you compute

Mi+1 := Mi * T * R

with M being the transformation matrix on the stack, T being the translation and R the rotation. The snippet in your 2nd post computes

Mi+1 := I * R * T

instead, where I is the identity matrix. Notice that (a) the matrix being formerly on the top of the stack is now ignored, and that (b) the order of translation and rotation is exchanged.

Hence try to change this line

Matrix4 result = rot * trans;

into

Matrix4 result = trans * rot;

Further, if the former stack matrix should play a role, instead of
GL.LoadMatrix(result.OpenGL);
use
GL.MultMatrix(result.OpenGL);

Wow, GREAT CATCH! Rookie mistake on my part! You where correct in both cases, first i multiplied the matrix instead of loading; and the multiplication order did need to be reversed also. The matrix constructor was correct. Thank you so much for the help, it works flawlesly now!

For anyone who might be interested, my final code ended up being:


// Debug Normal
GL.Color3(1f, 1f, 0f);
GL.Begin(PrimitiveType.Lines);
GL.Vertex3(0f, 0f, 0f);
GL.Vertex3(Normal.X * 500, Normal.Y * 500, Normal.Y * 500);
GL.End();

GL.Color3(1f, 1f, 1f);
Vector3 forward = new Vector3(Normal.X, Normal.Y, Normal.Z);
Vector3 up = new Vector3(0f, 1f, 0f);
Vector3 right = Vector3.Cross(forward, up);
up = Vector3.Cross(right, forward);

Matrix4 rot = new Matrix4(right.X, up.X, -forward.X, 0.0f,
    right.Y, up.Y, -forward.Y, 0.0f,
    right.Z, up.Z, -forward.Z, 0.0f,
    0.0f, 0.0f, 0.0f, 1.0f);
Matrix4 trans = Matrix4.Translate(Normal * Distance);

Matrix4 result = trans * rot;

GL.PushMatrix();
GL.MultMatrix(result.OpenGL);

// Draw Plane
GL.Begin(PrimitiveType.Quads);
GL.Vertex3(-1, -1, 0);
GL.Vertex3(-1, 1, 0);
GL.Vertex3(1, 1, 0);
GL.Vertex3(1, -1, 0);
GL.End();

// Debug Points
GL.Begin(PrimitiveType.Points);
GL.Color3(1f, 1f, 0f);
GL.Vertex3(0f, 0f, 0f);
GL.Color3(1f, 0f, 1f);
GL.Vertex3(Normal.X * Distance, Normal.Y * Distance, Normal.Z * Distance);
GL.End();

GL.PopMatrix();

Tough my math lib is a bit wonky, you might need to adjust.

This topic is closed to new replies.

Advertisement