如何删除属于另一个 object C++ 的 object
How to delete an object which is a member of another object c++
我有一个函数 ( AddChild(child) ),它的目的是将 object 作为参数并将此 object 添加为 child parent object 调用函数。
创建场景和调用函数的代码
Scene *scene = new Scene();
// Create a light.
Light *light = new PointLight(vec3(10.0f));
light->SetPosition(vec3(-5.0f, 3.0f, 2.0f));
scene->AddChild(light);
所以正如你在这里看到的,场景应该添加一盏灯作为它的 child
在AddChild(child)函数中,检查Object是否已经有一个parent,如果有,需要删除这个[=101] =](稍后在另一个 class 中有一个函数检查堆中的所有 object,如果 parent object 没有被删除,它仍然在堆并导致错误)并将其 parent 更新为调用该函数的 object。您可以在下面看到将导致此堆错误的代码:
void Raytracer::SimpleAccelerator::AddObject(const SceneObject *object)
{
if (object->IsInstanceOf(SceneObjectType_PhysicalObject))
physicalObjects.push_back((PhysicalObject *)object);
if (object->IsInstanceOf(SceneObjectType_Light))
lights.push_back((Light *)object);
foreach_c (SceneObject *, child, object->GetChildren())
AddObject(*child);
}
但我遇到的主要问题是,当我检查 child 是否有 parent,而 parent 不是 object 调用函数,然后我想删除这个 child 的 parent 并相应地更新。唯一的问题是当我尝试删除 child 的 parent Visual Studio 崩溃时,我调试了导致错误的代码及其在下面指示的行上。
bool SceneObject::AddChild(SceneObject *child)
{
if (child == NULL) {
return false;
}
else if (child->GetParent() != this) {
delete child->parent; <------------This is the line which breaks the code
child->parent = this;
children.push_back(child);
child->UpdateTransformations();
return true;
}
else {
this->children.push_back(child);
child->parent = this;
child->UpdateTransformations();
return true;
}
}
child 和 parent 都是 class 场景 Object 的成员,您可以在下面看到
Class SceneObject
{
private:
glm::mat4x4 globalTransformation;
public:
std::vector<SceneObject *> children;
SceneObject * parent;
SceneObject *GetParent() const;
const std::vector<SceneObject *> &GetChildren() const;
};
删除此成员的最佳方法是什么,以便它和它的成员变量在 Accelerator 函数期间不存在于堆中?
MCVC
SceneObject.h
#ifndef RAYTRACER_SCENES_SCENEOBJECT_H
#define RAYTRACER_SCENES_SCENEOBJECT_H
#include <Raytracer/Scenes/SceneObjectType.h>
#include <vector>
namespace Raytracer
{
namespace Scenes
{
class SceneObject
{
private:
glm::mat4x4 globalTransformation;
void UpdateTransformations();
public:
std::vector<SceneObject *> children;
SceneObject * parent;
SceneObject();
virtual ~SceneObject();
bool AddChild(SceneObject *child);
const std::vector<SceneObject *> &GetChildren() const;
const glm::vec3 GetGlobalPosition() const;
const glm::mat4x4 &GetGlobalToLocal() const;
const glm::mat4x4 &GetGlobalTransformation() const;
SceneObject *GetParent() const;
};
}
}
#endif // RAYTRACER_SCENES_SCENEOBJECT_H
SceneObject.cpp
#define RAYTRACER_USE_FOREACH
#include <iostream>
#include <Raytracer/Raytracer.h>
using namespace glm;
using namespace Raytracer::Scenes;
SceneObject::SceneObject()
{
SetGlobalTransformation(mat4x4(1.0f));
}
SceneObject::~SceneObject()
{
}
bool SceneObject::AddChild(SceneObject *child)
{
if (child == NULL) {
return false;
}
else if (child->GetParent() != this) {
child->parent = nullptr;
child->parent = this;
this->children.push_back(child);
child->UpdateTransformations();
return true;
}
else {
this->children.push_back(child);
child->parent = this;
child->UpdateTransformations();
return true;
}
}
void delete_pointed_to(SceneObject* const ptr)
{
delete ptr;
}
const std::vector<SceneObject *> &SceneObject::GetChildren() const
{
// TODO: Geben Sie eine Liste der Kindobjekte dieses Objekts zurück.
static std::vector<SceneObject *> empty = this->children;
return empty;
}
const mat4x4 &SceneObject::GetGlobalTransformation() const
{
return globalTransformation;
}
SceneObject *SceneObject::GetParent() const
{
// TODO: Geben Sie eine Zeiger auf das Elternobjekt zurück oder NULL, falls dieses Objekt kein
// Elternobjekt hat.
if (this->parent == NULL) {
return NULL;
}
else {
return this->parent;
}
}
main.cpp
#include <stdio.h>
#include <vector>
#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include <Raytracer/Raytracer.h>
using namespace glm;
using namespace Raytracer;
using namespace Raytracer::Scenes;
using namespace Raytracer::Objects;
/**
* Creates a transformation matrix for a rotation around the x axis.
*
* @param a The rotation angle in degrees
*/
mat4x4 RotationX(float a)
{
return rotate(mat4x4(1.0f), a, vec3(1.0f, 0.0f, 0.0f));
}
/**
* Creates a transformation matrix for a rotation around the y axis.
*
* @param a The rotation angle in degrees
*/
mat4x4 RotationY(float a)
{
return rotate(mat4x4(1.0f), a, vec3(0.0f, 1.0f, 0.0f));
}
/**
* Creates a transformation matrix for a rotation around the z axis.
*
* @param a The rotation angle in degrees
*/
mat4x4 RotationZ(float a)
{
return rotate(mat4x4(1.0f), a, vec3(0.0f, 0.0f, 1.0f));
}
bool CreateSphereLevels(Sphere *parent, float childRadiusRatio, int levels,
Material** materials, int firstMaterial, int materialCount)
{
// TODO: Implementieren Sie die Funktion nach Ihrer in Aufgabe 1 definierten Vorschrift.
// Der Methodenaufruf CreateSphereLevels(...) in dieser Form ist nur ein Vorschlag,
// Sie können ihn beliebig anpassen und eine andere Logik verwenden
return true;
}
/**
* Places a few spheres in the scene and adds some lights.
*
* @param scene The scene
*/
Scene *BuildScene(int depth, float aspect)
{
const int materialCount = 6;
vec3 colors[materialCount] =
{
vec3(1.0f, 0.0f, 0.0f),
vec3(1.0f, 1.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f),
vec3(0.0f, 1.0f, 1.0f),
vec3(0.0f, 0.0f, 1.0f),
vec3(1.0f, 0.0f, 1.0f)
};
Material *materials[materialCount];
for (int i = 0; i < materialCount; i++)
{
materials[i] = new Material();
if (materials[i] == NULL)
return NULL;
vec3 ambient = colors[i] * 0.01f;
materials[i]->SetAmbient(ambient);
materials[i]->SetDiffuse(colors[i]);
materials[i]->SetShininess(25.0f);
}
if (depth <= 0)
return NULL;
// Create the scene.
Scene *scene = new Scene();
if (scene == NULL)
return NULL;
// TODO: Erstellen Sie hier die Kugelwolke der Tiefe depth und fügen Sie sie in die Szene ein.
// Verwenden Sie die Materialien in materials zum Einfärben der Kugeln.
// Impelementieren Sie hierfür z.B. die Funktion CreateSphereLevels(...) (s.o.)
// Create a light.
Light *light = new PointLight(vec3(10.0f));
if (light == NULL)
{
delete scene;
return NULL;
}
light->SetPosition(vec3(-5.0f, 3.0f, 2.0f));
scene->AddChild(light);
// Create a camera.
Camera *camera = new Camera(vec3(-2.0f, 2.0f, 4.0f), vec3(0.0f, 0.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), Camera::DefaultFov, aspect);
if (camera == NULL)
{
delete scene;
return NULL;
}
scene->AddChild(camera);
scene->SetActiveCamera(camera);
return scene;
}
/**
* Renders the scene and saves the result to a BMP file.
*
* @param fileName The name of the file
* @param width The image width
* @param height The image height
*/
void Render(const char *fileName, int width, int height)
{
if (fileName == NULL || width <= 0 || height <= 0)
return;
SimpleRenderer renderer;
renderer.SetAccelerator(new SimpleAccelerator());
renderer.SetIntegrator(new PhongIntegrator());
puts("Generiere Szene...");
Scene *scene = BuildScene(3, (float)width / height);
if (scene == NULL)
return;
puts("Rendere Bild...");
Image *image = renderer.Render(*scene, width, height);
if (image != NULL)
{
puts("Speichere Ergebnis...");
image->SaveBMP(fileName, 2.2f);
delete image;
}
delete scene;
}
/**
* The main program
*/
int main()
{
Render("image.bmp", 512, 512);
return 0;
}
简单加速器
#include <limits>
#define RAYTRACER_USE_FOREACH
#include <Raytracer/Raytracer.h>
using namespace Raytracer;
using namespace Raytracer::Scenes;
bool SimpleAccelerator::HitTest(const Ray &ray, RayHit *hit) const
{
if (hit == NULL)
{
// Search for any intersection.
foreach_c (PhysicalObject *, object, physicalObjects)
{
Ray objectRay = ray.Transform((*object)->GetGlobalToLocal());
if ((*object)->HitTest(objectRay, NULL))
return true;
}
return false;
}
else
{
// Search for the closest intersection.
hit->Set(ray, 0, NULL);
foreach_c (PhysicalObject *, object, physicalObjects)
{
Ray objectRay = ray.Transform((*object)->GetGlobalToLocal());
RayHit objectHit;
if ((*object)->HitTest(objectRay, &objectHit) &&
(hit->GetObject() == NULL || objectHit.GetDistance() < hit->GetDistance()))
{
*hit = objectHit;
}
}
return (hit->GetObject() != NULL);
}
}
void Raytracer::SimpleAccelerator::SetScene(const Scenes::Scene *scene)
{
this->scene = scene;
physicalObjects.clear();
lights.clear();
if (scene == NULL)
return;
AddObject(scene);
}
void Raytracer::SimpleAccelerator::AddObject(const SceneObject *object)
{
if (object->IsInstanceOf(SceneObjectType_PhysicalObject))
physicalObjects.push_back((PhysicalObject *)object);
if (object->IsInstanceOf(SceneObjectType_Light))
lights.push_back((Light *)object);
foreach_c (SceneObject *, child, object->GetChildren())
AddObject(*child);
}
const std::vector<Light *> &SimpleAccelerator::GetLights() const
{
return lights;
}
Renderer.cpp
#include <Raytracer/Raytracer.h>
using namespace glm;
using namespace Raytracer;
using namespace Raytracer::Scenes;
Renderer::Renderer()
{
accelerator = NULL;
integrator = NULL;
}
Renderer::~Renderer()
{
delete accelerator;
delete integrator;
}
vec3 Renderer::RenderPixel(const Camera &camera, float x, float y) const
{
Ray ray;
camera.SpawnRay(x, y, ray);
return integrator->GetColor(ray, *accelerator);
}
IIntegrator *Renderer::GetIntegrator() const
{
return integrator;
}
void Renderer::SetIntegrator(IIntegrator *integrator)
{
delete this->integrator;
this->integrator = integrator;
}
Accelerator *Raytracer::Renderer::GetAccelerator() const
{
return accelerator;
}
void Raytracer::Renderer::SetAccelerator(Accelerator *accelerator)
{
delete this->accelerator;
this->accelerator = accelerator;
}
Image *Renderer::Render(const Scenes::Scene &scene, int width, int height)
{
Camera *camera = scene.GetActiveCamera();
if (camera == NULL || accelerator == NULL || integrator == NULL || width <= 0 || height <= 0)
return NULL;
Image *image = new Image(width, height);
if (image == NULL)
return NULL;
accelerator->SetScene(&scene);
RenderImage(*camera, image);
return image;
}
PhongIntegrator.cpp
Raytracer::PhongIntegrator::PhongIntegrator()
{
backgroundColor = vec3(0, 0, 0);
}
Renderer.h
#ifndef RAYTRACER_RENDERER_H
#define RAYTRACER_RENDERER_H
#include <glm.hpp>
#include <Raytracer/Image.h>
#include <Raytracer/Scenes/Camera.h>
#include <Raytracer/Scenes/Scene.h>
namespace Raytracer
{
/**
* Renders an image of a scene. The renderer object is not thread-safe.
*/
class Renderer
{
private:
Accelerator *accelerator;
IIntegrator *integrator;
protected:
/**
* Renders a single pixel.
*
* @param camera The camera
* @param x The normalized x coordinate of the pixel in the 0-1 range
* @param y The normalized y coordinate of the pixel in the 0-1 range
*
* @return The color of the pixel
*/
virtual glm::vec3 RenderPixel(const Scenes::Camera &camera, float x, float y) const;
/**
* Renders an image.
*
* @param camera The camera to use for the rendering
* @param image The image to be filled with rendered pixels
*/
virtual void RenderImage(const Scenes::Camera &camera, Image *image) const = 0;
public:
/**
* Constructs a new Renderer object.
*/
Renderer();
/**
* Destructs a Renderer object.
*/
virtual ~Renderer();
/**
* Retrieves the IIntegrator interface used for rendering.
*
* @return The IIntegrator interface used for rendering. The Renderer object owns this
* interface.
*/
IIntegrator *GetIntegrator() const;
/**
* Sets the IIntegrator interface used for rendering.
*
* @param integrator The IIntegrator interface used for rendering. The Renderer object
* takes ownership of this interface.
*/
void SetIntegrator(IIntegrator *integrator);
/**
* Retrieves the Accelerator object used for rendering.
*
* @return The Accelerator object used for rendering. The Renderer object owns the
* accelerator.
*/
Accelerator *GetAccelerator() const;
/**
* Sets the Accelerator object used for rendering.
*
* @param accelerator The Accelerator object used for rendering. The Renderer object takes
* ownership of the accelerator.
*/
void SetAccelerator(Accelerator *accelerator);
/**
* Renders an image of a scene.
*
* @param scene The scene
* @param width The image width in pixels
* @param height The image height in pixels
* @return The rendered image or NULL if the rendering failed
* @remarks You cannot use the same Renderer object to render different scenes
* simultaneously.
*/
Image *Render(const Scenes::Scene &scene, int width, int height);
};
}
#endif // RAYTRACER_RENDERER_H
SimpleAccelerator.h
#ifndef RAYTRACER_SIMPLEACCELERATOR_H
#define RAYTRACER_SIMPLEACCELERATOR_H
#include <vector>
#include <Raytracer/Accelerator.h>
// #include <Raytracer/Ray.h>
namespace Raytracer
{
class Ray;
class RayHit;
namespace Scenes
{
class Light;
class PhysicalObject;
class Scene;
class SceneObject;
}
/**
* A simple accelerator that uses brute force testing of all objects to find intersections.
*/
class SimpleAccelerator : public Accelerator
{
private:
/**
* A list of all physical objects in the scene
*/
std::vector<Scenes::PhysicalObject *> physicalObjects;
std::vector<Scenes::Light *> lights;
void AddObject(const Scenes::SceneObject *object);
public:
virtual const std::vector<Scenes::Light *> &GetLights() const;
virtual bool HitTest(const Ray &ray, RayHit *hit) const;
virtual void SetScene(const Scenes::Scene *scene);
};
}
#endif // RAYTRACER_SIMPLEACCELERATOR_H
冯Integrator.h
#ifndef RAYTRACER_PHONGINTEGRATOR_H
#define RAYTRACER_PHONGINTEGRATOR_H
#include <glm.hpp>
#include <Raytracer/IIntegrator.h>
namespace Raytracer
{
namespace Scenes
{
class Scene;
}
/**
* Calculates the visible color seen by a ray using the Phong illumination model.
*/
class PhongIntegrator : public IIntegrator
{
private:
/**
* The background color seen by rays that exit the scene
*/
glm::vec3 backgroundColor;
public:
/**
* Constructs a new PhongIntegrator object.
*/
PhongIntegrator();
glm::vec3 GetColor(Ray &ray, const Accelerator &accelerator);
};
}
#endif // RAYTRACER_PHONGINTEGRATOR_H
Light.cpp
#include <Raytracer/Raytracer.h>
using namespace Raytracer::Scenes;
bool Light::IsInstanceOf(SceneObjectType type) const
{
return (type == SceneObjectType_Light);
}
Light.h
#ifndef RAYTRACER_SCENES_LIGHT_H
#define RAYTRACER_SCENES_LIGHT_H
#include <glm.hpp>
#include <Raytracer/Intersection.h>
#include <Raytracer/Scenes/SceneObject.h>
namespace Raytracer
{
struct Sample;
namespace Scenes
{
class Scene;
/**
* A light source
*/
class Light : public SceneObject
{
public:
/**
* Computes the direct contribution of this light in the illumination of a surface
* point.
*
* @param accelerator An accelerator object that can be used to trace secondary rays
* through the scene
* @param intersection An intersection of a view ray with an object
* @return A color value representing the direct contribution
*/
virtual glm::vec3 ComputeDirectContribution(const Accelerator *accelerator,
const Intersection &intersection) = 0;
virtual bool IsInstanceOf(SceneObjectType type) const;
};
}
}
#endif // RAYTRACER_SCENES_LIGHT_H
Scene.h
#ifndef RAYTRACER_SCENES_SCENE_H
#define RAYTRACER_SCENES_SCENE_H
#include <Raytracer/Scenes/SceneObject.h>
namespace Raytracer
{
class Ray;
namespace Scenes
{
class Camera;
class Scene : public SceneObject
{
private:
/**
* The camera that is to be used for rendering the scene
*/
Camera *activeCamera;
public:
/**
* Constructs a new Scene object.
*/
Scene();
/**
* Retrieves the active camera, i.e. the camera object to be used for rendering the
* scene.
*
* @return The active camera or NULL if there is no active camera
*/
Camera *GetActiveCamera() const;
virtual bool IsInstanceOf(SceneObjectType type) const;
/**
* Sets the active camera, i.e. the camera object to be used for rendering the scene.
*
* @param camera The new active camera or NULL to set no active camera
*/
void SetActiveCamera(Camera *camera);
};
}
}
#endif // RAYTRACER_SCENES_SCENE_H
Scene.cpp
#define RAYTRACER_USE_FOREACH
#include <Raytracer/Raytracer.h>
using namespace Raytracer;
using namespace Raytracer::Scenes;
Scene::Scene()
{
activeCamera = NULL;
}
Camera *Scene::GetActiveCamera() const
{
return activeCamera;
}
bool Scene::IsInstanceOf(SceneObjectType type) const
{
return (type == SceneObjectType_Scene);
}
void Scene::SetActiveCamera(Camera *camera)
{
this->activeCamera = camera;
}
如果 parent
应该 拥有 children,我会将成员更改为
std::vector<std::unique_ptr<SceneObject>> children;
然后当 SceneObject
超出范围时,它将确保隐式 delete
每个 children 而无需您做任何进一步的努力。
因此您可以将 AddChild
方法更改为
bool SceneObject::AddChild(std::unique_ptr<SceneObject> child)
并调用它
scene->AddChild(std::make_unique<PointLight>(vec3(10.0f)));
在 AddChild
方法中,您可以传递指针,这样 this
现在拥有该指针
children.push_back(std::move(child));
您需要告诉旧父对象此对象不再是其子对象,然后该父对象必须更新其子对象列表以不再包含指向此对象的指针。
例如:
bool SceneObject::AddChild(SceneObject *child)
{
if (child == NULL) {
return false;
}
else if (child->GetParent() != this) {
child->parent->RemoveChild(child);
child->parent = this;
children.push_back(child);
child->UpdateTransformations();
return true;
}
else {
this->children.push_back(child);
child->parent = this;
child->UpdateTransformations();
return true;
}
}
和
bool SceneObject::RemoveChild(SomeObject* child)
{
auto iter = std::find(children.begin(), children.end(), child);
if (iter == children.end())
return false;
else
{
children.erase(iter);
return true;
}
}
我有一个函数 ( AddChild(child) ),它的目的是将 object 作为参数并将此 object 添加为 child parent object 调用函数。
创建场景和调用函数的代码
Scene *scene = new Scene();
// Create a light.
Light *light = new PointLight(vec3(10.0f));
light->SetPosition(vec3(-5.0f, 3.0f, 2.0f));
scene->AddChild(light);
所以正如你在这里看到的,场景应该添加一盏灯作为它的 child
在AddChild(child)函数中,检查Object是否已经有一个parent,如果有,需要删除这个[=101] =](稍后在另一个 class 中有一个函数检查堆中的所有 object,如果 parent object 没有被删除,它仍然在堆并导致错误)并将其 parent 更新为调用该函数的 object。您可以在下面看到将导致此堆错误的代码:
void Raytracer::SimpleAccelerator::AddObject(const SceneObject *object)
{
if (object->IsInstanceOf(SceneObjectType_PhysicalObject))
physicalObjects.push_back((PhysicalObject *)object);
if (object->IsInstanceOf(SceneObjectType_Light))
lights.push_back((Light *)object);
foreach_c (SceneObject *, child, object->GetChildren())
AddObject(*child);
}
但我遇到的主要问题是,当我检查 child 是否有 parent,而 parent 不是 object 调用函数,然后我想删除这个 child 的 parent 并相应地更新。唯一的问题是当我尝试删除 child 的 parent Visual Studio 崩溃时,我调试了导致错误的代码及其在下面指示的行上。
bool SceneObject::AddChild(SceneObject *child)
{
if (child == NULL) {
return false;
}
else if (child->GetParent() != this) {
delete child->parent; <------------This is the line which breaks the code
child->parent = this;
children.push_back(child);
child->UpdateTransformations();
return true;
}
else {
this->children.push_back(child);
child->parent = this;
child->UpdateTransformations();
return true;
}
}
child 和 parent 都是 class 场景 Object 的成员,您可以在下面看到
Class SceneObject
{
private:
glm::mat4x4 globalTransformation;
public:
std::vector<SceneObject *> children;
SceneObject * parent;
SceneObject *GetParent() const;
const std::vector<SceneObject *> &GetChildren() const;
};
删除此成员的最佳方法是什么,以便它和它的成员变量在 Accelerator 函数期间不存在于堆中?
MCVC
SceneObject.h
#ifndef RAYTRACER_SCENES_SCENEOBJECT_H
#define RAYTRACER_SCENES_SCENEOBJECT_H
#include <Raytracer/Scenes/SceneObjectType.h>
#include <vector>
namespace Raytracer
{
namespace Scenes
{
class SceneObject
{
private:
glm::mat4x4 globalTransformation;
void UpdateTransformations();
public:
std::vector<SceneObject *> children;
SceneObject * parent;
SceneObject();
virtual ~SceneObject();
bool AddChild(SceneObject *child);
const std::vector<SceneObject *> &GetChildren() const;
const glm::vec3 GetGlobalPosition() const;
const glm::mat4x4 &GetGlobalToLocal() const;
const glm::mat4x4 &GetGlobalTransformation() const;
SceneObject *GetParent() const;
};
}
}
#endif // RAYTRACER_SCENES_SCENEOBJECT_H
SceneObject.cpp
#define RAYTRACER_USE_FOREACH
#include <iostream>
#include <Raytracer/Raytracer.h>
using namespace glm;
using namespace Raytracer::Scenes;
SceneObject::SceneObject()
{
SetGlobalTransformation(mat4x4(1.0f));
}
SceneObject::~SceneObject()
{
}
bool SceneObject::AddChild(SceneObject *child)
{
if (child == NULL) {
return false;
}
else if (child->GetParent() != this) {
child->parent = nullptr;
child->parent = this;
this->children.push_back(child);
child->UpdateTransformations();
return true;
}
else {
this->children.push_back(child);
child->parent = this;
child->UpdateTransformations();
return true;
}
}
void delete_pointed_to(SceneObject* const ptr)
{
delete ptr;
}
const std::vector<SceneObject *> &SceneObject::GetChildren() const
{
// TODO: Geben Sie eine Liste der Kindobjekte dieses Objekts zurück.
static std::vector<SceneObject *> empty = this->children;
return empty;
}
const mat4x4 &SceneObject::GetGlobalTransformation() const
{
return globalTransformation;
}
SceneObject *SceneObject::GetParent() const
{
// TODO: Geben Sie eine Zeiger auf das Elternobjekt zurück oder NULL, falls dieses Objekt kein
// Elternobjekt hat.
if (this->parent == NULL) {
return NULL;
}
else {
return this->parent;
}
}
main.cpp
#include <stdio.h>
#include <vector>
#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include <Raytracer/Raytracer.h>
using namespace glm;
using namespace Raytracer;
using namespace Raytracer::Scenes;
using namespace Raytracer::Objects;
/**
* Creates a transformation matrix for a rotation around the x axis.
*
* @param a The rotation angle in degrees
*/
mat4x4 RotationX(float a)
{
return rotate(mat4x4(1.0f), a, vec3(1.0f, 0.0f, 0.0f));
}
/**
* Creates a transformation matrix for a rotation around the y axis.
*
* @param a The rotation angle in degrees
*/
mat4x4 RotationY(float a)
{
return rotate(mat4x4(1.0f), a, vec3(0.0f, 1.0f, 0.0f));
}
/**
* Creates a transformation matrix for a rotation around the z axis.
*
* @param a The rotation angle in degrees
*/
mat4x4 RotationZ(float a)
{
return rotate(mat4x4(1.0f), a, vec3(0.0f, 0.0f, 1.0f));
}
bool CreateSphereLevels(Sphere *parent, float childRadiusRatio, int levels,
Material** materials, int firstMaterial, int materialCount)
{
// TODO: Implementieren Sie die Funktion nach Ihrer in Aufgabe 1 definierten Vorschrift.
// Der Methodenaufruf CreateSphereLevels(...) in dieser Form ist nur ein Vorschlag,
// Sie können ihn beliebig anpassen und eine andere Logik verwenden
return true;
}
/**
* Places a few spheres in the scene and adds some lights.
*
* @param scene The scene
*/
Scene *BuildScene(int depth, float aspect)
{
const int materialCount = 6;
vec3 colors[materialCount] =
{
vec3(1.0f, 0.0f, 0.0f),
vec3(1.0f, 1.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f),
vec3(0.0f, 1.0f, 1.0f),
vec3(0.0f, 0.0f, 1.0f),
vec3(1.0f, 0.0f, 1.0f)
};
Material *materials[materialCount];
for (int i = 0; i < materialCount; i++)
{
materials[i] = new Material();
if (materials[i] == NULL)
return NULL;
vec3 ambient = colors[i] * 0.01f;
materials[i]->SetAmbient(ambient);
materials[i]->SetDiffuse(colors[i]);
materials[i]->SetShininess(25.0f);
}
if (depth <= 0)
return NULL;
// Create the scene.
Scene *scene = new Scene();
if (scene == NULL)
return NULL;
// TODO: Erstellen Sie hier die Kugelwolke der Tiefe depth und fügen Sie sie in die Szene ein.
// Verwenden Sie die Materialien in materials zum Einfärben der Kugeln.
// Impelementieren Sie hierfür z.B. die Funktion CreateSphereLevels(...) (s.o.)
// Create a light.
Light *light = new PointLight(vec3(10.0f));
if (light == NULL)
{
delete scene;
return NULL;
}
light->SetPosition(vec3(-5.0f, 3.0f, 2.0f));
scene->AddChild(light);
// Create a camera.
Camera *camera = new Camera(vec3(-2.0f, 2.0f, 4.0f), vec3(0.0f, 0.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), Camera::DefaultFov, aspect);
if (camera == NULL)
{
delete scene;
return NULL;
}
scene->AddChild(camera);
scene->SetActiveCamera(camera);
return scene;
}
/**
* Renders the scene and saves the result to a BMP file.
*
* @param fileName The name of the file
* @param width The image width
* @param height The image height
*/
void Render(const char *fileName, int width, int height)
{
if (fileName == NULL || width <= 0 || height <= 0)
return;
SimpleRenderer renderer;
renderer.SetAccelerator(new SimpleAccelerator());
renderer.SetIntegrator(new PhongIntegrator());
puts("Generiere Szene...");
Scene *scene = BuildScene(3, (float)width / height);
if (scene == NULL)
return;
puts("Rendere Bild...");
Image *image = renderer.Render(*scene, width, height);
if (image != NULL)
{
puts("Speichere Ergebnis...");
image->SaveBMP(fileName, 2.2f);
delete image;
}
delete scene;
}
/**
* The main program
*/
int main()
{
Render("image.bmp", 512, 512);
return 0;
}
简单加速器
#include <limits>
#define RAYTRACER_USE_FOREACH
#include <Raytracer/Raytracer.h>
using namespace Raytracer;
using namespace Raytracer::Scenes;
bool SimpleAccelerator::HitTest(const Ray &ray, RayHit *hit) const
{
if (hit == NULL)
{
// Search for any intersection.
foreach_c (PhysicalObject *, object, physicalObjects)
{
Ray objectRay = ray.Transform((*object)->GetGlobalToLocal());
if ((*object)->HitTest(objectRay, NULL))
return true;
}
return false;
}
else
{
// Search for the closest intersection.
hit->Set(ray, 0, NULL);
foreach_c (PhysicalObject *, object, physicalObjects)
{
Ray objectRay = ray.Transform((*object)->GetGlobalToLocal());
RayHit objectHit;
if ((*object)->HitTest(objectRay, &objectHit) &&
(hit->GetObject() == NULL || objectHit.GetDistance() < hit->GetDistance()))
{
*hit = objectHit;
}
}
return (hit->GetObject() != NULL);
}
}
void Raytracer::SimpleAccelerator::SetScene(const Scenes::Scene *scene)
{
this->scene = scene;
physicalObjects.clear();
lights.clear();
if (scene == NULL)
return;
AddObject(scene);
}
void Raytracer::SimpleAccelerator::AddObject(const SceneObject *object)
{
if (object->IsInstanceOf(SceneObjectType_PhysicalObject))
physicalObjects.push_back((PhysicalObject *)object);
if (object->IsInstanceOf(SceneObjectType_Light))
lights.push_back((Light *)object);
foreach_c (SceneObject *, child, object->GetChildren())
AddObject(*child);
}
const std::vector<Light *> &SimpleAccelerator::GetLights() const
{
return lights;
}
Renderer.cpp
#include <Raytracer/Raytracer.h>
using namespace glm;
using namespace Raytracer;
using namespace Raytracer::Scenes;
Renderer::Renderer()
{
accelerator = NULL;
integrator = NULL;
}
Renderer::~Renderer()
{
delete accelerator;
delete integrator;
}
vec3 Renderer::RenderPixel(const Camera &camera, float x, float y) const
{
Ray ray;
camera.SpawnRay(x, y, ray);
return integrator->GetColor(ray, *accelerator);
}
IIntegrator *Renderer::GetIntegrator() const
{
return integrator;
}
void Renderer::SetIntegrator(IIntegrator *integrator)
{
delete this->integrator;
this->integrator = integrator;
}
Accelerator *Raytracer::Renderer::GetAccelerator() const
{
return accelerator;
}
void Raytracer::Renderer::SetAccelerator(Accelerator *accelerator)
{
delete this->accelerator;
this->accelerator = accelerator;
}
Image *Renderer::Render(const Scenes::Scene &scene, int width, int height)
{
Camera *camera = scene.GetActiveCamera();
if (camera == NULL || accelerator == NULL || integrator == NULL || width <= 0 || height <= 0)
return NULL;
Image *image = new Image(width, height);
if (image == NULL)
return NULL;
accelerator->SetScene(&scene);
RenderImage(*camera, image);
return image;
}
PhongIntegrator.cpp
Raytracer::PhongIntegrator::PhongIntegrator()
{
backgroundColor = vec3(0, 0, 0);
}
Renderer.h
#ifndef RAYTRACER_RENDERER_H
#define RAYTRACER_RENDERER_H
#include <glm.hpp>
#include <Raytracer/Image.h>
#include <Raytracer/Scenes/Camera.h>
#include <Raytracer/Scenes/Scene.h>
namespace Raytracer
{
/**
* Renders an image of a scene. The renderer object is not thread-safe.
*/
class Renderer
{
private:
Accelerator *accelerator;
IIntegrator *integrator;
protected:
/**
* Renders a single pixel.
*
* @param camera The camera
* @param x The normalized x coordinate of the pixel in the 0-1 range
* @param y The normalized y coordinate of the pixel in the 0-1 range
*
* @return The color of the pixel
*/
virtual glm::vec3 RenderPixel(const Scenes::Camera &camera, float x, float y) const;
/**
* Renders an image.
*
* @param camera The camera to use for the rendering
* @param image The image to be filled with rendered pixels
*/
virtual void RenderImage(const Scenes::Camera &camera, Image *image) const = 0;
public:
/**
* Constructs a new Renderer object.
*/
Renderer();
/**
* Destructs a Renderer object.
*/
virtual ~Renderer();
/**
* Retrieves the IIntegrator interface used for rendering.
*
* @return The IIntegrator interface used for rendering. The Renderer object owns this
* interface.
*/
IIntegrator *GetIntegrator() const;
/**
* Sets the IIntegrator interface used for rendering.
*
* @param integrator The IIntegrator interface used for rendering. The Renderer object
* takes ownership of this interface.
*/
void SetIntegrator(IIntegrator *integrator);
/**
* Retrieves the Accelerator object used for rendering.
*
* @return The Accelerator object used for rendering. The Renderer object owns the
* accelerator.
*/
Accelerator *GetAccelerator() const;
/**
* Sets the Accelerator object used for rendering.
*
* @param accelerator The Accelerator object used for rendering. The Renderer object takes
* ownership of the accelerator.
*/
void SetAccelerator(Accelerator *accelerator);
/**
* Renders an image of a scene.
*
* @param scene The scene
* @param width The image width in pixels
* @param height The image height in pixels
* @return The rendered image or NULL if the rendering failed
* @remarks You cannot use the same Renderer object to render different scenes
* simultaneously.
*/
Image *Render(const Scenes::Scene &scene, int width, int height);
};
}
#endif // RAYTRACER_RENDERER_H
SimpleAccelerator.h
#ifndef RAYTRACER_SIMPLEACCELERATOR_H
#define RAYTRACER_SIMPLEACCELERATOR_H
#include <vector>
#include <Raytracer/Accelerator.h>
// #include <Raytracer/Ray.h>
namespace Raytracer
{
class Ray;
class RayHit;
namespace Scenes
{
class Light;
class PhysicalObject;
class Scene;
class SceneObject;
}
/**
* A simple accelerator that uses brute force testing of all objects to find intersections.
*/
class SimpleAccelerator : public Accelerator
{
private:
/**
* A list of all physical objects in the scene
*/
std::vector<Scenes::PhysicalObject *> physicalObjects;
std::vector<Scenes::Light *> lights;
void AddObject(const Scenes::SceneObject *object);
public:
virtual const std::vector<Scenes::Light *> &GetLights() const;
virtual bool HitTest(const Ray &ray, RayHit *hit) const;
virtual void SetScene(const Scenes::Scene *scene);
};
}
#endif // RAYTRACER_SIMPLEACCELERATOR_H
冯Integrator.h
#ifndef RAYTRACER_PHONGINTEGRATOR_H
#define RAYTRACER_PHONGINTEGRATOR_H
#include <glm.hpp>
#include <Raytracer/IIntegrator.h>
namespace Raytracer
{
namespace Scenes
{
class Scene;
}
/**
* Calculates the visible color seen by a ray using the Phong illumination model.
*/
class PhongIntegrator : public IIntegrator
{
private:
/**
* The background color seen by rays that exit the scene
*/
glm::vec3 backgroundColor;
public:
/**
* Constructs a new PhongIntegrator object.
*/
PhongIntegrator();
glm::vec3 GetColor(Ray &ray, const Accelerator &accelerator);
};
}
#endif // RAYTRACER_PHONGINTEGRATOR_H
Light.cpp
#include <Raytracer/Raytracer.h>
using namespace Raytracer::Scenes;
bool Light::IsInstanceOf(SceneObjectType type) const
{
return (type == SceneObjectType_Light);
}
Light.h
#ifndef RAYTRACER_SCENES_LIGHT_H
#define RAYTRACER_SCENES_LIGHT_H
#include <glm.hpp>
#include <Raytracer/Intersection.h>
#include <Raytracer/Scenes/SceneObject.h>
namespace Raytracer
{
struct Sample;
namespace Scenes
{
class Scene;
/**
* A light source
*/
class Light : public SceneObject
{
public:
/**
* Computes the direct contribution of this light in the illumination of a surface
* point.
*
* @param accelerator An accelerator object that can be used to trace secondary rays
* through the scene
* @param intersection An intersection of a view ray with an object
* @return A color value representing the direct contribution
*/
virtual glm::vec3 ComputeDirectContribution(const Accelerator *accelerator,
const Intersection &intersection) = 0;
virtual bool IsInstanceOf(SceneObjectType type) const;
};
}
}
#endif // RAYTRACER_SCENES_LIGHT_H
Scene.h
#ifndef RAYTRACER_SCENES_SCENE_H
#define RAYTRACER_SCENES_SCENE_H
#include <Raytracer/Scenes/SceneObject.h>
namespace Raytracer
{
class Ray;
namespace Scenes
{
class Camera;
class Scene : public SceneObject
{
private:
/**
* The camera that is to be used for rendering the scene
*/
Camera *activeCamera;
public:
/**
* Constructs a new Scene object.
*/
Scene();
/**
* Retrieves the active camera, i.e. the camera object to be used for rendering the
* scene.
*
* @return The active camera or NULL if there is no active camera
*/
Camera *GetActiveCamera() const;
virtual bool IsInstanceOf(SceneObjectType type) const;
/**
* Sets the active camera, i.e. the camera object to be used for rendering the scene.
*
* @param camera The new active camera or NULL to set no active camera
*/
void SetActiveCamera(Camera *camera);
};
}
}
#endif // RAYTRACER_SCENES_SCENE_H
Scene.cpp
#define RAYTRACER_USE_FOREACH
#include <Raytracer/Raytracer.h>
using namespace Raytracer;
using namespace Raytracer::Scenes;
Scene::Scene()
{
activeCamera = NULL;
}
Camera *Scene::GetActiveCamera() const
{
return activeCamera;
}
bool Scene::IsInstanceOf(SceneObjectType type) const
{
return (type == SceneObjectType_Scene);
}
void Scene::SetActiveCamera(Camera *camera)
{
this->activeCamera = camera;
}
如果 parent
应该 拥有 children,我会将成员更改为
std::vector<std::unique_ptr<SceneObject>> children;
然后当 SceneObject
超出范围时,它将确保隐式 delete
每个 children 而无需您做任何进一步的努力。
因此您可以将 AddChild
方法更改为
bool SceneObject::AddChild(std::unique_ptr<SceneObject> child)
并调用它
scene->AddChild(std::make_unique<PointLight>(vec3(10.0f)));
在 AddChild
方法中,您可以传递指针,这样 this
现在拥有该指针
children.push_back(std::move(child));
您需要告诉旧父对象此对象不再是其子对象,然后该父对象必须更新其子对象列表以不再包含指向此对象的指针。
例如:
bool SceneObject::AddChild(SceneObject *child)
{
if (child == NULL) {
return false;
}
else if (child->GetParent() != this) {
child->parent->RemoveChild(child);
child->parent = this;
children.push_back(child);
child->UpdateTransformations();
return true;
}
else {
this->children.push_back(child);
child->parent = this;
child->UpdateTransformations();
return true;
}
}
和
bool SceneObject::RemoveChild(SomeObject* child)
{
auto iter = std::find(children.begin(), children.end(), child);
if (iter == children.end())
return false;
else
{
children.erase(iter);
return true;
}
}