GitHub上三维空间中射线与三角形相交检测代码(Ray-Triangle)
程序员文章站
2024-03-16 18:58:58
...
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;
}
};
}
#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;
}
上一篇: Android常用加密解密实现方式
下一篇: GitHub 访问加速方法