首先,我想寫一個普通的,簡單的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;
};
正如你所看到的,我已經包含了幾個虛擬函數在其他地方實現。在這種情況下,我只有兩個派生類 - 球體和三角形,它們都實現了缺少的成員函數。最後,我有一個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()方法以外的對象填充它。現在出於某種奇怪的原因,我把雷放在i = j = 0的位置,一切都很好。但是,在第二次射線投射時,存儲在我的場景中的所有對象不再識別它們的vfptr(也就是說,我仍然可以訪問除虛擬場景以外的所有SceneObject方法)!我用調試器遍歷代碼,發現所有vfptr的信息都在getColor()結束和循環的延續之間丟失。但是,如果我更改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();
}
}
對不起 - 我完全無法理解。然而,我會觀察到你的基類需要一個虛擬析構函數。 – 2010-04-25 10:06:44
這聽起來很像你在'Scene'的複製構造函數和/或析構函數中有不正確的代碼,但是沒有看到'Scene'的定義,這很難確定。 – 2010-04-25 10:10:46
可能不相關,但請確保您的方法是「const」正確的(http://www.parashift.com/c++-faq-lite/const-correctness.html)。 – kennytm 2010-04-25 10:12:56