WIP Obj Loader

This commit is contained in:
Riku Avelar 2016-12-02 16:25:43 -05:00
parent 7510788533
commit 0aacf3fcae
8 changed files with 739 additions and 7 deletions

View File

@ -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
View 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
View 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

View File

@ -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);
} }

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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

View File

@ -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();
@ -118,6 +119,7 @@ private:
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