#pragma once #include "BVH.hpp" #include "Intersection.hpp" #include "Material.hpp" #include "OBJ_Loader.hpp" #include "Object.hpp" #include "Triangle.hpp" #include #include bool rayTriangleIntersect(const Vector3f& v0, const Vector3f& v1, const Vector3f& v2, const Vector3f& orig, const Vector3f& dir, float& tnear, float& u, float& v) { Vector3f edge1 = v1 - v0; Vector3f edge2 = v2 - v0; Vector3f pvec = crossProduct(dir, edge2); float det = dotProduct(edge1, pvec); if (det == 0 || det < 0) return false; Vector3f tvec = orig - v0; u = dotProduct(tvec, pvec); if (u < 0 || u > det) return false; Vector3f qvec = crossProduct(tvec, edge1); v = dotProduct(dir, qvec); if (v < 0 || u + v > det) return false; float invDet = 1 / det; tnear = dotProduct(edge2, qvec) * invDet; u *= invDet; v *= invDet; return true; } class Triangle : public Object { public: Vector3f v0, v1, v2; // vertices A, B ,C , counter-clockwise order Vector3f e1, e2; // 2 edges v1-v0, v2-v0; Vector3f t0, t1, t2; // texture coords Vector3f normal; Material* m; Triangle(Vector3f _v0, Vector3f _v1, Vector3f _v2, Material* _m = nullptr) : v0(_v0), v1(_v1), v2(_v2), m(_m) { e1 = v1 - v0; e2 = v2 - v0; normal = normalize(crossProduct(e1, e2)); } bool intersect(const Ray& ray) override; bool intersect(const Ray& ray, float& tnear, uint32_t& index) const override; Intersection getIntersection(Ray ray) override; void getSurfaceProperties(const Vector3f& P, const Vector3f& I, const uint32_t& index, const Vector2f& uv, Vector3f& N, Vector2f& st) const override { N = normal; // throw std::runtime_error("triangle::getSurfaceProperties not // implemented."); } Vector3f evalDiffuseColor(const Vector2f&) const override; Bounds3 getBounds() override; }; class MeshTriangle : public Object { public: MeshTriangle(const std::string& filename) { objl::Loader loader; loader.LoadFile(filename); assert(loader.LoadedMeshes.size() == 1); auto mesh = loader.LoadedMeshes[0]; Vector3f min_vert = Vector3f{std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()}; Vector3f max_vert = Vector3f{-std::numeric_limits::infinity(), -std::numeric_limits::infinity(), -std::numeric_limits::infinity()}; for (int i = 0; i < mesh.Vertices.size(); i += 3) { std::array face_vertices; for (int j = 0; j < 3; j++) { auto vert = Vector3f(mesh.Vertices[i + j].Position.X, mesh.Vertices[i + j].Position.Y, mesh.Vertices[i + j].Position.Z) * 60.f; face_vertices[j] = vert; min_vert = Vector3f(std::min(min_vert.x, vert.x), std::min(min_vert.y, vert.y), std::min(min_vert.z, vert.z)); max_vert = Vector3f(std::max(max_vert.x, vert.x), std::max(max_vert.y, vert.y), std::max(max_vert.z, vert.z)); } auto new_mat = new Material(MaterialType::DIFFUSE_AND_GLOSSY, Vector3f(0.5, 0.5, 0.5), Vector3f(0, 0, 0)); new_mat->Kd = 0.6; new_mat->Ks = 0.0; new_mat->specularExponent = 0; triangles.emplace_back(face_vertices[0], face_vertices[1], face_vertices[2], new_mat); } bounding_box = Bounds3(min_vert, max_vert); std::vector ptrs; for (auto& tri : triangles) ptrs.push_back(&tri); bvh = new BVHAccel(ptrs); } bool intersect(const Ray& ray) { return true; } bool intersect(const Ray& ray, float& tnear, uint32_t& index) const { bool intersect = false; for (uint32_t k = 0; k < numTriangles; ++k) { const Vector3f& v0 = vertices[vertexIndex[k * 3]]; const Vector3f& v1 = vertices[vertexIndex[k * 3 + 1]]; const Vector3f& v2 = vertices[vertexIndex[k * 3 + 2]]; float t, u, v; if (rayTriangleIntersect(v0, v1, v2, ray.origin, ray.direction, t, u, v) && t < tnear) { tnear = t; index = k; intersect |= true; } } return intersect; } Bounds3 getBounds() { return bounding_box; } void getSurfaceProperties(const Vector3f& P, const Vector3f& I, const uint32_t& index, const Vector2f& uv, Vector3f& N, Vector2f& st) const { const Vector3f& v0 = vertices[vertexIndex[index * 3]]; const Vector3f& v1 = vertices[vertexIndex[index * 3 + 1]]; const Vector3f& v2 = vertices[vertexIndex[index * 3 + 2]]; Vector3f e0 = normalize(v1 - v0); Vector3f e1 = normalize(v2 - v1); N = normalize(crossProduct(e0, e1)); const Vector2f& st0 = stCoordinates[vertexIndex[index * 3]]; const Vector2f& st1 = stCoordinates[vertexIndex[index * 3 + 1]]; const Vector2f& st2 = stCoordinates[vertexIndex[index * 3 + 2]]; st = st0 * (1 - uv.x - uv.y) + st1 * uv.x + st2 * uv.y; } Vector3f evalDiffuseColor(const Vector2f& st) const { float scale = 5; float pattern = (fmodf(st.x * scale, 1) > 0.5) ^ (fmodf(st.y * scale, 1) > 0.5); return lerp(Vector3f(0.815, 0.235, 0.031), Vector3f(0.937, 0.937, 0.231), pattern); } Intersection getIntersection(Ray ray) { Intersection intersec; if (bvh) { intersec = bvh->Intersect(ray); } return intersec; } Bounds3 bounding_box; std::unique_ptr vertices; uint32_t numTriangles; std::unique_ptr vertexIndex; std::unique_ptr stCoordinates; std::vector triangles; BVHAccel* bvh; Material* m; }; inline bool Triangle::intersect(const Ray& ray) { return true; } inline bool Triangle::intersect(const Ray& ray, float& tnear, uint32_t& index) const { return false; } inline Bounds3 Triangle::getBounds() { return Union(Bounds3(v0, v1), v2); } inline Intersection Triangle::getIntersection(Ray ray) { Intersection inter; if (dotProduct(ray.direction, normal) > 0) return inter; double u, v, t_tmp = 0; Vector3f pvec = crossProduct(ray.direction, e2); double det = dotProduct(e1, pvec); if (fabs(det) < EPSILON) return inter; double det_inv = 1. / det; Vector3f tvec = ray.origin - v0; u = dotProduct(tvec, pvec) * det_inv; if (u < 0 || u > 1) return inter; Vector3f qvec = crossProduct(tvec, e1); v = dotProduct(ray.direction, qvec) * det_inv; if (v < 0 || u + v > 1) return inter; t_tmp = dotProduct(e2, qvec) * det_inv; // TODO find ray triangle intersection if(t_tmp<0) return inter; inter.distance = t_tmp; inter.happened = true; inter.m=m; inter.obj = this; inter.normal = normal; inter.coords = ray(t_tmp); return inter; return inter; } inline Vector3f Triangle::evalDiffuseColor(const Vector2f&) const { return Vector3f(0.5, 0.5, 0.5); }