[CORE][ADD] Hit Test

This commit is contained in:
Linloir 2022-12-18 17:30:46 +08:00
parent db04a46510
commit 98a1321af2
No known key found for this signature in database
GPG Key ID: 58EEB209A0F2C366
4 changed files with 49 additions and 37 deletions

View File

@ -5,15 +5,17 @@
class HitRecord {
private:
bool _hitted;
float _t;
glm::vec3 _position = glm::vec3(0.0f);
glm::vec3 _normal = glm::vec3(0.0f);
public:
HitRecord() : _hitted(false) {}
HitRecord(glm::vec3 position, glm::vec3 normal) : _hitted(true), _position(position), _normal(normal) {}
HitRecord() : _hitted(false), _t(std::numeric_limits<float>::max()) {}
HitRecord(float t, glm::vec3 position, glm::vec3 normal) : _hitted(true), _t(t), _position(position), _normal(normal) {}
public:
inline bool hitted() const { return _hitted; }
inline float t() const { return _t; }
inline glm::vec3 position() const { return _position; }
inline glm::vec3 normal() const { return _normal; }
};

View File

@ -83,7 +83,7 @@ HitRecord Mesh::hit(const Ray& ray) const {
// Hit
glm::vec3 normal = glm::normalize(glm::cross(edge1, edge2));
glm::vec3 hitPoint = ray.origin() + t * ray.direction();
return HitRecord(hitPoint, normal);
return HitRecord(t, hitPoint, normal);
}
}
return HitRecord();

View File

@ -11,6 +11,8 @@
SceneViewer::SceneViewer(QWidget* parent)
: QOpenGLWidget(parent)
{
// Set mouse tracking
setMouseTracking(true);
// OpenGL initialize
QSurfaceFormat format;
format.setProfile(QSurfaceFormat::CoreProfile);
@ -57,6 +59,33 @@ void SceneViewer::extractShaderResorce(const QString& shaderName) {
QFile::setPermissions(shaderTempPath, QFile::ReadOwner | QFile::WriteOwner);
}
void SceneViewer::hitTest(const Ray& ray) {
HitRecord newRecord = HitRecord();
Renderable* newObject = nullptr;
int newObjectIndex = -1;
for (int i = 0; i < _objects.size(); i++) {
Logger::debug("Testing object " + std::to_string(i));
Renderable* obj = _objects[i];
HitRecord hitRecord = obj->hit(ray);
if (hitRecord.hitted()) {
Logger::debug("Hitted object " + std::to_string(i));
}
else {
Logger::debug("Missed object " + std::to_string(i));
}
if (hitRecord.hitted() && hitRecord.t() < newRecord.t()) {
newRecord = hitRecord;
newObject = obj;
newObjectIndex = i;
}
}
if (newRecord.hitted()) {
Logger::debug("Hit test hitted object with index " + std::to_string(newObjectIndex));
}
_hitRecord = newRecord;
_hoveredObject = newObject;
}
void SceneViewer::initializeGL() {
initializeOpenGLFunctions();
@ -95,10 +124,10 @@ 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));
_objects.push_back(backpack);
Renderable* backpack2 = new Renderable(model);
backpack2->move(glm::vec3(-5.0f, -2.0f, -2.0f));
backpack2->makeLight();
backpack2->originalLight()->setIdealDistance(500);
_objects.push_back(backpack2);
@ -173,9 +202,6 @@ void SceneViewer::mousePressEvent(QMouseEvent* event) {
}
void SceneViewer::mouseMoveEvent(QMouseEvent* event) {
if (event->buttons() != Qt::NoButton) {
Logger::debug("Mouse moved with offset: " + std::to_string(event->x() - _lastMousePosition.x()) + ", " + std::to_string(event->y() - _lastMousePosition.y()));
}
// Check the type of button pressed
switch (event->buttons()) {
case Qt::LeftButton: {
@ -212,6 +238,14 @@ void SceneViewer::mouseMoveEvent(QMouseEvent* event) {
Logger::debug("Center at: " + std::to_string(_rotateCenter.x) + ", " + std::to_string(_rotateCenter.y) + ", " + std::to_string(_rotateCenter.z));
break;
}
case Qt::NoButton: {
// If no button pressed, do hit test and move the current object if selected
float relX = (float)event->x() / (float)width();
float relY = 1 - (float)event->y() / (float)height();
Ray ray = _camera.generateRay(glm::vec2(relX, relY), (float)width() / (float)height());
hitTest(ray);
break;
}
default: {
Logger::warning("Unknown mouse button input");
Logger::warning("Mouse button: " + std::to_string(event->buttons()));
@ -236,29 +270,3 @@ void SceneViewer::wheelEvent(QWheelEvent* event) {
// Update the view
parentWidget()->update();
}
void SceneViewer::showEvent(QShowEvent* event) {
// Call show event of super class
QOpenGLWidget::showEvent(event);
if (_initialized) {
return;
}
//// Create mask for rounded corner
//QPainterPath mask;
//mask.addRoundedRect(rect(), _cornerRadius, _cornerRadius);
//setMask(mask.toFillPolygon().toPolygon());
_initialized = true;
}
void SceneViewer::resizeEvent(QResizeEvent* event) {
// Call resize event of super class
QOpenGLWidget::resizeEvent(event);
//// Create mask for rounded corner
//QPainterPath mask;
//mask.addRoundedRect(rect(), _cornerRadius, _cornerRadius);
//setMask(mask.toFillPolygon().toPolygon());
}

View File

@ -37,9 +37,14 @@ private:
// Rotate center
glm::vec3 _rotateCenter = glm::vec3(0.0f, 0.0f, 0.0f);
// User preferences
bool _stickToSurface = false; // whether to rotate the object to the normal of the hitted surface
// User Interaction flags section---------------------
QPoint _lastMousePosition;
Renderable* _hoveredObject = nullptr;
Renderable* _selectedObject = nullptr;
HitRecord _hitRecord;
// UI interface control
const int _cornerRadius = 10;
@ -51,6 +56,7 @@ public:
private:
void extractShaderResorce(const QString& shaderName);
void hitTest(const Ray& ray);
protected:
// OpenGL functions
@ -62,8 +68,4 @@ protected:
virtual void mousePressEvent(QMouseEvent* event) override;
virtual void mouseMoveEvent(QMouseEvent* event) override;
virtual void wheelEvent(QWheelEvent* event) override;
// UI update events
virtual void showEvent(QShowEvent* event) override;
virtual void resizeEvent(QResizeEvent* event) override;
};