games101-hw/06/Assignment6/Triangle.hpp

252 lines
7.8 KiB
C++
Raw Normal View History

2023-06-19 17:02:04 +08:00
#pragma once
#include "BVH.hpp"
#include "Intersection.hpp"
#include "Material.hpp"
#include "OBJ_Loader.hpp"
#include "Object.hpp"
#include "Triangle.hpp"
#include <cassert>
#include <array>
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<float>::infinity(),
std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::infinity()};
Vector3f max_vert = Vector3f{-std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity()};
for (int i = 0; i < mesh.Vertices.size(); i += 3) {
std::array<Vector3f, 3> 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<Object*> 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<Vector3f[]> vertices;
uint32_t numTriangles;
std::unique_ptr<uint32_t[]> vertexIndex;
std::unique_ptr<Vector2f[]> stCoordinates;
std::vector<Triangle> 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);
}