mirror of
https://github.com/Linloir/SceneEditor.git
synced 2025-12-16 23:18:12 +08:00
[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:
parent
98a1321af2
commit
9d95220073
@ -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" />
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)
|
||||
};
|
||||
@ -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));
|
||||
}
|
||||
@ -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;
|
||||
};
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user