Assimp can't load other textures except diffuse texture of FBX - c++

I try to load the FBX model in the last contains of this learnopengl tutorial, but I only can load diffuse texture of the FBX. I had tried the solution of adjusting the order of layout in vertex shader, but it didn't work. The result of material->GetTextureCount(type) is 0 when type isn't aiTextureType_DIFFUSE.
Here is my code:
mesh.h
#ifndef Mesh_h
#define Mesh_h
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "ReviewShader.h"
struct Vertex{
glm::vec3 Position;
glm::vec3 Normal;
glm::vec2 TexCoord;
};
struct Texture{
unsigned int id;
string type;
string path;
};
class Mesh{
public:
vector<Texture> textures;
vector<unsigned int> indices;
unsigned int VAO;
Mesh(vector<Vertex> vertices, vector<Texture> textures, vector<unsigned int> indices){
this->vertices = vertices;
this->textures = textures;
this->indices = indices;
setupMesh();
}
void Draw(ReviewShader shader){
int diffuseCount = 1;
int specularCount = 1;
int reflectionCount = 1;
shader.use();
for(int i = 0; i < textures.size(); i++){
string name = textures[i].type;
string num;
if(name == "texture_diffuse")
num = to_string(diffuseCount++);
else if(name == "texture_specular")
num = to_string(specularCount++);
else if(name == "texture_reflection")
num = to_string(reflectionCount++);
shader.setInt((name+num).c_str(), i);
glActiveTexture(GL_TEXTURE0+i);
glBindTexture(GL_TEXTURE_2D, textures[i].id);
}
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(0);
}
private:
vector<Vertex> vertices;
unsigned int VBO, EBO;
void setupMesh(){
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size(), &vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoord));
glEnableVertexAttribArray(2);
glBindVertexArray(0);
}
};
#endif /* Mesh_h */
model.h
#ifndef Model_h
#define Model_h
#include <iostream>
using namespace std;
#include <string>
#include <vector>
#include "Mesh.h"
#include "ReviewShader.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
//#define STB_IMAGE_IMPLEMENTATION
#include <stb-master/stb_image.h>
vector<Texture> loaded_textures;
class Model{
public:
vector<Mesh> meshes;
string directory;
Model(char *path){
loadModel(path);
}
void Draw(ReviewShader shader){
for(int i = 0; i < meshes.size(); i++){
meshes[i].Draw(shader);
}
}
private:
void loadModel(string path){
Assimp::Importer importer;
// const aiScene *scene = importer.ReadFile(path, aiProcess_FlipUVs | aiProcess_Triangulate);
const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);
if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode){
cout << "ERROR::ASSIMP::" << importer.GetErrorString() << endl;
return;
}
directory = path.substr(0, path.find_last_of("/"));
processNode(scene->mRootNode, scene);
}
void processNode(aiNode *node, const aiScene *scene){
for(int i = 0; i < node->mNumMeshes; i++){
aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
meshes.push_back(processMesh(mesh, scene));
}
for(int i = 0; i < node->mNumChildren; i++){
processNode(node->mChildren[i], scene);
}
}
Mesh processMesh(aiMesh *mesh, const aiScene *scene){
vector<Vertex> vertices;
vector<Texture> textures;
vector<unsigned int> indices;
for(int i = 0; i < mesh->mNumVertices; i++){
Vertex vertex;
glm::vec3 vector;
vector.x = mesh->mVertices[i].x;
vector.y = mesh->mVertices[i].y;
vector.z = mesh->mVertices[i].z;
vertex.Position = vector;
vector.x = mesh->mNormals[i].x;
vector.y = mesh->mNormals[i].y;
vector.z = mesh->mNormals[i].z;
vertex.Normal = vector;
if(mesh->mTextureCoords[0]){
glm::vec2 tex;
tex.x = mesh->mTextureCoords[0][i].x;
tex.y = mesh->mTextureCoords[0][i].y;
vertex.TexCoord = tex;
}
else{
vertex.TexCoord = glm::vec2(0.0, 0.0);
}
vertices.push_back(vertex);
}
for(int i = 0; i < mesh->mNumFaces; i++){
aiFace face = mesh->mFaces[i];
for(int j = 0; j < face.mNumIndices; j++){
indices.push_back(face.mIndices[j]);
}
}
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
vector<Texture> texture_diffuse = loadMaterialTexture(material, aiTextureType_DIFFUSE, "texture_diffuse");
textures.insert(textures.end(), texture_diffuse.begin(), texture_diffuse.end());
vector<Texture> texture_specular = loadMaterialTexture(material, aiTextureType_SPECULAR, "texture_specular");
textures.insert(textures.end(), texture_specular.begin(), texture_specular.end());
vector<Texture> texture_ambient = loadMaterialTexture(material, aiTextureType_SHININESS, "texture_reflection");
textures.insert(textures.end(), texture_ambient.begin(), texture_ambient.end());
return Mesh(vertices, textures, indices);
}
vector<Texture> loadMaterialTexture(aiMaterial *material, aiTextureType type, string Typename){
vector<Texture> textures;
cout << material->GetTextureCount(type) << endl;
for(int i = 0; i < material->GetTextureCount(type); i++){
bool skip = false;
aiString str;
material->GetTexture(type, i, &str);
string tempStr = str.C_Str();
tempStr.replace(tempStr.find("\\"), 1, "/");
cout << tempStr << endl;
for(int j = 0; j < loaded_textures.size(); j++){
if(strcmp(loaded_textures[j].path.c_str(), tempStr.c_str()) == 0){
skip = true;
textures.push_back(loaded_textures[i]);
break;
}
}
if(!skip){
Texture tex;
tex.id = loadTextureFromFile(tempStr, directory);
tex.type = Typename;
tex.path = str.C_Str();
textures.push_back(tex);
loaded_textures.push_back(tex);
}
}
return textures;
}
unsigned int loadTextureFromFile(string path, string &Directory){
unsigned int textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
string filepath = Directory + "/" + path;
int width, height, urChannel;
unsigned char *data = stbi_load(filepath.c_str(), &width, &height, &urChannel, 0);
if(data){
GLenum format;
if(urChannel == 1)
format = GL_RED;
if(urChannel == 3)
format = GL_RGB;
if(urChannel == 4)
format = GL_RGBA;
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);
}
else{
cout << "Read texture Data failed\n";
stbi_image_free(data);
}
return textureID;
}
};
#endif /* Model_h */
model.vs
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aNormal;
layout(location = 2) in vec2 aUV;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
out vec3 Normal;
out vec2 UV;
out vec3 Position;
void main(){
gl_Position = projection * view * model * vec4(aPos, 1.0);
UV = aUV;
Normal = mat3(transpose(inverse(model))) * aNormal;
Position = vec3(model * vec4(aPos, 1.0));
}
model.fs
#version 330 core
out vec4 FragColor;
uniform sampler2D texture_diffuse;
uniform sampler2D texture_specular;
uniform sampler2D texture_roughness;
in vec3 Normal;
in vec2 UV;
in vec3 Position;
void main(){
FragColor = texture(texture_diffuse, UV);
}
main.cpp
#include <...>
...
using namespace std;
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow *window);
unsigned int loadTexture(const char *path);
unsigned int loadHDRTexture(char const * path);
unsigned int loadCubemap(vector<string> faces);
void renderQuad();
void renderCube();
void renderPlane();
void renderSphere();
float lerp(float a, float b, float scale);
// size settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
glm::vec3 lightPos = glm::vec3(2.0, 4.0, -2.0);
glm::vec3 lightColor = glm::vec3(0.2, 0.2, 0.7);
// calculation parameter
const float Pi = 3.14159265359;
const float doublePi = Pi * 2.0;
// camera
Camera camera(glm::vec3(0.0f, 0.0f, 10.0f));
float lastX = (float)SCR_WIDTH / 2.0;
float lastY = (float)SCR_HEIGHT / 2.0;
bool firstMouse = true;
// timing
float deltaTime = 0.0f;
float lastFrame = 0.0f;
// texture normal
glm::vec3 normal(0.0, 0.0, 1.0);
// plane normal
glm::vec3 planeNormal = glm::vec3(0.0, 1.0, 0.0);
int main()
{
// glfw: initialize and configure
// ------------------------------
...
// Create shaders
...
ReviewShader modelShader("shader/model.vs", "shader/model.fs");
// pbr configure
...
Model gunModel = Model("Gun_Model/Cerberus_LP.FBX");
while(!glfwWindowShouldClose(window))
{
// avoid delay
// -----------
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
// process input
// -------------
processInput(window);
glViewport(0, 0, SCR_WIDTH * 2, SCR_HEIGHT * 2);
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 model = glm::mat4(1.0);
glm::mat4 view = camera.getViewMatrix();
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
modelShader.use();
model = glm::mat4(1.0);
model = glm::scale(model, glm::vec3(0.1));
model = glm::rotate(model, glm::radians(-90.0f), glm::vec3(1.0, 0.0, 0.0));
modelShader.setMat4("model", model);
modelShader.setMat4("view", view);
modelShader.setMat4("projection", projection);
gunModel.Draw(modelShader);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}

At first: which version of the Asset-Importer-Lib do you use? We made a lot of improvements in the FBX-Importer, so switching to the latest 5.0-release is strongly recommended.
Normally when the number of textures shows zero it is a sign that there is only one texture used in our model. To verify that yo can just use Blender, The interal Asset-Importer-Viewer or the Editor of the Godot-Engine to check that your model is right.
If there is more than just a diffuse-texture stored in your model please create a new issue report here: Assimp-Bugtracker . And please add a model which we can use to reproduce the issue. Thanks in advance!

Related

my simple OpenGL program can't draw a model load by assimp

I divide my code to two cpp files, one cpp contains main()function and another one contains model loading codes.
here's the first part
#define STB_IMAGE_IMPLEMENTATION
//OpenGL relations
#include "stb_image.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
//math and time
#include <math.h>
#include <cstdio>
#include <time.h>
#include <iostream>
//matrix
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
//
#include "modelload.h"
// const values here //
const char* defaultpath = "woodenbox.jpeg";
const char* cottagetex = "cottage.fbx";
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec2 aTexCoord;\n"
"out vec2 TexCoord;\n"
"uniform mat4 transform;\n"
"void main()\n"
"{\n"
" gl_Position = transform * vec4(aPos.x, aPos.y, aPos.z, 1.0f);\n"
" TexCoord = aTexCoord;\n"
"}\0";
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D ourTexture;\n"
"void main()\n"
"{\n"
" FragColor = texture(ourTexture, TexCoord);\n"
"}\n\0";
// functions here //
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void loadtexture(unsigned int& texture, const char* path = defaultpath) {
int width, height, nrChannels;
unsigned char* data = stbi_load(path, &width, &height, &nrChannels, 4);
glGenTextures(1, &texture);
//glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
}
void renderInit(unsigned int& shaderProgram) {
unsigned int vertexShader, fragmentShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
}
// main function //
int main(int argc, char* argv[])
{
//初始化glfw
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL-1", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
//渲染初始化,生成着色器程序、VAO、顶点初始数据
clock_t start, ends;
start = clock();
//build shader
unsigned int shaderProgram;
renderInit(shaderProgram);
unsigned int texture;
glGenTextures(1, &texture);
// 为当前绑定的纹理对象设置环绕、过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
loadtexture(texture);
model* ct1 = new model(cottagetex);
glm::mat4 ori_trans = glm::mat4(1.0f);
glm::mat4 view_trans = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f));//glm::translate(ori_trans, glm::vec3(0.0f, 0.0f, -3.0f));
glm::mat4 proj_trans = glm::perspective(glm::radians(45.0f), (float)(800 / 600), 0.1f, 100.0f);
glm::mat4 rotate_trans = glm::mat4(1.0f);
unsigned int count = 0;
float radius = 10.0f;
glEnable(GL_DEPTH_TEST);
// initialization completed
while (!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
float camX = sin(glfwGetTime()) * radius;
float camZ = cos(glfwGetTime()) * radius;
view_trans = glm::lookAt(glm::vec3(camX, 0.0, camZ), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
//glEnableVertexAttribArray(0);
glUseProgram(shaderProgram);
rotate_trans = proj_trans * view_trans * glm::rotate(ori_trans, glm::radians((float)((clock() - start) - cos(clock() - start) * 4) / 40), glm::vec3(1.0, 1.0, -1.0));
unsigned int transformLoc = glGetUniformLocation(shaderProgram, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(rotate_trans));
ct1->draw();
//glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
rotate_trans = glm::translate(proj_trans * view_trans, glm::vec3(1.0f, 1.0f, -3.0f));
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(rotate_trans));
ct1->draw();
//glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
//std::cout << count << " frame updated" << (float)-(0.25 + sin(clock() - start) / 4) << std::endl;
count++;
glfwSwapBuffers(window);
glfwPollEvents();
}
/*
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
*/
glDeleteProgram(shaderProgram);
glfwTerminate();
return 0;
}
and the second part
//OpenGL relations
#include <glad/glad.h>
#include <GLFW/glfw3.h>
//math and time
#include <math.h>
#include <vector>
#include <time.h>
#include <iostream>
//matrix
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
//assets
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
struct Vertex {
glm::vec3 Position;
glm::vec2 TexCoords;
glm::vec3 Normal;
};
class Mesh {
public:
/* 网格数据 */
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
//std::vector<unsigned int> textures;// materials
/* 函数 */
Mesh(std::vector<Vertex> vertices, std::vector<unsigned int> indices) {
this->vertices = vertices;
this->indices = indices;
}//, std::vector<unsigned int> textures
void Draw();
void setupMesh();
private:
/* 渲染数据 */
unsigned int VAO, VBO, EBO;
/* 函数 */
};
class model {
public:
model(const char* path);
void draw();
private:
std::vector<Mesh> meshes;
void processnode(aiNode* node, const aiScene* scene);
Mesh processmesh(aiMesh* mesh, const aiScene* scene);
// loadmaterials
};
#include "modelload.h"
//STL vector in namespace std
void Mesh::setupMesh() {
/*
for (int i = 0; i < vertices.size(); i++) {
std::cout<<vertices[i].Position.x<<std::endl;
}
*/
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//std::cout << sizeof(Vertex) << std::endl;
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
//glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(5 * sizeof(float)));
//glEnableVertexAttribArray(2);
//glBindVertexArray(0);// reload VAO before rendering
}
void Mesh::Draw() {
//std::cout << vertices.size() << std::endl; //vertices:988 indices:1434
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
}
model::model(const char* path) {
Assimp::Importer import;
const aiScene* scene = import.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
{
std::cout << "ERROR::ASSIMP::" << import.GetErrorString() << std::endl;
return;
}
processnode((scene->mRootNode), scene);
}
void model::processnode(aiNode* node, const aiScene* scene) {
for (int i = 0; i < node->mNumMeshes; i++) {
meshes.push_back(processmesh(scene->mMeshes[node->mMeshes[i]], scene));
meshes.back().setupMesh();
}
for (int i = 0; i < node->mNumChildren; i++) {
processnode(node->mChildren[i], scene);
}
}
Mesh model::processmesh(aiMesh* mesh, const aiScene* scene) {
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
for (int i = 0; i < (mesh->mNumVertices); i++) {
Vertex tvertex;
tvertex.Position.x = mesh->mVertices[i].x/3;
tvertex.Position.y = mesh->mVertices[i].y/3;
tvertex.Position.z = mesh->mVertices[i].z/3;
tvertex.Normal.x = mesh->mNormals[i].x;
tvertex.Normal.y = mesh->mNormals[i].y;
tvertex.Normal.z = mesh->mNormals[i].z;
tvertex.TexCoords.x = mesh->mTextureCoords[0][i].x;
tvertex.TexCoords.y = mesh->mTextureCoords[0][i].y;
vertices.push_back(tvertex);
//std::cout << tvertex.Position.x<<" "<< tvertex.Position.y<<" "<< tvertex.Position.z << std::endl;
//std::cout << tvertex.TexCoords.x << " " << tvertex.TexCoords.y << std::endl;
}
for (unsigned int i = 0; i < mesh->mNumFaces; i++)
{
aiFace face = mesh->mFaces[i];
for (unsigned int j = 0; j < face.mNumIndices; j++)
indices.push_back(face.mIndices[j]);
}
return Mesh(vertices, indices);
}
void model::draw() {
for (int i = 0; i < meshes.size(); i++) {
//std::cout << i << std::endl;
meshes[i].Draw();
}
}
It can only draw the background color, but it works when I draw a model I made by myself like:
-0.5, -0.5f, 0.5f, 0.0f,0.0f,//left bottom front 0
-0.5, 0.5f, 0.5f, 0.0f,1.0f,//left ceil front 1
0.5, 0.5f, 0.5f, 1.0f,1.0f,//right ceil front 2
0.5, -0.5f, 0.5f, 1.0f,0.0f,//right bottom front 3
-0.5, -0.5f, -0.5f, 1.0f,0.0f,//left bottom behind 4
-0.5, 0.5f, -0.5f, 1.0f,1.0f,//left ceil behind 5
0.5, 0.5f, -0.5f, 0.0f,1.0f,//right ceil behind 6
0.5, -0.5f, -0.5f, 0.0f,0.0f//right bottom behind 7
};
unsigned int indices[] = { // note that we start from 0!
0, 1, 2,
0, 2, 3,
0, 4, 1,
1, 4, 5,
1, 2, 6,
1, 6, 5,
4, 5, 6,
4, 6, 7,
2, 3, 7,
2, 7, 6,
0, 3, 4,
4, 7, 3
};
I checked memory where the model data is, it seems like many same points was loaded.
enter image description here

Segmentation Fault: 11 On DrawElementsCall

In Mesh.h, I am getting a segmentation error: 11 in my draw function on the "glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);" function call.
I tried calling "glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)" after the VAO buffer was bound like some people suggested but it has not helped.
Modeloading.cpp:
// ModelLoading.cpp
// LightingTutorials
//
// Created by Roma Desai on 6/6/19.
// Copyright © 2019 Roma Desai. All rights reserved.
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "Camera.cpp"
#include <../include/Model.h>
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <iostream>
/*
int main () {
std::cout<<"hello";
}
*/
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
// camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
std::string loadShaderString (const char* file);
//object shaders
std::string temp1 = loadShaderString("../shaders/vertexShader7a.glsl");
const char* vertex_shader = temp1.c_str();
std::string temp2 = loadShaderString("../shaders/fragmentShader7a.glsl");
const char* fragment_shader = temp2.c_str();
int main()
{
// glfw: initialize and configure
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
#endif
// glfw window creation
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Window", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// start GLEW extension handler
glewExperimental = GL_TRUE;
glewInit();
// configure global opengl state
glEnable(GL_DEPTH_TEST);
// build and compile shaders
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vertex_shader, NULL);
glCompileShader(vs);
GLint status = GL_TRUE;
glGetShaderiv( vs, GL_COMPILE_STATUS, &status );
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fragment_shader, NULL);
glCompileShader(fs);
GLuint shader_program = glCreateProgram(); //creating joint shader program
glAttachShader(shader_program, fs);
glAttachShader(shader_program, vs);
glLinkProgram(shader_program);
// load models
Model ourModel("../model/nanosuit/nanosuit.obj", shader_program);
// render loop
while (!glfwWindowShouldClose(window))
{
// render
glClearColor(0.05f, 0.05f, 0.05f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shader_program);
// view/projection transformations
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glm::mat4 view = camera.GetViewMatrix();
glUniformMatrix4fv(glGetUniformLocation(shader_program,"projection"), 1, GL_FALSE, &projection[0][0]);
glUniformMatrix4fv(glGetUniformLocation(shader_program,"view"), 1, GL_FALSE, &view[0][0]);
// render the loaded model
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(0.0f, -1.75f, 0.0f)); // translate down
model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f)); // scale it down
glUniformMatrix4fv(glGetUniformLocation(shader_program,"model"), 1, GL_FALSE, &model[0][0]);
ourModel.Draw(shader_program);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
glfwSwapBuffers(window);
glfwPollEvents();
}
// glfw: terminate, clearing all previously allocated GLFW resources.
glfwTerminate();
return 0;
}
/* function for loading shader from text file */
std::string loadShaderString (const char* file) {
std::ifstream input(file);
return std::string(std::istreambuf_iterator<char>(input),
std::istreambuf_iterator<char>());
}
Model.h:
//
// Model.cpp
// LightingTutorials
//
// Created by Roma Desai on 6/6/19.
// Copyright © 2019 Roma Desai. All rights reserved.
//
#ifndef MODEL_H
#define MODEL_H
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
//#define STB_IMAGE_IMPLEMENTATION
#include <../include/stb_image.h>
#include <../include/Mesh.h>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <map>
#include <vector>
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <stdio.h>
/*
int main() {
std::cout << "hello";
}
*/
using namespace std;
unsigned int TextureFromFile(const char *path, const string &directory, bool gamma = false);
class Model
{
public:
// Model Data
vector<Texture> textures_loaded; // stores all the textures loaded so far, optimization to make sure textures aren't loaded more than once.
vector<Mesh> meshes;
string directory;
bool gammaCorrection;
GLuint shader;
// Functions
// constructor, expects a filepath to a 3D model.
Model(string const &path, GLuint shader, bool gamma = false) : gammaCorrection(gamma)
{
this->shader = shader;
loadModel(path);
}
// draws the model, and thus all its meshes
void Draw(GLuint shader)
{
for(unsigned int i = 0; i < meshes.size(); i++) {
meshes[i].Draw(shader);
}
}
private:
// Functions
// loads a model with supported ASSIMP extensions from file and stores the resulting meshes in the meshes vector.
void loadModel(string const &path)
{
// read file via ASSIMP
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);
// check for errors
if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // if is Not Zero
{
cout << "ERROR::ASSIMP:: " << importer.GetErrorString() << endl;
return;
}
// retrieve the directory path of the filepath
directory = path.substr(0, path.find_last_of('/'));
// process ASSIMP's root node recursively
processNode(scene->mRootNode, scene);
}
// processes a node in a recursive fashion. Processes each individual mesh located at the node and repeats this process on its children nodes (if any).
void processNode(aiNode *node, const aiScene *scene)
{
// process each mesh located at the current node
for(unsigned int i = 0; i < node->mNumMeshes; i++)
{
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
meshes.push_back(processMesh(mesh, scene));
}
for(unsigned int i = 0; i < node->mNumChildren; i++)
{
processNode(node->mChildren[i], scene);
}
}
Mesh processMesh(aiMesh *mesh, const aiScene *scene)
{
// data to fill
vector<Vertex> vertices;
vector<unsigned int> indices;
vector<Texture> textures;
// Walk through each of the mesh's vertices
for(unsigned int i = 0; i < mesh->mNumVertices; i++)
{
Vertex vertex;
glm::vec3 vector; // we declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to glm's vec3 class so we transfer the data to this placeholder glm::vec3 first.
// positions
vector.x = mesh->mVertices[i].x;
vector.y = mesh->mVertices[i].y;
vector.z = mesh->mVertices[i].z;
vertex.Position = vector;
// normals
vector.x = mesh->mNormals[i].x;
vector.y = mesh->mNormals[i].y;
vector.z = mesh->mNormals[i].z;
vertex.Normal = vector;
// texture coordinates
if(mesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
{
glm::vec2 vec;
// a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't
// use models where a vertex can have multiple texture coordinates so we always take the first set (0).
vec.x = mesh->mTextureCoords[0][i].x;
vec.y = mesh->mTextureCoords[0][i].y;
vertex.TexCoords = vec;
}
else {
vertex.TexCoords = glm::vec2(0.0f, 0.0f);
// tangent
vector.x = mesh->mTangents[i].x;
vector.y = mesh->mTangents[i].y;
vector.z = mesh->mTangents[i].z;
vertex.Tangent = vector;
// bitangent
vector.x = mesh->mBitangents[i].x;
vector.y = mesh->mBitangents[i].y;
vector.z = mesh->mBitangents[i].z;
vertex.Bitangent = vector;
vertices.push_back(vertex);
}
}
for(unsigned int i = 0; i < mesh->mNumFaces; i++)
{
aiFace face = mesh->mFaces[i];
for(unsigned int j = 0; j < face.mNumIndices; j++)
indices.push_back(face.mIndices[j]);
}
// process materials
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
// we assume a convention for sampler names in the shaders. Each diffuse texture should be named
// as 'texture_diffuseN' where N is a sequential number ranging from 1 to MAX_SAMPLER_NUMBER.
// Same applies to other texture as the following list summarizes:
// diffuse: texture_diffuseN
// specular: texture_specularN
// normal: texture_normalN
// 1. diffuse maps
vector<Texture> diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
// 2. specular maps
vector<Texture> specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
// 3. normal maps
std::vector<Texture> normalMaps = loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal");
textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
// 4. height maps
std::vector<Texture> heightMaps = loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_height");
textures.insert(textures.end(), heightMaps.begin(), heightMaps.end());
// return a mesh object created from the extracted mesh data
return Mesh(vertices, indices, textures, shader);
}
// checks all material textures of a given type and loads the textures if they're not loaded yet.
// the required info is returned as a Texture struct.
vector<Texture> loadMaterialTextures(aiMaterial *mat, aiTextureType type, string typeName)
{
vector<Texture> textures;
for(unsigned int i = 0; i < mat->GetTextureCount(type); i++)
{
aiString str;
mat->GetTexture(type, i, &str);
bool skip = false;
for(unsigned int j = 0; j < textures_loaded.size(); j++)
{
if(std::strcmp(textures_loaded[j].path.data(), str.C_Str()) == 0)
{
textures.push_back(textures_loaded[j]);
skip = true; // a texture with the same filepath has already been loaded, continue to next one. (optimization)
break;
}
}
if(!skip)
{ // if texture hasn't been loaded already, load it
Texture texture;
texture.id = TextureFromFile(str.C_Str(), this->directory);
texture.type = typeName;
texture.path = str.C_Str();
textures.push_back(texture);
textures_loaded.push_back(texture); // store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures.
}
}
return textures;
}
};
unsigned int TextureFromFile(const char *path, const string &directory, bool gamma)
{
string filename = string(path);
filename = directory + '/' + filename;
unsigned int textureID;
glGenTextures(1, &textureID);
int width, height, nrComponents;
unsigned char *data = stbi_load(filename.c_str(), &width, &height, &nrComponents, 0);
if (data)
{
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
}
else
{
std::cout << "Texture failed to load at path: " << path << std::endl;
stbi_image_free(data);
}
return textureID;
}
#endif
Mesh.h:
// Mesh.cpp
// LightingTutorials
// Created by Roma Desai on 6/6/19.
// Copyright © 2019 Roma Desai. All rights reserved.
#include <iostream>
#include <GL/glew.h>
#define GLFW_DLL
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
struct Vertex {
glm::vec3 Position;
glm::vec3 Normal;
glm::vec2 TexCoords;
glm::vec3 Tangent;
glm::vec3 Bitangent;
};
struct Texture {
unsigned int id;
std::string type;
std::string path;
};
class Mesh {
public:
/* Mesh Data */
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
std::vector<Texture> textures;
unsigned int VAO;
GLuint shader;
/* Functions */
Mesh(std::vector<Vertex> vertices, std::vector<unsigned int> indices, std::vector<Texture> textures, GLuint shader)
{
this->vertices = vertices;
this->indices = indices;
this->textures = textures;
this->shader = shader;
// set the vertex buffers/attribute pointers.
setupMesh();
}
void Draw(GLuint shader)
{
unsigned int diffuseNr = 1;
unsigned int specularNr = 1;
unsigned int normalNr = 1;
unsigned int heightNr = 1;
for(unsigned int i = 0; i < textures.size(); i++)
{
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;
if(name == "texture_diffuse") {
number = std::to_string(diffuseNr++);
}
else if(name == "texture_specular") {
number = std::to_string(specularNr++);
}
else if(name == "texture_normal") {
number = std::to_string(normalNr++); // transfer unsigned int to stream
}
else if(name == "texture_height") {
number = std::to_string(heightNr++);
}
//glUseProgram(shader);
glUniform1i(glGetUniformLocation(shader, (name + number).c_str()), i);
glBindTexture(GL_TEXTURE_2D, textures[i].id);
}
glActiveTexture(GL_TEXTURE0);
// draw mesh
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
private:
/* Render data */
unsigned int VBO, EBO;
/* Functions */
void setupMesh()
{
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int),
&indices[0], GL_STATIC_DRAW);
//find locations
GLint loc_pos = glGetAttribLocation(shader, "aPos" );
GLint loc_texCoords = glGetAttribLocation(shader, "aTexCoords" );
//std::cout << "apos position: " << loc_pos << " ";
//std::cout << "texCoords position: " << loc_texCoords << " ";
// vertex positions
glEnableVertexAttribArray(loc_pos);
glVertexAttribPointer(loc_pos, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
// vertex normals
//glEnableVertexAttribArray(1);
// glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
// vertex texture coords
glEnableVertexAttribArray(loc_texCoords);
glVertexAttribPointer(loc_texCoords, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
// vertex tangent
// glEnableVertexAttribArray(3);
// glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Tangent));
// vertex bitangent
//glEnableVertexAttribArray(4);
//glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Bitangent));
glBindVertexArray(0);
}
};
I read many posts online but I seem to be getting the same error despite having fixed implemented some of the changes.

Black window when render obj file in opengl

I used opengl in qt5 on ubuntu 18.4, i wanted to load a simple cube(store in an .obj file) and render it. I followed the tutorial here http://www.opengl-tutorial.org/beginners-tutorials/tutorial-7-model-loading/, but i got a black window at last. Here is my code, thank you very much:
myopengl.hpp
class MyOpenGL : public QOpenGLWidget, protected QOpenGLFunctions
{
public:
MyOpenGL(const QString& obj_file);
protected:
virtual void initializeGL() Q_DECL_OVERRIDE;
virtual void paintGL() Q_DECL_OVERRIDE;
virtual void resizeGL(int width, int height) Q_DECL_OVERRIDE;
void CheckGLerror();
private:
std::vector< glm::vec3 > vertices;
std::vector< glm::vec2 > uvs;
std::vector< glm::vec3 > normals;
/* Render data */
GLuint VAO, VBO, EBO;
};
myopengl.cpp
MyOpenGL ::MyOpenGL (const QString& obj_file) :
VAO(0),
VBO(0),
EBO(0)
{
std::vector< unsigned int > vertex_indices, uv_indices, normal_indices;
std::vector< glm::vec3 > temp_vertices;
std::vector< glm::vec2 > temp_uvs;
std::vector< glm::vec3 > temp_normals;
//parse obj file
QFile file(obj_file);
file.open(QFile::ReadOnly | QFile::Text);
QTextStream in(&file);
while(!in.atEnd()) {
QString line = in.readLine();
QStringList list = line.replace(",","").split(' ', QString::SkipEmptyParts);
if (list.size() >= 3) {
if (list.at(0) == "v") { //veertex
bool ok1, ok2, ok3;
float v1 = list.at(1).toFloat(&ok1);
float v2 = list.at(2).toFloat(&ok2);
float v3 = list.at(3).toFloat(&ok3);
if (ok1 && ok2 && ok3) {
glm::vec3 vertex;
vertex.x = v1;
vertex.y = v2;
vertex.z = v3;
temp_vertices.push_back(vertex);
}
} else if (list.at(0) == "vn") {
bool ok1, ok2, ok3;
float v1 = list.at(1).toFloat(&ok1);
float v2 = list.at(2).toFloat(&ok2);
float v3 = list.at(3).toFloat(&ok3);
if (ok1 && ok2 && ok3) {
glm::vec3 normal;
normal.x = v1;
normal.y = v2;
normal.z = v3;
temp_normals.push_back(normal);
}
} else if (list.at(0) == "vt") {
bool ok1, ok2;
float v1 = list.at(1).toFloat(&ok1);
float v2 = list.at(2).toFloat(&ok2);
if (ok1 && ok2) {
glm::vec2 uv;
uv.x = v1;
uv.y = v2;
temp_uvs.push_back(uv);
}
} else if (list.at(0) == "f") {
bool f_ok1, f_ok2, f_ok3;
bool t_ok1, t_ok2, t_ok3;
bool n_ok1, n_ok2, n_ok3;
unsigned int v_index1, v_index2, v_index3;
unsigned int t_index1, t_index2, t_index3;
unsigned int n_index1, n_index2, n_index3;
QStringList f_list = list.at(1).split('/');
if (f_list.size() >= 3) {
v_index1 = f_list.at(0).toUInt(&f_ok1);
if (f_ok1) {
v_index1 -= 1;
}
t_index1 = f_list.at(1).toUInt(&t_ok1);
if (t_ok1) {
t_index1 -= 1;
}
n_index1 = f_list.at(2).toUInt(&n_ok1);
if (n_ok1) {
n_index1 -= 1;
}
}
f_list = list.at(2).split('/');
if (f_list.size() >= 3) {
v_index2 = f_list.at(0).toUInt(&f_ok2);
if (f_ok2) {
v_index2 -= 1;
}
t_index2 = f_list.at(1).toUInt(&t_ok2);
if (t_ok2) {
t_index2 -= 1;
}
n_index2 = f_list.at(2).toUInt(&n_ok2);
if (n_ok2) {
n_index2 -= 1;
}
}
f_list = list.at(3).split('/');
if (f_list.size() >= 3) {
v_index3 = f_list.at(0).toUInt(&f_ok3);
if (f_ok3) {
v_index3 -= 1;
}
t_index3 = f_list.at(1).toUInt(&t_ok3);
if (t_ok3) {
t_index3 -= 1;
}
n_index3 = f_list.at(2).toUInt(&n_ok3);
if (n_ok3) {
n_index3 -= 1;
}
}
if (f_ok1 && f_ok2 && f_ok3 && n_ok1 && n_ok2 && n_ok3
&& t_ok1 && t_ok2 && t_ok3) {
vertex_indices.push_back(v_index1);
vertex_indices.push_back(v_index2);
vertex_indices.push_back(v_index3);
uv_indices.push_back(t_index1);
uv_indices.push_back(t_index2);
uv_indices.push_back(t_index3);
normal_indices.push_back(n_index1);
normal_indices.push_back(n_index2);
normal_indices.push_back(n_index3);
}
}
}
}
file.close();
for (unsigned int i = 0; i < vertex_indices.size(); ++i) {
glm::vec3 vertex = temp_vertices.at(vertex_indices.at(i));
vertices.push_back(vertex);
}
for (unsigned int i = 0; i < uv_indices.size(); ++i) {
glm::vec2 uv = temp_uvs.at(uv_indices.at(i));
uvs.push_back(uv);
}
for (unsigned int i = 0; i < normal_indices.size(); ++i) {
glm::vec3 normal = temp_normals.at(normal_indices.at(i));
normals.push_back(normal);
}
}
void MyOpenGL::initializeGL()
{
initializeOpenGLFunctions();
glClearColor(0.0,0.0,0.0,1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glEnable(GL_LIGHT0);
glewExperimental = GL_TRUE;
GLenum status = glewInit();
if (status != GLEW_OK)
{
glfwTerminate();
std::system("pause");
return;
}
glGenVertexArrays(1, &this->VAO);
glBindVertexArray(this->VAO);
glGenBuffers(1, &this->VBO);
glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(glm::vec3), &this->vertices[0], GL_STATIC_DRAW);
glBindVertexArray(0);
}
void MyOpenGL::resizeGL(int width, int height)
{
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-width/2,width/2,-height/2,height/2,-1,1);
glMatrixMode(GL_MODELVIEW);
}
void MyOpenGL::paintGL()
{
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
glDrawArrays(GL_TRIANGLES, 0, vertices.size());
glDisableVertexAttribArray(0);
}
You have to define an array of generic vertex attribute data by glVertexAttribPointer.
Note, the vertex buffer object is only a data store for the vertex data. But you have to specify how to "use" them. The specification and states of the vertex attributes are stored in the vertex array object. It is sufficient to bind the vertex array object when you want to draw the mesh:
specification:
glBindVertexArray(this->VAO);
glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
draw:
glBindVertexArray(this->VAO);
glDrawArrays(GL_TRIANGLES, 0, vertices.size());
glBindVertexArray(0);
Extension:
Is it essential to use vertex shader and fragment shader? I didn't use them for current.
If you don't have a shader, then you have to use the Fixed Function Pipeline and to define the fixed function attributes, by glVertexPointer respectively glEnableClientState( GL_VERTEX_ARRAY ).
But since you only use one attribute, the vertex coordiante with attribute index 0, you can still define the attribute by glVertexAttribPointer and glEnableVertexAttribArray.
See What are the Attribute locations for fixed function pipeline in OpenGL 4.0++ core profile?
Note, in this case you have to use a compatibility OpenGL Context.

OpenGL texture distortion on 3D model

I'm building a 3D model viewer in OpenGL 3.3 but I can't get my textures to show properly. I'm pretty sure the texcoords (coming from the object I'm loading) are correct.
This is my code:
main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "InputState.h"
#include "Viewer.h"
#include "Shader.hpp"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"
std::string folder = "cube-tex/";
std::string objPath = folder + "cube-tex.obj";
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::vector<GLuint> texID;
std::string meshMode = "WIREFRAME";
std::string lightMode = "DIRECTIONAL";
double startTime = glfwGetTime();
float initScale = 1;
float zoom = 0;
float xRot, yRot;
int winX = 500;
int winY = 500;
std::vector<unsigned int> vaoHandle;
ObjectViewer *ObjCam;
Viewer *Camera;
glm::vec3 cameraPos(0.0f, 0.0f, -10.0f);
// Data structure storing mouse input info
InputState Input;
unsigned int programID;
unsigned int debugShader;
unsigned int lightTexShader;
//
// Callbacks
//
void key_callback(GLFWwindow* window,
int key, int scancode, int action, int mods)
{
if (action == GLFW_PRESS) {
switch(key)
{
case GLFW_KEY_S:
if (programID == lightTexShader) {
programID = debugShader;
meshMode = "WIREFRAME";
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
else {
programID = lightTexShader;
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
break;
case GLFW_KEY_ESCAPE: // escape key pressed
glfwSetWindowShouldClose(window, GL_TRUE);
break;
case GLFW_KEY_D:
if(programID == debugShader){
if(meshMode == "WIREFRAME") {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
meshMode = "NORMAL";
}else if(meshMode == "NORMAL"){
meshMode = "MATERIAL";
}else{
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
meshMode = "WIREFRAME";
}
}
break;
case GLFW_KEY_L:
if(programID == lightTexShader){
if(lightMode == "DIRECTIONAL") {
lightMode = "HEADLIGHT";
}else if(lightMode == "HEADLIGHT"){
lightMode = "ROTATING";
}else{
lightMode = "DIRECTIONAL";
}
}
break;
default:
break;
}
}
}
// Set the projection matrix. Takes into account window aspect ratio, so called
// when the window is resized.
void setProjection(unsigned int id)
{
glm::mat4 projection;
projection = glm::perspective( (float)M_PI/3.0f, (float) winX / winY, 1.0f, 30.0f );
// Load it to the shader program
int projHandle = glGetUniformLocation(id, "projection");
if (projHandle == -1) {
std::cout << "Uniform: projection_matrix is not an active uniform label\n";
}
glUniformMatrix4fv( projHandle, 1, false, glm::value_ptr(projection) );
}
// Called when the window is resized.
void reshape_callback( GLFWwindow *window, int x, int y )
{
winX = x;
winY = y;
setProjection(programID);
glViewport( 0, 0, x, y );
}
void mouse_pos_callback(GLFWwindow* window, double x, double y)
{
// Use a global data structure to store mouse info
// We can then use it however we want
Input.update((float)x, (float)y);
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS) {
Input.rMousePressed = true;
}
else if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_RELEASE) {
Input.rMousePressed = false;
}
else if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
Input.lMousePressed = true;
}
else if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) {
Input.lMousePressed = false;
}
}
int setupLight()
{
// light position uniform
int lightposHandle = glGetUniformLocation(programID, "light_pos");
if (lightposHandle == -1) {
fprintf(stderr, "Error: can't find matrix uniforms\n");
exit(1);
}
// Uniform lighting variables
int lightambientHandle = glGetUniformLocation(programID, "light_ambient");
int lightdiffuseHandle = glGetUniformLocation(programID, "light_diffuse");
int lightspecularHandle = glGetUniformLocation(programID, "light_specular");
if ( lightambientHandle == -1 ||
lightdiffuseHandle == -1 ||
lightspecularHandle == -1) {
fprintf(stderr, "Error: can't find light uniform variables\n");
return 1;
}
float lightPos[4]; // light position //= { 0.0f, 10.0f, 0.0f, 1.0f };
float lightambient[3]; // ambient light components
float lightdiffuse[3]; // diffuse light components
float lightspecular[3]; // specular light components
if(lightMode == "DIRECTIONAL"){
lightambient[0] = 0.0f;
lightambient[1] = 0.0f;
lightambient[2] = 0.0f;
lightdiffuse[0] = 0.5f;
lightdiffuse[1] = 0.5f;
lightdiffuse[2] = 1.0f;
lightspecular[0] = 1.0f;
lightspecular[1] = 1.0f;
lightspecular[2] = 1.0f;
lightPos[0] = -10.0f;
lightPos[1] = -10.0f;
lightPos[2] = -10.0f;
lightPos[3] = 0.0f;
}else if(lightMode == "HEADLIGHT"){
lightambient[0] = 0.0f;
lightambient[1] = 0.0f;
lightambient[2] = 0.0f;
lightdiffuse[0] = 1.0f;
lightdiffuse[1] = 1.0f;
lightdiffuse[2] = 1.0f;
lightspecular[0] = 1.0f;
lightspecular[1] = 1.0f;
lightspecular[2] = 1.0f;
glm::mat3 rotMat(Camera->getViewMtx());
glm::vec3 d((Camera->getViewMtx())[3]);
glm::vec3 tmp = -d * rotMat;
lightPos[0] = tmp[0];
lightPos[1] = tmp[1];
lightPos[2] = tmp[2];
lightPos[3] = 1.0f;
}else if(lightMode == "ROTATING"){
lightambient[0] = 0.0f;
lightambient[1] = 0.0f;
lightambient[2] = 0.0f;
lightdiffuse[0] = 1.0f;
lightdiffuse[1] = 1.0f;
lightdiffuse[2] = 0.2f;
lightspecular[0] = 1.0f;
lightspecular[1] = 1.0f;
lightspecular[2] = 0.2f;
double now = glfwGetTime();
lightPos[0] = 10 * cos((now - startTime));
lightPos[1] = 0.0f;
lightPos[2] = 10 * sin((now - startTime));
lightPos[3] = 1.0f;
}
glUniform4fv(lightposHandle, 1, lightPos);
glUniform3fv(lightambientHandle, 1, lightambient);
glUniform3fv(lightdiffuseHandle, 1, lightdiffuse);
glUniform3fv(lightspecularHandle, 1, lightspecular);
return 0; // return success
}
void computeInitScale(){
float minX = 0;
float minY = 0;
float maxX = 0;
float maxY = 0;
for(int i = 0; i < shapes.size(); i++){
for(int j = 0; j < shapes[i].mesh.positions.size()/3; j++){
//max and min X
if(shapes[i].mesh.positions[3*j+0] > maxX){
maxX = shapes[i].mesh.positions[3*j+0];
}else if(shapes[i].mesh.positions[3*j+0] < minX){
minX = shapes[i].mesh.positions[3*j+0];
}
//max and min Y
if(shapes[i].mesh.positions[3*j+1] > maxY){
maxY = shapes[i].mesh.positions[3*j+1];
}else if(shapes[i].mesh.positions[3*j+1] < minY){
minY = shapes[i].mesh.positions[3*j+1];
}
}
}
initScale = 2 / std::max(maxX - minX, maxY - minY);
}
void loadRGBTexture(const char *path)
{
int x, y, n;
// Load from file. Force RGB image pixel format
unsigned char *data = stbi_load(path, &x, &y, &n, 3);
// Copy to GPU as data for the currently active texture.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, x, y, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
glGenerateMipmap(GL_TEXTURE_2D);
}
void setMaterials(int i){
// material
int mtlambientHandle = glGetUniformLocation(programID, "mtl_ambient");
int mtldiffuseHandle = glGetUniformLocation(programID, "mtl_diffuse");
int mtlspecularHandle = glGetUniformLocation(programID, "mtl_specular");
if (mtlambientHandle == -1 || mtldiffuseHandle == -1 || mtlspecularHandle == -1) {
fprintf(stderr, "Error: can't find material uniform variables\n");
}
float mtlambient[3];
mtlambient[0] = materials[shapes[i].mesh.material_ids[0]].ambient[0];
mtlambient[1] = materials[shapes[i].mesh.material_ids[0]].ambient[1];
mtlambient[2] = materials[shapes[i].mesh.material_ids[0]].ambient[2];
float mtldiffuse[3];
mtldiffuse[0] = materials[shapes[i].mesh.material_ids[0]].diffuse[0];
mtldiffuse[1] = materials[shapes[i].mesh.material_ids[0]].diffuse[1];
mtldiffuse[2] = materials[shapes[i].mesh.material_ids[0]].diffuse[2];
float mtlspecular[3];
mtlspecular[0] = materials[shapes[i].mesh.material_ids[0]].specular[0];
mtlspecular[1] = materials[shapes[i].mesh.material_ids[0]].specular[1];
mtlspecular[2] = materials[shapes[i].mesh.material_ids[0]].specular[2];
glUniform3fv(mtlambientHandle, 1, mtlambient);
glUniform3fv(mtldiffuseHandle, 1, mtldiffuse);
glUniform3fv(mtlspecularHandle, 1, mtlspecular);
}
void loadObj(){
std::string err;
bool ret = tinyobj::LoadObj(shapes, materials, err, objPath.c_str(), folder.c_str());
if (!err.empty()) {
std::cerr << err << std::endl;
}
if (!ret) {
exit(1);
}
std::cout << "# of shapes : " << shapes.size() << std::endl;
std::cout << "# of materials : " << materials.size() << std::endl;
for (size_t i = 0; i < shapes.size(); i++) {
printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
printf("Size of shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size());
printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
assert((shapes[i].mesh.indices.size() % 3) == 0);
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
printf(" idx[%ld] = %d, %d, %d. mat_id = %d\n", f, shapes[i].mesh.indices[3*f+0], shapes[i].mesh.indices[3*f+1], shapes[i].mesh.indices[3*f+2], shapes[i].mesh.material_ids[f]);
}
printf("shape[%ld].vertices: %ld\n", i, shapes[i].mesh.positions.size());
assert((shapes[i].mesh.positions.size() % 3) == 0);
for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++) {
printf(" v[%ld] = (%f, %f, %f)\n", v,
shapes[i].mesh.positions[3*v+0],
shapes[i].mesh.positions[3*v+1],
shapes[i].mesh.positions[3*v+2]);
}
}
for (size_t i = 0; i < materials.size(); i++) {
printf("material[%ld].name = %s\n", i, materials[i].name.c_str());
printf(" material.Ka = (%f, %f ,%f)\n", materials[i].ambient[0], materials[i].ambient[1], materials[i].ambient[2]);
printf(" material.Kd = (%f, %f ,%f)\n", materials[i].diffuse[0], materials[i].diffuse[1], materials[i].diffuse[2]);
printf(" material.Ks = (%f, %f ,%f)\n", materials[i].specular[0], materials[i].specular[1], materials[i].specular[2]);
printf(" material.Tr = (%f, %f ,%f)\n", materials[i].transmittance[0], materials[i].transmittance[1], materials[i].transmittance[2]);
printf(" material.Ke = (%f, %f ,%f)\n", materials[i].emission[0], materials[i].emission[1], materials[i].emission[2]);
printf(" material.Ns = %f\n", materials[i].shininess);
printf(" material.Ni = %f\n", materials[i].ior);
printf(" material.dissolve = %f\n", materials[i].dissolve);
printf(" material.illum = %d\n", materials[i].illum);
printf(" material.map_Ka = %s\n", materials[i].ambient_texname.c_str());
printf(" material.map_Kd = %s\n", materials[i].diffuse_texname.c_str());
printf(" material.map_Ks = %s\n", materials[i].specular_texname.c_str());
printf(" material.map_Ns = %s\n", materials[i].specular_highlight_texname.c_str());
std::map<std::string, std::string>::const_iterator it(materials[i].unknown_parameter.begin());
std::map<std::string, std::string>::const_iterator itEnd(materials[i].unknown_parameter.end());
for (; it != itEnd; it++) {
printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str());
}
printf("\n");
}
computeInitScale();
}
void createVAO()
{
for(int i = 0; i < shapes.size(); i++){
vaoHandle.push_back(0);
glGenVertexArrays(1, &vaoHandle[i]);
glBindVertexArray(vaoHandle[i]);
unsigned int buffer[5];
glGenBuffers(4, buffer);
// Set vertex attribute
glBindBuffer(GL_ARRAY_BUFFER, buffer[0]);
glBufferData(GL_ARRAY_BUFFER,
sizeof(float) * shapes[i].mesh.positions.size(), &shapes[i].mesh.positions[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Set vertex attribute
glBindBuffer(GL_ARRAY_BUFFER, buffer[1]);
glBufferData(GL_ARRAY_BUFFER,
sizeof(float) * shapes[i].mesh.normals.size(), &shapes[i].mesh.normals[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
// create material array
float diffuse[shapes[i].mesh.indices.size() * 3];
for(int j = 0; j<shapes[i].mesh.indices.size(); j++){
int index = j*3;
diffuse[index] = materials[shapes[i].mesh.material_ids[j/3]].diffuse[0];
diffuse[index + 1] = materials[shapes[i].mesh.material_ids[j/3]].diffuse[1];
diffuse[index + 2] = materials[shapes[i].mesh.material_ids[j/3]].diffuse[2];
}
// Set vertex attribute
glBindBuffer(GL_ARRAY_BUFFER, buffer[2]);
glBufferData(GL_ARRAY_BUFFER,
shapes[i].mesh.indices.size() * 3 * sizeof(float) , &diffuse[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Set element attributes. Notice the change to using GL_ELEMENT_ARRAY_BUFFER
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[3]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
sizeof(float) * shapes[i].mesh.indices.size(), &shapes[i].mesh.indices[0], GL_STATIC_DRAW);
// load textures
texID.push_back(0);
glGenTextures(1, &texID[i] );
glActiveTexture(GL_TEXTURE0);
glBindTexture( GL_TEXTURE_2D, texID[i] );
loadRGBTexture((folder + (std::string) materials[shapes[i].mesh.material_ids[0]].diffuse_texname).c_str());
// load texture coordinates
int texLoc = glGetAttribLocation(programID, "a_tex_coord");
glBindBuffer(GL_ARRAY_BUFFER, buffer[4]);
glBufferData(GL_ARRAY_BUFFER,
shapes[i].mesh.texcoords.size() * sizeof(float) , &shapes[i].mesh.texcoords[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(texLoc);
glVertexAttribPointer(texLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Un-bind
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
}
void render()
{
glUseProgram(programID);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
setProjection(programID);
Camera->update(Input);
glm::mat4 viewMatrix;
viewMatrix = Camera->getViewMtx();
// Load viex to the shader program
int viewHandle = glGetUniformLocation(programID, "view");
if (viewHandle == -1) {
std::cout << "Uniform: view is not an active uniform label\n";
}
glUniformMatrix4fv( viewHandle, 1, false, glm::value_ptr(viewMatrix) );
// Load the model matrix
int modelUniformHandle = glGetUniformLocation(programID, "model");
if (modelUniformHandle == -1)
exit(1);
// calculate zoom
if(Input.rMousePressed){
zoom += Input.yDiff/10;
if (zoom < 0) zoom = 0;
if (zoom > 1.5) zoom = 1.5;
}
glm::mat4 model;
model = glm::scale( model, glm::vec3(initScale + zoom, initScale + zoom, initScale + zoom));
glUniformMatrix4fv( modelUniformHandle, 1, false, glm::value_ptr(model) );
if (programID == debugShader){
// set colour mode
int modeHandle = glGetUniformLocation(programID, "mode");
if (modeHandle == -1) {
std::cout << "Uniform: mode is not an active uniform label\n";
}
if(meshMode == "MATERIAL"){
glUniform1i( modeHandle, 1);
}else{
glUniform1i( modeHandle, 0);
}
}else{
setupLight();
}
// Load meshes
for(int i = 0; i < shapes.size(); i++){
glBindVertexArray(vaoHandle[i]);
glDrawElements(GL_TRIANGLES, shapes[i].mesh.indices.size(), GL_UNSIGNED_INT, 0);
if (programID == lightTexShader){
setMaterials(i);
int texHandle = glGetUniformLocation(programID, "texMap");
if (texHandle == -1) {
fprintf(stderr, "Could not find uniform variables\n");
exit(1);
}
glBindTexture(GL_TEXTURE_2D, texID[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_NEAREST);
}
glBindVertexArray(0);
}
}
/**
* Error callback for GLFW. Simply prints error message to stderr.
*/
static void error_callback(int error, const char* description)
{
fputs(description, stderr);
}
int main (int argc, char **argv)
{
GLFWwindow* window;
glfwSetErrorCallback(error_callback);
if (!glfwInit()) {
exit(1);
}
// Specify that we want OpenGL 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Create the window and OpenGL context
window = glfwCreateWindow(winX, winY, "Modelling and viewing", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(1);
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
// Initialize GLEW
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
exit(1);
}
// load shaders
debugShader = LoadShaders("mview.vert", "mview.frag");
lightTexShader = LoadShaders("light-texture.vert", "light-texture.frag");
if (debugShader == 0 || lightTexShader == 0) {
exit(1);
}
programID = debugShader;
// Set OpenGL state we need for this application.
glClearColor(0.5F, 0.5F, 0.5F, 0.0F);
glEnable(GL_DEPTH_TEST);
glUseProgram(programID);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// Set up the scene and the cameras
//setProjection(debugShader);
//setProjection(lightTexShader);
loadObj();
createVAO();
ObjCam = new ObjectViewer( cameraPos );
Camera = ObjCam;
// Define callback functions and start main loop
glfwSetKeyCallback(window, key_callback);
glfwSetCursorPosCallback(window, mouse_pos_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback);
glfwSetFramebufferSizeCallback(window, reshape_callback);
while (!glfwWindowShouldClose(window))
{
render();
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
exit(0);
return 0;
}
Vertex shader
#version 330
uniform mat4 projection_matrix;
uniform mat4 modelview_matrix;
//uniform mat3 normal_matrix;
layout (location = 0) in vec3 a_vertex;
layout (location = 1) in vec3 a_normal;
layout (location = 2) in vec3 a_diffuse;
in vec2 a_tex_coord;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
//uniform int mode;
uniform vec3 mtl_diffuse;
out vec4 vertex; // vertex position in eye space
out vec3 normal; // the eye space normal
out vec2 st;
void main(void)
{
vertex = view * model * vec4(a_vertex, 1.0);
//normal = normalize(normal_matrix * a_normal);
normal = a_normal;
st = a_tex_coord;
gl_Position = projection * view * model * vec4(a_vertex, 1.0);
}
Fragment shader
#version 330
in vec4 vertex;
in vec3 normal;
in vec2 st;
out vec4 fragColour;
uniform sampler2D texMap;
uniform vec4 light_pos;
uniform vec3 light_ambient; // Light ambient RGBA values
uniform vec3 light_diffuse; // Light diffuse RGBA values
uniform vec3 light_specular; // Light specular RGBA values
uniform vec3 mtl_ambient; // Ambient surface colour
uniform vec3 mtl_diffuse; // Diffuse surface colour
uniform vec3 mtl_specular; // Specular surface colour
const float shininess = 32;
vec3 phongPointLight(in vec4 position, in vec3 norm)
{
vec3 s = normalize(vec3(light_pos - position));
if(light_pos.w == 0.0){
s = -normalize(light_pos.xyz);
}
vec3 v = normalize(-position.xyz);
vec3 r = reflect( -s, norm );
vec3 ambient = light_ambient * mtl_ambient;
// The diffuse component
float sDotN = max( dot(s,norm), 0.0 );
vec3 diffuse = light_diffuse * mtl_diffuse * sDotN;
// The specular component BLINN
vec3 spec = vec3(0.0);
vec3 halfwayDir = normalize(s + v);
if ( sDotN > 0.0 )
spec = light_specular * mtl_specular * pow(max(dot(normalize(normal), halfwayDir), 0.0), 32.0);
return ambient + diffuse + spec;
}
void main(void)
{
fragColour = vec4(phongPointLight(vertex, normalize(normal)), 1.0) * texture(texMap, st);
}
This is the result. As you can see the texture is not properly positioned on the car.

How to make one object "orbit" another object?

I'm currently working on a project involving two cubes. The first cube meant to be static, while the second is going to rotate, or orbit, around the first. I'm very new to OpenGL programming, so I'm having quite a bit of difficulty getting this to work. Can anyone point me in the right direction? So far, I just have two cubes, but I am unable to get them to move as if they were animated. Here is my code if you would like to offer suggestions. Thank you so much!
Main:
#include "vgl.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <vector>
#include "Box.h"
#include "Camera.h"
#include "VertexBufferData.h"
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>
using namespace std;
using namespace glm;
#define SPACEBAR_KEY 32
#define ESCAPE_KEY 033
Camera* camera;
vector<Box * > gameObjects;
bool keyDown[255];
void CheckKeyboard(){
if (keyDown['a'])
camera->RotateLeft();
if (keyDown['d'])
camera->RotateRight();
if (keyDown['w'])
camera->MoveForward();
if (keyDown['s'])
camera->MoveBackWard();
if (keyDown['e'])
camera->StrafeRight();
if (keyDown['q'])
camera->StrafeLeft();
}
void closeApp()
{
delete camera;
for (auto it = gameObjects.begin(); it != gameObjects.end(); ++it) {
delete (*it);
}
}
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case ESCAPE_KEY: // ASCII Escape Key Code
closeApp();
exit(EXIT_SUCCESS);
break;
default:
keyDown[key] = true;
}
glutPostRedisplay();
}
void keyboardUp(unsigned char key, int x, int y)
{
keyDown[key] = false;
}
void mouseWheel(int button, int direction, int x, int y)
{
if (button == 16)
camera->ResetFOV();
else if (direction > 0)
camera->ZoomIn();
else
camera->ZoomOut();
}
void mouseMovement(int x, int y)
{
static bool warp = true;
if (warp)
{
if (x>glutGet(GLUT_WINDOW_WIDTH) / 2)
camera->RotateRight();
else if (x<glutGet(GLUT_WINDOW_WIDTH) / 2)
camera->RotateLeft();
if (y>glutGet(GLUT_WINDOW_HEIGHT) / 2)
camera->RotateUp();
else if (y<glutGet(GLUT_WINDOW_HEIGHT) / 2)
camera->RotateDown();
glutWarpPointer(glutGet(GLUT_WINDOW_WIDTH) / 2, glutGet(GLUT_WINDOW_HEIGHT) / 2);
warp = false;
}
else
warp = true;
}
void timer(int value)
{
glutPostRedisplay();
glutTimerFunc(25, timer, 0);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
CheckKeyboard();
camera->Update();
for (auto it = gameObjects.begin(); it != gameObjects.end(); ++it) {
(*it)->shaderProgram->bindShader();
glm::mat4 MVP = camera->ProjectionMatrix * camera->ViewMatrix * (*it)->getModelMatrix();
(*it)->shaderProgram->sendUniform4x4("MVP", glm::value_ptr(MVP));
(*it)->Draw();
}
glutSwapBuffers();
}
void init()
{
int i = 0, forever = 0;
camera = new Camera();
memset(keyDown, false, sizeof(keyDown));
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
glutWarpPointer(glutGet(GLUT_WINDOW_WIDTH) / 2, glutGet(GLUT_WINDOW_HEIGHT) / 2);
glutSetCursor(GLUT_CURSOR_FULL_CROSSHAIR);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_CULL_FACE);
VertexBufferData vertexBufferData = VertexBufferData("Data\\Models\\Objects.xml");
gameObjects.push_back(new Box(vertexBufferData, glm::vec3(-2.0f, 0.0f, 0.0f), "Data\\Shaders\\Vertex.shader", "Data\\Shaders\\Fragment.shader"));
gameObjects.push_back(new Box(vertexBufferData, glm::vec3(2.0f, 0.0f, 0.0f), "Data\\Shaders\\Vertex.shader", "Data\\Shaders\\Fragment.shader"));
gameObjects[1]->setRotation(45.0f, vec3(0.0f, 0.0f, 1.0f));
gameObjects[0]->setScaleMatrix(vec3(2, 2, 2));
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(1024, 768);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutCreateWindow("Satterwhite_Project_3");
if (glewInit())
{
cerr << "Unable to init glew" << endl;
exit(EXIT_FAILURE);
}
init();
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutKeyboardUpFunc(keyboardUp);
glutPassiveMotionFunc(mouseMovement);
glutMouseWheelFunc(mouseWheel);
glutTimerFunc(25, timer, 0);
glutMainLoop();
return 0;
}
Box.cpp
#include "Box.h"
Box::Box(VertexBufferData &vbd, vec3 initialPosition,const string vertexShader, const string fragmentShader):GameObject(vertexShader, fragmentShader)
{
Position=initialPosition;
vertexBufferData =vbd;
RotationMatrix=mat4(1.0f);
OrbitMatrix = mat4(1.0f);
ScaleMatrix=mat4(1.0f);
TranslationMatrix =translate(glm::mat4(1.0f), Position);
if (!shaderProgram->initialize())
{
std::cerr << "Could not initialize the shaders" << std::endl;
}
shaderProgram->bindShader();
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vertexBufferData.verticiesSize, &vertexBufferData.verticies[0], GL_STATIC_DRAW);
glGenBuffers(1, &fragmentBuffer);
glBindBuffer(GL_ARRAY_BUFFER, fragmentBuffer);
glBufferData(GL_ARRAY_BUFFER, vertexBufferData.colorSize, &vertexBufferData.colors[0], GL_STATIC_DRAW);
shaderProgram->linkProgram();
}
void Box::setRotation(float degrees, vec3 axis)
{
RotationMatrix=rotate(glm::mat4(1.0f), degrees, axis);
RotationMatrix=rotate(RotationMatrix, degrees, vec3(1.0f,0.0f,0.0f));
}
void Box::setScaleMatrix(vec3 scale)
{
ScaleMatrix = glm::scale(mat4(1.0f), scale);
}
/*void Box::setOrbitMatrix(vec3 Position, vec3 axis)
{
OrbitMatrix =
}*/
void Box::Draw()
{
shaderProgram->bindShader();
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(0, 3, GL_FLOAT,GL_FALSE, 0, BUFFER_OFFSET(0));
glBindBuffer(GL_ARRAY_BUFFER, fragmentBuffer);
glVertexAttribPointer(1, 3, GL_FLOAT,GL_FALSE, 0, BUFFER_OFFSET(0));
glDrawArrays(GL_TRIANGLES, 0, vertexBufferData.verticies.size());
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
Box.h
#pragma once
#include "GameObject.h"
class Box : public GameObject
{
private:
mat4 ModelMatrix;
mat4 RotationMatrix;
mat4 OrbitMatrix;
mat4 TranslationMatrix;
mat4 ScaleMatrix;
public:
void Draw();
virtual ObjectType getType() const { return BOX; }
mat4 getModelMatrix() {return TranslationMatrix*RotationMatrix*ScaleMatrix;}
mat4 getMRotationMatrix() {return RotationMatrix;}
mat4 getTranslationMatrix() {return TranslationMatrix;}
mat4 getOrbitMatrix(){ return OrbitMatrix; }
mat4 getScaleMatrix() {return ScaleMatrix;}
void setRotation(float degrees, vec3 axis);
void setScaleMatrix(vec3 scale);
void setOrbitMatrix(vec3 Position, vec3 axis);
Box(VertexBufferData &vertexBufferData, vec3 initialPosition, const string vertexShader, const string fragmentShader);
vec3 Position;
mat4 rot;
mat4 scale;
};