2010-04-25 2 views
1

시작하려면 실용적인 간단한 Ray Tracer를 작성하려고합니다. 레이 트레이서 (Ray Tracer)에서 전 세계에 여러 유형의 지오메트리가 있습니다. 모두 "SceneObject"라는 기본 클래스에서 파생되었습니다. 여기에 헤더를 포함했습니다.파생 된 클래스 객체에 대한 포인터 손실 vfptr

/** 
Interface for all objects that will appear in a scene 
*/ 
class SceneObject 
{ 
public: 
mat4 M, M_inv; 
Color c; 

SceneObject(); 
~SceneObject(); 

/** 
The transformation matrix to be applied to all points 
of this object. Identity leaves the object in world frame. 
*/ 
void setMatrix(mat4 M); 
void setMatrix(MatrixStack mStack); 
void getMatrix(mat4& M); 

/** 
The color of the object 
*/ 
void setColor(Color c); 
void getColor(Color& c); 

/** 
Alter one portion of the color, leaving 
the rest as they were. 
*/ 
void setDiffuse(vec3 rgb); 
void setSpecular(vec3 rgb); 
void setEmission(vec3 rgb); 
void setAmbient(vec3 rgb); 
void setShininess(double s); 

/** 
Fills 'inter' with information regarding an intersection between 
this object and 'ray'. Ray should be in world frame. 
*/ 
virtual void intersect(Intersection& inter, Ray ray) = 0; 

/** 
Returns a copy of this SceneObject 
*/ 
virtual SceneObject* clone() = 0; 

/** 
Print information regarding this SceneObject for debugging 
*/ 
virtual void print() = 0; 
}; 

여기서 알 수 있듯이 몇 가지 가상 함수를 다른 곳에서 구현할 수 있습니다. 이 경우 필자에게는 Sphere와 Triangle이라는 두 개의 파생 클래스 만 있는데이 둘은 누락 된 멤버 함수를 구현합니다. 마지막으로 Parser 클래스가 있는데,이 클래스는 실제 "광선 추적"부분을 수행하는 정적 메서드로 가득 차 있습니다. 여기에 현재 관련 부분

void Parser::trace(Camera cam, Scene scene, string outputFile, int maxDepth) { 
int width = cam.getNumXPixels(); 
int height = cam.getNumYPixels(); 
vector<vector<vec3>> colors; 
colors.clear(); 
for (int i = 0; i< width; i++) { 
    vector<vec3> ys; 
    for (int j = 0; j<height; j++) { 
    Intersection intrsct; 
    Ray ray; cam.getRay(ray, i, j); 
    vec3 color; 
    printf("Obtaining color for Ray[%d,%d]\n", i,j); 
    getColor(color, scene, ray, maxDepth); 
    ys.push_back(color); 
    } 
    colors.push_back(ys); 
} 
printImage(colors, width, height, outputFile); 
} 

void Parser::getColor(vec3& color, Scene scene, Ray ray, int numBounces) 
{ 
Intersection inter; scene.intersect(inter,ray); 
if(inter.isIntersecting()){ 
    Color c; inter.getColor(c); 
    c.getAmbient(color); 
} else { 
    color = vec3(0,0,0); 
} 
} 

에 대한 몇 조각을, 난 부분을 추적 진정한 레이 사라지는했고 어떤 경우 대신 단순히 첫 번째 개체 히트의 색상을 반환합니다. 여러분이 의심의 여지가 없으므로, 컴퓨터가 광선이 물체와 교차했다는 것을 아는 유일한 방법은 Scene.intersect()입니다. 사용 된 멤버 변수는 "벡터 객체" 끝 부분을 참조하십시오.

이제 문제가 생겼습니다. 먼저 장면을 만들고 Parser :: trace() 메서드 외부의 객체로 채 웁니다. 이상한 이유가 있기 때문에 저는 Ray를 i = j = 0으로 캐스팅했습니다. 모든 것이 멋지게 작동합니다. 그러나 두 번째 광선이 캐스팅 될 때까지는 내 Scene에 저장된 모든 객체가 더 이상 자신의 가상 객체를 인식하지 못합니다 (가상 객체를 제외한 모든 SceneObject 메서드에 계속 액세스 할 수 있습니다)! 나는 디버거로 코드를 밟아서 모든 vfptr에 대한 정보가 getColor()의 끝과 루프의 연속 사이에서 어딘가에서 손실된다는 것을 알았다. 그러나 장면 대신 & Scene을 사용하도록 getColor() 인수를 변경하면 손실이 발생하지 않습니다. 이게 무슨 미친 짓이야? 요청에 따라 장면에 대한

코드 :

#include <vector> 
#include <limits> 
#include "Intersection.h" 
#include "LightSource.h" 
#include "SceneObject.h" 

using namespace std; 

/** 
Contains a list of scene objects. A ray can be 
intersected with a scene to find its color 
*/ 
class Scene 
{ 
public: 
    vector<SceneObject*> objects; 
    vector<LightSource*> lights; 

    Scene(void); 
    ~Scene(void); 

    /** 
    Add an object to the scene 
    */ 
    void addObject(SceneObject& o); 

    /** 
    Add a light source to the scene 
    */ 
    void addLight(LightSource& l); 

    /** 
    Fill 'l' with all light sources in the scene 
    */ 
    void getLightSources(vector<LightSource*>& l); 

    /** 
    Fills 'i' with information regarding an 
    intersection with the closest object in the scene 
    IF there is an intersection. Check i.isIntersecting() 
    to see if an intersection was actually found. 
    */ 
    void intersect(Intersection& i, Ray r); 

    void print(); 
}; 

#include "Scene.h" 

Scene::Scene(void) 
{ 
} 

Scene::~Scene(void) 
{ 
    for(int i=0;i<objects.size();i++){ 
     delete objects[i]; 
    } 
    for(int i=0;i<lights.size();i++){ 
     delete lights[i]; 
    } 
} 

void Scene::addObject(SceneObject& o) 
{ 
    objects.push_back(o.clone()); 
} 

void Scene::addLight(LightSource& l) 
{ 
    lights.push_back(l.clone()); 
} 

void Scene::getLightSources(vector<LightSource*>& l) 
{ 
    l = lights; 
} 

void Scene::intersect(Intersection& i, Ray r) 
{ 
    Intersection result; 
    result.setDistance(numeric_limits<double>::infinity()); 
    result.setIsIntersecting(false); 

    double oldDist; result.getDistance(oldDist); 

    /* Cycle through all objects, making result 
    the closest one */ 
    for(int ind=0; ind<objects.size(); ind++){ 
     SceneObject* thisObj = objects[ind]; 
     Intersection betterIntersect; 
     thisObj->intersect(betterIntersect, r); 

     double newDist; betterIntersect.getDistance(newDist); 
     if (newDist < oldDist){ 
      result = betterIntersect; 
      oldDist = newDist; 
     } 
    } 

    i = result; 
} 

void Scene::print() 
{ 
    printf("%d Objects:\n", objects.size()); 
    for(int i=0;i<objects.size();i++){ 
     objects[i]->print(); 
    } 
} 
+1

죄송합니다. 완전히 이해할 수 없습니다. 그러나 나는 당신의 기본 클래스가 가상 소멸자를 필요로한다는 것을 관찰 할 것이다. –

+1

'Scene'의 복사 생성자 및/또는 소멸자에 잘못된 코드가있는 것처럼 들리지만'Scene'의 정의를 보지 않고서는 확실치 않습니다. –

+0

관련이 없지만 메소드가 'const' 올바른지 확인하십시오 (http://www.parashift.com/c++-faq-lite/const-correctness.html). – kennytm

답변

5

문제는 당신이 Scene의 소멸자에 SceneObjects을 삭제하는 것이 그리고 당신은 포인터의 벡터로 전체 복사본을 수행하는 기본 복사 생성자를 사용합니다. 즉, Scene의 각 사본은 동일한 SceneObjects을 참조합니다. 이러한 Scene 중 하나가 destry되면 그들 모두 참조 된 개체를 잃게됩니다. 장면을 참조로 전달하는 경우 아무런 문제가 없습니다.이 경우 복사가 수행되지 않고 나중에 파괴됩니다.

+0

완벽하게 맞습니다. 고맙습니다! – duckworthd

관련 문제