[CORE][FIX] Hit test fix

- Add critical debug logs
- Change transforming ray to local space to transforming vex to world space (because of scaling)
- Fix not updating bounding box causing hit test failure
This commit is contained in:
Linloir 2022-12-18 18:07:18 +08:00
parent 98a1321af2
commit 9d95220073
No known key found for this signature in database
GPG Key ID: 58EEB209A0F2C366
10 changed files with 33 additions and 46 deletions

View File

@ -120,7 +120,6 @@
<ClCompile Include="modelthumbnailwidget.cpp" />
<ClCompile Include="pagewidget.cpp" />
<ClCompile Include="pushbutton.cpp" />
<ClCompile Include="ray.cpp" />
<ClCompile Include="renderable.cpp" />
<ClCompile Include="roundedcornerwidget.cpp" />
<ClCompile Include="sceneviewer.cpp" />

View File

@ -171,9 +171,6 @@
<ClCompile Include="skybox.cpp">
<Filter>Source Files\OpenGL Abstractions</Filter>
</ClCompile>
<ClCompile Include="ray.cpp">
<Filter>Source Files\OpenGL Abstractions</Filter>
</ClCompile>
<ClCompile Include="boundary.cpp">
<Filter>Source Files\OpenGL Abstractions</Filter>
</ClCompile>

View File

@ -54,7 +54,7 @@ void Mesh::setupMesh() {
//_vao.setVertexAttributePointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)OFFSETOF(Vertex, _bitangent));
}
HitRecord Mesh::hit(const Ray& ray) const {
HitRecord Mesh::hit(const Ray& ray, const glm::mat4& modelMatrix) const {
// Test whether the ray hits the mesh
// Traverse the indices to test every triangle
@ -64,20 +64,30 @@ HitRecord Mesh::hit(const Ray& ray) const {
Vertex v1 = _vertices[_indices[i + 1]];
Vertex v2 = _vertices[_indices[i + 2]];
glm::vec3 v0pos = glm::vec3(modelMatrix * glm::vec4(v0._position, 1.0f));
glm::vec3 v1pos = glm::vec3(modelMatrix * glm::vec4(v1._position, 1.0f));
glm::vec3 v2pos = glm::vec3(modelMatrix * glm::vec4(v2._position, 1.0f));
// Moller Trumbore algorithm
// https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
glm::vec3 edge1 = v1._position - v0._position;
glm::vec3 edge2 = v2._position - v0._position;
glm::vec3 edge1 = v1pos - v0pos;
glm::vec3 edge2 = v2pos - v0pos;
glm::vec3 pvec = glm::cross(ray.direction(), edge2);
float det = glm::dot(edge1, pvec);
if (det < 0.0001f) continue;
if (abs(det) < 0.0001f) {
continue;
}
float invDet = 1.0f / det;
glm::vec3 tvec = ray.origin() - v0._position;
glm::vec3 tvec = ray.origin() - v0pos;
float u = glm::dot(tvec, pvec) * invDet;
if (u < 0.0f || u > 1.0f) continue;
if (u < 0.0f || u > 1.0f) {
continue;
}
glm::vec3 qvec = glm::cross(tvec, edge1);
float v = glm::dot(ray.direction(), qvec) * invDet;
if (v < 0.0f || u + v > 1.0f) continue;
if (v < 0.0f || u + v > 1.0f) {
continue;
}
float t = glm::dot(edge2, qvec) * invDet;
if (t > 0.0001f) {
// Hit

View File

@ -36,7 +36,7 @@ public:
public:
void render(const ShaderProgram& shader) const ;
HitRecord hit(const Ray& ray) const;
HitRecord hit(const Ray& ray, const glm::mat4& modelMatrix) const;
private:
void setupMesh();

View File

@ -189,22 +189,14 @@ void Model::render(const ShaderProgram& shader) const {
}
}
HitRecord Model::hit(const Ray& ray) const {
// 1. use the aabb method to test whether hit the boundary box
// 2. if hit, use the mesh hit method to test whether hit the mesh
if (_boundBox.hit(ray)) {
for (unsigned int i = 0; i < _meshes.size(); i++) {
HitRecord hitRecord = _meshes[i].hit(ray);
if (hitRecord.hitted()) {
return hitRecord;
}
HitRecord Model::hit(const Ray& ray, const glm::mat4& modelMatrix) const {
for (unsigned int i = 0; i < _meshes.size(); i++) {
HitRecord hitRecord = _meshes[i].hit(ray, modelMatrix);
if (hitRecord.hitted()) {
return hitRecord;
}
return HitRecord();
}
else {
return HitRecord(); // return a false hit record
}
return HitRecord();
}
Model* Model::copyToCurrentContext() const {

View File

@ -49,5 +49,5 @@ private:
public:
void render(const ShaderProgram& shader) const;
HitRecord hit(const Ray& ray) const; // test the hit record of an input array (transformed into local space)
HitRecord hit(const Ray& ray, const glm::mat4& modelMatrix) const; // test the hit record of an input array (transformed into local space)
};

View File

@ -1,14 +0,0 @@
#include "ray.h"
Ray Ray::toLocalSpace(glm::mat4 modelMatrix) const {
// The model matrix is the matrix that transforms local space to world space
// Therefore the inverse of the model matrix transforms world space to local space
glm::mat4 inversedModelMatrix = glm::inverse(modelMatrix);
// Transform the origin and direction of the ray to local space
glm::vec4 localOrigin = inversedModelMatrix * glm::vec4(_origin, 1.0f);
glm::vec4 localDirection = inversedModelMatrix * glm::vec4(_direction, 0.0f);
// Return the new ray
return Ray(glm::vec3(localOrigin), glm::vec3(localDirection));
}

View File

@ -14,7 +14,4 @@ public:
public:
inline glm::vec3 origin() const { return _origin; }
inline glm::vec3 direction() const { return _direction; }
public:
Ray toLocalSpace(glm::mat4 modelMatrix) const;
};

View File

@ -75,12 +75,17 @@ void Renderable::render(ShaderProgram shader) {
void Renderable::updateBoundary() {
// Traverse every vertex in the transferred model and update the boundary
Boundary newBoundary;
glm::mat4 model = modelMatrix();
for (auto& mesh : _model->meshes()) {
for (auto& vertex : mesh.vertices()) {
glm::vec4 transformedVertex = modelMatrix() * glm::vec4(vertex._position, 1.0f);
glm::vec4 transformedVertex = model * glm::vec4(vertex._position, 1.0f);
newBoundary.updateControlPoints(glm::vec3(transformedVertex));
}
}
_boundary = newBoundary;
Logger::debug("Boundary updated");
Logger::debug("[+] Bottom control point: " + std::to_string(newBoundary.bottomControlPoint().x) + ", " + std::to_string(newBoundary.bottomControlPoint().y) + ", " + std::to_string(newBoundary.bottomControlPoint().z));
Logger::debug("[+] Top control point: " + std::to_string(newBoundary.topControlPoint().x) + ", " + std::to_string(newBoundary.topControlPoint().y) + ", " + std::to_string(newBoundary.topControlPoint().z));
}
HitRecord Renderable::hit(const Ray& ray) const {
@ -90,6 +95,6 @@ HitRecord Renderable::hit(const Ray& ray) const {
}
else {
// If the ray hits the boundary box
return _model->hit(ray.toLocalSpace(modelMatrix()));
return _model->hit(ray, modelMatrix());
}
}

View File

@ -125,6 +125,7 @@ void SceneViewer::initializeGL() {
Model* model = new Model("E:\\Repositories\\CollegeProjects\\CGAssignments\\FinalProject\\Models\\backpack\\backpack.obj");
Renderable* backpack = new Renderable(model);
backpack->move(glm::vec3(-5.0f, -2.0f, -2.0f));
backpack->updateBoundary();
_objects.push_back(backpack);
Renderable* backpack2 = new Renderable(model);