mit6837的assignment1的总结

来源:互联网 发布:lm324n中文数据手册 编辑:程序博客网 时间:2024/05/16 04:50

       assignment1是光线跟踪部分的起始,这里我们先建立了框架,建立一个纯虚的Object3D类作为父类,然后Group类作为子类,这里我们只建立了Sphere类这种实体。他们拥有bool intersect(const Ray &r, Hit &h, float tmin)这个函数,这个函数就是为了进行一道光打过去具体和那个物体相交的判定。另外我们还需要建立纯虚的Camera类,以及在这个assignment中用到的OrthographicCamera类,他们拥有Ray generateRay(Vec2f point)这个函数来生成光线。

       下面是各部分的代码:

       为了优化点,我们改动了hit.h的代码,主要是因为material本来就是指针,所以感觉原来的函数  Hit(const Hit &h)的过程中    material = h.material; 这一句不太好,我们改成new出一个material;然后顺带把material类写在hit.h里面。hit.h代码如下:

#ifndef _HIT_H
#define _HIT_H

#include "vectors.h"
#include "ray.h"


// ====================================================================
// ====================================================================


class Material{
public:
 Material(){};
 Material(Vec3f c):color(c){}

 Material(const Material& ma)
 {
  color = ma.color;
 }
 ~Material(){};
 void setMaterial(Vec3f c)
 {
  color=c;
 }
 Vec3f getColor(){return color;}
private:
 Vec3f color;
};


class Hit {
 
public:

  // CONSTRUCTOR & DESTRUCTOR
  Hit() { material = NULL; }

  Hit(float _t, Material *m, Vec3f n)
  {
    t = _t; material = m; normal = n;
  }


  Hit(const Hit &h)
  {
    t = h.t;
    material =new Material( *(h.material)) ;
    normal = h.normal;
    intersectionPoint = h.intersectionPoint;
  }


  ~Hit() {}

  // ACCESSORS
  float getT() const { return t; }
  Material* getMaterial() const { return material; }
  Vec3f getNormal() const { return normal; }
  Vec3f getIntersectionPoint() const { return intersectionPoint; }
 
  // MODIFIER
  void set(float _t, Material *m, Vec3f n, const Ray &ray) {
    t = _t; material = m; normal = n;
    intersectionPoint = ray.pointAtParameter(t); }

private:

  // REPRESENTATION
  float t;
  Material *material;
  Vec3f normal;
  Vec3f intersectionPoint;

};

inline ostream &operator<<(ostream &os, const Hit &h) {
  os << "Hit <" <<h.getT()<<", "<<h.getNormal()<<">";
  return os;
}
// ====================================================================
// ====================================================================

#endif

 


 

对于scene_parser.c这个文件,把里面和这次assignment不想关的东西注释掉就可以了,这里是一个读入场景文件到各个变量中的一个流程,写类的成员时候,需要参考里面的函数。

 

然后是camera.h和camera.c文件,注意下Ray generateRay(Vec2f point);函数,我们让他读入的point是将其单位化到(0,1)*(0,1)区间的,这样写的时候不需要考虑size大小什么的。具体代码如下:

camera.h:

#ifndef _CAMERA_H
#define _CAMERA_H

#include "vectors.h"
class Ray;

class Camera
{
public:
 Camera(){};
 ~Camera(){};
 virtual Ray generateRay(Vec2f point) = 0;
 virtual float getsize() = 0;
};

class OrthographicCamera:public Camera
{

public:
 OrthographicCamera(Vec3f c,Vec3f p,Vec3f u,float s)
  :center(c)
  ,projection(p)
  ,up(u)
  ,size(s)
 {
  Vec3f h;
  Vec3f::Cross3(h,p,u);
  horizontal=h;
 }
 OrthographicCamera(){};
 ~OrthographicCamera(){};
 float getsize(){return size;}
 virtual Ray generateRay(Vec2f point);
private:
 Vec3f center;
 Vec3f projection;
 Vec3f up;
 Vec3f horizontal;
 float size;
};
#endif

 

camera.c:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "camera.h"
#include "ray.h"
#include "vectors.h"
#include "matrix.h"
#include "image.h"
#include "scene_parser.h"
#include "hit.h"
#include "object3d.h"

Ray OrthographicCamera::generateRay(Vec2f apoint)
{
 Vec3f Porigin;
 Vec3f nh=horizontal;
 Vec3f nu=up;
 nh.Normalize();
 nu.Normalize();
 projection.Normalize();
 Porigin=center+nh*(apoint.x()-0.5)*size+nu*(apoint.y()-0.5)*size;
 Ray cameraray=Ray(projection,Porigin);
 return cameraray;
}

 

然后是object3D.h和object3D.c文件,需要注意的有两点,一个是对于Group,由于要带addObject操作,所以要带成员Object3D数组,另外注意到,在addObject的时候,我们读入的是一个指针,所以 Object3D **objects定义私有成员,另外就是注意Object3D是纯虚类,不能初始化成员,所以我们用malloc来分配空间给它。代码如下:

object3D.h:

#ifndef _OBJECT3D_H
#define _OBJECT3D_H
#include "hit.h"
#include "ray.h"
#include "vectors.h"

 

class Object3D{
public:
 Object3D(){};
 ~Object3D(){};
 virtual bool intersect(const Ray &r, Hit &h, float tmin) = 0;
private:
 Vec3f color;
};

class Sphere :public Object3D{
public:
 Sphere(){};
 Sphere(Vec3f ce,float r,Vec3f co)
  :center(ce)
  ,radius(r)
  ,color(co)
 {
 }
 ~Sphere(){};
 virtual bool intersect(const Ray &r, Hit &h, float tmin);
private:
 Vec3f center;
 float radius;
 Vec3f color;
};

class Group :public Object3D{
public:
 Group(){};
 Group(const int gnum)
  :num_object(gnum)
 {
  int n = sizeof(Object3D *);
  objects = (Object3D** )malloc(gnum * n);
 }
 ~Group(){};
 bool intersect(const Ray &r, Hit &h, float tmin);
 void addObject(int index, Object3D *obj);
private:
 int num_object;
 Object3D **objects;
};

#endif

 

对于object3D.c,我写的时候开始发生的一个问题就是sphere的intersect函数的实现中,material没有new出来,然后后读入的覆盖了前读入的,发生了错误。代码如下:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "camera.h"
#include "ray.h"
#include "vectors.h"
#include "matrix.h"
#include "object3d.h"
#include "hit.h"




bool Sphere::intersect(const Ray &ar, Hit &ah, float tmin){
float a,b,c,d,sradius,newt,oldt;
Vec3f sd,sr,sn;
sradius=this->radius;
a=1;
sd=ar.getDirection();
sr=ar.getOrigin();
sr=sr-center;
b=2*sd.Dot3(sr);
c=sr.Dot3(sr)-sradius*sradius;
if(b*b-4*a*c>=0)
{
Material* sm=new Material(color);
d=sqrt(b*b-4*a*c);
newt=(-b-d)/(2*a);
oldt=ah.getT();
Vec3f intersection=ar.pointAtParameter(newt);
sn=center-intersection;
sn.Normalize();
if(newt>=tmin && newt<oldt)
{
ah.set(newt,sm,sn,ar);
return 1;
}
return 0;
delete sm;
}
return 0;
};
bool Group::intersect(const Ray &br, Hit &bh, float tmin){
bool x=0;
for(int i=0;i<=num_object-1;i++){
if(objects[i]->intersect(br,bh,tmin))
x=1;
}
return x;
}


void Group::addObject(int in, Object3D *ob){
if (in<num_object && in>=0)
{
objects[in]=ob;
}



}

 

最后是parse.c函数,要注意的也和上面一样,如果没改hit.h文件的话,这里的material就要在循环体里面new出来,不过由于改了hit.h,我们在循环外new出来也没事.代码如下:

parse.c:

#include <stdio.h>

#include <string.h>
#include "image.h"
#include "vectors.h"
#include "matrix.h"
#include "scene_parser.h"
#include "object3d.h"
#include "camera.h"
// ========================================================
// ========================================================
// Some sample code you might like to use for parsing
// command line arguments
Image* render(char* filename,float width,float height)
{
 SceneParser scene=SceneParser(filename);
 Image* myimage=new Image(width,height);
 const Vec3f groundcolor=scene.getBackgroundColor();
 Camera* myCamera=scene.getCamera();
 float csize = myCamera->getsize();
 Group* myGroup=scene.getGroup();
 Material* orignm=new Material(groundcolor);
 myimage->SetAllPixels(groundcolor);
 for(int i=0;i<width;i++)
  for(int j=0;j<height;j++)
  {
   Ray oneray = myCamera->generateRay(Vec2f(i/width,j/height));
   int tmin=numeric_limits<float>::min();     
   Hit rhit=Hit::Hit(numeric_limits<float>::max(),orignm,Vec3f(0,0,0));
   bool l=myGroup->intersect(oneray,rhit,tmin);
   Material *currentmaterial=rhit.getMaterial();
   Vec3f currentcolor=currentmaterial->getColor();
   myimage->SetPixel(i,j,currentcolor);
  
  }
  delete orignm;
  return myimage;
}

int main(int argc,char *argv[]){
 char *input_file = NULL;
 int width = 100;
 int height = 100;
 char *output_file = NULL;
 float depth_min = 0;
 float depth_max = 1;
 char *depth_file = NULL;

 // sample command lines:
 // raycast -input input.txt -size 100 100 -output output.tga
 // raycast -input input.txt -size 100 100 -depth 5.5 8.8 output.tga

 for (int i = 1; i < argc; i++) {
  if (!strcmp(argv[i],"-input")) {
   i++; assert (i < argc);
   input_file = argv[i];
  } else if (!strcmp(argv[i],"-size")) {
   i++; assert (i < argc);
   width = atoi(argv[i]);
   i++; assert (i < argc);
   height = atoi(argv[i]);
  } else if (!strcmp(argv[i],"-output")) {
   i++; assert (i < argc);
   output_file = argv[i];
  } else if (!strcmp(argv[i],"-depth")) {
   i++; assert (i < argc);
   depth_min = atof(argv[i]);
   i++; assert (i < argc);
   depth_max = atof(argv[i]);
   i++; assert (i < argc);
   depth_file = argv[i];
  } else {
   printf ("whoops error with command line argument %d: '%s'\n",i,argv[i]);
   assert(0);
  }
 }
 Image *myimage=render(input_file,width,height);
 myimage->SaveTGA(output_file);
 delete myimage;
}
// ========================================================
// ========================================================

 

这样整个assignment1就算完成了.