1

始めに、私はありふれた、単純なレイトレーサーを書こうとしています。私のレイトレーサーには、世界中に複数のタイプのジオメトリがあり、すべて「SceneObject」と呼ばれる基本クラスから派生しています。ここにそのヘッダーを含めました。

/**
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の2つだけで、どちらも欠落しているメンバー関数を実装しています。最後に、実際の「レイトレーシング」部分を実行する静的メソッドでいっぱいのパーサークラスがあります。関連する部分のスニペットをいくつか示します

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にキャストしましたが、すべてがうまく機能しています。ただし、2番目のレイがキャストされるまでに、シーンに保存されているすべてのオブジェクトはvfptrを認識しなくなります(つまり、仮想メソッドを除くすべてのSceneObjectメソッドにアクセスできます)。デバッガーを使用してコードをステップ実行したところ、getColor()の終了とループの継続の間のどこかで、すべてのvfptrへの情報が失われていることがわかりました。ただし、getColor()の引数を変更して、Sceneの代わりにScene&を使用すると、損失は発生しません。これは何のクレイジーなブードゥーですか?

要求に応じて、シーンのコード:

#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();
    }
}
4

1 に答える 1

5

SceneObjects問題は、のデストラクタでを削除Sceneし、ポインタのベクトルを使用してフラットコピーを実行するデフォルトのコピーコンストラクタを使用することです。つまり、Scene参照の各コピーは同じを参照しSceneObjectsます。これらSceneのいずれかが破棄されると、参照されているオブジェクトはすべて失われます。参照によってシーンを渡す場合、これは問題ではありません。その場合、コピーは作成されず、後で破棄されるためです。

于 2010-04-25T10:50:15.950 に答える