//------------------------------------------------------------------------------- /// /// \file scene.h /// \author Cem Yuksel (www.cemyuksel.com) /// \version 7.0 /// \date August 21, 2019 /// /// \brief Example source for CS 6620 - University of Utah. /// //------------------------------------------------------------------------------- #ifndef _SCENE_H_INCLUDED_ #define _SCENE_H_INCLUDED_ //------------------------------------------------------------------------------- #define TEXTURE_SAMPLE_COUNT 32 //------------------------------------------------------------------------------- #include #define _USE_MATH_DEFINES #include #include #include #include "lodepng.h" #include "cyVector.h" #include "cyMatrix.h" #include "cyColor.h" using namespace cy; //------------------------------------------------------------------------------- #define BIGFLOAT 1.0e30f //------------------------------------------------------------------------------- class Ray { public: Vec3f p, dir; Ray() {} Ray( Vec3f const &_p, Vec3f const &_dir ) : p(_p), dir(_dir) {} Ray( Ray const &r ) : p(r.p), dir(r.dir) {} void Normalize() { dir.Normalize(); } }; //------------------------------------------------------------------------------- class Box { public: Vec3f pmin, pmax; // Constructors Box() { Init(); } Box(Vec3f const &_pmin, Vec3f const &_pmax) : pmin(_pmin), pmax(_pmax) {} Box(float xmin, float ymin, float zmin, float xmax, float ymax, float zmax ) : pmin(xmin,ymin,zmin), pmax(xmax,ymax,zmax) {} Box(float const *dim) : pmin(dim[0],dim[1],dim[2]), pmax(dim[3],dim[4],dim[5]) {} // Initializes the box, such that there exists no point inside the box (i.e. it is empty). void Init() { pmin.Set(BIGFLOAT,BIGFLOAT,BIGFLOAT); pmax.Set(-BIGFLOAT,-BIGFLOAT,-BIGFLOAT); } // Returns true if the box is empty; otherwise, returns false. bool IsEmpty() const { return pmin.x>pmax.x || pmin.y>pmax.y || pmin.z>pmax.z; } // Returns one of the 8 corner point of the box in the following order: // 0:(x_min,y_min,z_min), 1:(x_max,y_min,z_min) // 2:(x_min,y_max,z_min), 3:(x_max,y_max,z_min) // 4:(x_min,y_min,z_max), 5:(x_max,y_min,z_max) // 6:(x_min,y_max,z_max), 7:(x_max,y_max,z_max) Vec3f Corner( int i ) const // 8 corners of the box { Vec3f p; p.x = (i & 1) ? pmax.x : pmin.x; p.y = (i & 2) ? pmax.y : pmin.y; p.z = (i & 4) ? pmax.z : pmin.z; return p; } // Enlarges the box such that it includes the given point p. void operator += (Vec3f const &p) { for ( int i=0; i<3; i++ ) { if ( pmin[i] > p[i] ) pmin[i] = p[i]; if ( pmax[i] < p[i] ) pmax[i] = p[i]; } } // Enlarges the box such that it includes the given box b. void operator += (const Box &b) { for ( int i=0; i<3; i++ ) { if ( pmin[i] > b.pmin[i] ) pmin[i] = b.pmin[i]; if ( pmax[i] < b.pmax[i] ) pmax[i] = b.pmax[i]; } } // Returns true if the point is inside the box; otherwise, returns false. bool IsInside(Vec3f const &p) const { for ( int i=0; i<3; i++ ) if ( pmin[i] > p[i] || pmax[i] < p[i] ) return false; return true; } // Returns true if the ray intersects with the box for any parameter that is smaller than t_max; otherwise, returns false. bool IntersectRay(Ray const &r, float t_max) const; }; //------------------------------------------------------------------------------- class Node; #define HIT_NONE 0 #define HIT_FRONT 1 #define HIT_BACK 2 #define HIT_FRONT_AND_BACK (HIT_FRONT|HIT_BACK) struct HitInfo { float z; // the distance from the ray center to the hit point Vec3f p; // position of the hit point Vec3f N; // surface normal at the hit point Vec3f uvw; // texture coordinate at the hit point Vec3f duvw[2];// derivatives of the texture coordinate Node const *node; // the object node that was hit bool front; // true if the ray hits the front side, false if the ray hits the back side int mtlID; // sub-material index HitInfo() { Init(); } void Init() { z=BIGFLOAT; node=nullptr; front=true; uvw.Set(0.5f,0.5f,0.5f); duvw[0].Zero(); duvw[1].Zero(); mtlID=0; } }; //------------------------------------------------------------------------------- class ItemBase { private: char *name; // The name of the item public: ItemBase() : name(nullptr) {} virtual ~ItemBase() { if ( name ) delete [] name; } char const* GetName() const { return name ? name : ""; } void SetName(char const *newName) { if ( name ) delete [] name; if ( newName ) { int n = strlen(newName); name = new char[n+1]; for ( int i=0; i class ItemList : public std::vector { public: virtual ~ItemList() { DeleteAll(); } void DeleteAll() { int n=(int)this->size(); for ( int i=0; iat(i) ) delete this->at(i); } }; template class ItemFileList { public: void Clear() { list.DeleteAll(); } void Append( T* item, char const *name ) { list.push_back( new FileInfo(item,name) ); } T* Find( char const *name ) const { int n=list.size(); for ( int i=0; iGetName())==0 ) return list[i]->GetObj(); return nullptr; } private: class FileInfo : public ItemBase { private: T *item; public: FileInfo() : item(nullptr) {} FileInfo(T *_item, char const *name) : item(_item) { SetName(name); } ~FileInfo() { Delete(); } void Delete() { if (item) delete item; item=nullptr; } void SetObj(T *_item) { Delete(); item=_item; } T* GetObj() { return item; } }; ItemList list; }; //------------------------------------------------------------------------------- class Transformation { private: Matrix3f tm; // Transformation matrix to the local space Vec3f pos; // Translation part of the transformation matrix mutable Matrix3f itm; // Inverse of the transformation matrix (cached) public: Transformation() : pos(0,0,0) { tm.SetIdentity(); itm.SetIdentity(); } Matrix3f const& GetTransform () const { return tm; } Vec3f const& GetPosition () const { return pos; } Matrix3f const& GetInverseTransform() const { return itm; } Vec3f TransformTo ( Vec3f const &p ) const { return itm * (p - pos); } // Transform to the local coordinate system Vec3f TransformFrom( Vec3f const &p ) const { return tm*p + pos; } // Transform from the local coordinate system // Transforms a vector to the local coordinate system (same as multiplication with the inverse transpose of the transformation) Vec3f VectorTransformTo( Vec3f const &dir ) const { return TransposeMult(tm,dir); } // Transforms a vector from the local coordinate system (same as multiplication with the inverse transpose of the transformation) Vec3f VectorTransformFrom( Vec3f const &dir ) const { return TransposeMult(itm,dir); } void Translate( Vec3f const &p ) { pos+=p; } void Rotate ( Vec3f const &axis, float degrees ) { Matrix3f m; m.SetRotation(axis,degrees*(float)M_PI/180.0f); Transform(m); } void Scale ( float sx, float sy, float sz ) { Matrix3f m; m.Zero(); m[0]=sx; m[4]=sy; m[8]=sz; Transform(m); } void Transform( Matrix3f const &m ) { tm=m*tm; pos=m*pos; tm.GetInverse(itm); } void InitTransform() { pos.Zero(); tm.SetIdentity(); itm.SetIdentity(); } private: // Multiplies the given vector with the transpose of the given matrix static Vec3f TransposeMult( Matrix3f const &m, Vec3f const &dir ) { Vec3f d; d.x = m.GetColumn(0) % dir; d.y = m.GetColumn(1) % dir; d.z = m.GetColumn(2) % dir; return d; } }; //------------------------------------------------------------------------------- class Material; // Base class for all object types class Object { public: virtual bool IntersectRay( Ray const &ray, HitInfo &hInfo, int hitSide=HIT_FRONT ) const=0; virtual Box GetBoundBox() const=0; virtual void ViewportDisplay(const Material *mtl) const {} // used for OpenGL display }; typedef ItemFileList