PDA

View Full Version : Convert 3d point to 2d always flat to camera



ax2638
01-08-2016, 08:42 AM
I'm new to opengl and I'm trying to project a polygon into 2d, but I need that the polygon always stay flat to the camera to get
a orthographic projection (something like billboard)

What I did was to calculate the normal vector of the polygon and then set the view from the extreme of the
normal vector to the point of the polygon, so the view is totally flat.

But I cannot get the right 2d coords.

if I move/rotate the viewport, the 2d coord change, and I don't want that.
For me the important are the relation between points of the polygon, because I need this data to triangulate, so the position relative to viewport is not important.


This is the code. The initial routine is: stroke_2d_flat



/* get 2d location */
void get_2d_loc(GLdouble objx, GLdouble objy, GLdouble objz, int r_co[2])
{
GLdouble modelMatrix[16];
GLdouble projMatrix[16];
GLint viewport[4];

glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
glGetIntegerv(GL_VIEWPORT, viewport);

GLdouble win_x;
GLdouble win_y;
GLdouble win_z;

int result = gluProject(objx, objy, objz, modelMatrix, projMatrix, viewport,
&win_x, &win_y, &win_z);
r_co[0] = (int)win_x;
// reverse y to adapt from OpenGL to windows
r_co[1] = viewport[1] + viewport[3] - (int)win_y;

}
/* get points always flat to view */
void stroke_2d_flat(bGPDspoint *points, int totpoints, float(*points2d)[2])
{
bGPDspoint *pt;
int i;

GLfloat modelMatrix[4][4];
GLfloat projMatrix[4][4];
GLint viewport[4];

glGetIntegerv(GL_VIEWPORT, viewport);
bGPDspoint dpt0 = points[0];
bGPDspoint dpt1 = points[1];
bGPDspoint dpt2 = points[2];

// Create vectors
GLdouble v1[3] = { dpt1.x - dpt0.x, dpt1.y - dpt0.y, dpt1.z - dpt0.z };
GLdouble v2[3] = { dpt2.x - dpt1.x, dpt2.y - dpt1.y, dpt2.z - dpt1.z };

// Cross product to get normal vector (no need normalize)
GLdouble cx = (v1[1] * v2[2]) - (v1[2] * v2[1]);
GLdouble cy = (v1[2] * v2[0]) - (v1[0] * v2[2]);
GLdouble cz = (v1[0] * v2[1]) - (v1[1] * v2[0]);

// Set camera from normal to vertice (point 2)
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
gluLookAt(cx + dpt1.x, cy + dpt1.y, cz + dpt1.z, dpt1.x, dpt1.y, dpt1.z, 0, 1, 0);

// Create orthographic projection matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, 0, viewport[2], viewport[3], 0.0f, 1.0f);

// Convert all points to 2d
printf("Points:\n");
for (i = 0, pt = points; i < totpoints; i++, pt++)
{
int co[2];
get_2d_loc(pt->x, pt->y, pt->z, co);
printf("%d: 3d: %f, %f, %f \t 2d: %d,%d\n", i, pt->x, pt->y, pt->z, co[0], co[1]);
points2d[i][0] = co[0];
points2d[i][1] = co[1];
}

// Reset
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();

Dark Photon
01-08-2016, 07:01 PM
I'm new to opengl and I'm trying to project a polygon into 2d, but I need that the polygon always stay flat to the camera to get
a orthographic projection (something like billboard)

...

if I move/rotate the viewport, the 2d coord change, and I don't want that.


Ok, let's get clear on your requirements first.

You want these polygons to be billboarded so that they always face the camera.

It sounds like you want these polygons to be rendered in orthographic.

It also sounds like you want these polygons to be rendered in screen-space (window-relative), not in world-space (world-relative) so that their position and size is fixed relative to the window.

If so, why not activate an orthographic projection with an identity (or constant) modelview transformation when rendering these polygons? You don't have to render these polygons with the same transformations as you render scene objects unless you have some other requirements which desire (or require) it.

ax2638
01-09-2016, 03:22 AM
Ok, let's get clear on your requirements first..

Really I don't want render the polygon. I have the polygon on screen already, what I need is convert all 3d points to 2d, but I need to get "always" a flat polygon (the camera must look at the polygon surface orthogonal as a billboard). I need these 2d points to use in a routine and if I convert 3d to 2d points with the current rotation, the 2d points change depending of the rotation and I don't want this.

To put the camera, I used a normal vector calculated using the 3 first points of the polygon and apply the cross product.

Maybe my solution is totally wrong and there is a simple method.

ax2638
01-13-2016, 11:19 AM
I got a solution:



void stroke_to2d_flat(Mypoint *points, int totpoints, float(*points2d)[2])
{
GLfloat locx[3];
GLfloat loc3[3];

GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);

// local X axis (p0-p1)
locx[0] = points[1].x - points[0].x;
locx[1] = points[1].y - points[0].y;
locx[2] = points[1].z - points[0].z;

// point vector at 3/4
int p3 = totpoints * 0.75;
loc3[0] = points[p3].x - points[0].x;
loc3[1] = points[p3].y - points[0].y;
loc3[2] = points[p3].z - points[0].z;

// vector orthogonal to polygon plane
GLfloat normal[3];
cross_v3_v3v3(normal, locx, loc3);

// local Y axis (cross to normal/x axis)
GLfloat locy[3];
cross_v3_v3v3(locy, normal, locx);

// Normalize vectors
normalize_v3(locx);
normalize_v3(locy);

// Get all points in local space
for (int i = 0; i < totpoints; i++)
{
GLfloat loc[3];
// Get local space using first point as origin
loc[0] = points[i].x - points[0].x;
loc[1] = points[i].y - points[0].y;
loc[2] = points[i].z - points[0].z;

GLfloat co[2];
co[0] = dot_v3v3(loc, locx);
co[1] = dot_v3v3(loc, locy);
points2d[i][0] = co[0];
points2d[i][1] = co[1];
}
}