diff --git a/CMakeLists.txt b/CMakeLists.txt index 3606fc6..c1ecc17 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ link_directories(/usr/lib/) set(CMAKE_BUILD_TYPE Debug) set(gui text.cpp rectangle.cpp) set(utils util.cpp) -set(math quaternion.cpp vector.cpp) +set(math quaternion.cpp vector.cpp ray.cpp) set(render waterPlane.cpp particleEmitter.cpp camera.cpp light.cpp material.cpp mesh.cpp model.cpp node.cpp quad.cpp box.cpp root.cpp shader.cpp texture.cpp) add_library(vb01 SHARED main.cpp ${render} ${math} ${utils} ${gui}) diff --git a/mesh.h b/mesh.h index a76b61a..ed2bae8 100755 --- a/mesh.h +++ b/mesh.h @@ -16,6 +16,7 @@ namespace vb01{ Vector3 pos,norm; Vector2 texCoords; }; + Mesh(Vertex*,unsigned int*,int); ~Mesh(); virtual void update(); @@ -28,6 +29,8 @@ namespace vb01{ inline std::vector& getMeshes(){return meshes;} inline bool isCastShadow(){return castShadow;} inline int getNumVerts(){return 3*numTris;} + inline Vertex* getVerts(){return vertices;} + inline unsigned int* getIndices(){return indices;} private: Material *material=nullptr; Node *node=nullptr; diff --git a/node.cpp b/node.cpp index d0b519a..5245d02 100755 --- a/node.cpp +++ b/node.cpp @@ -120,4 +120,59 @@ namespace vb01{ descendants.push_back(node->getChild(i)); } } + + Node::Transform Node::getWorldTransform(){ + Transform t; + Vector3 scale=Vector3::VEC_IJK; + Quaternion orient=Quaternion::QUAT_W; + Vector3 origin=Vector3::VEC_ZERO,axis[]={Vector3::VEC_I,Vector3::VEC_J,Vector3::VEC_K}; + vector ancestors; + ancestors.push_back(this); + Node *parent=this->getParent(); + while(parent){ + ancestors.push_back(parent); + parent=parent->getParent(); + } + while(!ancestors.empty()){ + int id=ancestors.size()-1; + Quaternion o=ancestors[id]->getOrientation(); + Vector3 p=ancestors[id]->getPosition(),s=ancestors[id]->getScale(); + origin=origin+axis[0]*p.x*s.x+axis[1]*p.y*s.y+axis[2]*p.z*s.z; + orient=o*orient; + scale=s; + for(int i=0;i<3;i++) + axis[i]=orient*axis[i]; + ancestors.pop_back(); + } + + t.position=origin,t.orientation=orient,t.scale=scale; + return t; + } + + Vector3 Node::getLocalAxis(int i){ + Transform t; + Vector3 pos=Vector3::VEC_ZERO,scale=Vector3::VEC_IJK; + Quaternion orient=Quaternion::QUAT_W; + Vector3 origin=Vector3::VEC_ZERO,axis[]={Vector3::VEC_I,Vector3::VEC_J,Vector3::VEC_K}; + vector ancestors; + ancestors.push_back(this); + Node *parent=this->getParent(); + while(parent){ + ancestors.push_back(parent); + parent=parent->getParent(); + } + while(!ancestors.empty()){ + int id=ancestors.size()-1; + Quaternion o=ancestors[id]->getOrientation(); + Vector3 p=ancestors[id]->getPosition(),s=ancestors[id]->getScale(); + origin=origin+axis[0]*p.x*s.x+axis[1]*p.y*s.y+axis[2]*p.z*s.z; + orient=o*orient; + scale=s; + for(int i=0;i<3;i++) + axis[i]=orient*axis[i]; + ancestors.pop_back(); + } + + return axis[i]; + } } diff --git a/node.h b/node.h index 36ca4f0..289e281 100755 --- a/node.h +++ b/node.h @@ -14,6 +14,11 @@ namespace vb01{ class Node{ public: + struct Transform{ + Vector3 position,scale; + Quaternion orientation; + }; + Node(Vector3=Vector3::VEC_ZERO,Quaternion=Quaternion::QUAT_W,Vector3=Vector3::VEC_IJK); ~Node(); void attachMesh(Mesh*); @@ -23,6 +28,12 @@ namespace vb01{ void dettachChild(Node*); void addLight(Light*); void addText(Text*); + Transform getWorldTransform(); + Vector3 getLocalAxis(int); + inline Text* getText(int i){return texts[i];} + inline Vector3 getWorldPosition(){return getWorldTransform().position;} + inline Quaternion getWorldOrientation(){return getWorldTransform().orientation;} + inline Vector3 getWorldScale(){return getWorldTransform().scale;} inline std::vector& getMeshes(){return meshes;} inline Node* getParent(){return parent;} inline void setParent(Node *par){this->parent=par;} diff --git a/quaternion.h b/quaternion.h index 185f388..4e441f6 100755 --- a/quaternion.h +++ b/quaternion.h @@ -30,7 +30,7 @@ namespace vb01{ } inline vb01::Vector3 operator* (vb01::Vector3 v){ Quaternion vQuat=(*this)*Quaternion(0,v.x,v.y,v.z)*recip(); - return Vector3(vQuat.x,vQuat.y,vQuat.z).norm(); + return Vector3(vQuat.x,vQuat.y,vQuat.z); } inline vb01::Quaternion fromAngle(float angle, Vector3 axis){ return Quaternion(cos(angle/2),axis.x*sin(angle/2),axis.y*sin(angle/2),axis.z*sin(angle/2)); diff --git a/ray.cpp b/ray.cpp new file mode 100644 index 0000000..6d2d7f0 --- /dev/null +++ b/ray.cpp @@ -0,0 +1,63 @@ +#include +#include"ray.h" +#include"mesh.h" +#include"node.h" + +using namespace std; + +namespace vb01{ + void retrieveCollisions(Vector3 rayPos, Vector3 rayDir,Node *node,std::vector &results, const float rayLength){ + Vector3 pos=node->getWorldPosition(); + Quaternion rot=node->getWorldOrientation(); + for(Mesh *m : node->getMeshes()){ + const int numVerts=m->getNumVerts(); + Mesh::Vertex *vertices=m->getVerts(); + u32 *indices=m->getIndices(); + + for(int i=0;iPI/2){ + a1=PI-a1; + perpVec=-perpVec; + } + float perpLine=hypVec.getLength()*cos(a1); + float a2=perpVec.norm().getAngleBetween(rayDir.norm()); + if(a2<=PI/2){ + float distance=perpLine/cos(a2); + if((distance<=rayLength&&rayLength!=.0)||rayLength==.0){ + Vector3 contactPoint=rayPos+rayDir.norm()*distance; + float angleA=(pointB-pointA).norm().getAngleBetween((pointC-pointA).norm()); + float angleB=(pointA-pointB).norm().getAngleBetween((pointC-pointB).norm()); + float angleC=(pointB-pointC).norm().getAngleBetween((pointA-pointC).norm()); + Vector3 bisecAVec=((pointB-pointA)+(pointC-pointA)); + Vector3 bisecBVec=((pointA-pointB)+(pointC-pointB)); + Vector3 bisecCVec=((pointB-pointC)+(pointA-pointC)); + bool withinBisecA=(contactPoint-pointA).norm().getAngleBetween(bisecAVec.norm())<=angleA/2; + bool withinBisecB=(contactPoint-pointB).norm().getAngleBetween(bisecBVec.norm())<=angleB/2; + //bool withinBisecC=(contactPoint-pointC).norm().getAngleBetween(bisecCVec.norm())<=angleC/2; + if(withinBisecA&&withinBisecB){ + CollisionResult result; + result.pos=contactPoint; + result.distance=distance; + result.mesh=m; + results.push_back(result); + } + } + } + } + } + for(Node *c : node->getChildren()) + retrieveCollisions(rayPos,rayDir,c,results,rayLength); + } + + void sortResults(std::vector &results){ + for(int i=0;iresults[i2].distance) + swap(results[i],results[i2]); + } + } +} diff --git a/ray.h b/ray.h new file mode 100644 index 0000000..172b01a --- /dev/null +++ b/ray.h @@ -0,0 +1,17 @@ +#include"vector.h" +#include"util.h" +#include + +namespace vb01{ + class Node; + class Mesh; + + struct CollisionResult{ + Vector3 pos; + float distance; + Mesh *mesh=nullptr; + }; + + void retrieveCollisions(Vector3,Vector3,Node*,std::vector&,const float=.0); + void sortResults(std::vector&); +} diff --git a/vector.h b/vector.h index b5691b6..ff07253 100755 --- a/vector.h +++ b/vector.h @@ -31,6 +31,7 @@ namespace vb01{ this->z=z; } bool operator==(const Vector3 &v){return x==v.x&&y==v.y&&z==v.z;} + Vector3 operator-(){return Vector3(-x,-y,-z);} Vector3 operator-(const Vector3 &v){return Vector3(x-v.x,y-v.y,z-v.z);} Vector3 operator+(const Vector3 &v){return Vector3(x+v.x,y+v.y,z+v.z);} templateVector3 operator+(T s){return Vector3(x+s,y+s,z+s);}