GitHub地址:sebrussell/Ray-TriangleIntersection https://github.com/sebrussell/Ray-TriangleIntersection点击打开链接
Math.h
#ifndef MATH_H #define MATH_H #include <math.h> #include <vector> #include <iostream> #include <memory> struct Vector3 { Vector3() {}; Vector3(float _x, float _y, float _z) { x = _x, y = _y, z = _z; } float x, y, z; }; struct Ray { Ray() {}; Ray(float startingX, float startingY, float startingZ, float directionX, float directionY, float directionZ) { startingPoint.x = startingX; startingPoint.y = startingY; startingPoint.z = startingZ; direction.x = directionX; direction.y = directionY; direction.z = directionZ; } Vector3 startingPoint, direction; }; struct Plane { Plane(float ax, float ay, float az, float bx, float by, float bz, float cx, float cy, float cz) { a = Vector3(ax, ay, az); b = Vector3(bx, by, bz); c = Vector3(cx, cy, cz); } Vector3 a, b, c; Vector3 normal; float k; }; class Math { public: static float GetMagnitude(Vector3 _vector); static float GetDotProduct(Vector3 _vector1, Vector3 _vector2); static Vector3 GetPlaneNormal(Plane _plane); static float GetShortestAngle(Vector3 _vector1, Vector3 _vector2); static Vector3 GetCrossProduct(Vector3 _vector1, Vector3 _vector2); static float GetTripleProduct(Vector3 _vector1, Vector3 _vector2, Vector3 _vector3); static float GetAntiClockwiseAngle(Vector3 _vector1, Vector3 _vector2, Vector3 _viewVector); static float GetQuickSqrt(float _number); static float GetQuickMagnitude(Vector3 _vector); static Vector3 CheckForIntersection(Ray _Ray1, Ray _Ray2); static void WriteVector(Vector3 _vector); static Vector3 AddVectors(Vector3 _vector1, Vector3 _vector2); static Vector3 SubtractVectors(Vector3 _vector1, Vector3 _vector2); static Vector3 MultiplyVectorWithFloat(Vector3 _vector1, float _float); static bool CheckForPlaneIntersection(Plane _plane, Ray _ray, std::shared_ptr<Vector3> _intersectionPoint); static Plane SetupPlane(Plane _plane); }; #endif
Math.cpp
#include "Math.h" #include <iostream> float Math::GetQuickMagnitude(Vector3 _vector) { return GetQuickSqrt(pow(_vector.x, 2) + pow(_vector.y, 2) + pow(_vector.z, 2)); } float Math::GetMagnitude(Vector3 _vector) { return pow(pow(_vector.x, 2) + pow(_vector.y, 2) + pow(_vector.z, 2), 0.5); } float Math::GetDotProduct(Vector3 _vector1, Vector3 _vector2) { return (_vector1.x * _vector2.x) + (_vector1.y * _vector2.y) + (_vector1.z * _vector2.z); } float Math::GetShortestAngle(Vector3 _vector1, Vector3 _vector2) { return acos((GetDotProduct(_vector1, _vector2)) / (GetMagnitude(_vector1) * GetMagnitude(_vector2))) * 180 / 3.1459; } Vector3 Math::GetCrossProduct(Vector3 _vector1, Vector3 _vector2) { Vector3 result(0, 0, 0); result.x = (_vector1.y * _vector2.z) - (_vector1.z * _vector2.y); result.y = (_vector1.z * _vector2.x) - (_vector1.x * _vector2.z); result.z = (_vector1.x * _vector2.y) - (_vector1.y * _vector2.x); return result; } float Math::GetTripleProduct(Vector3 _vector1, Vector3 _vector2, Vector3 _vector3) { float result; Vector3 cross = GetCrossProduct(_vector1, _vector2); result = GetDotProduct(_vector3, cross); return result; } float Math::GetAntiClockwiseAngle(Vector3 _vector1, Vector3 _vector2, Vector3 _viewVector) { float result = GetShortestAngle(_vector1, _vector2); float tripleProduct = GetTripleProduct(_vector1, _vector2, _viewVector); if(tripleProduct < 0) { result = 360 - result; } return result; } float Math::GetQuickSqrt(float _number) { float y = _number; long i = *(long *)&y; i = 0x1fbd1df5 + (i >> 1); return *(float *)&i; } Vector3 Math::CheckForIntersection(Ray _Ray1, Ray _Ray2) { Ray tempRay1, tempRay2, totalRay; Vector3 interestionPoint; float sValue; float tValue; //finds the multiplier float xMultiplier = _Ray1.direction.y; float yMultiplier = _Ray1.direction.x; //multiplies out the first 2 equations - similinatneous equations tempRay1.startingPoint.x = _Ray1.startingPoint.x * xMultiplier; tempRay1.direction.x = _Ray1.direction.x * xMultiplier; tempRay1.startingPoint.y = _Ray1.startingPoint.y * yMultiplier; tempRay1.direction.y = _Ray1.direction.y * yMultiplier; tempRay2.startingPoint.x = _Ray2.startingPoint.x * xMultiplier; tempRay2.direction.x = _Ray2.direction.x * xMultiplier; tempRay2.startingPoint.y = _Ray2.startingPoint.y * yMultiplier; tempRay2.direction.y = _Ray2.direction.y * yMultiplier; //finds out the value of the integerer on the right hand side float x = tempRay2.startingPoint.x - tempRay2.startingPoint.y; //works out the s value sValue = (tempRay1.startingPoint.x - tempRay1.startingPoint.y - x) / (tempRay2.direction.x - tempRay2.direction.y); //from the s value it can calculate the t value tValue = ((tempRay2.startingPoint.y + (tempRay2.direction.y * sValue)) - tempRay1.startingPoint.y) / tempRay1.direction.y; //checks with the 3rd equation to see if the intersect if((_Ray1.startingPoint.z + (_Ray1.direction.z * tValue)) == (_Ray2.startingPoint.z + (_Ray2.direction.z * sValue))) { interestionPoint.x = _Ray1.startingPoint.x + (_Ray1.direction.x * tValue); interestionPoint.y = _Ray1.startingPoint.y + (_Ray1.direction.y * tValue); interestionPoint.z = _Ray1.startingPoint.z + (_Ray1.direction.z * tValue); } //if they dont intersect else { //return 0, 0, 0 interestionPoint = Vector3(0, 0, 0); } return interestionPoint; } void Math::WriteVector(Vector3 _vector) { std::cout << "X Component: " << _vector.x << std::endl; std::cout << "Y Component: " << _vector.y << std::endl; std::cout << "Z Component: " << _vector.z << std::endl; } Vector3 Math::GetPlaneNormal(Plane _plane) { Vector3 a = SubtractVectors(_plane.b, _plane.a); Vector3 b = SubtractVectors(_plane.c, _plane.a); Vector3 topVector = GetCrossProduct(a, b); float bottomVector = GetMagnitude(topVector); topVector.x = topVector.x / bottomVector; topVector.y = topVector.y / bottomVector; topVector.z = topVector.z / bottomVector; return topVector; } Vector3 Math::AddVectors(Vector3 _vector1, Vector3 _vector2) { Vector3 temp; temp.x = _vector1.x + _vector2.x; temp.y = _vector1.y + _vector2.y; temp.z = _vector1.z + _vector2.z; return temp; } Vector3 Math::SubtractVectors(Vector3 _vector1, Vector3 _vector2) { Vector3 temp; temp.x = _vector1.x - _vector2.x; temp.y = _vector1.y - _vector2.y; temp.z = _vector1.z - _vector2.z; return temp; } Vector3 Math::MultiplyVectorWithFloat(Vector3 _vector1, float _float) { Vector3 temp; temp.x = _vector1.x * _float; temp.y = _vector1.y * _float; temp.z = _vector1.z * _float; return temp; } bool Math::CheckForPlaneIntersection(Plane _plane, Ray _ray, std::shared_ptr<Vector3> _intersectionPoint) { float top = _plane.k - GetDotProduct(_plane.normal, _ray.startingPoint); float bottom = GetDotProduct(_plane.normal, _ray.direction); float t = top / bottom; if(isinf(t)) { return false; } else { Vector3 temp = AddVectors(_ray.startingPoint, MultiplyVectorWithFloat(_ray.direction, t)); _intersectionPoint->x = temp.x; _intersectionPoint->y = temp.y; _intersectionPoint->z = temp.z; return true; } } Plane Math::SetupPlane(Plane _plane) { _plane.normal = GetPlaneNormal(_plane); _plane.k = GetDotProduct(_plane.normal, _plane.a); return _plane; }
// OBJ_Loader.h - A Single Header OBJ Model Loader #pragma once // Vector - STD Vector/Array Library #include <vector> #include <math.h> // String - STD String Library #include <string> // fStream - STD File I/O Library #include <fstream> // Print progress to console while loading (large models) #define OBJL_CONSOLE_OUTPUT // Namespace: OBJL // // Description: The namespace that holds eveyrthing that // is needed and used for the OBJ Model Loader namespace objl { // Structure: Vector2 // // Description: A 2D Vector that Holds Positional Data struct Vector2 { // Default Constructor Vector2() { X = 0.0f; Y = 0.0f; } // Variable Set Constructor Vector2(float X_, float Y_) { X = X_; Y = Y_; } // Bool Equals Operator Overload bool operator==(const Vector2& other) const { return (this->X == other.X && this->Y == other.Y); } // Bool Not Equals Operator Overload bool operator!=(const Vector2& other) const { return !(this->X == other.X && this->Y == other.Y); } // Addition Operator Overload Vector2 operator+(const Vector2& right) const { return Vector2(this->X + right.X, this->Y + right.Y); } // Subtraction Operator Overload Vector2 operator-(const Vector2& right) const { return Vector2(this->X - right.X, this->Y - right.Y); } // Float Multiplication Operator Overload Vector2 operator*(const float& other) const { return Vector2(this->X *other, this->Y * other); } // Positional Variables float X; float Y; }; // Structure: Vector3 // // Description: A 3D Vector that Holds Positional Data struct Vector3 { // Default Constructor Vector3() { X = 0.0f; Y = 0.0f; Z = 0.0f; } // Variable Set Constructor Vector3(float X_, float Y_, float Z_) { X = X_; Y = Y_; Z = Z_; } // Bool Equals Operator Overload bool operator==(const Vector3& other) const { return (this->X == other.X && this->Y == other.Y && this->Z == other.Z); } // Bool Not Equals Operator Overload bool operator!=(const Vector3& other) const { return !(this->X == other.X && this->Y == other.Y && this->Z == other.Z); } // Addition Operator Overload Vector3 operator+(const Vector3& right) const { return Vector3(this->X + right.X, this->Y + right.Y, this->Z + right.Z); } // Subtraction Operator Overload Vector3 operator-(const Vector3& right) const { return Vector3(this->X - right.X, this->Y - right.Y, this->Z - right.Z); } // Float Multiplication Operator Overload Vector3 operator*(const float& other) const { return Vector3(this->X *other, this->Y * other, this->Z - other); } // Positional Variables float X; float Y; float Z; }; // Structure: Vertex // // Description: Model Vertex object that holds // a Position, Normal, and Texture Coordinate struct Vertex { // Position Vector Vector3 Position; // Normal Vector Vector3 Normal; // Texture Coordinate Vector Vector2 TextureCoordinate; }; struct Material { Material() { name; Ns = 0.0f; Ni = 0.0f; d = 0.0f; illum = 0; } // Material Name std::string name; // Ambient Color Vector3 Ka; // Diffuse Color Vector3 Kd; // Specular Color Vector3 Ks; // Specular Exponent float Ns; // Optical Density float Ni; // Dissolve float d; // Illumination int illum; // Ambient Texture Map std::string map_Ka; // Diffuse Texture Map std::string map_Kd; // Specular Texture Map std::string map_Ks; // Specular Hightlight Map std::string map_Ns; // Alpha Texture Map std::string map_d; // Bump Map std::string map_bump; }; // Structure: Mesh // // Description: A Simple Mesh Object that holds // a name, a vertex list, and an index list struct Mesh { // Default Constructor Mesh() { } // Variable Set Constructor Mesh(std::vector<Vertex>& _Vertices, std::vector<unsigned int>& _Indices) { Vertices = _Vertices; Indices = _Indices; } // Mesh Name std::string MeshName; // Vertex List std::vector<Vertex> Vertices; // Index List std::vector<unsigned int> Indices; // Material Material MeshMaterial; }; // Namespace: Math // // Description: The namespace that holds all of the math // functions need for OBJL namespace math { // Vector3 Cross Product Vector3 CrossV3(const Vector3 a, const Vector3 b) { return Vector3(a.Y * b.Z - a.Z * b.Y, a.Z * b.X - a.X * b.Z, a.X * b.Y - a.Y * b.X); } // Vector3 Magnitude Calculation float MagnitudeV3(const Vector3 in) { return (sqrtf(powf(in.X, 2) + powf(in.Y, 2) + powf(in.Z, 2))); } // Vector3 DotProduct float DotV3(const Vector3 a, const Vector3 b) { return (a.X * b.X) + (a.Y * b.Y) + (a.Z * b.Z); } // Angle between 2 Vector3 Objects float AngleBetweenV3(const Vector3 a, const Vector3 b) { float angle = DotV3(a, b); angle /= (MagnitudeV3(a) * MagnitudeV3(b)); return angle = acosf(angle); } } // Namespace: Algorithm // // Description: The namespace that holds all of the // Algorithms needed for OBJL namespace algorithm { // Vector3 Multiplication Opertor Overload Vector3 operator*(const float& left, const Vector3& right) { return Vector3(right.X * left, right.Y * left, right.Z * left); } // Check to see if a Vector3 Point is within a 3 Vector3 Triangle bool inTriangle(Vector3 point, Vector3 tri1, Vector3 tri2, Vector3 tri3) { // Starting vars Vector3 u = tri2 - tri1; Vector3 v = tri3 - tri1; Vector3 w = point - tri1; Vector3 n = math::CrossV3(u, v); float y = (math::DotV3(math::CrossV3(u, w), n) / math::DotV3(n, n)); float b = (math::DotV3(math::CrossV3(u, w), n) / math::DotV3(n, n)); float a = 1 - y - b; // Projected point Vector3 p = (a * tri1) + (b * tri2) + (y * tri3); if (a >= 0 && a <= 1 && b >= 0 && b <= 1 && y >= 0 && y <= 1) { return true; } else return false; } // Split a String into a string array at a given token inline void split(const std::string &in, std::vector<std::string> &out, std::string token) { out.clear(); std::string temp; for (int i = 0; i < int(in.size()); i++) { std::string test = in.substr(i, token.size()); if (test == token) { if (!temp.empty()) { out.push_back(temp); temp.clear(); i += (int)token.size() - 1; } else { out.push_back(""); } } else if (i + token.size() >= in.size()) { temp += in.substr(i, token.size()); out.push_back(temp); break; } else { temp += in[i]; } } } // Get tail of string after first token and possibly following spaces inline std::string tail(const std::string &in) { size_t token_start = in.find_first_not_of(" \t"); size_t space_start = in.find_first_of(" \t", token_start); size_t tail_start = in.find_first_not_of(" \t", space_start); size_t tail_end = in.find_last_not_of(" \t"); if (tail_start != std::string::npos && tail_end != std::string::npos) { return in.substr(tail_start, tail_end - tail_start + 1); } else if (tail_start != std::string::npos) { return in.substr(tail_start); } return ""; } // Get first token of string inline std::string firstToken(const std::string &in) { if (!in.empty()) { size_t token_start = in.find_first_not_of(" \t"); size_t token_end = in.find_first_of(" \t", token_start); if (token_start != std::string::npos && token_end != std::string::npos) { return in.substr(token_start, token_end - token_start); } else if (token_start != std::string::npos) { return in.substr(token_start); } } return ""; } // Get element at given index position template <class T> inline const T & getElement(const std::vector<T> &elements, std::string &index) { int idx = std::stoi(index); if (idx < 0) idx = int(elements.size()) + idx; else idx--; return elements[idx]; } } // Class: Loader // // Description: The OBJ Model Loader class Loader { public: // Default Constructor Loader() { } ~Loader() { LoadedMeshes.clear(); } // Load a file into the loader // // If file is loaded return true // // If the file is unable to be found // or unable to be loaded return false bool LoadFile(std::string Path) { // If the file is not an .obj file return false if (Path.substr(Path.size() - 4, 4) != ".obj") return false; std::ifstream file(Path); if (!file.is_open()) return false; LoadedMeshes.clear(); LoadedVertices.clear(); LoadedIndices.clear(); std::vector<Vector3> Positions; std::vector<Vector2> TCoords; std::vector<Vector3> Normals; std::vector<Vertex> Vertices; std::vector<unsigned int> Indices; std::vector<std::string> MeshMatNames; bool listening = false; std::string meshname; Mesh tempMesh; #ifdef OBJL_CONSOLE_OUTPUT const unsigned int outputEveryNth = 1000; unsigned int outputIndicator = outputEveryNth; #endif std::string curline; while (std::getline(file, curline)) { #ifdef OBJL_CONSOLE_OUTPUT if ((outputIndicator = ((outputIndicator + 1) % outputEveryNth)) == 1) { if (!meshname.empty()) { std::cout << "\r- " << meshname << "\t| vertices > " << Positions.size() << "\t| texcoords > " << TCoords.size() << "\t| normals > " << Normals.size() << "\t| triangles > " << (Vertices.size() / 3) << (!MeshMatNames.empty() ? "\t| material: " + MeshMatNames.back() : ""); } } #endif // Generate a Mesh Object or Prepare for an object to be created if (algorithm::firstToken(curline) == "o" || algorithm::firstToken(curline) == "g" || curline[0] == 'g') { if (!listening) { listening = true; if (algorithm::firstToken(curline) == "o" || algorithm::firstToken(curline) == "g") { meshname = algorithm::tail(curline); } else { meshname = "unnamed"; } } else { // Generate the mesh to put into the array if (!Indices.empty() && !Vertices.empty()) { // Create Mesh tempMesh = Mesh(Vertices, Indices); tempMesh.MeshName = meshname; // Insert Mesh LoadedMeshes.push_back(tempMesh); // Cleanup Vertices.clear(); Indices.clear(); meshname.clear(); meshname = algorithm::tail(curline); } else { if (algorithm::firstToken(curline) == "o" || algorithm::firstToken(curline) == "g") { meshname = algorithm::tail(curline); } else { meshname = "unnamed"; } } } #ifdef OBJL_CONSOLE_OUTPUT std::cout << std::endl; outputIndicator = 0; #endif } // Generate a Vertex Position if (algorithm::firstToken(curline) == "v") { std::vector<std::string> spos; Vector3 vpos; algorithm::split(algorithm::tail(curline), spos, " "); vpos.X = std::stof(spos[0]); vpos.Y = std::stof(spos[1]); vpos.Z = std::stof(spos[2]); Positions.push_back(vpos); } // Generate a Vertex Texture Coordinate if (algorithm::firstToken(curline) == "vt") { std::vector<std::string> stex; Vector2 vtex; algorithm::split(algorithm::tail(curline), stex, " "); vtex.X = std::stof(stex[0]); vtex.Y = std::stof(stex[1]); TCoords.push_back(vtex); } // Generate a Vertex Normal; if (algorithm::firstToken(curline) == "vn") { std::vector<std::string> snor; Vector3 vnor; algorithm::split(algorithm::tail(curline), snor, " "); vnor.X = std::stof(snor[0]); vnor.Y = std::stof(snor[1]); vnor.Z = std::stof(snor[2]); Normals.push_back(vnor); } // Generate a Face (vertices & indices) if (algorithm::firstToken(curline) == "f") { // Generate the vertices std::vector<Vertex> vVerts; GenVerticesFromRawOBJ(vVerts, Positions, TCoords, Normals, curline); // Add Vertices for (int i = 0; i < int(vVerts.size()); i++) { Vertices.push_back(vVerts[i]); LoadedVertices.push_back(vVerts[i]); } std::vector<unsigned int> iIndices; VertexTriangluation(iIndices, vVerts); // Add Indices for (int i = 0; i < int(iIndices.size()); i++) { unsigned int indnum = (unsigned int)((Vertices.size()) - vVerts.size()) + iIndices[i]; Indices.push_back(indnum); indnum = (unsigned int)((LoadedVertices.size()) - vVerts.size()) + iIndices[i]; LoadedIndices.push_back(indnum); } } // Get Mesh Material Name if (algorithm::firstToken(curline) == "usemtl") { MeshMatNames.push_back(algorithm::tail(curline)); // Create new Mesh, if Material changes within a group if (!Indices.empty() && !Vertices.empty()) { // Create Mesh tempMesh = Mesh(Vertices, Indices); tempMesh.MeshName = meshname; int i = 2; while(1) { tempMesh.MeshName = meshname + "_" + std::to_string(i); for (auto &m : LoadedMeshes) if (m.MeshName == tempMesh.MeshName) continue; break; } // Insert Mesh LoadedMeshes.push_back(tempMesh); // Cleanup Vertices.clear(); Indices.clear(); } #ifdef OBJL_CONSOLE_OUTPUT outputIndicator = 0; #endif } // Load Materials if (algorithm::firstToken(curline) == "mtllib") { // Generate LoadedMaterial // Generate a path to the material file std::vector<std::string> temp; algorithm::split(Path, temp, "/"); std::string pathtomat = ""; if (temp.size() != 1) { for (int i = 0; i < temp.size() - 1; i++) { pathtomat += temp[i] + "/"; } } pathtomat += algorithm::tail(curline); #ifdef OBJL_CONSOLE_OUTPUT std::cout << std::endl << "- find materials in: " << pathtomat << std::endl; #endif // Load Materials LoadMaterials(pathtomat); } } #ifdef OBJL_CONSOLE_OUTPUT std::cout << std::endl; #endif // Deal with last mesh if (!Indices.empty() && !Vertices.empty()) { // Create Mesh tempMesh = Mesh(Vertices, Indices); tempMesh.MeshName = meshname; // Insert Mesh LoadedMeshes.push_back(tempMesh); } file.close(); // Set Materials for each Mesh for (int i = 0; i < MeshMatNames.size(); i++) { std::string matname = MeshMatNames[i]; // Find corresponding material name in loaded materials // when found copy material variables into mesh material for (int j = 0; j < LoadedMaterials.size(); j++) { if (LoadedMaterials[j].name == matname) { LoadedMeshes[i].MeshMaterial = LoadedMaterials[j]; break; } } } if (LoadedMeshes.empty() && LoadedVertices.empty() && LoadedIndices.empty()) { return false; } else { return true; } } // Loaded Mesh Objects std::vector<Mesh> LoadedMeshes; // Loaded Vertex Objects std::vector<Vertex> LoadedVertices; // Loaded Index Positions std::vector<unsigned int> LoadedIndices; // Loaded Material Objects std::vector<Material> LoadedMaterials; private: // Generate vertices from a list of positions, // tcoords, normals and a face line void GenVerticesFromRawOBJ(std::vector<Vertex>& oVerts, const std::vector<Vector3>& iPositions, const std::vector<Vector2>& iTCoords, const std::vector<Vector3>& iNormals, std::string icurline) { std::vector<std::string> sface, svert; Vertex vVert; algorithm::split(algorithm::tail(icurline), sface, " "); bool noNormal = false; // For every given vertex do this for (int i = 0; i < int(sface.size()); i++) { // See What type the vertex is. int vtype; algorithm::split(sface[i], svert, "/"); // Check for just position - v1 if (svert.size() == 1) { // Only position vtype = 1; } // Check for position & texture - v1/vt1 if (svert.size() == 2) { // Position & Texture vtype = 2; } // Check for Position, Texture and Normal - v1/vt1/vn1 // or if Position and Normal - v1//vn1 if (svert.size() == 3) { if (svert[1] != "") { // Position, Texture, and Normal vtype = 4; } else { // Position & Normal vtype = 3; } } // Calculate and store the vertex switch (vtype) { case 1: // P { vVert.Position = algorithm::getElement(iPositions, svert[0]); vVert.TextureCoordinate = Vector2(0, 0); noNormal = true; oVerts.push_back(vVert); break; } case 2: // P/T { vVert.Position = algorithm::getElement(iPositions, svert[0]); vVert.TextureCoordinate = algorithm::getElement(iTCoords, svert[1]); noNormal = true; oVerts.push_back(vVert); break; } case 3: // P//N { vVert.Position = algorithm::getElement(iPositions, svert[0]); vVert.TextureCoordinate = Vector2(0, 0); vVert.Normal = algorithm::getElement(iNormals, svert[2]); oVerts.push_back(vVert); break; } case 4: // P/T/N { vVert.Position = algorithm::getElement(iPositions, svert[0]); vVert.TextureCoordinate = algorithm::getElement(iTCoords, svert[1]); vVert.Normal = algorithm::getElement(iNormals, svert[2]); oVerts.push_back(vVert); break; } default: { break; } } } // take care of missing normals // these may not be truly acurate but it is the // best they get for not compiling a mesh with normals if (noNormal) { Vector3 A = oVerts[0].Position - oVerts[1].Position; Vector3 B = oVerts[2].Position - oVerts[1].Position; Vector3 normal = math::CrossV3(A, B); for (int i = 0; i < int(oVerts.size()); i++) { oVerts[i].Normal = normal; } } } // Triangulate a list of vertices into a face by printing // inducies corresponding with triangles within it void VertexTriangluation(std::vector<unsigned int>& oIndices, const std::vector<Vertex>& iVerts) { // If there are 2 or less verts, // no triangle can be created, // so exit if (iVerts.size() < 3) { return; } // If it is a triangle no need to calculate it if (iVerts.size() == 3) { oIndices.push_back(0); oIndices.push_back(1); oIndices.push_back(2); return; } // Create a list of vertices std::vector<Vertex> tVerts = iVerts; while (true) { // For every vertex for (int i = 0; i < int(tVerts.size()); i++) { // pPrev = the previous vertex in the list Vertex pPrev; if (i == 0) { pPrev = tVerts[tVerts.size() - 1]; } else { pPrev = tVerts[i - 1]; } // pCur = the current vertex; Vertex pCur = tVerts[i]; // pNext = the next vertex in the list Vertex pNext; if (i == tVerts.size() - 1) { pNext = tVerts[0]; } else { pNext = tVerts[i + 1]; } // Check to see if there are only 3 verts left // if so this is the last triangle if (tVerts.size() == 3) { // Create a triangle from pCur, pPrev, pNext for (int j = 0; j < int(tVerts.size()); j++) { if (iVerts[j].Position == pCur.Position) oIndices.push_back(j); if (iVerts[j].Position == pPrev.Position) oIndices.push_back(j); if (iVerts[j].Position == pNext.Position) oIndices.push_back(j); } tVerts.clear(); break; } if (tVerts.size() == 4) { // Create a triangle from pCur, pPrev, pNext for (int j = 0; j < int(iVerts.size()); j++) { if (iVerts[j].Position == pCur.Position) oIndices.push_back(j); if (iVerts[j].Position == pPrev.Position) oIndices.push_back(j); if (iVerts[j].Position == pNext.Position) oIndices.push_back(j); } Vector3 tempVec; for (int j = 0; j < int(tVerts.size()); j++) { if (tVerts[j].Position != pCur.Position && tVerts[j].Position != pPrev.Position && tVerts[j].Position != pNext.Position) { tempVec = tVerts[j].Position; break; } } // Create a triangle from pCur, pPrev, pNext for (int j = 0; j < int(iVerts.size()); j++) { if (iVerts[j].Position == pPrev.Position) oIndices.push_back(j); if (iVerts[j].Position == pNext.Position) oIndices.push_back(j); if (iVerts[j].Position == tempVec) oIndices.push_back(j); } tVerts.clear(); break; } // If Vertex is not an interior vertex float angle = math::AngleBetweenV3(pPrev.Position - pCur.Position, pNext.Position - pCur.Position) * (180 / 3.14159265359); if (angle <= 0 && angle >= 180) continue; // If any vertices are within this triangle bool inTri = false; for (int j = 0; j < int(iVerts.size()); j++) { if (algorithm::inTriangle(iVerts[j].Position, pPrev.Position, pCur.Position, pNext.Position) && iVerts[j].Position != pPrev.Position && iVerts[j].Position != pCur.Position && iVerts[j].Position != pNext.Position) { inTri = true; break; } } if (inTri) continue; // Create a triangle from pCur, pPrev, pNext for (int j = 0; j < int(iVerts.size()); j++) { if (iVerts[j].Position == pCur.Position) oIndices.push_back(j); if (iVerts[j].Position == pPrev.Position) oIndices.push_back(j); if (iVerts[j].Position == pNext.Position) oIndices.push_back(j); } // Delete pCur from the list for (int j = 0; j < int(tVerts.size()); j++) { if (tVerts[j].Position == pCur.Position) { tVerts.erase(tVerts.begin() + j); break; } } // reset i to the start // -1 since loop will add 1 to it i = -1; } // if no triangles were created if (oIndices.size() == 0) break; // if no more vertices if (tVerts.size() == 0) break; } } // Load Materials from .mtl file bool LoadMaterials(std::string path) { // If the file is not a material file return false if (path.substr(path.size() - 4, path.size()) != ".mtl") return false; std::ifstream file(path); // If the file is not found return false if (!file.is_open()) return false; Material tempMaterial; bool listening = false; // Go through each line looking for material variables std::string curline; while (std::getline(file, curline)) { // new material and material name if (algorithm::firstToken(curline) == "newmtl") { if (!listening) { listening = true; if (curline.size() > 7) { tempMaterial.name = algorithm::tail(curline); } else { tempMaterial.name = "none"; } } else { // Generate the material // Push Back loaded Material LoadedMaterials.push_back(tempMaterial); // Clear Loaded Material tempMaterial = Material(); if (curline.size() > 7) { tempMaterial.name = algorithm::tail(curline); } else { tempMaterial.name = "none"; } } } // Ambient Color if (algorithm::firstToken(curline) == "Ka") { std::vector<std::string> temp; algorithm::split(algorithm::tail(curline), temp, " "); if (temp.size() != 3) continue; tempMaterial.Ka.X = std::stof(temp[0]); tempMaterial.Ka.Y = std::stof(temp[1]); tempMaterial.Ka.Z = std::stof(temp[2]); } // Diffuse Color if (algorithm::firstToken(curline) == "Kd") { std::vector<std::string> temp; algorithm::split(algorithm::tail(curline), temp, " "); if (temp.size() != 3) continue; tempMaterial.Kd.X = std::stof(temp[0]); tempMaterial.Kd.Y = std::stof(temp[1]); tempMaterial.Kd.Z = std::stof(temp[2]); } // Specular Color if (algorithm::firstToken(curline) == "Ks") { std::vector<std::string> temp; algorithm::split(algorithm::tail(curline), temp, " "); if (temp.size() != 3) continue; tempMaterial.Ks.X = std::stof(temp[0]); tempMaterial.Ks.Y = std::stof(temp[1]); tempMaterial.Ks.Z = std::stof(temp[2]); } // Specular Exponent if (algorithm::firstToken(curline) == "Ns") { tempMaterial.Ns = std::stof(algorithm::tail(curline)); } // Optical Density if (algorithm::firstToken(curline) == "Ni") { tempMaterial.Ni = std::stof(algorithm::tail(curline)); } // Dissolve if (algorithm::firstToken(curline) == "d") { tempMaterial.d = std::stof(algorithm::tail(curline)); } // Illumination if (algorithm::firstToken(curline) == "illum") { tempMaterial.illum = std::stoi(algorithm::tail(curline)); } // Ambient Texture Map if (algorithm::firstToken(curline) == "map_Ka") { tempMaterial.map_Ka = algorithm::tail(curline); } // Diffuse Texture Map if (algorithm::firstToken(curline) == "map_Kd") { tempMaterial.map_Kd = algorithm::tail(curline); } // Specular Texture Map if (algorithm::firstToken(curline) == "map_Ks") { tempMaterial.map_Ks = algorithm::tail(curline); } // Specular Hightlight Map if (algorithm::firstToken(curline) == "map_Ns") { tempMaterial.map_Ns = algorithm::tail(curline); } // Alpha Texture Map if (algorithm::firstToken(curline) == "map_d") { tempMaterial.map_d = algorithm::tail(curline); } // Bump Map if (algorithm::firstToken(curline) == "map_Bump" || algorithm::firstToken(curline) == "map_bump") { tempMaterial.map_bump = algorithm::tail(curline); } } // Deal with last material // Push Back loaded Material LoadedMaterials.push_back(tempMaterial); // Test to see if anything was loaded // If not return false if (LoadedMaterials.empty()) return false; // If so return true else return true; } }; }
扫描二维码关注公众号,回复:
1137508 查看本文章
#include <iostream> #include <time.h> #include "OBJ_Loader.h" #include "Math.h" int main(int argc, char* argv[]) { objl::Loader loader; loader.LoadFile("..//models/teapot.obj"); std::vector<Plane> triangles; Ray ray(0, 1, 5, 0, 0, 1); std::shared_ptr<Vector3> intersectionPoint(new Vector3); for(int i = 0; i < loader.LoadedIndices.size() / 3; i++) { int n = i * 3; float x, y, z; x = loader.LoadedVertices[loader.LoadedIndices[n]].Position.X; y = loader.LoadedVertices[loader.LoadedIndices[n]].Position.Y; z = loader.LoadedVertices[loader.LoadedIndices[n]].Position.Z; float g, h, j; g = loader.LoadedVertices[loader.LoadedIndices[n + 1]].Position.X; h = loader.LoadedVertices[loader.LoadedIndices[n + 1]].Position.Y; j = loader.LoadedVertices[loader.LoadedIndices[n + 1]].Position.Z; float c, v, b; c = loader.LoadedVertices[loader.LoadedIndices[n + 2]].Position.X; v = loader.LoadedVertices[loader.LoadedIndices[n + 2]].Position.Y; b = loader.LoadedVertices[loader.LoadedIndices[n + 2]].Position.Z; Plane plane(x, y, z, g, h, j, c, v, b); plane = Math::SetupPlane(plane); triangles.push_back(plane); } for(int i = 0; i < triangles.size(); i++) { if(Math::CheckForPlaneIntersection(triangles[i], ray, intersectionPoint)) { Math::WriteVector(Vector3(intersectionPoint->x, intersectionPoint->y, intersectionPoint->z)); } } return 0; }