Linloir 9d95220073
[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
2022-12-18 18:07:18 +08:00

101 lines
3.8 KiB
C++

#pragma once
#include "mesh.h"
#include "utils.h"
#include "logger.h"
Mesh::Mesh(const std::vector<Vertex>& vertices, const std::vector<unsigned int>& indices, const std::vector<Texture>& textures) {
_vertices = vertices;
_indices = indices;
_textures = textures;
setupMesh();
}
Mesh::Mesh(const std::vector<Vertex>& vertices, const std::vector<Texture>& textures) {
_vertices = vertices;
_textures = textures;
setupMesh();
}
void Mesh::render(const ShaderProgram& shader) const {
unsigned int diffuseNr = 1;
unsigned int specularNr = 1;
shader.setUniform("material.shininess",_shininess);
for (int i = 0; i < _textures.size(); i++) {
OPENGL_EXTRA_FUNCTIONS->glActiveTexture(GL_TEXTURE0 + i); // activate proper texture unit before binding
// retrieve texture number (the N in diffuse_textureN)
std::string number;
std::string name = _textures[i].type() == TextureType::DIFFUSE ? "texture_diffuse" : "texture_specular";
name = "material." + name;
if (_textures[i].type() == TextureType::DIFFUSE)
number = std::to_string(diffuseNr++);
else if (_textures[i].type() == TextureType::SPECULAR)
number = std::to_string(specularNr++);
shader.setUniform(name + number, i);
_textures[i].bind();
}
OPENGL_EXTRA_FUNCTIONS->glActiveTexture(GL_TEXTURE0);
_vao.bind();
OPENGL_EXTRA_FUNCTIONS->glDrawElements(GL_TRIANGLES, _indices.size(), GL_UNSIGNED_INT, 0);
_vao.unbind();
}
void Mesh::setupMesh() {
_vao = VertexArrayObject(_vertices, _indices);
_vao.setVertexAttributePointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
_vao.setVertexAttributePointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)OFFSETOF(Vertex, _normal));
_vao.setVertexAttributePointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)OFFSETOF(Vertex, _texCoords));
//_vao.setVertexAttributePointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)OFFSETOF(Vertex, _tangent));
//_vao.setVertexAttributePointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)OFFSETOF(Vertex, _bitangent));
}
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
for (int i = 0; i < _indices.size(); i += 3) {
// Get the three vertices of the triangle
Vertex v0 = _vertices[_indices[i]];
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 = v1pos - v0pos;
glm::vec3 edge2 = v2pos - v0pos;
glm::vec3 pvec = glm::cross(ray.direction(), edge2);
float det = glm::dot(edge1, pvec);
if (abs(det) < 0.0001f) {
continue;
}
float invDet = 1.0f / det;
glm::vec3 tvec = ray.origin() - v0pos;
float u = glm::dot(tvec, pvec) * invDet;
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;
}
float t = glm::dot(edge2, qvec) * invDet;
if (t > 0.0001f) {
// Hit
glm::vec3 normal = glm::normalize(glm::cross(edge1, edge2));
glm::vec3 hitPoint = ray.origin() + t * ray.direction();
return HitRecord(t, hitPoint, normal);
}
}
return HitRecord();
}