Re: 3 channel projection system

New Message Reply Date view Thread view Subject view Author view

Angus Dorbie (dorbie++at++sgi.com)
Thu, 21 May 1998 15:04:31 -0700


Greg Larson wrote:
>
> Eric Brandwine wrote:
> >
> > We have a medium fidelity cockpit simulator, and have just ordered a
> > number of hardware upgrades.
> >
> > We currently have an Onyx Reality Station w/MCO, driving 3 projectors
> > on an ~150 degree arc. The projectors display on 3 flat screens,
> > like \_/.
> >
> > We just ordered an Onyx2 IR w/DG8, 3 new projectors w/contrast
> > modulation, and a single curved screen. We want to do edge blending,
> > but are not sure of a couple of things.
> >
> > 1) Can the DG8 lay out channels in any geometry? The MCO would allow
> > you to pick resolution/channel count, but you were stuck with the
> > layout they gave you (to fit in a 2kx2k virtual buffer).
> >
> > We run 3++at++960x680, with 3 screens tiled horizontally, while the 3
> > channels are tiled vertically.
>
> Take a look at the ircombine utility in /usr/gfx. This is a gui tool to
> help with channel layout. You can also do some edge blending with the
> projector alignment and tuning depending on the projector.
>
> >
> > 2) How should we set up Performer to drive this projection system?
> > Right now, we have 3 channels defined, with the center as the
> > master, the 2 side channels offset ~50 degrees. This means 3
> > rendering passes for our single pipeline. Is there any way that we
> > could define a single channel with a 150 degree field of view, and
> > divide it across 3 outputs of the DG8? Also, how should we get
> > edge blenging working? Right now, the 3 channels that we are
> > displaying are not co-planar, so even if we were to increase the
> > horizontal field of view per channel a bit, and overlap the
> > projected images, the overlapped region would not match due to the
> > different geometries. Is this acceptable? Is there some way to
> > tell Performer to make some number of pixels on the edge of the
> > channel the same as the next channel over?
>
> Ircombine will help with your channel layout and allows for an easy way
> to overlap the output channels. Ircombine is also discussed in the
> Onyx2 online mannuals.

For this type of config (symmetrically rotated projectors) you can't
overlap the video channels in ircombine and make the projection work.

Your video config should do what it does now (array the video
horizontally or vertically, it doesn't matter, but your pfChannels
should include the FOV for the full channel and the heading offset
(pre viewing rotation about Z) should match the angle between
projector headings. The offset should therefore be less than the
FOV to provide the right overlap in the video images at the
expense of a little redundant rendering.

You then do something like draw a 3D test pattern to match the screen
and align the channels on the display surface.

You should be able to drive 3++at++1280x1024_60 from the DG5-8 in your
ONYX2 iR if you have 2 Raster Managers. If you only have one
RM your managed area will be limited to 2*1280x1024 or equivalent
so you'll have to go with a smaller video resolution or build a
.cmb file with DVR resize built in.

I've attached some C OpenGL code to render a test pattern for
the above alignment procedure. It assumes a managed area of
3840*1024 and horizontally arrayed video channels or 1280x1024.
with left to right video matching left to right channel alignment.
Adjust the field of view & resolution settings and the heading
offset rotation for your display file and managed area size.

Note any cylindricalor spherical screen section with horizontal
top & base will lose pixels in the top and bottom center of each
channel when correctly aligned.

Cheers,Angus.

-- 
"Only the mediocre are always at their best." -- Jean Giraudoux 

For advanced 3D graphics Performer + OpenGL based examples and tutors: http://www.dorbie.com/

/* * Copyright (c) 1998 Silicon Graphics, All rights Reserved. * multifrust.c * * To compile: * cc -o multifrust -O2 -n32 -mips3 multifrust.c -lGL -lX11 -lm */

#include <stdlib.h> #include <stdarg.h> #include <unistd.h> #include <stdio.h> #include <sys/types.h> #include <sys/param.h> #include <sys/time.h> #include <time.h> #include <ctype.h> #include <string.h> #include <GL/glx.h> #include <GL/glu.h> #include <math.h>

#define WIN_SIZEX (1280*3) /* maximum window width/height */ #define WIN_SIZEY 1024 /* maximum window width/height */

#define DEGTORAD (M_PI/180.0f)

Display *display; /* connection to X server */ XVisualInfo *vi; /* window visual */ Window window; /* window for drawing */ GLXContext context; /* graphics context */

int RGBattributes[] = { GLX_RGBA, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, None };

/* * wait_for_map_notify * * Callback for XIfEvent. */

int wait_for_map_notify(Display *display, XEvent *event, char *arg) { return(event->type == MapNotify && event->xmap.window == (Window)arg); }

/* * open_window * * Create an X window. */

void open_window(void) { XSetWindowAttributes swa; XSizeHints hints; XEvent event; XVisualInfo template; int c, x, y;

display = XOpenDisplay(0); if (display == NULL) { fprintf(stderr, "Can't connect to display \"%s\"\n", getenv("DISPLAY")); exit(1); } vi = glXChooseVisual(display, DefaultScreen(display), RGBattributes); if (vi == NULL) { fprintf(stderr, "can't find appropriate visual\n"); exit(1); } swa.border_pixel = 0; swa.override_redirect = 1; swa.colormap = XCreateColormap(display, RootWindow(display, vi->screen), vi->visual, AllocNone); swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask; x = (DisplayWidth(display, vi->screen) - WIN_SIZEX) / 2; y = (DisplayHeight(display, vi->screen) - WIN_SIZEY) / 2; window = XCreateWindow(display, RootWindow(display, vi->screen), x, y, WIN_SIZEX, WIN_SIZEY, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &swa); if (window == 0) { fprintf(stderr, "could not create a window\n"); exit(1); } XStoreName(display, window, "Perspective Quad Warp"); hints.x = x; hints.y = y; hints.width = WIN_SIZEX; hints.height = WIN_SIZEY; hints.flags = USPosition | PSize; XSetNormalHints(display, window, &hints); XMapWindow(display, window); XIfEvent(display, &event, wait_for_map_notify, (char *)window); context = glXCreateContext(display, vi, 0, GL_TRUE); glXMakeCurrent(display, window, context); }

void draw_test_pat(void) { float angle; int i, elevation; GLubyte *texdata;

/* draw azimuth lines */ glBegin(GL_LINES); for(angle = 0.0f, i=0; angle < M_PI*2; angle += DEGTORAD, i++) { if(!(i%10)) glColor3f(1.0f, 1.0f, 1.0f); else { if(!(i%5)) glColor3f(0.5f, 0.5f, 0.5f); else glColor3f(0.25f, 0.25f, 0.25f); } glVertex3f(sinf(angle)*10.0f, -100.0, cosf(angle)*10.0f); glVertex3f(sinf(angle)*10.0f, 100.0, cosf(angle)*10.0f); } glEnd();

/* draw elevation lines */ for(elevation = -88; elevation < 89; elevation++) { glBegin(GL_LINE_LOOP); for(angle = 0.0f; angle < M_PI*2; angle += DEGTORAD) { if(!(elevation%10)) glColor3f(1.0f, 1.0f, 1.0f); else { if(!(elevation%5)) glColor3f(0.5f, 0.5f, 0.5f); else glColor3f(0.25f, 0.25f, 0.25f); } glVertex3f(sinf(angle)*10.0f, tanf(DEGTORAD*(float)elevation)*10.0f, cosf(angle)*10.0f); } glEnd(); }

/* draw markers */ glColor3f(1.0f, 1.0f, 1.0f); glPushMatrix(); for(i=0; i<18; i++) { glRotatef(20.0f, 0.0f, 1.0f, 0.0f); glBegin(GL_LINES); glVertex3f(0.1f, 0.1f, 10.0f); glVertex3f(0.2f, 0.2f, 10.0f); glVertex3f(-0.1f,-0.1f, 10.0f); glVertex3f(-0.2f, -0.2f, 10.0f); glVertex3f(0.1f,-0.1f, 10.0f); glVertex3f(0.2f, -0.2f, 10.0f); glVertex3f(-0.1f,0.1f, 10.0f); glVertex3f(-0.2f, 0.2f, 10.0f); glEnd(); } glPopMatrix();

glPushMatrix(); glRotatef(10.0f, 0.0f, 1.0f, 0.0f); for(i=0; i<18; i++) { glRotatef(20.0f, 0.0f, 1.0f, 0.0f); glBegin(GL_LINES); glVertex3f(0.1f, 0.2f, 10.0f); glVertex3f(0.2f, 0.1f, 10.0f); glVertex3f(-0.1f, 0.2f, 10.0f); glVertex3f(-0.2f, 0.1f, 10.0f); glVertex3f(-0.1f, -0.2f, 10.0f); glVertex3f(-0.2f, -0.1f, 10.0f); glVertex3f(0.1f, -0.2f, 10.0f); glVertex3f(0.2f, -0.1f, 10.0f); glEnd(); } glPopMatrix(); }

/* float hfov = 48.0f; float vfov = 41.0f; float hoff = 36.0f; */

float hfov = 58.0f; float vfov = 44.0f; float hoff = 50.0f;

void main(int argc, char **argv) { open_window();

glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-tanf(DEGTORAD*hfov/2), tanf(DEGTORAD*hfov/2), -tanf(DEGTORAD*vfov/2), tanf(DEGTORAD*vfov/2), 1.0, 1000.0); glMatrixMode(GL_MODELVIEW);

glDrawBuffer(GL_FRONT); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glViewport(0, 0, WIN_SIZEX/3.0f, WIN_SIZEY); glLoadIdentity(); glRotatef(-hoff, 0.0f, 1.0f, 0.0f); draw_test_pat();

glViewport(WIN_SIZEX/3.0f, 0, WIN_SIZEX/3.0f, WIN_SIZEY); glLoadIdentity(); draw_test_pat();

glViewport(2.0f * WIN_SIZEX/3.0f, 0, WIN_SIZEX/3.0f, WIN_SIZEY); glLoadIdentity(); glRotatef(hoff, 0.0f, 1.0f, 0.0f); draw_test_pat();

glFinish(); while(1); }

======================================================================= List Archives, FAQ, FTP: http://www.sgi.com/Technology/Performer/ Submissions: info-performer++at++sgi.com Admin. requests: info-performer-request++at++sgi.com


New Message Reply Date view Thread view Subject view Author view

This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:57:25 PDT

This message has been cleansed for anti-spam protection. Replace '++at++' in any mail addresses with the '@' symbol.