mirror of
https://github.com/ConjureETS/LOG750-LAB2.git
synced 2026-03-24 03:21:19 +00:00
WIP Obj Loader
This commit is contained in:
parent
7510788533
commit
0aacf3fcae
@ -29,7 +29,8 @@ SOURCES += QGLViewer/camera.cpp \
|
|||||||
src/viewer/simpleViewer.cpp \
|
src/viewer/simpleViewer.cpp \
|
||||||
src/glnodes/glnode.cpp \
|
src/glnodes/glnode.cpp \
|
||||||
src/glnodes/shapes.cpp \
|
src/glnodes/shapes.cpp \
|
||||||
src/glnodes/scenegroup.cpp
|
src/glnodes/scenegroup.cpp \
|
||||||
|
src/libs/OBJLoader.cpp
|
||||||
|
|
||||||
HEADERS += QGLViewer/camera.h \
|
HEADERS += QGLViewer/camera.h \
|
||||||
QGLViewer/config.h \
|
QGLViewer/config.h \
|
||||||
@ -49,7 +50,8 @@ HEADERS += QGLViewer/camera.h \
|
|||||||
src/glnodes/shapes.h \
|
src/glnodes/shapes.h \
|
||||||
src/interfaces/ivisitable.h \
|
src/interfaces/ivisitable.h \
|
||||||
src/interfaces/visitor.h \
|
src/interfaces/visitor.h \
|
||||||
src/glnodes/scenegroup.h
|
src/glnodes/scenegroup.h \
|
||||||
|
src/libs/OBJLoader.h
|
||||||
|
|
||||||
DISTFILES += src/shaders/basicShader.vert \
|
DISTFILES += src/shaders/basicShader.vert \
|
||||||
src/shaders/basicShader.frag \
|
src/shaders/basicShader.frag \
|
||||||
|
|||||||
436
src/libs/OBJLoader.cpp
Normal file
436
src/libs/OBJLoader.cpp
Normal file
@ -0,0 +1,436 @@
|
|||||||
|
#include "OBJLoader.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using namespace OBJLoader;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// 2D/3D point data structures
|
||||||
|
struct Point3D
|
||||||
|
{
|
||||||
|
Point3D() : x(0), y(0), z(0) {}
|
||||||
|
|
||||||
|
float x,y,z;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Point2D
|
||||||
|
{
|
||||||
|
Point2D() : x(0), y(0) {}
|
||||||
|
|
||||||
|
float x,y;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extract path from a string
|
||||||
|
std::string extractPath(const std::string& filepathname)
|
||||||
|
{
|
||||||
|
std::size_t pos = filepathname.find_last_of("/\\");
|
||||||
|
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
return std::string(".");
|
||||||
|
|
||||||
|
return filepathname.substr(0, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Constructors / Destructors
|
||||||
|
Loader::Loader()
|
||||||
|
: _isLoaded(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Loader::Loader(const std::string& filename)
|
||||||
|
: _isLoaded(false)
|
||||||
|
{
|
||||||
|
loadFile(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader::~Loader()
|
||||||
|
{}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Load file
|
||||||
|
bool Loader::loadFile(const std::string& filename)
|
||||||
|
{
|
||||||
|
// Clear current data
|
||||||
|
unload();
|
||||||
|
|
||||||
|
// Open the input file
|
||||||
|
std::ifstream file(filename, std::ifstream::in);
|
||||||
|
if (!file.is_open())
|
||||||
|
{
|
||||||
|
std::cout << "Error: Failed to open file " << filename << " for reading!" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract path. It will be useful later when loading the mtl file
|
||||||
|
std::string path = extractPath(filename);
|
||||||
|
|
||||||
|
// Create the default material
|
||||||
|
Material defaultMat;
|
||||||
|
defaultMat.Ka[0] = 1.0; defaultMat.Ka[1] = 1.0; defaultMat.Ka[2] = 1.0; defaultMat.Ka[3] = 1.0;
|
||||||
|
defaultMat.Ke[0] = 0.0; defaultMat.Ke[1] = 0.0; defaultMat.Ke[2] = 0.0; defaultMat.Ke[3] = 1.0;
|
||||||
|
defaultMat.Kd[0] = 1.0; defaultMat.Kd[1] = 1.0; defaultMat.Kd[2] = 1.0; defaultMat.Kd[3] = 1.0;
|
||||||
|
defaultMat.Ks[0] = 1.0; defaultMat.Ks[1] = 1.0; defaultMat.Ks[2] = 1.0; defaultMat.Ks[3] = 1.0;
|
||||||
|
defaultMat.Kn = 128;
|
||||||
|
defaultMat.name = "(Default)";
|
||||||
|
_materials.push_back(defaultMat);
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int currentMaterial = 0;
|
||||||
|
|
||||||
|
// Create default mesh (default group)
|
||||||
|
Mesh defaultMesh;
|
||||||
|
_meshes.push_back(defaultMesh);
|
||||||
|
|
||||||
|
unsigned int currentMesh = 0;
|
||||||
|
|
||||||
|
// Create vertices' position, normal, and uv lists with default values
|
||||||
|
std::vector<Point3D> vertices(1);
|
||||||
|
std::vector<Point3D> normals(1);
|
||||||
|
std::vector<Point2D> uvs(1);
|
||||||
|
|
||||||
|
// Read file
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(file, line))
|
||||||
|
{
|
||||||
|
if (line[0] == '#')
|
||||||
|
{
|
||||||
|
// Comments... just ignore the line
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (line[0] == 'v' && line[1] == ' ')
|
||||||
|
{
|
||||||
|
// Vertex! Add it to the list.
|
||||||
|
Point3D v;
|
||||||
|
std::stringstream ss(line.substr(2));
|
||||||
|
ss >> v.x >> v.y >> v.z;
|
||||||
|
vertices.push_back(v);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (line[0] == 'v' && line[1] == 'n')
|
||||||
|
{
|
||||||
|
// Normal! Add it to the list.
|
||||||
|
Point3D n;
|
||||||
|
std::stringstream ss(line.substr(3));
|
||||||
|
ss >> n.x >> n.y >> n.z;
|
||||||
|
normals.push_back(n);
|
||||||
|
}
|
||||||
|
else if (line[0] == 'v' && line[1] == 't')
|
||||||
|
{
|
||||||
|
// Tex coord! Add it to the list
|
||||||
|
Point2D uv;
|
||||||
|
std::stringstream ss(line.substr(3));
|
||||||
|
ss >> uv.x >> uv.y;
|
||||||
|
uvs.push_back(uv);
|
||||||
|
}
|
||||||
|
else if (line[0] == 'u')
|
||||||
|
{
|
||||||
|
// usemtl! First, get the material's name
|
||||||
|
std::string name;
|
||||||
|
std::string dummy;
|
||||||
|
std::stringstream ss(line);
|
||||||
|
ss >> dummy >> name;
|
||||||
|
|
||||||
|
// Find it, and attach it to the current mesh
|
||||||
|
currentMaterial = findMaterial(name);
|
||||||
|
_meshes[currentMesh].materialID = currentMaterial;
|
||||||
|
}
|
||||||
|
else if (line[0] == 'g')
|
||||||
|
{
|
||||||
|
// Group! Set it as the current mesh
|
||||||
|
std::string dummy;
|
||||||
|
std::string name;
|
||||||
|
std::stringstream ss(line);
|
||||||
|
ss >> dummy >> name;
|
||||||
|
|
||||||
|
currentMesh = getMesh(name);
|
||||||
|
_meshes[currentMesh].materialID = currentMaterial;
|
||||||
|
}
|
||||||
|
else if (line[0] == 'f')
|
||||||
|
{
|
||||||
|
// Face! First, get its vertices data
|
||||||
|
std::string vertexData;
|
||||||
|
std::string dummy;
|
||||||
|
std::stringstream ssLine(line.substr(2));
|
||||||
|
std::vector<unsigned int> vertexIDs;
|
||||||
|
std::vector<unsigned int> uvIDs;
|
||||||
|
std::vector<unsigned int> normalIDs;
|
||||||
|
while (std::getline(ssLine, vertexData, ' '))
|
||||||
|
{
|
||||||
|
unsigned int index = vertexIDs.size();
|
||||||
|
vertexIDs.push_back(0);
|
||||||
|
uvIDs.push_back(0);
|
||||||
|
normalIDs.push_back(0);
|
||||||
|
|
||||||
|
std::stringstream ss(vertexData);
|
||||||
|
std::string stringVal;
|
||||||
|
std::getline(ss, stringVal, '/');
|
||||||
|
std::stringstream ss2(stringVal);
|
||||||
|
ss2 >> vertexIDs[index];
|
||||||
|
|
||||||
|
std::getline(ss, stringVal, '/');
|
||||||
|
std::stringstream ss3(stringVal);
|
||||||
|
ss3 >> uvIDs[index];
|
||||||
|
|
||||||
|
std::getline(ss, stringVal, '/');
|
||||||
|
std::stringstream ss4(stringVal);
|
||||||
|
ss4 >> normalIDs[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create first triangle
|
||||||
|
if (vertexIDs.size() < 3)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (unsigned int i=0; i<3; ++i)
|
||||||
|
{
|
||||||
|
Vertex v;
|
||||||
|
v.position[0] = vertices[vertexIDs[i]].x;
|
||||||
|
v.position[1] = vertices[vertexIDs[i]].y;
|
||||||
|
v.position[2] = vertices[vertexIDs[i]].z;
|
||||||
|
|
||||||
|
v.normal[0] = normals[normalIDs[i]].x;
|
||||||
|
v.normal[1] = normals[normalIDs[i]].y;
|
||||||
|
v.normal[2] = normals[normalIDs[i]].z;
|
||||||
|
|
||||||
|
v.uv[0] = uvs[uvIDs[i]].x;
|
||||||
|
v.uv[1] = uvs[uvIDs[i]].y;
|
||||||
|
|
||||||
|
_meshes[currentMesh].vertices.push_back(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create subsequent triangles (1 per additional vertices)
|
||||||
|
// Note: These triangles are created using a triangle fan approach
|
||||||
|
for (unsigned int i=3; i<vertexIDs.size(); ++i)
|
||||||
|
{
|
||||||
|
// First vertex of triangle is always the first vertex that has been specified
|
||||||
|
Vertex v1;
|
||||||
|
v1.position[0] = vertices[vertexIDs[0]].x;
|
||||||
|
v1.position[1] = vertices[vertexIDs[0]].y;
|
||||||
|
v1.position[2] = vertices[vertexIDs[0]].z;
|
||||||
|
v1.normal[0] = normals[normalIDs[0]].x;
|
||||||
|
v1.normal[1] = normals[normalIDs[0]].y;
|
||||||
|
v1.normal[2] = normals[normalIDs[0]].z;
|
||||||
|
v1.uv[0] = uvs[uvIDs[0]].x;
|
||||||
|
v1.uv[1] = uvs[uvIDs[0]].y;
|
||||||
|
|
||||||
|
// Second vertex is the previous vertex
|
||||||
|
Vertex v2;
|
||||||
|
v2.position[0] = vertices[vertexIDs[i-1]].x;
|
||||||
|
v2.position[1] = vertices[vertexIDs[i-1]].y;
|
||||||
|
v2.position[2] = vertices[vertexIDs[i-1]].z;
|
||||||
|
v2.normal[0] = normals[normalIDs[i-1]].x;
|
||||||
|
v2.normal[1] = normals[normalIDs[i-1]].y;
|
||||||
|
v2.normal[2] = normals[normalIDs[i-1]].z;
|
||||||
|
v2.uv[0] = uvs[uvIDs[i-1]].x;
|
||||||
|
v2.uv[1] = uvs[uvIDs[i-1]].y;
|
||||||
|
|
||||||
|
// Third vertex is the current vertex
|
||||||
|
Vertex v3;
|
||||||
|
v3.position[0] = vertices[vertexIDs[i]].x;
|
||||||
|
v3.position[1] = vertices[vertexIDs[i]].y;
|
||||||
|
v3.position[2] = vertices[vertexIDs[i]].z;
|
||||||
|
v3.normal[0] = normals[normalIDs[i]].x;
|
||||||
|
v3.normal[1] = normals[normalIDs[i]].y;
|
||||||
|
v3.normal[2] = normals[normalIDs[i]].z;
|
||||||
|
v3.uv[0] = uvs[uvIDs[i]].x;
|
||||||
|
v3.uv[1] = uvs[uvIDs[i]].y;
|
||||||
|
|
||||||
|
// Add the triangle
|
||||||
|
_meshes[currentMesh].vertices.push_back(v1);
|
||||||
|
_meshes[currentMesh].vertices.push_back(v2);
|
||||||
|
_meshes[currentMesh].vertices.push_back(v3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (line[0] == 'm')
|
||||||
|
{
|
||||||
|
// Get file name
|
||||||
|
std::string filename;
|
||||||
|
std::string dummy;
|
||||||
|
std::stringstream ss(line);
|
||||||
|
ss >> dummy >> filename;
|
||||||
|
|
||||||
|
// Add path to filename
|
||||||
|
std::string pathname = path;
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
pathname.append("\\");
|
||||||
|
#else
|
||||||
|
pathname.append("/");
|
||||||
|
#endif
|
||||||
|
pathname.append(filename);
|
||||||
|
|
||||||
|
// Load file
|
||||||
|
loadMtlFile(pathname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything is loaded! Now remove empty meshes (this generally happens with the default group)
|
||||||
|
std::vector<Mesh>::iterator it = _meshes.begin();
|
||||||
|
while (it != _meshes.end())
|
||||||
|
{
|
||||||
|
if ((*it).vertices.size() == 0)
|
||||||
|
{
|
||||||
|
it = _meshes.erase(it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Close file
|
||||||
|
file.close();
|
||||||
|
_isLoaded = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Load material file
|
||||||
|
void Loader::loadMtlFile(const std::string& filename)
|
||||||
|
{
|
||||||
|
// Open the input file
|
||||||
|
std::ifstream file(filename, std::ifstream::in);
|
||||||
|
if (!file.is_open())
|
||||||
|
{
|
||||||
|
std::cout << "Error: Failed to open material file " << filename << " for reading!" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read file
|
||||||
|
std::string line;
|
||||||
|
unsigned int currentMaterial = 0;
|
||||||
|
while (std::getline(file, line))
|
||||||
|
{
|
||||||
|
if (line[0] == '#')
|
||||||
|
{
|
||||||
|
// Comments... just ignore this line
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (line[0] == 'n')
|
||||||
|
{
|
||||||
|
// newmtl! Create the new material
|
||||||
|
Material newMtl;
|
||||||
|
newMtl.Ka[0] = 0.0; newMtl.Ka[1] = 0.0; newMtl.Ka[2] = 0.0; newMtl.Ka[3] = 0.0;
|
||||||
|
newMtl.Ke[0] = 0.0; newMtl.Ke[1] = 0.0; newMtl.Ke[2] = 0.0; newMtl.Ke[3] = 0.0;
|
||||||
|
newMtl.Kd[0] = 0.0; newMtl.Kd[1] = 0.0; newMtl.Kd[2] = 0.0; newMtl.Kd[3] = 0.0;
|
||||||
|
newMtl.Ks[0] = 0.0; newMtl.Ks[1] = 0.0; newMtl.Ks[2] = 0.0; newMtl.Ks[3] = 0.0;
|
||||||
|
newMtl.Kn = 0;
|
||||||
|
|
||||||
|
// Get its name
|
||||||
|
std::string dummy;
|
||||||
|
std::stringstream ss(line);
|
||||||
|
ss >> dummy >> newMtl.name;
|
||||||
|
|
||||||
|
// Add it to the list and set as current material
|
||||||
|
currentMaterial = _materials.size();
|
||||||
|
_materials.push_back(newMtl);
|
||||||
|
}
|
||||||
|
else if (line[0] == 'N')
|
||||||
|
{
|
||||||
|
// Shininess
|
||||||
|
std::stringstream ss(line);
|
||||||
|
std::string dummy;
|
||||||
|
float shininess;
|
||||||
|
ss >> dummy >> shininess;
|
||||||
|
|
||||||
|
// Change from range [0, 1000] to range [0, 128]
|
||||||
|
shininess /= 1000.0;
|
||||||
|
shininess *= 128.0;
|
||||||
|
|
||||||
|
_materials[currentMaterial].Kn = shininess;
|
||||||
|
}
|
||||||
|
else if (line[0] == 'K')
|
||||||
|
{
|
||||||
|
Material& mat = _materials[currentMaterial];
|
||||||
|
std::string dummy;
|
||||||
|
std::stringstream ss(line);
|
||||||
|
|
||||||
|
if (line[1] == 'd')
|
||||||
|
{
|
||||||
|
// Diffuse coefficient
|
||||||
|
ss >> dummy >> mat.Kd[0] >> mat.Kd[1] >> mat.Kd[2];
|
||||||
|
mat.Kd[3] = 1.0f;
|
||||||
|
}
|
||||||
|
else if (line[1] == 's')
|
||||||
|
{
|
||||||
|
// Diffuse coefficient
|
||||||
|
ss >> dummy >> mat.Ks[0] >> mat.Ks[1] >> mat.Ks[2];
|
||||||
|
mat.Ks[3] = 1.0f;
|
||||||
|
}
|
||||||
|
else if (line[1] == 'a')
|
||||||
|
{
|
||||||
|
// Diffuse coefficient
|
||||||
|
ss >> dummy >> mat.Ka[0] >> mat.Ka[1] >> mat.Ka[2];
|
||||||
|
mat.Ka[3] = 1.0f;
|
||||||
|
}
|
||||||
|
else if (line[1] == 'e')
|
||||||
|
{
|
||||||
|
// Diffuse coefficient
|
||||||
|
ss >> dummy >> mat.Ke[0] >> mat.Ke[1] >> mat.Ke[2];
|
||||||
|
mat.Ke[3] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close file
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Find a material by its name
|
||||||
|
unsigned int Loader::findMaterial(const std::string& name)
|
||||||
|
{
|
||||||
|
unsigned int id = 0;
|
||||||
|
for (unsigned int i=0; i<_materials.size(); ++i)
|
||||||
|
{
|
||||||
|
const Material& mat = _materials[i];
|
||||||
|
if (mat.name.compare(name) == 0)
|
||||||
|
{
|
||||||
|
id = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Find a mesh by its name
|
||||||
|
unsigned int Loader::getMesh(const std::string& name)
|
||||||
|
{
|
||||||
|
unsigned int id = 0;
|
||||||
|
bool found = false;
|
||||||
|
for (unsigned int i=0; i<_meshes.size(); ++i)
|
||||||
|
{
|
||||||
|
const Mesh& mesh = _meshes[i];
|
||||||
|
if (mesh.name.compare(name) == 0)
|
||||||
|
{
|
||||||
|
id = i;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
Mesh newMesh;
|
||||||
|
newMesh.name = name;
|
||||||
|
|
||||||
|
id = _meshes.size();
|
||||||
|
_meshes.push_back(newMesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Clear data
|
||||||
|
void Loader::unload()
|
||||||
|
{
|
||||||
|
// Clear everything!
|
||||||
|
_meshes.clear();
|
||||||
|
_materials.clear();
|
||||||
|
_isLoaded = false;
|
||||||
|
}
|
||||||
67
src/libs/OBJLoader.h
Normal file
67
src/libs/OBJLoader.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#ifndef OBJLOADER_H
|
||||||
|
#define OBJLOADER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace OBJLoader
|
||||||
|
{
|
||||||
|
// Structure used to store a material's properties
|
||||||
|
struct Material
|
||||||
|
{
|
||||||
|
float Ka[4]; // Ambient color
|
||||||
|
float Ke[4]; // Emissive color
|
||||||
|
float Kd[4]; // Diffuse color
|
||||||
|
float Ks[4]; // Specular color
|
||||||
|
float Kn; // Specular exponent
|
||||||
|
|
||||||
|
std::string name; // Material's name
|
||||||
|
};
|
||||||
|
|
||||||
|
// Structure used to store a vertex
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
float position[3];
|
||||||
|
float normal[3];
|
||||||
|
float uv[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Structure used to store a mesh data.
|
||||||
|
// Each triplet of vertices forms a triangle.
|
||||||
|
struct Mesh
|
||||||
|
{
|
||||||
|
Mesh() : materialID(0), name("") {}
|
||||||
|
|
||||||
|
std::vector<Vertex> vertices;
|
||||||
|
unsigned int materialID;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Class responsible for loading all the meshes included in an OBJ file
|
||||||
|
class Loader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Loader();
|
||||||
|
Loader(const std::string& filename);
|
||||||
|
~Loader();
|
||||||
|
|
||||||
|
bool loadFile(const std::string& filename);
|
||||||
|
bool isLoaded() const { return _isLoaded; }
|
||||||
|
void unload();
|
||||||
|
|
||||||
|
const std::vector<Mesh>& getMeshes() const { return _meshes; }
|
||||||
|
const std::vector<Material>& getMaterials() const { return _materials; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void loadMtlFile(const std::string& filename);
|
||||||
|
unsigned int findMaterial(const std::string& name);
|
||||||
|
unsigned int getMesh(const std::string& name);
|
||||||
|
|
||||||
|
std::vector<Mesh> _meshes;
|
||||||
|
std::vector<Material> _materials;
|
||||||
|
|
||||||
|
bool _isLoaded;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OBJLOADER_H
|
||||||
@ -30,7 +30,7 @@ vec4 calcDirLight(vec4 tex, vec3 fPos, vec3 fNorm) {
|
|||||||
|
|
||||||
if(useNormalMap) {
|
if(useNormalMap) {
|
||||||
vec3 vNorm = texture(texNormal, texCoords).rgb;
|
vec3 vNorm = texture(texNormal, texCoords).rgb;
|
||||||
nfNormal = normalize(normalMatrix * vNorm);
|
nfNormal = -normalize(normalMatrix * vNorm);
|
||||||
} else {
|
} else {
|
||||||
nfNormal = normalize(fNorm);
|
nfNormal = normalize(fNorm);
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ vec4 calcPointLight(vec4 tex, vec3 fPos, vec3 fNorm, int i) {
|
|||||||
|
|
||||||
if(useNormalMap) {
|
if(useNormalMap) {
|
||||||
vec3 vNorm = texture(texNormal, texCoords).rgb;
|
vec3 vNorm = texture(texNormal, texCoords).rgb;
|
||||||
nfNormal = normalize(normalMatrix * vNorm);
|
nfNormal = -normalize(normalMatrix * vNorm);
|
||||||
} else {
|
} else {
|
||||||
nfNormal = normalize(fNorm);
|
nfNormal = normalize(fNorm);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,87 @@
|
|||||||
|
#version 400 core
|
||||||
|
uniform vec3 Kd;
|
||||||
|
uniform vec3 Ks;
|
||||||
|
uniform float Kn;
|
||||||
|
|
||||||
|
#version 400 core
|
||||||
|
uniform sampler2D texCol;
|
||||||
|
uniform sampler2D texNormal;
|
||||||
|
|
||||||
|
uniform vec3 lDirection;
|
||||||
|
uniform bool isPhong;
|
||||||
|
uniform vec3 pointLight[3];
|
||||||
|
uniform vec4 pointLightCol[3];
|
||||||
|
uniform mat3 normalMatrix;
|
||||||
|
|
||||||
|
in vec3 fNormal;
|
||||||
|
in vec3 fPosition;
|
||||||
|
|
||||||
|
out vec4 fColor;
|
||||||
|
|
||||||
|
|
||||||
|
vec4 calcDirLight(vec4 tex, vec3 fPos, vec3 fNorm) {
|
||||||
|
// Get lighting vectors
|
||||||
|
vec3 LightDirection = normalize(lDirection);
|
||||||
|
vec3 nviewDirection = normalize(fPos);
|
||||||
|
vec3 nfNormal;
|
||||||
|
|
||||||
|
// Compute diffuse component
|
||||||
|
float diff = 0.2*max(0.0, dot(nfNormal, -LightDirection));
|
||||||
|
|
||||||
|
// Compute specular component
|
||||||
|
vec3 Rl = reflect(LightDirection, nfNormal);
|
||||||
|
float spec = 0.2*pow(max(0.0, dot(/*normalMatrix */ Rl, nviewDirection)), 64);
|
||||||
|
|
||||||
|
// Compute ambient component
|
||||||
|
float amb = 0.2;
|
||||||
|
|
||||||
|
float mult = 1;//max(0.0, -LightDirection.y+1.5);
|
||||||
|
|
||||||
|
//return vec4(0);
|
||||||
|
return vec4(tex.xyz * (diff + amb + spec) * mult, tex.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 calcPointLight(vec4 tex, vec3 fPos, vec3 fNorm, int i) {
|
||||||
|
// Get lighting vectors
|
||||||
|
vec3 LightDirection = normalize(pointLight[i] + fPos);
|
||||||
|
// vec3 nfNormal = normalize(fNorm);
|
||||||
|
vec3 nviewDirection = normalize(fPos);
|
||||||
|
vec3 nfNormal;
|
||||||
|
|
||||||
|
// Attenuation
|
||||||
|
float distance = length(nviewDirection - pointLight[i] - fPos) / 3;
|
||||||
|
float attenuation = 0.5 + 1 / max(0.25, distance * distance);
|
||||||
|
|
||||||
|
// Compute diffuse component
|
||||||
|
float diff = 0.3 * max(0.0, dot(nfNormal, LightDirection));
|
||||||
|
|
||||||
|
// Compute specular component
|
||||||
|
vec3 Rl = reflect(-LightDirection, /*normalMatrix */ nfNormal);
|
||||||
|
float spec = 0.5 * pow(max(0.0, dot(Rl, nviewDirection)), 32);
|
||||||
|
|
||||||
|
// Compute ambient component
|
||||||
|
float amb = 0.2;
|
||||||
|
|
||||||
|
return vec4(pointLightCol[i].xyz * attenuation * (amb + diff + spec) * tex.xyz, pointLightCol[i].w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
vec4 texColor;
|
||||||
|
|
||||||
|
texColor = ifColor;
|
||||||
|
if(isPhong) {
|
||||||
|
// Get lighting vectors
|
||||||
|
vec3 LightDirection = normalize(lDirection);
|
||||||
|
vec3 nfNormal = normalize(fNormal);
|
||||||
|
vec3 nviewDirection = normalize(fPosition);
|
||||||
|
|
||||||
|
fColor = calcDirLight(texColor, fPosition, fNormal)
|
||||||
|
+ calcPointLight(texColor, fPosition, fNormal, 0)/4
|
||||||
|
+ calcPointLight(texColor, fPosition, fNormal, 1)/4
|
||||||
|
+ calcPointLight(texColor, fPosition, fNormal, 2)/4;
|
||||||
|
} else {
|
||||||
|
fColor = texColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
#version 400 core
|
||||||
|
uniform mat4 mvMatrix;
|
||||||
|
uniform mat4 projMatrix;
|
||||||
|
uniform mat3 normalMatrix;
|
||||||
|
uniform bool isPhong;
|
||||||
|
uniform vec3 lDirection;
|
||||||
|
|
||||||
|
uniform vec3 pointLight[3];
|
||||||
|
|
||||||
|
in vec4 vPosition;
|
||||||
|
in vec3 vNormal;
|
||||||
|
out vec3 fNormal;
|
||||||
|
out vec3 fPosition;
|
||||||
|
|
||||||
|
vec4 calcDirLight(vec4 eye, vec3 fPos, vec3 fNorm) {
|
||||||
|
// Get lighting vectors
|
||||||
|
vec3 LightDirection = normalize(lDirection);
|
||||||
|
vec3 nfNormal = normalize(fNorm);
|
||||||
|
vec3 nviewDirection = normalize(fPos);
|
||||||
|
|
||||||
|
// Compute diffuse component
|
||||||
|
float diff = 0.65 * max(0.0, dot(nfNormal, LightDirection));
|
||||||
|
|
||||||
|
// Compute specular component
|
||||||
|
//vec3 Rl = normalize(-LightDirection+2.0*nfNormal*dot(nfNormal,LightDirection));
|
||||||
|
|
||||||
|
vec3 Rl = reflect(-LightDirection, fNorm);
|
||||||
|
float spec = 0.1*pow(max(0.0, dot(Rl, nviewDirection)), 16);
|
||||||
|
|
||||||
|
// Compute ambient component
|
||||||
|
vec3 amb = vec3(0.1);
|
||||||
|
|
||||||
|
return vec4(amb + diff + spec, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 calcPointLight(vec4 eye, vec3 fPos, vec3 fNorm, int i) {
|
||||||
|
// Get lighting vectors
|
||||||
|
vec3 LightDirection = normalize(pointLight[i] - fPos);
|
||||||
|
vec3 nfNormal = normalize(fNorm);
|
||||||
|
vec3 nviewDirection = normalize(fPos);
|
||||||
|
|
||||||
|
// Attenuation
|
||||||
|
float distance = length(pointLight[i] - nviewDirection);
|
||||||
|
float attenuation = 1.0f / (distance * distance);
|
||||||
|
|
||||||
|
// Compute diffuse component
|
||||||
|
float diff = attenuation * 0.65 * max(0.0, dot(nfNormal, LightDirection));
|
||||||
|
|
||||||
|
// Compute specular component
|
||||||
|
vec3 Rl = normalize(-LightDirection+2.0*nfNormal*dot(nfNormal,LightDirection));
|
||||||
|
float spec = attenuation * 0.1*pow(max(0.0, dot(Rl, nviewDirection)), 16);
|
||||||
|
|
||||||
|
// Compute ambient component
|
||||||
|
vec3 amb = attenuation * vec3(0.1);
|
||||||
|
|
||||||
|
return 0.3 * vec4(amb + diff + spec, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
vec4 vEyeCoord = mvMatrix * vPosition;
|
||||||
|
gl_Position = projMatrix * vEyeCoord;
|
||||||
|
|
||||||
|
fPosition = vEyeCoord.xyz;
|
||||||
|
fNormal = normalMatrix*vNormal;
|
||||||
|
}
|
||||||
|
|
||||||
@ -24,12 +24,12 @@
|
|||||||
#include "../interfaces/visitor.h"
|
#include "../interfaces/visitor.h"
|
||||||
#include "../glnodes/scenegroup.h"
|
#include "../glnodes/scenegroup.h"
|
||||||
#include "../glnodes/shapes.h"
|
#include "../glnodes/shapes.h"
|
||||||
|
#include "../libs/OBJLoader.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include <qopengl.h>
|
#include <qopengl.h>
|
||||||
#include <QOpenGLShaderProgram>
|
#include <QOpenGLShaderProgram>
|
||||||
|
#include <QCoreApplication>
|
||||||
#include <qopengl.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
@ -93,6 +93,9 @@ void Viewer::cleanup()
|
|||||||
delete m_program;
|
delete m_program;
|
||||||
m_program = 0;
|
m_program = 0;
|
||||||
|
|
||||||
|
delete objShader;
|
||||||
|
objShader = 0;
|
||||||
|
|
||||||
// Delete buffers
|
// Delete buffers
|
||||||
glDeleteBuffers(NumBuffers, m_Buffers);
|
glDeleteBuffers(NumBuffers, m_Buffers);
|
||||||
glDeleteVertexArrays(NumVAOs, m_VAOs);
|
glDeleteVertexArrays(NumVAOs, m_VAOs);
|
||||||
@ -131,6 +134,58 @@ void Viewer::drawSkybox()
|
|||||||
glDrawArrays(GL_TRIANGLES, 0, 36);
|
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Viewer::loadToolObj() {
|
||||||
|
|
||||||
|
// Load the obj file
|
||||||
|
OBJLoader::Loader loader("../data/sonic_screwdriver.obj");
|
||||||
|
|
||||||
|
// Create a GL object for each mesh extracted from the OBJ file
|
||||||
|
const std::vector<OBJLoader::Mesh>& meshes = loader.getMeshes();
|
||||||
|
const std::vector<OBJLoader::Material>& materials = loader.getMaterials();
|
||||||
|
for (unsigned int i=0; i<meshes.size(); ++i)
|
||||||
|
{
|
||||||
|
if (meshes[i].vertices.size()==0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
MeshGL meshGL;
|
||||||
|
meshGL.numVertices = meshes[i].vertices.size();
|
||||||
|
|
||||||
|
// Set material properties of the mesh
|
||||||
|
const float *Kd = materials[meshes[i].materialID].Kd;
|
||||||
|
const float *Ks = materials[meshes[i].materialID].Ks;
|
||||||
|
|
||||||
|
meshGL.diffuse = QVector3D(Kd[0], Kd[1], Kd[2]);
|
||||||
|
meshGL.specular = QVector3D(Ks[0], Ks[1], Ks[2]);
|
||||||
|
meshGL.specularExponent = materials[meshes[i].materialID].Kn;
|
||||||
|
|
||||||
|
// Create its VAO and VBO object
|
||||||
|
glGenVertexArrays(1, &meshGL.vao);
|
||||||
|
glGenBuffers(1, &meshGL.vbo);
|
||||||
|
|
||||||
|
// Fill VBO with vertices data
|
||||||
|
GLsizei dataSize = meshes[i].vertices.size() * sizeof(OBJLoader::Vertex);
|
||||||
|
GLsizei stride = sizeof(OBJLoader::Vertex);
|
||||||
|
GLsizeiptr positionOffset = 0;
|
||||||
|
GLsizeiptr normalOffset = sizeof(OBJLoader::Vertex::position);
|
||||||
|
//GLsizeiptr uvOffset = normalOffset + sizeof(OBJLoader::Vertex::normal);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, meshGL.vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, dataSize, &meshes[i].vertices[0], GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
// Set VAO that binds the shader vertices inputs to the buffer data
|
||||||
|
glBindVertexArray(meshGL.vao);
|
||||||
|
|
||||||
|
glVertexAttribPointer(m_vPositionLoc, 3, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(positionOffset));
|
||||||
|
glEnableVertexAttribArray(m_vPositionLoc);
|
||||||
|
|
||||||
|
glVertexAttribPointer(m_vNormalLoc, 3, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(normalOffset));
|
||||||
|
glEnableVertexAttribArray(m_vNormalLoc);
|
||||||
|
|
||||||
|
// Add it to the list
|
||||||
|
_meshesGL.push_back(meshGL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Viewer::draw()
|
void Viewer::draw()
|
||||||
{
|
{
|
||||||
// Bind our vertex/fragment shaders
|
// Bind our vertex/fragment shaders
|
||||||
|
|||||||
@ -105,6 +105,7 @@ private:
|
|||||||
void initGeometries();
|
void initGeometries();
|
||||||
void initBuffers();
|
void initBuffers();
|
||||||
void deselect();
|
void deselect();
|
||||||
|
void loadToolObj();
|
||||||
PickedGeom pickGeom(int, int);
|
PickedGeom pickGeom(int, int);
|
||||||
|
|
||||||
void animate();
|
void animate();
|
||||||
@ -117,7 +118,8 @@ private:
|
|||||||
QOpenGLShaderProgram *colorPickerShaderProgram;
|
QOpenGLShaderProgram *colorPickerShaderProgram;
|
||||||
QOpenGLShaderProgram *textureRenderShaderprogram;
|
QOpenGLShaderProgram *textureRenderShaderprogram;
|
||||||
QOpenGLShaderProgram *skyboxRenderShaderProgram;
|
QOpenGLShaderProgram *skyboxRenderShaderProgram;
|
||||||
QOpenGLShaderProgram *m_program;
|
QOpenGLShaderProgram *m_program;
|
||||||
|
QOpenGLShaderProgram *objShader;
|
||||||
int m_vPositionLocation;
|
int m_vPositionLocation;
|
||||||
int m_texColor;
|
int m_texColor;
|
||||||
int m_texNormal;
|
int m_texNormal;
|
||||||
@ -220,6 +222,21 @@ private:
|
|||||||
double frame;
|
double frame;
|
||||||
|
|
||||||
void rotateSelected(RotateDirection);
|
void rotateSelected(RotateDirection);
|
||||||
|
|
||||||
|
// VAOs and VBOs
|
||||||
|
struct MeshGL
|
||||||
|
{
|
||||||
|
GLuint vao;
|
||||||
|
GLuint vbo;
|
||||||
|
|
||||||
|
QVector3D diffuse;
|
||||||
|
QVector3D specular;
|
||||||
|
GLfloat specularExponent;
|
||||||
|
|
||||||
|
unsigned int numVertices;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<MeshGL> _meshesGL;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SIMPLEVIEWER_H
|
#endif // SIMPLEVIEWER_H
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user