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/glnodes/glnode.cpp \
|
||||
src/glnodes/shapes.cpp \
|
||||
src/glnodes/scenegroup.cpp
|
||||
src/glnodes/scenegroup.cpp \
|
||||
src/libs/OBJLoader.cpp
|
||||
|
||||
HEADERS += QGLViewer/camera.h \
|
||||
QGLViewer/config.h \
|
||||
@ -49,7 +50,8 @@ HEADERS += QGLViewer/camera.h \
|
||||
src/glnodes/shapes.h \
|
||||
src/interfaces/ivisitable.h \
|
||||
src/interfaces/visitor.h \
|
||||
src/glnodes/scenegroup.h
|
||||
src/glnodes/scenegroup.h \
|
||||
src/libs/OBJLoader.h
|
||||
|
||||
DISTFILES += src/shaders/basicShader.vert \
|
||||
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) {
|
||||
vec3 vNorm = texture(texNormal, texCoords).rgb;
|
||||
nfNormal = normalize(normalMatrix * vNorm);
|
||||
nfNormal = -normalize(normalMatrix * vNorm);
|
||||
} else {
|
||||
nfNormal = normalize(fNorm);
|
||||
}
|
||||
@ -60,7 +60,7 @@ vec4 calcPointLight(vec4 tex, vec3 fPos, vec3 fNorm, int i) {
|
||||
|
||||
if(useNormalMap) {
|
||||
vec3 vNorm = texture(texNormal, texCoords).rgb;
|
||||
nfNormal = normalize(normalMatrix * vNorm);
|
||||
nfNormal = -normalize(normalMatrix * vNorm);
|
||||
} else {
|
||||
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 "../glnodes/scenegroup.h"
|
||||
#include "../glnodes/shapes.h"
|
||||
#include "../libs/OBJLoader.h"
|
||||
#include <math.h>
|
||||
|
||||
#include <qopengl.h>
|
||||
#include <QOpenGLShaderProgram>
|
||||
|
||||
#include <qopengl.h>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <iostream>
|
||||
#include <stack>
|
||||
@ -93,6 +93,9 @@ void Viewer::cleanup()
|
||||
delete m_program;
|
||||
m_program = 0;
|
||||
|
||||
delete objShader;
|
||||
objShader = 0;
|
||||
|
||||
// Delete buffers
|
||||
glDeleteBuffers(NumBuffers, m_Buffers);
|
||||
glDeleteVertexArrays(NumVAOs, m_VAOs);
|
||||
@ -131,6 +134,58 @@ void Viewer::drawSkybox()
|
||||
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()
|
||||
{
|
||||
// Bind our vertex/fragment shaders
|
||||
|
||||
@ -105,6 +105,7 @@ private:
|
||||
void initGeometries();
|
||||
void initBuffers();
|
||||
void deselect();
|
||||
void loadToolObj();
|
||||
PickedGeom pickGeom(int, int);
|
||||
|
||||
void animate();
|
||||
@ -118,6 +119,7 @@ private:
|
||||
QOpenGLShaderProgram *textureRenderShaderprogram;
|
||||
QOpenGLShaderProgram *skyboxRenderShaderProgram;
|
||||
QOpenGLShaderProgram *m_program;
|
||||
QOpenGLShaderProgram *objShader;
|
||||
int m_vPositionLocation;
|
||||
int m_texColor;
|
||||
int m_texNormal;
|
||||
@ -220,6 +222,21 @@ private:
|
||||
double frame;
|
||||
|
||||
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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user