Creating a 3D Fly-by Movie

#include #include #include #include #include #include #include #include using namespace std; double pi = 3.14158748587; typedef struct start_t { double RA; double DEC; double MAG; }Star; typedef struct camera_t { double fovx; double fovy; double f; int width; int height; double RA; double distance; }Camera; typedef struct image_t { int width; int height; unsigned char *data; }Image; typedef struct moon_t { Image texture; double radius; }Moon; // print an error message void error(string message) { cout << "Error: "<< message << endl; exit(1); } // initialize the image structure void setImage(int width,int height,Image & img) { img.width=width; img.height=height; img.data=new unsigned char[width*height]; for(int i=0; i> img.width; ss >> img.height; setImage(img.width,img.height,img); in.read((char*)img.data,img.width*img.height); in.close(); } // convert from HH:MM:SS.FRAC to double double convertFormat(string str) { double parts[3]; int part=0; int start=0; for (int i=0; i<=str.length(); ++i) { if(str[i]==':' || str[i]=='\0') { str[i]='\0'; parts[part++]=atof(str.substr(start,i-start).c_str()); start=i+1; } } if(parts[0]<0) return -(-parts[0]+parts[1]/60.+parts[2]/3600.); else return parts[0]+parts[1]/60.+parts[2]/3600.; } // load the bright star catalog vector readCatalog() { vector stars; ifstream catalog; string buffer; catalog.open("kpno_brightstar_catalog"); if(!catalog.is_open()) error("Unable to open catalog file!"); getline(catalog,buffer); // get rid of header getline(catalog,buffer); while(getline(catalog,buffer)) { if(buffer.find("????")!=std::string::npos) // invalid line continue; Star star; stringstream ss(buffer); int line; string ra,dec,temp; ss >> line; ss >> ra; ss >> dec; ss >> temp; ss >> temp; ss >> temp; ss >> star.MAG; star.RA=(convertFormat(ra)*360.0/24.0)*pi/180.0; // convert to rads star.DEC=convertFormat(dec)*pi/180.0; // convert to rads stars.push_back(star); } return stars; } void setCamera(double fovx,double fovy,int width,Camera & camera) { camera.width=width; camera.fovx=fovx*pi/180.0; camera.f = 0.5*camera.width/tan(0.5*camera.fovx); // same focus for both directions camera.fovy=fovy*pi/180.0; camera.height=ceil(2*tan(0.5*camera.fovy)*camera.f); // round up camera.RA = 0.0; } // position camera at the right ascencion RA in degrees void positionCamera(double RA,double position,Camera & camera) { camera.RA = RA*pi/180.0; camera.distance=position; } // determine if the star is in the field of view of the camera int in_FOV(Star star,Camera camera) { double startAngle,endAngle; if(star.DEC < 0.5*camera.fovy && star.DEC>-0.5*camera.fovy) { // vertical visibility startAngle=camera.RA-0.5*camera.fovx; endAngle=camera.RA+0.5*camera.fovx; if(startAngle<0) { startAngle=2*pi+startAngle; if(star.RA > startAngle && star.RA < 2*pi) return 1; else if(star.RA >= 0 && star.RA < endAngle) return 1; else return 0; } else if(endAngle>2*pi) { endAngle=endAngle-2*pi; if(star.RA > startAngle && star.RA < 2*pi) return 1; else if(star.RA >= 0 && star.RA < endAngle) return 1; else return 0; } else if(star.RA > startAngle && star.RA < endAngle) return 1; } return 0; } // put a pixel in the image, trim if necessary void putPixel(int x,int y,unsigned char color,Image img) { if(x<0 || x>=img.width) return; if(y<0 || y>=img.height) return; int pos=(img.height-1-y)*img.width+img.width-1-x; unsigned newColor=color+img.data[pos]; if(newColor>255) newColor=255; img.data[pos]=newColor; } // put a pixel in the image, discard previous content void setPixel(int x,int y,unsigned char color,Image img) { if(x<0 || x>=img.width) return; if(y<0 || y>=img.height) return; int pos=(img.height-1-y)*img.width+img.width-1-x; img.data[pos]=color; } // get a pixel from the image unsigned char getPixel(int x,int y,Image img) { if(x<0 || x>=img.width) return 0; if(y<0 || y>=img.height) return 0; int pos=y*img.width+img.width-1-x; return img.data[pos]; } // draw a star as a small blob void drawStar(Star star,Camera camera,Image img) { double k = 2.0*star.MAG; // luminosity decay double startAngle=camera.RA-0.5*camera.fovx; double endAngle=camera.RA+0.5*camera.fovx; double y0 = (0.5*camera.fovy+star.DEC); double x0 = (star.RA - startAngle ); if(startAngle<0) { startAngle=2*pi+startAngle; if(star.RA > startAngle && star.RA < 2*pi) x0= (star.RA - startAngle ); } else if(endAngle>2*pi) { endAngle=endAngle-2*pi; if(star.RA > startAngle && star.RA < 2*pi) x0= (star.RA - startAngle ); else if(star.RA >= 0 && star.RA < endAngle) x0= (star.RA - startAngle + 2*pi ); } x0=x0*img.width/camera.fovx; y0=y0*img.height/camera.fovy; for(int x=-14; x<=14; ++x) { for(int y=-14; y<=14; ++y) { double r=x*x+y*y; int color=255*exp(-r/k); putPixel(x0+x,y0+y,color,img); } } } // draw the moon using the texture void drawMoon(Camera camera,Image img,Moon moon) { double theta = 2.0*atan(moon.radius/camera.distance); int d=theta*img.width/camera.fovx; for(double x=-d/2; x<=d/2; ++x) for(double y=-d/2; y<=d/2; ++y) { if(x*x+y*y<=d*d/4.0) { double yp=y*camera.distance/camera.f; double xp=x*camera.distance/camera.f; double rho=sqrt(xp*xp+yp*yp); double c = asin(rho/moon.radius); double lat = asin(yp/moon.radius); double lon = camera.RA + pi + atan2((xp/moon.radius),cos(c)); double u = 0.5 + atan2(sin(lon),cos(lon))/(2.*pi); double v = 0.5 - lat/pi; int tx=(moon.texture.width-1)*u; int ty=(moon.texture.height-1)*v; double px,py; px=x+img.width/2; py=y+img.height/2; setPixel(px,py,0.8*getPixel(tx,ty,moon.texture),img); } } } // render the picture void render(vector stars,Camera camera,Image img,Moon moon) { for(int i=0; i stars=readCatalog(); setCamera(24.0,16.0,1200,camera); Image img,texture; setImage(camera.width,camera.height,img); loadPGM("moon_shaded_1k.pgm",texture); Moon moon; moon.radius=1737; moon.texture=texture; int frame=0; int nframes = 500; for(double RA=0.0; RA<=360; RA+=360./nframes) { clearImage(img); positionCamera(RA,80000,camera); render(stars,camera,img,moon); stringstream ss; ss << "img_"; ss << ceil(camera.fovx*180/pi) << "x"; ss << ceil(camera.fovy*180/pi) << "_"; ss << setw(4) << setfill('0') << right << frame << ".pgm"; savePGM(ss.str().c_str(),img); frame++; } return (0); }