Doxygen
new Sampler object
replacing rendering algorithm with more flexible one -- this breaks most of demos and disables threads and (over-/sub-)sampling functionality, need a rewrote
/*
* scene.h: classes for objects in scene
*
* This file is part of Pyrit Ray Tracer.
*
* Copyright 2006, 2007 Radek Brich
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef SCENE_H
#define SCENE_H
#include <vector>
#include <typeinfo>
#include "noise.h"
#include "vector.h"
#include "quaternion.h"
/*
triangle intersection alghoritm
chooses are:
TRI_PLUCKER
TRI_BARI
TRI_BARI_PRE
*/
#if !defined(TRI_PLUCKER) && !defined(TRI_BARI) && !defined(TRI_BARI_PRE)
# define TRI_BARI_PRE
#endif
using namespace std;
class Ray
{
public:
Vector3 o, dir;
Ray(const Vector3 &ao, const Vector3 &adir):
o(ao), dir(adir) {};
};
/**
* sample
*/
class Sample
{
public:
Float x,y;
};
/**
* A abstract sampler.
* It generates screen samples in coordinates between [-1..1] for height
* and [-w/h..w/h] for width. It works in phases: initSampleSet returns
* number of samples for each phase, then samples can be generated using
* nextSample method. The resulting colour of each sample should be returned
* via saveSample method. The sampler should save the results to given buffer
* and decide if other phase is needed. When the picture is complete,
* initSampleSet returns zero and picture can be read from buffer.
*/
class Sampler
{
public:
Float *buffer;
int w,h;
Sampler(Float *abuffer, int &aw, int &ah): buffer(abuffer), w(aw), h(ah) {};
void resetBuffer(Float *abuffer, int &aw, int &ah) { buffer = abuffer; w = aw; h = ah; };
virtual void init() = 0;
virtual int initSampleSet() = 0;
virtual Sample *nextSample(Sample *prev) = 0;
virtual void saveSample(Sample *samp, Colour &col) = 0;
};
/**
* default sample
*/
class DefaultSample: public Sample
{
friend class DefaultSampler;
int sx,sy;
};
/**
* Default sampler.
*/
class DefaultSampler: public Sampler
{
int phase;
public:
DefaultSampler(Float *abuffer, int &aw, int &ah): Sampler(abuffer, aw, ah), phase(-1) {};
void init() { phase = 0; };
int initSampleSet();
Sample *nextSample(Sample *prev);
void saveSample(Sample *samp, Colour &col);
};
/**
* a camera
*/
class Camera
{
public:
Vector3 eye, p, u, v;
Float f;
Camera(): eye(0,0,10), p(0,0,-1), u(-1,0,0), v(0,1,0), f(3.14/4.0) {};
Camera(const Vector3 &C, const Vector3 &ap, const Vector3 &au, const Vector3 &av):
eye(C), p(ap), u(au), v(av), f(3.14/4.0) {};
void setEye(const Vector3 &aeye) { eye = aeye; };
void setFocalLength(const Float af) { f = af; };
void rotate(const Quaternion &q);
void move(const Float fw, const Float left, const Float up);
Ray makeRay(Sample *samp);
};
/**
* axis-aligned bounding box
*/
class BBox
{
public:
Vector3 L;
Vector3 H;
BBox(): L(), H() {};
BBox(const Vector3 aL, const Vector3 aH): L(aL), H(aH) {};
Float w() { return H.x-L.x; };
Float h() { return H.y-L.y; };
Float d() { return H.z-L.z; };
bool intersect(const Ray &ray, Float &a, Float &b);
};
/**
* light object
*/
class Light
{
public:
Vector3 pos;
Colour colour;
bool cast_shadows;
Light():
pos(Vector3(0,0,0)), colour(Colour(1,1,1)), cast_shadows(true) {};
Light(const Vector3 &position, const Colour &acolour):
pos(position), colour(acolour), cast_shadows(true) {};
void castShadows(bool cast) { cast_shadows = cast; };
};
/**
* texture
*/
class Texture
{
public:
virtual Colour evaluate(Vector3 point) = 0;
};
/**
* material
*/
class Material
{
public:
Colour colour;
Float ambient, diffuse, specular, shininess; // Phong constants
Float reflectivity; // how much reflective is the surface
Float transmissivity, refract_index; // part of light which can be refracted; index of refraction
Texture *texture;
Material(const Colour &acolour): colour(acolour), texture(NULL)
{
ambient = 0.2;
diffuse = 0.8;
specular = 0.2;
shininess = 0.5;
reflectivity = 0.2;
transmissivity = 0.0;
refract_index = 1.3;
}
void setPhong(const Float amb, const Float dif, const Float spec, const Float shin)
{ ambient = amb; diffuse = dif; specular = spec; shininess = shin; };
void setReflectivity(const Float refl) { reflectivity = refl; };
void setTransmissivity(const Float trans, const Float rindex)
{ transmissivity = trans; refract_index = rindex; };
};
/**
* shape
*/
class Shape
{
public:
Material *material;
Shape() {};
virtual ~Shape() {};
// first intersection point
virtual bool intersect(const Ray &ray, Float &dist) const = 0;
// all intersections (only for CSG)
virtual bool intersect_all(const Ray &ray, Float dist, vector<Float> &allts) const = 0;
// intersection with AABB
virtual bool intersect_bbox(const BBox &bbox) const = 0;
// normal at point P
virtual const Vector3 normal(const Vector3 &P) const = 0;
virtual BBox get_bbox() const = 0;
};
/**
* list of shapes
*/
class ShapeList: public vector<Shape*>
{
};
/**
* sphere shape
*/
class Sphere: public Shape
{
Float sqr_radius;
Float inv_radius;
public:
Vector3 center;
Float radius;
Sphere(const Vector3 &acenter, const Float aradius, Material *amaterial):
sqr_radius(aradius*aradius), inv_radius(1.0f/aradius),
center(acenter), radius(aradius) { material = amaterial; }
bool intersect(const Ray &ray, Float &dist) const;
bool intersect_all(const Ray &ray, Float dist, vector<Float> &allts) const;
bool intersect_bbox(const BBox &bbox) const;
const Vector3 normal(const Vector3 &P) const { return (P - center) * inv_radius; };
BBox get_bbox() const;
};
/**
* box shape
*/
class Box: public Shape
{
Vector3 L;
Vector3 H;
public:
Box(const Vector3 &aL, const Vector3 &aH, Material *amaterial): L(aL), H(aH)
{
for (int i = 0; i < 3; i++)
if (L.cell[i] > H.cell[i])
swap(L.cell[i], H.cell[i]);
material = amaterial;
};
bool intersect(const Ray &ray, Float &dist) const;
bool intersect_all(const Ray &ray, Float dist, vector<Float> &allts) const { return false; };
bool intersect_bbox(const BBox &bbox) const;
const Vector3 normal(const Vector3 &P) const;
BBox get_bbox() const { return BBox(L, H); };
};
/**
* triangle vertex
*/
class Vertex
{
public:
Vector3 P;
Vertex(const Vector3 &aP): P(aP) {};
};
/**
* triangle vertex with normal
*/
class NormalVertex: public Vertex
{
public:
Vector3 N;
NormalVertex(const Vector3 &aP): Vertex(aP) {};
NormalVertex(const Vector3 &aP, const Vector3 &aN): Vertex(aP), N(aN) {};
const Vector3 &getNormal() { return N; };
void setNormal(const Vector3 &aN) { N = aN; };
};
/**
* triangle shape
*/
class Triangle: public Shape
{
#ifdef TRI_BARI_PRE
Float nu, nv, nd;
int k; // dominant axis
Float bnu, bnv;
Float cnu, cnv;
#endif
#ifdef TRI_BARI
int k; // dominant axis
#endif
#ifdef TRI_PLUCKER
Float pla[6], plb[6], plc[6];
#endif
Vector3 N;
bool smooth;
const Vector3 smooth_normal(const Vector3 &P) const
{
#ifdef TRI_BARI_PRE
const Vector3 &NA = static_cast<NormalVertex*>(A)->N;
const Vector3 &NB = static_cast<NormalVertex*>(B)->N;
const Vector3 &NC = static_cast<NormalVertex*>(C)->N;
static const int modulo3[5] = {0,1,2,0,1};
register const int ku = modulo3[k+1];
register const int kv = modulo3[k+2];
const Float pu = P[ku] - A->P[ku];
const Float pv = P[kv] - A->P[kv];
const Float u = pv * bnu + pu * bnv;
const Float v = pu * cnv + pv * cnu;
Vector3 n = NA + u * (NB - NA) + v * (NC - NA);
n.normalize();
return n;
#else
return N; // not implemented for other algorithms
#endif
};
public:
Vertex *A, *B, *C;
Triangle(Vertex *aA, Vertex *aB, Vertex *aC, Material *amaterial);
bool intersect(const Ray &ray, Float &dist) const;
bool intersect_all(const Ray &ray, Float dist, vector<Float> &allts) const {return false;};
bool intersect_bbox(const BBox &bbox) const;
const Vector3 normal(const Vector3 &P) const { return (smooth ? smooth_normal(P) : N); };
const Vector3 getNormal() const { return N; };
void setSmooth() { smooth = true; };//(typeid(*A) == typeid(*B) == typeid(*C) == typeid(NormalVertex)); };
void setFlat() { smooth = false; };
bool getSmooth() const { return smooth; };
BBox get_bbox() const;
};
#endif