PDA

View Full Version : problem de-rotating a model

wmelgaard
05-06-2017, 07:25 PM
The following program writes an 8 line cube, allows a mouse drag to rotate it, and then attempts to label the corners in their rotated location.
However, the more the model is rotated, the farther away from the vertices the labels are placed.
??

// labels.c
// This program writes a cube, which can be spun with a mouse drag, and then labels the corners.
// compile as gcc labels.c -lm -lglut -lGLEW -lGL

#include <stdio.h>
#include<math.h>
#include<time.h>
#include <GL/glew.h>
#include <GL/glext.h>
#include <GL/glut.h>

float roll0 = 0.0, pitch0 = 0.0, roll = 0.0, pitch = 0.0, zoom = 1.0;
int xdown, ydown, WindowWidth = 720, WindowHeight = 540, mainWindow;

void init(){
roll = pitch = 0.0; zoom = 1.0;
glMatrixMode(GL_MODELVIEW);
}

// multiply 4X4 matrix A by matrix B; answer is copied into matrix A
void mult4matrix(float A[4][4], float B[4][4]){
int i, j, k;
float C[4][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
for(i=0; i<4; i++) for(j=0; j<4; j++) for(k=0; k<4; k++){
C[i][j] += A[i][k] *B[k][j];
}
for(i=0; i<4; i++) for(j=0; j<4; j++) A[i][j] = C[i][j];
}

void transform(float *in, float *t){
// build(?) a transformation matrix, multiply in[] by that matrix, put answers in in[]
// roll is rotation about X axis; pitch = rotation about Y axis
const double PI = 3.14159265358979323846;
float ix, iy, iz, rad, ox, oy, oz;
int i, j;
double iroll, ipitch, ialpha, igamma, oroll, opitch;
static float lroll=NAN, lpitch, lzoom=1.0, xmatrix[4][4]; // values from previous
const float imatrix[4][4] = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}; //identity
float mmatrix[4][4], vout[3] = {0, 0, 0};

if((lroll != roll) || (lpitch != pitch) || (lzoom != zoom)){
// compute transformation matrix based on updated values
lroll = roll; lpitch = pitch; lzoom = zoom;
// roll & pitch are in degrees; iroll & ipitch are in radians
iroll = roll *PI/180.0;
ipitch = pitch *PI/180.0;

// set xmatrix, mmatrix = identity matrix
for(i=0; i<4; i++) for(j=0; j<4; j++) xmatrix[i][j] = mmatrix[i][j] = imatrix[i][j];

xmatrix[0][0] = cos(iroll);
xmatrix[0][2] = sin(iroll);
xmatrix[2][0] = -sin(iroll);
xmatrix[2][2] = cos(iroll);

mmatrix[1][1] = cos(ipitch);
mmatrix[1][2] = -sin(ipitch);
mmatrix[2][1] = sin(ipitch);
mmatrix[2][2] = cos(ipitch);
mult4matrix(xmatrix, mmatrix);

for(i=0; i<4; i++) for(j=0; j<4; j++) mmatrix[i][j] = imatrix[i][j]; lzoom = 1.0;
mmatrix[0][0] = lzoom;
mmatrix[1][1] = lzoom;
mmatrix[2][2] = lzoom;
mult4matrix(xmatrix, mmatrix);
}
for(i=0; i<4; i++) for(j=0; j<4; j++)vout[i] += xmatrix[i][j] *in[j];
t[0] = vout[0]; t[1] = vout[1]; t[2] = vout[2]; t[3] = 0;
}

void printtext(int x, int y, char String[]) // labels etc for model
{
int i, stringsize;
//(x,y) is from the bottom left of the window
glPushMatrix();
glPushAttrib(GL_DEPTH_TEST);
glDisable(GL_DEPTH_TEST);
glRasterPos2i(x,y);

for(i=0; String[i] != 0 && i<10; i++){
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, String[i]);
}
glPopAttrib();
glPopMatrix();
}

void display(){
float g[8][3] = {{-10.0, -10.0, -10.0},{10.0, -10.0, -10.0}, {10.0, 10.0, -10.0}, {-10.0, 10.0, -10.0},
{-10.0, -10.0, 10.0},{10.0, -10.0, 10.0}, {10.0, 10.0, 10.0}, {-10.0, 10.0, 10.0}};
float t[3];
int i;
char label[10];
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glOrtho(-20.0, 20.0, -20.0, 20.0, -20.0, 20.0);
glScalef(zoom, zoom, zoom);
glRotatef(roll, 0.0, 1.0, 0.0);
glRotatef(pitch, 1.0, 0.0, 0.0);
glPointSize(2.5);
glColor3f(0.0, 1.0, 1.0);
glBegin(GL_POINTS);
for(i=0; i<8; i++) glVertex3fv(g[i]);
glEnd();

// print grid identification numbers to screen
glColor3f(0.0, 0.3, 1.0);
for(i=0; i<8; i++){
transform(g[i], t);
sprintf(label, "%d", i);
printtext((int)(t[0]), (int)(t[1] ), label);
// offset the labels from the grid points
// printtext((int)(t[0]+2), (int)(t[1] +2), label);
}

glColor3f(0.0, 0.0, 1.0);
glBegin(GL_LINE_STRIP);
for(i=0; i<4; i++) glVertex3fv(g[i]);
glVertex3fv(g[0]);
for(i=4; i<8; i++) glVertex3fv(g[i]);
glVertex3fv(g[4]);
glEnd();
glBegin(GL_LINES);
for(i=1; i<4; i++){
glVertex3fv(g[i]);
glVertex3fv(g[i+4]);
}
glEnd();
glutSwapBuffers();
}

void move(int x, int y){
roll = roll0 + 90*(xdown -x)/WindowWidth;
pitch = pitch0 + 90*(ydown -y)/WindowHeight;
display();
}

void mouse(int btn, int state, int x, int y){
static int gup = 1;
if(btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN){
xdown = x;
ydown = y;
gup = 0;
return;
}
else if(btn == 3){ // mouse wheel
zoom *= 1.1;
display();
}
else if(btn == 4){
zoom /= 1.1;
display();
}

else if (state = GLUT_UP){
if(gup == 1)return;
roll0 += pitch;
pitch0 += roll;
}
gup = 1;
display();
}

int main(int argc, char* argv[]){
int WindowWidth = 720, WindowHeigyt=540;

glutInit(&argc,argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(WindowWidth, WindowHeight);
glutInitWindowPosition(100, 100);
mainWindow = glutCreateWindow("Print Labels");
init();
glutDisplayFunc(display);
glutMouseFunc (mouse);
glutMotionFunc(move);
glutMainLoop();
return 0;
}

GClements
05-07-2017, 01:08 AM
Why are you using a mixture of legacy OpenGL matrix operations and your own matrix code?

The coordinates passed to glRasterPos() are transformed by the model-view and projection matrices in the same manner as for glVertex(), so if you want to position bitmaps relative to a vertex, you can just pass the vertex' position to glRasterPos() while using the same matrices. You can apply a screen-space offset to the transformed position by using glBitmap() to render an empty bitmap with appropriate values for the xmove and ymove parameters.

Alternatively, you can perform all of the matrix arithmetic yourself and just pass the final matrices to OpenGL using glLoadMatrix() or glMultMatrix().

wmelgaard
05-07-2017, 05:33 AM
My problem is that I don't know the location of the rotated and spun vertex.
Commenting out the transform command and placing the grid location into the printtext command utilizes the same transformations that rotated the vertices. However, passing the 2D printtext command into the resulting transformation matrix does not account for the depth (Z coordinate) being rotated. The result is that labels for all vertices sharing the same X and Y coordinates are overlaid.

// transform(g, t);
sprintf(label, "%d", i);
// printtext((int)(t[0]), (int)(t[1] ), label);
printtext((int)(g[i][0]), (int)(g[i][1] ), label);

Using glMultMatrix() instead of my own code does make sense.

Why are you using a mixture of legacy OpenGL matrix operations and your own matrix code?

The coordinates passed to glRasterPos() are transformed by the model-view and projection matrices in the same manner as for glVertex(), so if you want to position bitmaps relative to a vertex, you can just pass the vertex' position to glRasterPos() while using the same matrices. You can apply a screen-space offset to the transformed position by using glBitmap() to render an empty bitmap with appropriate values for the [i]xmove and ymove parameters.

Alternatively, you can perform all of the matrix arithmetic yourself and just pass the final matrices to OpenGL using glLoadMatrix() or glMultMatrix().

wmelgaard
05-09-2017, 12:45 PM
I have tried to implement your suggestion, unsuccessfully.
The matrix multiplication algorithm that I presented works. I have verified that using Octave. Even accounting for the fact that OpenGL uses column-major matrices instead of row-major matrices, I cannot get the same results using glMultMatrixf(matrix) as with my matrix multiplication subroutine. Partially, that is to be expected, since my answers do not result in placing the labels where they belong. However, neither does using glMultMatrixf..

This should be a math problem. Given that my matrix multiplication subroutine works, why are the labels incorrectly placed? After jumping that hurdle, I should be able to re-write the code using glMultMatrixf

Why are you using a mixture of legacy OpenGL matrix operations and your own matrix code?

The coordinates passed to glRasterPos() are transformed by the model-view and projection matrices in the same manner as for glVertex(), so if you want to position bitmaps relative to a vertex, you can just pass the vertex' position to glRasterPos() while using the same matrices. You can apply a screen-space offset to the transformed position by using glBitmap() to render an empty bitmap with appropriate values for the xmove and ymove parameters.

Alternatively, you can perform all of the matrix arithmetic yourself and just pass the final matrices to OpenGL using glLoadMatrix() or glMultMatrix().

wmelgaard
05-09-2017, 07:39 PM
Thank you.
Thankyouthankyouthankyou!

Carmine
05-09-2017, 11:39 PM
Reposting my solution with a few further mods.
This is a simplification of your code which does what GClements suggested.
Let OpenGL transform the labels for you.
You don't need to do your own matrix multiplications.

2367

// -------------------------------------------------------------------------------------------------
// -------------------------------- May 17, 2017. Carmine. ------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <GLUT/glut.h>
#include "glutstr.hpp"

int xdown, ydown, WindowWidth = 720, WindowHeight = 540;
float roll0 = 0.0, pitch0 = 0.0, roll = 0.0, pitch = 0.0, zoom = 1.0;

//------------------------------------------ moove ---------------------------------------------

void moove (int x, int y)
{
roll = roll0 + 90 * (xdown-x) / WindowWidth;
pitch = pitch0 + 90 * (ydown-y) / WindowHeight;

glutPostRedisplay (); // This should be used instead of 'display'.
}

//------------------------------------------ mouse ---------------------------------------------

void mouse (int btn, int state, int x, int y) {

static int gup = 1;

if (btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
xdown = x;
ydown = y;
gup = 0;
return;
} else if (btn == 3) { // mouse wheel
zoom *= 1.1;
} else if (btn == 4) {
zoom /= 1.1;
} else if (state = GLUT_UP) {
if (gup == 1) return;
roll0 += pitch;
pitch0 += roll;
}

gup = 1;
}

//----------------------------------------- display --------------------------------------------

void display (void)
{
int i;
char label[2];
static int g[8][3] = {{-10,-10,-10}, {10,-10,-10}, {10,10,-10}, {-10,10,-10},
{-10,-10, 10}, {10,-10, 10}, {10,10, 10}, {-10,10, 10}};

// Set up viewing transformations.

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glOrtho (-20.0, 20.0, -20.0, 20.0, -20.0, 20.0);
glScalef (zoom, zoom, zoom);
glRotatef ( roll, 0.0, 1.0, 0.0);
glRotatef (pitch, 1.0, 0.0, 0.0);

// Draw cube vertices.

glColor3f (0.0, 1.0, 1.0);
glBegin (GL_POINTS); for (i=0; i<8; i++) glVertex3iv(g[i]); glEnd();

// Label cube vertices.

for (i=0; i<8; i++) {
glRasterPos3iv (g[i]);
sprintf (label, "%d", i);
glutBitmapCharacter (GLUT_BITMAP_9_BY_15, ' ');
glutBitmapCharacter (GLUT_BITMAP_9_BY_15, label[0]);
}

// Draw cube edges.

glColor3f (0.0, 0.0, 1.0);
glBegin (GL_LINE_LOOP); for (i=0; i<4; i++) glVertex3iv(g[i]); glEnd();
glBegin (GL_LINE_LOOP); for (i=4; i<8; i++) glVertex3iv(g[i]); glEnd();
glBegin (GL_LINES); for (i=0; i<4; i++) {glVertex3iv(g[i]); glVertex3iv(g[i+4]);}
glEnd();

glutSwapBuffers ();
}

//----------------------------------------- Init_GL --------------------------------------------

void Init_GL (void)
{
glMatrixMode (GL_PROJECTION);
glMatrixMode (GL_MODELVIEW);

glEnable (GL_DEPTH_TEST);
glPointSize (6.5);
}

//---------------------------------------- Init_Glut -------------------------------------------

void Init_Glut (void)
{
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize (WindowWidth, WindowHeight);
glutInitWindowPosition (700, 400);
glutCreateWindow ("Print Labels");
glutMotionFunc ( moove );
glutMouseFunc ( mouse );
glutDisplayFunc (display);
}

//------------------------------------------ main ----------------------------------------------

int main (int argc, char* argv[])
{
glutInit (&argc,argv);
Init_Glut ();
Init_GL ();
glutMainLoop();
return 0;
}

Carmine
05-09-2017, 11:50 PM
Thank you.
Thankyouthankyouthankyou!

(You're welcome) x 4