smooth triangles (aka Phong shading)
extend Python binding to support vertex normals and smooth triangles
make bunny.py and realtime_dragon smooth, and fix other demos for new triangle constructor
add Vector::operator/=
+ − /*
+ − * C++ RayTracer
+ − * file: scene.h
+ − *
+ − * Radek Brich, 2006
+ − */
+ −
+ − #ifndef SCENE_H
+ − #define SCENE_H
+ −
+ − #include <vector>
+ − #include <typeinfo>
+ −
+ − #include "noise.h"
+ − #include "vector.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) {};
+ − };
+ −
+ − class Quaternion
+ − {
+ − public:
+ − Float a,b,c,d;
+ − Quaternion(): a(0), b(0), c(0), d(0) {};
+ − Quaternion(const Float aa, const Float ab, const Float ac, const Float ad):
+ − a(aa), b(ab), c(ac), d(ad) {};
+ − Quaternion(const Vector3& v): a(1), b(v.x), c(v.y), d(v.z) {};
+ −
+ − Vector3 toVector() { return Vector3(b/a, c/a, d/a); };
+ −
+ − Quaternion normalize()
+ − {
+ − Float f = 1.0f / sqrtf(a * a + b * b + c * c + d * d);
+ − a *= f;
+ − b *= f;
+ − c *= f;
+ − d *= f;
+ − return *this;
+ − };
+ − friend Quaternion operator*(const Quaternion &q1, const Quaternion &q2)
+ − {
+ − return Quaternion(
+ − q1.a*q2.a - q1.b*q2.b - q1.c*q2.c - q1.d*q2.d,
+ − q1.a*q2.b + q1.b*q2.a + q1.c*q2.d - q1.d*q2.c,
+ − q1.a*q2.c + q1.c*q2.a + q1.d*q2.b - q1.b*q2.d,
+ − q1.a*q2.d + q1.d*q2.a + q1.b*q2.c - q1.c*q2.b);
+ − };
+ − friend Quaternion conjugate(const Quaternion &q)
+ − {
+ − return Quaternion(q.a, -q.b, -q.c, -q.d);
+ − }
+ − };
+ −
+ − 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);
+ − };
+ −
+ − /* 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);
+ − };
+ −
+ − class Light
+ − {
+ − public:
+ − Vector3 pos;
+ − Colour colour;
+ − bool cast_shadows;
+ −
+ − Light(const Vector3 &position, const Colour &acolour):
+ − pos(position), colour(acolour), cast_shadows(true) {};
+ − void castShadows(bool cast) { cast_shadows = cast; };
+ − };
+ −
+ − class Texture
+ − {
+ − public:
+ − Colour colour;
+ − Colour evaluate(Vector3 point)
+ − {
+ − Float sum = 0.0;
+ − for (int i = 1; i < 5; i++)
+ − sum += fabsf(perlin(point.x*i, point.y*i, point.z*i))/i;
+ − Float value = sinf(point.x + sum)/2 + 0.5;
+ − return Colour(value*colour.r, value*colour.g, value*colour.b);
+ − };
+ − };
+ −
+ − class Material
+ − {
+ − public:
+ − Float ambient, diffuse, specular, shininess; // Phong constants
+ − Float reflection; // how much reflectife is the surface
+ − Float refraction; // refraction index
+ − Float transmitivity;
+ − Texture texture;
+ −
+ − Material(const Colour &acolour) {
+ − texture.colour = acolour;
+ − ambient = 0.1;
+ − diffuse = 0.5;
+ − specular = 0.1;
+ − shininess = 0.5;
+ − reflection = 0.5;
+ − }
+ − };
+ −
+ − 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;
+ −
+ − // normal at point P
+ − virtual const Vector3 normal(const Vector3 &P) const = 0;
+ −
+ − virtual BBox get_bbox() const = 0;
+ − };
+ −
+ − class ShapeList: public vector<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;
+ − const Vector3 normal(const Vector3 &P) const { return (P - center) * inv_radius; };
+ − BBox get_bbox() const;
+ − };
+ −
+ − 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; };
+ − const Vector3 normal(const Vector3 &P) const;
+ − BBox get_bbox() const { return BBox(L, H); };
+ − };
+ −
+ − class Vertex
+ − {
+ − public:
+ − Vector3 P;
+ − Vertex(const Vector3 &aP): P(aP) {};
+ − };
+ −
+ − 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; };
+ − };
+ −
+ −
+ − 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;};
+ − 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