📄 camera.cpp
字号:
#include "camera.h"
#define ROUND(X) ((int)floor((X) + 0.5))
#define COLOR(X) ((unsigned char)max(0, min(255, ROUND((X)*255.0))))
void Camera::status(ostream &myOut, long currentRay, int percent, Scene scn)
{
myOut << percent << "% completed (" << currentRay << " rays cast from eye, "
<< scn.shadowRays << " shadow rays cast, "
<< scn.reflRays << " reflection rays cast, "
<< scn.refrRays << " refraction rays cast)\r";
myOut.flush();
}
void Camera :: setModelViewMatrix(void)
{ // load modelview matrix with existing camera values
float m[16];
Vector3 eVec(eye.x, eye.y, eye.z); // a vector version of eye
m[0] = u.x; m[4] = u.y; m[8] = u.z; m[12] = -eVec.dot(u);
m[1] = v.x; m[5] = v.y; m[9] = v.z; m[13] = -eVec.dot(v);
m[2] = n.x; m[6] = n.y; m[10] = n.z; m[14] = -eVec.dot(n);
m[3] = 0; m[7] = 0; m[11] = 0; m[15] = 1.0;
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(m); // load OpenGL抯 modelview matrix
}
void Camera:: set(Point3 Eye, Point3 look, Vector3 up, bool tellOpenGL)
{ // create a modelview matrix and optionally send it to OpenGL
eye.set(Eye); // store the given eye position
n.set(eye.x - look.x, eye.y - look.y, eye.z - look.z); // make n
Vector3 t1;
t1 = up.cross(n);
u.set(t1); // make u = up X n
n.normalize(); u.normalize(); // make them unit length
Vector3 t2;
t2 = n.cross(u);
v.set(t2); // make v = n X u
// Pass modelview to OpenGL only if you are drawing polygons (not raytracing)
if(tellOpenGL)
setModelViewMatrix(); // tell OpenGL
}
//<<<<<<<<<<<<<<<<<<<<<< slide >>>>>>>>>>>>>>>>>>>>>>..
void Camera :: slide(float du, float dv, float dn)
{ // slide both eye and lookAt by amount du * u + dv * v + dn * n;
eye.x += du * u.x + dv * v.x + dn * n.x;
eye.y += du * u.y + dv * v.y + dn * n.y;
eye.z += du * u.z + dv * v.z + dn * n.z;
setModelViewMatrix();
}
//<<<<<<<<<<<<<<<<<<<<<<<< rotAxes >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
void Camera:: rotAxes(Vector3& a, Vector3& b, float angle)
{ // rotate orthogonal vectors a (like x axis) and b(like y axia) through angle degrees
float ang = 3.14159265/180*angle;
float C = cos(ang), S = sin(ang);
Vector3 t(C * a.x + S * b.x, C * a.y + S * b.y, C * a.z + S * b.z); // tmp for a vector
b.set(-S * a.x + C * b.x, -S * a.y + C * b.y,-S * a.z + C * b.z);
a.set(t.x, t.y, t.z); // put tmp into a'
}
//<<<<<<<<<<<<<<<<<<<<<<<< roll >>>>>>>>>>>>>>>>>>>>>>>>>>>
void Camera :: roll(float angle)
{
rotAxes(u, v, -angle); setModelViewMatrix();
}
//<<<<<<<<<<<<<<<<<<<<<<<< pitch >>>>>>>>>>>>>>>>>>>>>>>>>
void Camera :: pitch(float angle)
{
rotAxes(n, v, -angle);setModelViewMatrix();
}
//<<<<<<<<<<<<<<<<<<<<<<<<< yaw >>>>>>>>>>>>>>>>>>>>>>>>
void Camera :: yaw(float angle)
{
rotAxes(u, n, -angle);setModelViewMatrix();
}
void Camera:: setProjectionMatrix()
{
glMatrixMode(GL_PROJECTION); glLoadIdentity();
gluPerspective(viewAngle, aspect, nearDist, farDist);
glMatrixMode(GL_MODELVIEW); // set its mode back again
}
void Camera :: setDisplay(int numRows, int numCols)
{ // tell camera screen size
nRows = numRows; nCols = numCols;
}
void Camera:: drawOpenGL(Scene &scn)
{
//first set the lights for openGL
float globalAmbient[4];
scn.ambient.build4tuple(globalAmbient); //build 4tuple for global ambient
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,globalAmbient);
int num, lightNum = GL_LIGHT0; //grab defined int for GL's light0
float colr[4], posn[4]; // arrays to hold openGL lights: color and position
setModelViewMatrix(); // for this camera set up
setProjectionMatrix(); // for this camera
Light *p;
for(p = scn.light, num = 0; p && num < 8; p = p->next, lightNum++, num++)
{ // set up to 8 OpenGL lights
(p->color).build4tuple(colr);
(p->pos).build4tuple(posn);
float zero[] = {0.0,0.0,0.0,1.0}; // sources don't have ambient component
glLightfv(lightNum,GL_AMBIENT,zero); //lights don't have their own ambient part
glLightfv(lightNum,GL_DIFFUSE,colr); // tell openGL diffuse light color
glLightfv(lightNum,GL_SPECULAR,colr); // tell openGl specualt light color
glLightfv(lightNum,GL_POSITION,posn);
glEnable(lightNum); // enable it after specifying its properties
}
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glClearColor(scn.background.red, scn.background.green, scn.background.blue,1.0f);
for(GeomObj* q = scn.obj; q ; q = q->next)
q->drawOpenGL(); // draw it
glFlush();
}
//<<<<<<<<<<<<<<<<<<<<<<<<< set - takes 9 params >>>>>>>>>>>>>>>>>
void Camera :: set(float ex, float ey, float ez, float lx, float ly, float lz, float upx, float upy, float upz)
{
Point3 e(ex, ey, ez);
Point3 look(lx, ly, lz);
Vector3 Up(upx, upy, upz);
set(e,look, Up);
}
void Camera :: setShape(float vAng, float asp, float nearD, float farD, bool tellOpenGL)
{
viewAngle = vAng;
aspect = asp;
nearDist = nearD;
farDist = farD;
H = nearD * tan(vAng * M_PI/360); // tan(theta/2) theta in radians
W = H * asp;
// Pass perspective to OpenGL only if you are drawing polygons (not raytracing)
if(tellOpenGL)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(viewAngle, aspect, nearDist, farDist);
}
}
unsigned char* Camera::raytrace(Scene& scn, int blockSize, bool useOpenGL)
{
size_t rayCount = 0;
float percentage = 10;
Ray theRay;
Color3 clr;
// Initialize the image buffer
unsigned char *buffer;
buffer = new unsigned char[3*nRows*nCols];
if(buffer==NULL)
{
fprintf(stderr,"Error Allocating Memory\n");
return NULL;
}
// Move through image plane and shoot rays
theRay.setStart(eye);
for(int row=0; row < nRows; row+=blockSize)
{
for(int col=0; col < nCols; col+=blockSize)
{
// compute the ray's direction
float x = -W + col * 2 * W / (float) nCols;
float y = -H + row * 2 * H / (float) nRows;
theRay.setDir( -nearDist * n.x + x * u.x + y * v.x,
-nearDist * n.y + x * u.y + y * v.y,
-nearDist * n.z + x * u.z + y * v.z);
// Shoot the ray into the scene
clr = scn.shade(theRay);
// Write the resulting color to the image buffer
for(int i=0; i<blockSize; i++)
{
for(int j=0; j<blockSize; j++)
{
buffer[3*(nRows-1-row-i)*nCols+3*(col+j)] = COLOR(clr.red);
buffer[3*(nRows-1-row-i)*nCols+3*(col+j)+1] = COLOR(clr.green);
buffer[3*(nRows-1-row-i)*nCols+3*(col+j)+2] = COLOR(clr.blue);
}
}
// Increment the ray counter
rayCount++;
// Update the text progress message
if(100*rayCount/(float)(nRows*nCols) > percentage)
{
status(cout, rayCount, (int)floor(100*rayCount/(float)(nRows*nCols)), scn);
percentage += 10;
}
}
// Draw to OpenGL
if(useOpenGL)
{
glRasterPos2i(0, row);
glDrawPixels(nCols, 1, GL_RGB, GL_UNSIGNED_BYTE, buffer + (3*(nRows-(row+1))*nCols));
glFlush();
}
}
// Output final status message
status(cout, rayCount, 100, scn);
cout << endl;
// Return a pointer to the image buffer
return buffer;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -