How can I use multiple shader in my renderer? - c++

I am trying to make my renderer able to use either default or custom shader.
class Renderer
{
public:
void Create()
{
//Setup vao, vbo, ebo, quad indices, add data to ebo,
//create default Shader
//set camera projection
}
void Map()
{
vertexData = (VertexData*)glMapBufferRange(...);
}
void Draw(Rectangle destRect, Rectangle texCoordRect, Texture* texture)
{
//4 times for 4 different corners
float textureSlot = FindTexture(texture);
AddDataToMappedBuffer(position, texCoords, textureSlot, color);
indexCount += 6;
}
void Unmap()
{
glUnmapBuffer(...);
}
void Render()
{
Unmap();
shader.UniformMatrix4fv("projection", camera.getProjection());
for(uint i = 0; i < texture.size(); ++i)
{
texture[i]->Bind(i);
}
BindVAO();
DrawElements(TRIANGELS, indexCount, UNSIGNED_INT, nullptr);
UnbindVAO();
For(uint i = 0; i < texture.size(); ++i)
{
texture[i]->Unbind(i);
}
indexCount = 0;
texture.clear();
}
float Renderer2D::FindTexture(Texture* t)
{
float result = 0.0f;
bool found = false;
for (uint i = 0; i < texture.size(); ++i) {
if (texture[i] == t) {
result = static_cast<float>(i + 1);
found = true;
break;
}
}
if (!found) {
if (texture.size() >= MAX_TEXTURES) {
Render();
Map();
}
texture.push_back(t);
result = static_cast<float>(texture.size());
}
return result;
}
private:
std::vector<Texture*> texture;
uint vao, vbo, ebo;
VertexData* vertexData;
float FindTexture(Texture*);
Shader shader;
Camera2D camera;
};
int main()
{
Renderer renderer;
renderer.Create();
while(!quit)
{
//Clear color etc.
renderer.Map();
renderer.Draw(Rectangle(0.0f, 0.0f, 500.0f, 500.0f), Rectangle(0.0f, 0.0f, 1.0f, 1.0f), texture("sometexture.png"));
renderer.Render();
}
}
that is how it works right now.
I would like my renderer to be like this:
in Draw method set shader
check if this shader is in an array
if it is, do not do another draw call - use shader which is already in an array
if it is not, add this shader to an array, use it and do another draw call
I tried to do method which find shader - similar to texture - and go through all shaders and use them. It do not do exactly what I want.
std::vector<Shader*> shader;
void Renderer2D::FindShader(Shader* sh)
{
bool found = false;
for (uint i = 0; i < shader.size(); ++i) {
if (shader[i] == sh) {
found = true;
return;
}
}
if (!found) {
shader.push_back(sh);
Render();
Map();
}
}
void Render()
{
Unmap();
for(const auto& shader : shader)
{
shader->UseProgram();
shader.UniformMatrix4fv("projection", camera.getProjection());
}
for(uint i = 0; i < texture.size(); ++i)
{
texture[i]->Bind(i);
}
BindVAO();
DrawElements(TRIANGELS, indexCount, UNSIGNED_INT, nullptr);
UnbindVAO();
For(uint i = 0; i < texture.size(); ++i)
{
texture[i]->Unbind(i);
}
indexCount = 0;
texture.clear();
}
void Draw(Rectangle destRect, Rectangle texCoordRect, Texture* texture, Shader* shader)
{
FindShader(shader);
float textureSlot = FindTexture(texture);
AddDataToMappedBuffer(position, texCoords, textureSlot, color);
indexCount += 6;
}
I have also tried to find shader without doing another draw call when shader is not found - only add it to an array - and in render method loop through all shaders and do draw call. It also did not work well.
How should I do it?

Related

Getting vertices from a skeletal model with Assimp and DirectX C++

What I have is some code that I have got from trying to reverse engineer model loading code, because all the instructions that I have seen show how to transform the vertex positions in the shader and adapt the code to that. At first, I didn't know how I would store the information that needs to be loaded in because there are a few ways to do it. I finally just store bone IDs with their weights and pushed a vector for each mesh. The reason why I am writing code like this is that I want vertex positions from my model while I am animating it. This is something that I need for, some physics that I want to apply. I am not sure I got everything right because I am looking at OpenGL and using DirectX and some of the functions, I need I do not know what they are called. Here is my code.
//SkinMesh.h
#pragma once
#include "Vertex.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "ConstantBuffer.h"
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include "Texture.h"
//#include <vector>
struct BoneMatrix
{
aiMatrix4x4 offset_matrix;
aiMatrix4x4 final_world_transform;
//glm::mat4 offset_matrix;
//glm::mat4 final_world_transform;
};
struct pasvars {
std::vector<Vertex> vertices;
std::vector<DWORD> indices;
};
class SkinMesh
{
public:
SkinMesh(ID3D11Device* device, ID3D11DeviceContext* deviceContext, std::vector<Vertex>& vertices, std::vector<DWORD>& indices, std::vector<Texture>& textures, const DirectX::XMMATRIX& transformMatrix);
SkinMesh(const SkinMesh& mesh);
void Draw();
const DirectX::XMMATRIX& GetTransformMatrix();
pasvars getVars();
DirectX::XMFLOAT4 vertPos(UINT vert);
void setVert(DirectX::XMFLOAT4 pos, UINT vert);
private:
std::vector<Vertex> vertices;
VertexBuffer<Vertex> vertexbuffer;
std::vector<DWORD> inducies;
IndexBuffer indexbuffer;
ID3D11DeviceContext* deviceContext;
std::vector<Texture> textures;
DirectX::XMMATRIX transformMatrix;
};
//SkinMesh.cpp
#include "SkinMesh.h"
SkinMesh::SkinMesh(ID3D11Device* device, ID3D11DeviceContext* deviceContext, std::vector<Vertex>& vertices, std::vector<DWORD>& indices, std::vector<Texture>& textures, const DirectX::XMMATRIX& transformMatrix)
{
this->deviceContext = deviceContext;
this->textures = textures;
this->transformMatrix = transformMatrix;
this->vertices = vertices;
this->inducies = indices;
//HRESULT hr = this->vertexbuffer.Initialize(device, vertices.data(), vertices.size());
//COM_ERROR_IF_FAILED(hr, "Failed to initialize vertex buffer for SkinMesh.");
//
//hr = this->indexbuffer.Initialize(device, indices.data(), indices.size());
//COM_ERROR_IF_FAILED(hr, "Failed to initialize index buffer for SkinMesh.");
}
SkinMesh::SkinMesh(const SkinMesh& SkinMesh)
{
this->deviceContext = SkinMesh.deviceContext;
this->inducies = SkinMesh.inducies;
this->vertices = SkinMesh.vertices;
this->textures = SkinMesh.textures;
this->transformMatrix = SkinMesh.transformMatrix;
}
void SkinMesh::Draw()
{
UINT offset = 0;
for (int i = 0; i < textures.size(); i++)
{
if (textures[i].GetType() == aiTextureType::aiTextureType_DIFFUSE)
{
this->deviceContext->PSSetShaderResources(0, 1, textures[i].GetTextureResourceViewAddress());
break;
}
}
this->deviceContext->IASetVertexBuffers(0, 1, this->vertexbuffer.GetAddressOf(), this->vertexbuffer.StridePtr(), &offset);
this->deviceContext->IASetIndexBuffer(this->indexbuffer.Get(), DXGI_FORMAT::DXGI_FORMAT_R32_UINT, 0);
this->deviceContext->DrawIndexed(this->indexbuffer.IndexCount(), 0, 0);
}
const DirectX::XMMATRIX& SkinMesh::GetTransformMatrix()
{
return this->transformMatrix;
}
pasvars SkinMesh::getVars() {
pasvars ret;
ret.indices = this->inducies;
ret.vertices = this->vertices;
return ret;
}
DirectX::XMFLOAT4 SkinMesh::vertPos(UINT vert) {
return DirectX::XMFLOAT4(vertices.at(vert).pos.x, vertices.at(vert).pos.y, vertices.at(vert).pos.z, 1.0f);
}
void SkinMesh::setVert(DirectX::XMFLOAT4 pos, UINT vert) {
vertices.at(vert).pos.x = pos.x;
vertices.at(vert).pos.y = pos.y;
vertices.at(vert).pos.z = pos.z;
}
//SkinModel.h
#pragma once
#include "VertexBoneData.h"
#include <DirectXMath.h>
#include "SkinMesh.h"
#include <string>
#include <map>
using namespace std;
using namespace DirectX;
struct BoneAndWeight {
vector<UINT> boneIdx;
vector<float> weights;
};
struct BoneToMesh {
UINT meshNum;
vector<UINT> vertIdx;
vector<float> weights;
XMMATRIX boneMatrix;
};
struct BoneData {
vector<BoneAndWeight> access;
string name;
};
struct BoneMat {
XMMATRIX final;
XMMATRIX offset;
};
class SkinModel
{
public:
bool Initialize(const std::string& filePath, ID3D11Device* device, ID3D11DeviceContext* deviceContext, ConstantBuffer<CB_VS_vertexshader>& cb_vs_vertexshader);
void Draw(const XMMATRIX& worldMatrix, const XMMATRIX& viewProjectionMatrix);
void Transform();
private:
void getzero();
XMMATRIX zeroed;
void readNodeHierarchy(const aiNode* p_node, const XMMATRIX parent_transform);
XMMATRIX global_inverse;
map<string, UINT> m_bone_mapping;
std::vector<SkinMesh> meshes;
std::vector<SkinMesh> transformed;
bool LoadModel(const std::string& filePath);
void ProcessNode(aiNode* node, const aiScene* scene, const XMMATRIX& parentTransformMatrix);
SkinMesh ProcessMesh(aiMesh* mesh, const aiScene* scene, const XMMATRIX& transformMatrix);
TextureStorageType DetermineTextureStorageType(const aiScene* pScene, aiMaterial* pMat, unsigned int index, aiTextureType textureType);
std::vector<Texture> LoadMaterialTextures(aiMaterial* pMaterial, aiTextureType textureType, const aiScene* pScene);
int GetTextureIndex(aiString* pStr);
vector<UINT> meshinfo;
ID3D11Device* device = nullptr;
ID3D11DeviceContext* deviceContext = nullptr;
ConstantBuffer<CB_VS_vertexshader>* cb_vs_vertexshader = nullptr;
std::string directory = "";
UINT m_num_bones = 0;
int meshIndex = 0;
const aiNode* rootNode;
vector<BoneData> theBones;
vector<VertexBoneData> bones_id_weights;
vector<XMFLOAT3> boneRotations;
vector<BoneMat> m_bone_matrices;
//vector<MeshInfo> m_mesh_infos;
};
//SkinModel.cpp
#include "SkinModel.h"
bool SkinModel::Initialize(const std::string& filePath, ID3D11Device* device, ID3D11DeviceContext* deviceContext, ConstantBuffer<CB_VS_vertexshader>& cb_vs_vertexshader)
{
getzero();
this->device = device;
this->deviceContext = deviceContext;
this->cb_vs_vertexshader = &cb_vs_vertexshader;
try
{
if (!this->LoadModel(filePath))
return false;
}
catch (COMException& exception)
{
ErrorLogger::Log(exception);
return false;
}
return true;
}
void SkinModel::Draw(const XMMATRIX& worldMatrix, const XMMATRIX& viewProjectionMatrix)
{
this->deviceContext->VSSetConstantBuffers(0, 1, this->cb_vs_vertexshader->GetAddressOf());
for (int i = 0; i < transformed.size(); i++)
{
//Update Constant buffer with WVP Matrix
this->cb_vs_vertexshader->data.mat = meshes[i].GetTransformMatrix() * worldMatrix * viewProjectionMatrix; //Calculate World-View-Projection Matrix
this->cb_vs_vertexshader->data.mat = XMMatrixTranspose(this->cb_vs_vertexshader->data.mat);
this->cb_vs_vertexshader->ApplyChanges();
transformed[i].Draw();
}
}
bool SkinModel::LoadModel(const std::string& filePath)
{
this->directory = StringHelper::GetDirectoryFromPath(filePath);
Assimp::Importer importer;
const aiScene* pScene = importer.ReadFile(filePath,
aiProcess_Triangulate |
aiProcess_ConvertToLeftHanded);
if (pScene == nullptr)
return false;
rootNode = pScene->mRootNode;
global_inverse = XMMatrixTranspose(XMMATRIX(&pScene->mRootNode->mTransformation.a1));
//global_inverse = XMMatrixInverse(); // I dont know how to get an inverse in DirectX.
this->ProcessNode(pScene->mRootNode, pScene, DirectX::XMMatrixIdentity());
transformed.resize(meshes.size());
return true;
}
void SkinModel::ProcessNode(aiNode* node, const aiScene* scene, const XMMATRIX& parentTransformMatrix)
{
vector<VertexBoneData> bones_id_weights;
XMMATRIX nodeTransformMatrix = XMMatrixTranspose(XMMATRIX(&node->mTransformation.a1)) * parentTransformMatrix;
for (UINT i = 0; i < node->mNumMeshes; i++)
{
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
meshes.push_back(this->ProcessMesh(mesh, scene, nodeTransformMatrix));
}
for (UINT i = 0; i < node->mNumChildren; i++)
{
this->ProcessNode(node->mChildren[i], scene, nodeTransformMatrix);
}
}
SkinMesh SkinModel::ProcessMesh(aiMesh* mesh, const aiScene* scene, const XMMATRIX& transformMatrix)
{
vector<BoneAndWeight> bwstor;
bwstor.resize(mesh->mNumVertices);
// Data to fill
std::vector<Vertex> vertices;
std::vector<DWORD> indices;
//Get vertices
for (UINT i = 0; i < mesh->mNumVertices; i++)
{
Vertex vertex;
vertex.pos.x = mesh->mVertices[i].x;
vertex.pos.y = mesh->mVertices[i].y;
vertex.pos.z = mesh->mVertices[i].z;
if (mesh->mTextureCoords[0])
{
vertex.texCoord.x = (float)mesh->mTextureCoords[0][i].x;
vertex.texCoord.y = (float)mesh->mTextureCoords[0][i].y;
}
vertices.push_back(vertex);
}
//Get indices
for (UINT i = 0; i < mesh->mNumFaces; i++)
{
aiFace face = mesh->mFaces[i];
for (UINT j = 0; j < face.mNumIndices; j++)
indices.push_back(face.mIndices[j]);
}
bones_id_weights.resize(mesh->mNumVertices);
for (UINT i = 0; i < mesh->mNumBones; i++)
{
UINT bone_index = 0;
string bone_name(mesh->mBones[i]->mName.data);
if (m_bone_mapping.find(bone_name) == m_bone_mapping.end())
{
// Allocate an index for a new bone
bone_index = m_num_bones;
m_num_bones++;
XMMATRIX bi;
BoneMat pushMat;
pushMat.offset = bi;
m_bone_matrices.push_back(pushMat);
m_bone_matrices[bone_index].offset = XMMatrixTranspose(XMMATRIX(&mesh->mBones[i]->mOffsetMatrix.a1));
m_bone_mapping[bone_name] = bone_index;
BoneData abone;
theBones.push_back(abone);
}
else
{
bone_index = m_bone_mapping[bone_name];
}
BoneToMesh stor;
stor.meshNum = meshIndex;
for (UINT j = 0; j < mesh->mBones[i]->mNumWeights; j++)
{
UINT vertex_id = mesh->mBones[i]->mWeights[j].mVertexId;
float weight = mesh->mBones[i]->mWeights[j].mWeight;
bwstor.at(vertex_id).boneIdx.push_back(bone_index);
bwstor.at(vertex_id).weights.push_back(weight);
}
}
BoneData dat;
dat.access = bwstor;
theBones.push_back(dat);
std::vector<Texture> textures;
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
std::vector<Texture> diffuseTextures = LoadMaterialTextures(material, aiTextureType::aiTextureType_DIFFUSE, scene);
textures.insert(textures.end(), diffuseTextures.begin(), diffuseTextures.end());
meshIndex++;
return SkinMesh(this->device, this->deviceContext, vertices, indices, textures, transformMatrix);
}
TextureStorageType SkinModel::DetermineTextureStorageType(const aiScene* pScene, aiMaterial* pMat, unsigned int index, aiTextureType textureType)
{
if (pMat->GetTextureCount(textureType) == 0)
return TextureStorageType::None;
aiString path;
pMat->GetTexture(textureType, index, &path);
std::string texturePath = path.C_Str();
//Check if texture is an embedded indexed texture by seeing if the file path is an index #
if (texturePath[0] == '*')
{
if (pScene->mTextures[0]->mHeight == 0)
{
return TextureStorageType::EmbeddedIndexCompressed;
}
else
{
assert("SUPPORT DOES NOT EXIST YET FOR INDEXED NON COMPRESSED TEXTURES!" && 0);
return TextureStorageType::EmbeddedIndexNonCompressed;
}
}
//Check if texture is an embedded texture but not indexed (path will be the texture's name instead of #)
if (auto pTex = pScene->GetEmbeddedTexture(texturePath.c_str()))
{
if (pTex->mHeight == 0)
{
return TextureStorageType::EmbeddedCompressed;
}
else
{
assert("SUPPORT DOES NOT EXIST YET FOR EMBEDDED NON COMPRESSED TEXTURES!" && 0);
return TextureStorageType::EmbeddedNonCompressed;
}
}
//Lastly check if texture is a filepath by checking for period before extension name
if (texturePath.find('.') != std::string::npos)
{
return TextureStorageType::Disk;
}
return TextureStorageType::None; // No texture exists
}
std::vector<Texture> SkinModel::LoadMaterialTextures(aiMaterial* pMaterial, aiTextureType textureType, const aiScene* pScene)
{
std::vector<Texture> materialTextures;
TextureStorageType storetype = TextureStorageType::Invalid;
unsigned int textureCount = pMaterial->GetTextureCount(textureType);
if (textureCount == 0) //If there are no textures
{
storetype = TextureStorageType::None;
aiColor3D aiColor(0.0f, 0.0f, 0.0f);
switch (textureType)
{
case aiTextureType_DIFFUSE:
pMaterial->Get(AI_MATKEY_COLOR_DIFFUSE, aiColor);
if (aiColor.IsBlack()) //If color = black, just use grey
{
materialTextures.push_back(Texture(this->device, Colors::UnloadedTextureColor, textureType));
return materialTextures;
}
materialTextures.push_back(Texture(this->device, Color(aiColor.r * 255, aiColor.g * 255, aiColor.b * 255), textureType));
return materialTextures;
}
}
else
{
for (UINT i = 0; i < textureCount; i++)
{
aiString path;
pMaterial->GetTexture(textureType, i, &path);
TextureStorageType storetype = DetermineTextureStorageType(pScene, pMaterial, i, textureType);
switch (storetype)
{
case TextureStorageType::EmbeddedIndexCompressed:
{
int index = GetTextureIndex(&path);
Texture embeddedIndexedTexture(this->device,
reinterpret_cast<uint8_t*>(pScene->mTextures[index]->pcData),
pScene->mTextures[index]->mWidth,
textureType);
materialTextures.push_back(embeddedIndexedTexture);
break;
}
case TextureStorageType::EmbeddedCompressed:
{
const aiTexture* pTexture = pScene->GetEmbeddedTexture(path.C_Str());
Texture embeddedTexture(this->device,
reinterpret_cast<uint8_t*>(pTexture->pcData),
pTexture->mWidth,
textureType);
materialTextures.push_back(embeddedTexture);
break;
}
case TextureStorageType::Disk:
{
std::string filename = this->directory + '\\' + path.C_Str();
Texture diskTexture(this->device, filename, textureType);
materialTextures.push_back(diskTexture);
break;
}
}
}
}
if (materialTextures.size() == 0)
{
materialTextures.push_back(Texture(this->device, Colors::UnhandledTextureColor, aiTextureType::aiTextureType_DIFFUSE));
}
return materialTextures;
}
int SkinModel::GetTextureIndex(aiString* pStr)
{
assert(pStr->length >= 2);
return atoi(&pStr->C_Str()[1]);
}
void SkinModel::Transform() {
readNodeHierarchy(rootNode, XMMatrixIdentity());
for (UINT i = 0; i < meshes.size(); i++) {
for (UINT j = 0; j < theBones.at(i).access.size();j++) {
XMMATRIX trans = zeroed;
if (theBones.at(i).access.at(j).boneIdx.size() > 0) {
for (UINT k = 0; k < theBones.at(i).access.at(j).boneIdx.size(); k++) {
UINT curidx = theBones.at(i).access.at(j).boneIdx.at(k);
trans += m_bone_matrices.at(curidx).final * theBones.at(i).access.at(j).weights.at(k);
}
}else{
trans = XMMatrixIdentity();
}
XMFLOAT4 tomul = meshes.at(i).vertPos(j);
XMVECTOR amul = XMLoadFloat4(&tomul);
XMVector4Transform(amul, trans);
XMFLOAT4 tr;
//How do I get a vector position from this
transformed.at(i).setVert(tr, j);
}
}
}
void SkinModel::readNodeHierarchy(const aiNode* p_node, const XMMATRIX parent_transform) {
string node_name(p_node->mName.data);
if (m_bone_mapping.find(node_name) != m_bone_mapping.end()) // true if node_name exist in bone_mapping
{
UINT bonenum = m_bone_mapping[node_name];
XMMATRIX node_transform = XMMatrixRotationRollPitchYaw(boneRotations.at(bonenum).x, boneRotations.at(bonenum).y, boneRotations.at(bonenum).z);
const XMMATRIX global_transform = parent_transform * node_transform;
UINT bone_index = m_bone_mapping[node_name];
m_bone_matrices[bone_index].final = global_inverse * global_transform * m_bone_matrices[bone_index].offset;
for (UINT i = 0; i < p_node->mNumChildren; i++)
{
readNodeHierarchy(p_node->mChildren[i], global_transform);
}
}
}
void SkinModel::getzero() {
zeroed = XMMatrixSet(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}

Strange issue with ASSIMP mesh load

I have encountered an strange issue with ASSIMP mesh load.
Here is the thing, I have a complex model obj file to show a character, this model has 4 child Meshes, and in my code, I encapsulate the Mesh class to get the relevant data(vertices, indices, normals...), When I draw the 4 meshes together(in a for circle), I always get the wrong result:
But if I only load one mesh a time(hard code my assimp load class to do that), and only draw the one mesh, then I can draw the mesh correctly(but this issue only occured when I load the complex model obj file, not with the cube or plane, I can load multiple cube and plane obj files and draw them together):
Here is my ASSIMP load class code, I don't know where my issues are, please help me:
#include "AssetImport.h"
#include "Mesh.h"
#include "Model.h"
#include "ModelMgr.h"
#include "TextureMgr.h"
#include <string>
using namespace Assimp;
AssetImport::AssetImport()
{
}
AssetImport::~AssetImport()
{
}
int AssetImport::LoadModel(const char *path)
{
Importer import;
const aiScene *scene = import.ReadFile(path, aiProcess_Triangulate
| aiProcess_FlipUVs
| aiProcess_CalcTangentSpace
| aiProcess_GenNormals);
if (!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
{
return -1;
}
m_prePath = path;
auto index = m_prePath.lastIndexOf("/");
if (-1 != index) {
m_prePath = m_prePath.left(index + 1);
}
HandleChildNode(scene, scene->mRootNode);
return 0;
}
int AssetImport::HandleChildNode(const aiScene *scene, aiNode *node)
{
unsigned int numChild = node->mNumChildren;
for (unsigned int a = 0; a < 1; ++a)
{
**auto child = node->mChildren[3];// here is the hard code**
if (child->mNumChildren > 0) {
HandleChildNode(scene, child);
}
if (0) {
continue;
}
// create a new model for a child
Model *mod = ModelMgr::Instance().CreateNewModel();
mod->SetModelName(child->mName.C_Str());
auto numMeshes = child->mNumMeshes;
for (unsigned int i = 0; i < numMeshes; ++i)
{
// create new sub mesh, then you can add it to one model
Mesh *m = new Mesh;
auto mesh = scene->mMeshes[child->mMeshes[i]];
//handle the mesh's materials
auto mat = scene->mMaterials[mesh->mMaterialIndex];
HandleMeshMaterial(mat, m);
// add vertex info
for (unsigned int j = 0; j < mesh->mNumVertices; ++j)
{
auto vert = mesh->mVertices[j];
Mesh::VertInfo info;
info.pos = QVector3D(mesh->mVertices[j].x, mesh->mVertices[j].y, mesh->mVertices[j].z);
info.color = QVector4D(0.8f, 0.8f, 0.8f, 1);
info.normal = QVector3D(mesh->mNormals[j].x, mesh->mNormals[j].y, mesh->mNormals[j].z);
if (nullptr != mesh->mTangents)
{
info.tangent = QVector4D(mesh->mTangents[j].x, mesh->mTangents[j].y, mesh->mTangents[j].z, 0);
}
if (nullptr != mesh->mBitangents)
{
info.bitangent = QVector4D(mesh->mBitangents[j].x, mesh->mBitangents[j].y, mesh->mBitangents[j].z, 0);
}
if (nullptr != mesh->mTextureCoords[0])
{
info.uv1 = QVector2D(mesh->mTextureCoords[0][j].x, mesh->mTextureCoords[0][j].y);
}
m->AddVertInfo(info);
}
// add index info
for (unsigned int j = 0; j < mesh->mNumFaces; ++j)
{
auto face = mesh->mFaces[j];
for (unsigned int k = 0; k < face.mNumIndices; ++k)
{
m->AddIndex(face.mIndices[k]);
}
}
m->BindBuffer();
mod->AddMesh(m);
}
}
return 0;
}
int AssetImport::HandleMeshMaterial(aiMaterial *mat, Mesh *mesh)
{
auto diffuseTexCount = mat->GetTextureCount(aiTextureType_DIFFUSE);
auto specularTexCount = mat->GetTextureCount(aiTextureType_SPECULAR);
for (unsigned int i = 0; i < diffuseTexCount; ++i)
{
aiString path;
mat->GetTexture(aiTextureType_DIFFUSE, i, &path);
QString strPath = path.C_Str();
strPath.replace("/", "\\");
auto index = strPath.lastIndexOf("\\");
if (-1 != index) {
strPath = strPath.right(strPath.length() - index - 1);
strPath.prepend(m_prePath);
}
auto texID = TextureMgr::Instance().LoadTexture(strPath.toLocal8Bit());
mesh->SetDiffuseTexID(texID);
}
for (unsigned int i = 0; i < specularTexCount; ++i)
{
aiString strPath;
mat->GetTexture(aiTextureType_SPECULAR, i, &strPath);
}
return 0;
}
Here is my Mesh Class(with Draw Function):
#include "Mesh.h"
#include "TextureMgr.h"
#include "ShaderHelper.h"
#include "PreDef.h"
#include "QMatrix4x4"
Mesh::Mesh()
:m_vao(0), m_vbo(0), m_vaeo(0), m_instanceBufferId(0), m_tbo1(0)
, m_drawType(Triangle)
, m_skyboxTexID(0), m_projTexID(0), m_normalmapTexID(0)
, m_diffuseTex1ID(0)
{
initializeOpenGLFunctions();
m_normalmapTexID = TextureMgr::Instance().LoadTexture("./models/brickwall_normal.jpg");
}
Mesh::~Mesh()
{
}
void Mesh::AddVertex(QVector3D vert)
{
m_vertices.push_back(vert.x());
m_vertices.push_back(vert.y());
m_vertices.push_back(vert.z());
}
const float* Mesh::GetVertices() const
{
return m_vertices.data();
}
int Mesh::GetVerticesMemSize() const
{
return m_vertices.size() * sizeof(float);
}
int Mesh::GetVerticesNum() const
{
return m_vertices.size() / 3;
}
void Mesh::AddColor(QVector4D color)
{
m_colors.push_back(color.x());
m_colors.push_back(color.y());
m_colors.push_back(color.z());
m_colors.push_back(color.w());
}
const float* Mesh::GetColors() const
{
return m_colors.data();
}
int Mesh::GetColorsMemSize() const
{
return m_colors.size() * sizeof(float);
}
void Mesh::AddNormal(QVector3D normal)
{
m_normals.append(normal.x());
m_normals.append(normal.y());
m_normals.append(normal.z());
}
const float* Mesh::GetNormals() const
{
return m_normals.data();
}
int Mesh::GetNormalsMemSize() const
{
return m_normals.size() * sizeof(float);
}
int Mesh::GetNormalsNum() const
{
return m_normals.size() / 3;
}
void Mesh::AddTangent(QVector4D tangent)
{
m_tangents.append(tangent.x());
m_tangents.append(tangent.y());
m_tangents.append(tangent.z());
m_tangents.append(tangent.w());
}
const float* Mesh::GetTangents() const
{
return m_tangents.data();
}
int Mesh::GetTangentsMemSize() const
{
return m_tangents.size() * sizeof(float);
}
int Mesh::GetTangentsNum() const
{
return m_tangents.size() / 4;
}
void Mesh::AddBitangent(QVector4D binormal)
{
m_binormals.append(binormal.x());
m_binormals.append(binormal.y());
m_binormals.append(binormal.z());
m_binormals.append(binormal.w());
}
const float* Mesh::GetBitangents() const
{
return m_binormals.data();
}
int Mesh::GetBitangentsMemSize() const
{
return m_binormals.size() * sizeof(float);
}
int Mesh::GetBitangentsNum() const
{
return m_binormals.size() / 4;
}
void Mesh::AddUv1(QVector2D uv)
{
m_uvs1.append(uv.x());
m_uvs1.append(uv.y());
}
const float* Mesh::GetUvs1() const
{
return m_uvs1.data();
}
int Mesh::GetUvs1MemSize() const
{
return m_uvs1.size() * sizeof(float);
}
int Mesh::GetUvs1Num() const
{
return m_uvs1.size() / 2;
}
void Mesh::AddVertInfo(const VertInfo &info)
{
m_vertInfoVec.push_back(info);
AddVertex(info.pos);
AddColor(info.color);
AddNormal(info.normal);
AddTangent(info.tangent);
AddBitangent(info.bitangent);
AddUv1(info.uv1);
}
void Mesh::BindBuffer()
{
// init the shaders first
ShaderHelper::Instance();
BindVertexRelevantBuffer();
}
void Mesh::BindVertexRelevantBuffer()
{
const GLuint *vertex_indices = GetIndices();
const GLfloat *vertex_positions = GetVertices();
const GLfloat *vertex_uvs = GetUvs1();
const GLfloat *vertex_tangents = GetTangents();
const GLfloat *vertex_bitangents = GetBitangents();
const GLfloat *vertex_normals = GetNormals();
// set element array(index array) buffer
glGenBuffers(1, &m_vaeo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vaeo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GetIndicesMemSize(), vertex_indices, GL_STATIC_DRAW);
// set vertex array object
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
glVertexArrayElementBuffer(m_vao, m_vaeo);
glGenBuffers(1, &m_vbo);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferData(GL_ARRAY_BUFFER, GetVerticesMemSize() + GetUvs1MemSize()
+ GetTangentsMemSize() + GetBitangentsMemSize() + GetNormalsMemSize() /*+ 16 * sizeof(GLfloat) * 10*/, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, GetVerticesMemSize(), vertex_positions);
glBufferSubData(GL_ARRAY_BUFFER, GetVerticesMemSize(), GetUvs1MemSize(), vertex_uvs);
glBufferSubData(GL_ARRAY_BUFFER, GetVerticesMemSize() + GetUvs1MemSize(), GetTangentsMemSize(), vertex_tangents);
glBufferSubData(GL_ARRAY_BUFFER, GetVerticesMemSize() + GetUvs1MemSize() + GetTangentsMemSize(),
GetBitangentsMemSize(), vertex_bitangents);
glBufferSubData(GL_ARRAY_BUFFER, GetVerticesMemSize() + GetUvs1MemSize()
+ GetTangentsMemSize() + GetBitangentsMemSize(),
GetNormalsMemSize(), vertex_normals);
GLint positionLoc = 0;
GLint uvLoc = 1;
GLint tangentLoc = 2;
GLint bitangentLoc = 3;
GLint normalLoc = 4;
GLint modelMatLoc = -1;
glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, (0));
glEnableVertexAttribArray(positionLoc);
glVertexAttribPointer(uvLoc, 2, GL_FLOAT, GL_FALSE, 0, (void*)(GetVerticesMemSize()));
glEnableVertexAttribArray(uvLoc);
glVertexAttribPointer(tangentLoc, 3, GL_FLOAT, GL_FALSE, 0, (void*)(GetVerticesMemSize() + GetUvs1MemSize()));
glEnableVertexAttribArray(tangentLoc);
glVertexAttribPointer(bitangentLoc, 3, GL_FLOAT, GL_FALSE, 0,
(void*)(GetVerticesMemSize() + GetUvs1MemSize() + GetTangentsMemSize()));
glEnableVertexAttribArray(bitangentLoc);
glVertexAttribPointer(normalLoc, 3, GL_FLOAT, GL_FALSE, 0,
(void*)(GetVerticesMemSize() + GetUvs1MemSize() + GetTangentsMemSize() + GetBitangentsMemSize()));
glEnableVertexAttribArray(normalLoc);
// multi instances model matrix
if (-1 != modelMatLoc) {
// generate the new buffer for instances
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &m_instanceBufferId);
glBindBuffer(GL_ARRAY_BUFFER, m_instanceBufferId);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 16 * 10, nullptr, GL_STATIC_DRAW);
// m_instanceBufferId = m_vbo;
// mat4 type take space of 4 vec4, so we should circle 4 times
for (int i = 0; i < 4; ++i)
{
glVertexAttribPointer(modelMatLoc + i, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 16,
(void*)(/*GetVerticesMemSize() + GetUvs1MemSize() + GetTangentsMemSize() + GetBitangentsMemSize() + GetNormalsMemSize() +*/ sizeof(GLfloat) * 4 * i));
glEnableVertexAttribArray(modelMatLoc + i);
// implement the multi instances
glVertexAttribDivisor(modelMatLoc + i, 1);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
// sampler buffer bind
glGenBuffers(1, &m_tbo1);
glBindBuffer(GL_TEXTURE_BUFFER, m_tbo1);
glBufferData(GL_TEXTURE_BUFFER, sizeof(GLfloat) * 16 * 10, nullptr, GL_STATIC_DRAW);
GLuint tex1;
glCreateTextures(GL_TEXTURE_BUFFER, 1, &tex1);
glTextureBuffer(tex1, GL_RGBA32F, m_tbo1);
glBindTextureUnit(0, m_tbo1);
glBindBuffer(GL_TEXTURE_BUFFER, 0);
}
GLuint Mesh::GetVao()
{
return m_vao;
}
void Mesh::AddIndex(unsigned int index)
{
m_indices.push_back(index);
}
void Mesh::AddIndexVec(QVector<unsigned int> &indexVec)
{
m_indices = indexVec;
}
const unsigned int* Mesh::GetIndices() const
{
return m_indices.data();
}
int Mesh::GetIndicesMemSize() const
{
return m_indices.size() * sizeof(unsigned int);
}
int Mesh::GetIndicesNum() const
{
return m_indices.size();
}
GLuint Mesh::GetMultiInstanceModelMatrixOffset() const
{
return (GetVerticesMemSize() + GetUvs1MemSize() + GetTangentsMemSize()
+ GetBitangentsMemSize() + GetNormalsMemSize());
}
GLuint Mesh::GetInstancesBufferId() const
{
return m_instanceBufferId;
}
void Mesh::SetDiffuseTexID(GLuint id)
{
m_diffuseTex1ID = id;
}
void Mesh::AddSpecularTexture(GLuint id)
{
m_specularTex1ID = id;
}
GLuint Mesh::GetTextureBuffer1() const
{
return m_tbo1;
}
void Mesh::InitSkybox()
{
m_skyboxTexID = TextureMgr::Instance().LoadTexture("skybox");
}
void Mesh::InitProjTex()
{
m_projTexID = TextureMgr::Instance().LoadTexture("./textures/proj.jpg");
}
void Mesh::SetDrawType(eDrawType type)
{
m_drawType = type;
}
void Mesh::Draw(QMatrix4x4 matVP, QMatrix4x4 matModel, QVector3D camPos, QMatrix4x4 matProj, QMatrix4x4 matView,
QMatrix4x4 matOrtho)
{
if (0 != m_diffuseTex1ID)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_diffuseTex1ID);
}
if (0 != m_normalmapTexID)
{
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_normalmapTexID);
}
if (0 != m_skyboxTexID) {
glBindTexture(GL_TEXTURE_CUBE_MAP, m_skyboxTexID);
matModel.translate(camPos);
matModel.scale(10000);
glCullFace(GL_FRONT);
glDepthMask(0);
ShaderHelper::Instance().SetShaderType(ShaderHelper::Skybox);
}
else if (0 != m_projTexID) {
glActiveTexture(GL_TEXTURE10);
glBindTexture(GL_TEXTURE_2D, m_projTexID);
ShaderHelper::Instance().SetShaderType(ShaderHelper::Decal);
}
glBindVertexArray(GetVao());
matVP = matVP * matModel;
ShaderHelper::Instance().SetMVPMatrix(matVP);
ShaderHelper::Instance().SetWorldMatrix(matModel);
ShaderHelper::Instance().SetCamWorldPos(camPos);
ShaderHelper::Instance().SetProjMat(matProj);
ShaderHelper::Instance().SetViewMat(matView);
ShaderHelper::Instance().SetOrthoMat(matOrtho);
// Draw element(with indices)
if (Triangle == m_drawType)
{
glDrawElements(GL_TRIANGLES, GetIndicesNum(), GL_UNSIGNED_INT, 0);
}
else if (Point == m_drawType)
{
glDrawArrays(GL_POINTS, 0, GetVerticesNum());
}
if (0 != m_skyboxTexID) {
glCullFace(GL_BACK);
glDepthMask(1);
}
glBindVertexArray(0);
}
Here is the main draw function:
void OpenWidget::paintGL()
{
static int i = 0;
if (0 == i){
++i;
CreateOffScreenFrameBufferTexture();
}
glBindFramebuffer(GL_FRAMEBUFFER, m_fb);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
return;
}
paintClearAndReset();
QMatrix4x4 matVP = m_cam->GetVPMatrix();
QMatrix4x4 matProj = m_cam->GetProjectionMatrix();
QMatrix4x4 matOrtho = m_cam->GetOrthographicMatrix();
QMatrix4x4 matView = m_cam->GetViewMatrix();
QVector3D camPos = m_cam->GetCamPos().toVector3D();
auto modelNum = ModelMgr::Instance().GetModelNum();
for (unsigned int i = 0; i < modelNum; ++i)
{
Model *mod = ModelMgr::Instance().GetModel(i);
SwitchShader(ShaderHelper::Default);
QMatrix4x4 matModel = mod->GetWorldMat();
mod->Draw(matVP, matModel, camPos, matProj, matView, matOrtho);
if (modelNum - 1 == i) {
Model *pBox = ModelMgr::Instance().FindModelByName("Box001");
// SwitchShader(ShaderHelper::PlaneClip);
// glFrontFace(GL_CW);
// glEnable(GL_CLIP_PLANE0);
// glStencilMask(0xff);
// glStencilFunc(GL_ALWAYS, 1, 0xff);
// glColorMask(0, 0, 0, 0);
//
// pBox->Draw(matVP, pBox->GetWorldMat(), camPos);
// glFrontFace(GL_CCW);
// glDisable(GL_CLIP_PLANE0);
// glColorMask(1, 1, 1, 1);
//
// glStencilMask(0);
// glStencilFunc(GL_EQUAL, 1, 0xff);
// SwitchShader(ShaderHelper::PureColor);
// pBox->Draw(matVP, pBox->GetWorldMat(), camPos);
}
}
//-----------------------------------------------
// test the frame buffer
DrawOffScreenTexture();
}
Finally, I found where the problem is, I give up on this issue for a while, but today, I encountered another problem with my skybox(cubemap), I can only draw my skybox correctly at the last of my draw queue, otherwise the cubemap only show one face, so, no shortcut for me anymore, I decided to resolve this issue, after many hours debug, I found this issue caused by the create sequence of VAO and ElementBuffer, here is the wrong code:
// set element array(index array) buffer
glGenBuffers(1, &m_vaeo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vaeo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GetIndicesMemSize(), vertex_indices, GL_STATIC_DRAW);
// set vertex array object
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
glVertexArrayElementBuffer(m_vao, m_vaeo);
you should always create and bind VAO first:
// set vertex array object
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
// set element array(index array) buffer
glGenBuffers(1, &m_vaeo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vaeo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GetIndicesMemSize(), vertex_indices, GL_STATIC_DRAW);
glVertexArrayElementBuffer(m_vao, m_vaeo);
But, after all, I think it's so implicit, because of you can bind the element to vao after you create the element buffer, it seems like when you gen the element buffer it's nothing to do with the vao, what I can do, only be careful next time.

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 + Uniform Variables not reaching shaders + splines

I have a very peculiar problem that I can not figure out. For my scene I have created a spline class which I use to generate points for which my camera traverses. This works fine and dandy when I create an instance of the spline class in my scene and use it. I have some functionality in my spline class for showing the points on the spline that use uniform data to draw their position and give them a color. This all works fine when I create an instance directly in my scene.
HOWEVER, I want to create multiple splines to have my camera traverse so I created a fairly simple management class to handle multiple splines. This works however for some reason I can not puzzle out why when I create an instance of a spline with the manager the uniform variables aren't working. Everything else works fine. When I say they don't work what I mean is that the getLocation functions work (they get the locationIDs as expected), the data to be sent is the same, there are no errors or warnings concerning the functions that are supposed to actually send the data down to their locations. The spline draws properly however they are always black and haven't been translated.
Here is my scene class. The constructors for both my manager and the spline class its self are exactly the same so in my ClothScene.hpp I can switch the type of the mSplineManager object from the manager class to the spline class and the uniform variables work fine.
#include "ClothScene.hpp"
#include <atlas/core/GLFW.hpp>
#include <atlas/core/Log.hpp>
#include <atlas/core/Macros.hpp>
#include <atlas/core/Float.hpp>
#include <iostream>
ClothScene::ClothScene() :
mIsPlaying(false),
mLastTime(0.0f),
mFPS(60.0f),
mTick(1.0f / mFPS),
mAnimTime(0.0f),
mAnimLength(10.0f),
mSplineManager(int(mAnimLength * mFPS)),
ballPosition{ -10.0f, 0.0f, 14.0f }
{
glEnable(GL_DEPTH_TEST);
auto mat = glm::translate(atlas::math::Matrix4(1.0f), ballPosition);
mBall.transformGeometry(mat);
}
ClothScene::~ClothScene() {
}
void ClothScene::mousePressEvent(int button, int action, int modifiers, double xPos, double yPos) {
USING_ATLAS_MATH_NS;
if (button == GLFW_MOUSE_BUTTON_LEFT && modifiers == GLFW_MOD_ALT)
{
if (action == GLFW_PRESS)
{
mIsDragging = true;
//Camera tilt up and down or turn left, right
mCamera.mouseDown(Point2(xPos, yPos), ClothCamera::CameraMovements::TUMBLE);
}
else
{
mIsDragging = false;
mCamera.mouseUp();
}
}
else if (button == GLFW_MOUSE_BUTTON_MIDDLE && modifiers == GLFW_MOD_ALT)
{
if (action == GLFW_PRESS)
{
mIsDragging = true;
//Camera move left, right, up, down
mCamera.mouseDown(Point2(xPos, yPos), ClothCamera::CameraMovements::TRACK);
}
else
{
mIsDragging = false;
mCamera.mouseUp();
}
}
else if (button == GLFW_MOUSE_BUTTON_RIGHT && modifiers == GLFW_MOD_ALT)
{
if (action == GLFW_PRESS)
{
// first click.
mIsDragging = true;
//Camera move back and forth
mCamera.mouseDown(Point2(xPos, yPos), ClothCamera::CameraMovements::DOLLY);
}
else
{
mIsDragging = false;
mCamera.mouseUp();
}
}
else if (action != GLFW_PRESS)
{
mIsDragging = false;
mCamera.mouseUp();
}
}
void ClothScene::mouseMoveEvent(double xPos, double yPos) {
mCamera.mouseUpdate(glm::vec2(xPos, yPos));
}
void ClothScene::keyPressEvent(int key, int scancode, int action, int mods) {
UNUSED(scancode);
UNUSED(mods);
if (action == GLFW_PRESS)
{
switch (key)
{
case GLFW_KEY_T:
mCamera.resetCamera();
break;
case GLFW_KEY_W:
mCamera.strafeCamera(0);
break;
case GLFW_KEY_S:
mCamera.strafeCamera(1);
break;
case GLFW_KEY_A:
mCamera.strafeCamera(2);
break;
case GLFW_KEY_D:
mCamera.strafeCamera(3);
break;
case GLFW_KEY_R:
mCamera.strafeCamera(4);
break;
case GLFW_KEY_F:
mCamera.strafeCamera(5);
break;
case GLFW_KEY_Q:
mCamera.strafeCamera(6);
break;
case GLFW_KEY_E:
mCamera.strafeCamera(7);
break;
case GLFW_KEY_C:
mCamera.newPosition(glm::vec3(0.0f, 3.0f, 0.0f));
break;
case GLFW_KEY_U:
mSplineManager.showSpline();
break;
case GLFW_KEY_I:
mSplineManager.showControlPoints();
break;
case GLFW_KEY_O:
mSplineManager.showCage();
break;
case GLFW_KEY_P:
mSplineManager.showSplinePoints();
break;
case GLFW_KEY_SPACE:
mIsPlaying = !mIsPlaying;
default:
break;
}
}
}
void ClothScene::screenResizeEvent(int width, int height) {
glViewport(0, 0, width, height);
mProjection = glm::perspective(glm::radians(45.0),(double)width / height, 1.0, 1000.0);
}
void ClothScene::renderScene() {
float grey = 161.0f / 255.0f;
glClearColor(grey, grey, grey, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
mView = mCamera.getCameraMatrix();
mGrid.renderGeometry(mProjection, mView);
mSplineManager.renderGeometry(mProjection, mView);
mBall.renderGeometry(mProjection, mView);
}
void ClothScene::updateScene(double time)
{
mTime.currentTime = (float)time;
mTime.totalTime += (float)time;
if (atlas::core::geq(mTime.currentTime - mLastTime, mTick))
{
mLastTime += mTick;
mTime.deltaTime = mTick;
if (mIsPlaying)
{
mAnimTime += mTick;
mSplineManager.updateGeometry(mTime);
if (mSplineManager.doneInterpolation())
{
mIsPlaying = false;
return;
}
auto point = mSplineManager.getSplinePosition();
mCamera.newPosition(point);
mCamera.lookAt(ballPosition);
auto mat = glm::translate(atlas::math::Matrix4(1.0f), ballPosition);
mBall.transformGeometry(mat);
}
}
}
Here is my SplineManger class. It super simple, it just creates a vector of splines and then applies the exact same functionality iterated through all of the splines in the vector. For some reason this prevents the shader from receiving the uniform data.
#include "SplineManager.hpp"
SplineManager::SplineManager(int totalFrames) :
finishedAllSplines(false),
currentSpline(0)
{
mTotalFrames = totalFrames;
addSplines();
}
SplineManager::~SplineManager() {
}
void SplineManager::addSplines() {
mControlPoints = std::vector<Point>
{
{ -20, -5, 0 },
{ -19, 5, -15 },
{ 12.7f, -5, -1.4f },
{ 20, 8.2f, 4.4f }
};
mSplines.push_back(Spline(mTotalFrames, mControlPoints));
}
void SplineManager::renderGeometry(atlas::math::Matrix4 projection, atlas::math::Matrix4 view) {
for (int i = 0; i < mSplines.size(); ++i) {
mSplines[i].renderGeometry(projection, view);
}
}
void SplineManager::updateGeometry(atlas::utils::Time const& t) {
mSplines[currentSpline].updateGeometry(t);
if (mSplines[currentSpline].doneInterpolation()) {
++currentSpline;
if (currentSpline == mSplines.size()) {
finishedAllSplines = true;
}
}
}
atlas::math::Point SplineManager::getSplinePosition() {
return mSplines[currentSpline].getSplinePosition();
}
void SplineManager::showSpline() {
for (int i = 0; i < mSplines.size(); ++i) {
mSplines[i].showSpline();
}
}
void SplineManager::showControlPoints() {
for (int i = 0; i < mSplines.size(); ++i) {
mSplines[i].showControlPoints();
}
}
void SplineManager::showCage() {
for (int i = 0; i < mSplines.size(); ++i) {
mSplines[i].showCage();
}
}
void SplineManager::showSplinePoints() {
for (int i = 0; i < mSplines.size(); ++i) {
mSplines[i].showSplinePoints();
}
}
bool SplineManager::doneInterpolation() {
return finishedAllSplines;
}
Here is my spline class. Again, this all works totally fine when I directly create an instance of it in the scene class. When instances are created in the SplineManager the uniform variables don't work.
#include "Spline.h"
#include "ShaderPaths.hpp"
#include <atlas/core/Macros.hpp>
Spline::Spline(int totalFrames) :
mResolution(500),
mTotalFrames(totalFrames),
mCurrentFrame(0),
mShowControlPoints(false),
mShowCage(false),
mShowSplinePoints(false),
mShowSpline(false),
mIsInterpolationDone(false)
{
USING_ATLAS_MATH_NS;
USING_ATLAS_GL_NS;
//Bezier
mBasisMatrix = Matrix4(
1.0f, 0.0f, 0.0f, 0.0f,
-3.0f, 3.0f, 0.0f, 0.0f,
3.0f, -6.0f, 3.0f, 0.0f,
-1.0f, 3.0f, -3.0f, 1.0f);
mControlPoints = std::vector<Point>
{
{ -20, -5, 0 },
{ -19, 5, -15 },
{ 12.7f, -5, -1.4f },
{ 20, 8.2f, 4.4f }
};
std::vector<Point> splinePoints;
float scale = 1.0f / mResolution;
for (int res = 0; res < mResolution + 1; ++res)
{
splinePoints.push_back(evaluateSpline(scale * res));
}
generateArcLengthTable();
glGenVertexArrays(1, &mVao);
glBindVertexArray(mVao);
glGenBuffers(1, &mControlBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mControlBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Point) * mControlPoints.size(),
mControlPoints.data(), GL_STATIC_DRAW);
glGenBuffers(1, &mSplineBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mSplineBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Point) * splinePoints.size(), splinePoints.data(), GL_STATIC_DRAW);
std::string shaderDir = generated::ShaderPaths::getShaderDirectory();
std::vector<ShaderInfo> shaders
{
{ GL_VERTEX_SHADER, shaderDir + "spline.vs.glsl" },
{ GL_FRAGMENT_SHADER, shaderDir + "spline.fs.glsl" }
};
mShaders.push_back(ShaderPointer(new Shader));
mShaders[0]->compileShaders(shaders);
mShaders[0]->linkShaders();
GLuint var;
var = mShaders[0]->getUniformVariable("uMVP");
mUniforms.insert(UniformKey("uMVP", var));
var = mShaders[0]->getUniformVariable("fColour");
mUniforms.insert(UniformKey("fColour", var));
mShaders[0]->disableShaders();
glBindVertexArray(0);
}
Spline::~Spline()
{
glDeleteVertexArrays(1, &mVao);
glDeleteVertexArrays(1, &mControlBuffer);
glDeleteVertexArrays(1, &mSplineBuffer);
}
void Spline::renderGeometry(atlas::math::Matrix4 projection,
atlas::math::Matrix4 view)
{
USING_ATLAS_MATH_NS;
mShaders[0]->enableShaders();
glBindVertexArray(mVao);
Matrix4 mvp = projection * view * mModel;
glUniformMatrix4fv(mUniforms["uMVP"], 1, GL_FALSE, &mvp[0][0]);
// Draw the control points first.
glUniform3f(mUniforms["fColour"], 1, 0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, mControlBuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
if (mShowControlPoints)
{
glPointSize(5.0f);
glDrawArrays(GL_POINTS, 0, GLsizei(mControlPoints.size()));
glPointSize(1.0f);
}
if (mShowCage)
{
glDrawArrays(GL_LINE_STRIP, 0, GLsizei(mControlPoints.size()));
}
// Now draw the spline.
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, mSplineBuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glUniform3f(mUniforms["fColour"], 0, 1, 0);
if (mShowSpline)
{
glLineWidth(5.0f);
glDrawArrays(GL_LINE_STRIP, 0, mResolution + 1);
glLineWidth(1.0f);
}
if (mShowSplinePoints)
{
glPointSize(8.0f);
glDrawArrays(GL_POINTS, 1, mResolution);
glPointSize(1.0f);
}
glDisableVertexAttribArray(0);
mShaders[0]->disableShaders();
}
void Spline::updateGeometry(atlas::utils::Time const& t)
{
UNUSED(t);
mSplinePosition = interpolateOnSpline();
mCurrentFrame++;
if (mCurrentFrame == mTotalFrames)
{
mIsInterpolationDone = true;
return;
}
}
void Spline::showControlPoints()
{
mShowControlPoints = !mShowControlPoints;
}
void Spline::showCage()
{
mShowCage = !mShowCage;
}
void Spline::showSplinePoints()
{
mShowSplinePoints = !mShowSplinePoints;
}
void Spline::showSpline()
{
mShowSpline = !mShowSpline;
}
bool Spline::doneInterpolation()
{
return mIsInterpolationDone;
}
atlas::math::Point Spline::getSplinePosition()
{
return mSplinePosition;
}
atlas::math::Point Spline::interpolateOnSpline()
{
int n = int(mTable.size());
float totalDistance = mTable[n - 1];
float step = totalDistance / mTotalFrames;
float currDistance = step * mCurrentFrame;
int index = tableLookUp(currDistance);
float t = (1.0f / mResolution) * (index % mResolution);
return evaluateSpline(t);
}
atlas::math::Point Spline::evaluateSpline(float t)
{
USING_ATLAS_MATH_NS;
Vector4 xControls =
{
mControlPoints[0].x, mControlPoints[1].x,
mControlPoints[2].x, mControlPoints[3].x
};
Vector4 yControls =
{
mControlPoints[0].y, mControlPoints[1].y,
mControlPoints[2].y, mControlPoints[3].y
};
Vector4 zControls =
{
mControlPoints[0].z, mControlPoints[1].z,
mControlPoints[2].z, mControlPoints[3].z
};
Vector4 xCoeff = xControls * mBasisMatrix;
Vector4 yCoeff = yControls * mBasisMatrix;
Vector4 zCoeff = zControls * mBasisMatrix;
float xcr, ycr, zcr;
xcr = xCoeff[0] + t * xCoeff[1] + t * t * xCoeff[2] + t * t * t * xCoeff[3];
ycr = yCoeff[0] + t * yCoeff[1] + t * t * yCoeff[2] + t * t * t * yCoeff[3];
zcr = zCoeff[0] + t * zCoeff[1] + t * t * zCoeff[2] + t * t * t * zCoeff[3];
return Point(xcr, ycr, zcr);
}
void Spline::generateArcLengthTable()
{
USING_ATLAS_MATH_NS;
if (!mTable.empty())
{
mTable.clear();
}
float scale = 1.0f / mResolution;
mTable.push_back(0.0f);
for (int i = 1; i < mResolution + 1; ++i)
{
Point p0 = evaluateSpline((i - 1) * scale);
Point p1 = evaluateSpline(i * scale);
Point dist = p0 - p1;
mTable.push_back(mTable[i - 1] + glm::length(dist));
}
}
int Spline::tableLookUp(float distance)
{
// Find the entry in our table that corresponds to the given distance.
float epsilon = chooseEpsilon();
for (int i = 0; i < int(mTable.size()); ++i)
{
if (glm::abs(mTable[i] - distance) < epsilon)
{
return i;
}
}
return -1;
}
float Spline::chooseEpsilon()
{
// Find the largest difference and use that to look up distances
// in our table.
float epsilon = 0.0f;
float diff;
for (int i = 0; i < mTable.size() - 1; ++i)
{
diff = glm::abs(mTable[i] - mTable[i + 1]);
if (diff > epsilon)
{
epsilon = diff;
}
}
return epsilon;
}
void Spline::setSplineCoordinates(std::vector<atlas::math::Point> mControlPoints_) {
mControlPoints = mControlPoints_;
}
The header files for anyone interested.
SplineManager.hpp
#ifndef SPLINEMANAGER_HPP
#define SPLINEMANAGER_HPP
#pragma once
#include <atlas/utils/Geometry.hpp>
#include "Spline.h"
USING_ATLAS_MATH_NS;
USING_ATLAS_GL_NS;
class SplineManager : public atlas::utils::Geometry {
public:
SplineManager(int totalFrames);
~SplineManager();
atlas::math::Point getSplinePosition();
void addSplines();
void showSpline();
void showControlPoints();
void showCage();
void showSplinePoints();
bool doneInterpolation();
void updateGeometry(atlas::utils::Time const& t) override;
void renderGeometry(atlas::math::Matrix4 projection, atlas::math::Matrix4 view) override;
private:
std::vector<Spline> mSplines;
std::vector<atlas::math::Point> mControlPoints;
int mTotalFrames;
int currentSpline;
bool finishedAllSplines;
};
#endif
Spline.h
#ifndef LAB04_INCLUDE_SPLINE_HPP
#define LAB04_INCLUDE_SPLINE_HPP
#pragma once
#include <atlas/utils/Geometry.hpp>
#include <fstream>
class Spline : public atlas::utils::Geometry
{
public:
Spline(int totalFrames, std::vector<atlas::math::Point> mControlPoints_);
Spline(int totalFrames);
~Spline();
void renderGeometry(atlas::math::Matrix4 projection,
atlas::math::Matrix4 view) override;
void updateGeometry(atlas::utils::Time const& t) override;
void showControlPoints();
void showCage();
void showSplinePoints();
void showSpline();
bool doneInterpolation();
atlas::math::Point getSplinePosition();
void setSplineCoordinates(std::vector<atlas::math::Point> mControlPoints_);
private:
atlas::math::Point interpolateOnSpline();
atlas::math::Point evaluateSpline(float t);
void generateArcLengthTable();
int tableLookUp(float distance);
float chooseEpsilon();
atlas::math::Matrix4 mBasisMatrix;
std::vector<atlas::math::Point> mControlPoints;
std::vector<float> mTable;
atlas::math::Point mSplinePosition;
GLuint mVao;
GLuint mControlBuffer;
GLuint mSplineBuffer;
int mResolution;
int mTotalFrames;
int mCurrentFrame;
bool mShowControlPoints;
bool mShowCage;
bool mShowSplinePoints;
bool mShowSpline;
bool mIsInterpolationDone;
};
#endif
ClothScene.hpp
#ifndef SCENE_HPP
#define SCENE_HPP
#pragma once
#include <atlas\utils\Scene.hpp>
#include "ClothCamera.hpp"
#include "SplineManager.hpp"
#include "Grid.hpp"
#include "Spline.h"
#include "Ball.hpp"
//#include "Cloth.hpp"
class ClothScene : public atlas::utils::Scene {
public:
ClothScene();
~ClothScene();
void mousePressEvent(int button, int action, int modifiers, double xPos, double yPos) override;
void mouseMoveEvent(double xPos, double yPos) override;
void keyPressEvent(int key, int scancode, int action, int mods) override;
void screenResizeEvent(int width, int height) override;
void renderScene() override;
void updateScene(double time) override;
private:
bool mIsDragging;
bool mIsPlaying;
float mLastTime;
float mFPS;
float mTick;
float mAnimTime;
float mAnimLength;
glm::vec3 ballPosition;
ClothCamera mCamera;
Grid mGrid;
SplineManager mSplineManager;//, mSpline2;
Ball mBall;
std::vector<atlas::math::Point> mControlPoints;
};
#endif

Texture mapping with phong lighting

Im trying to add Phong lighting to my scene in which I have loaded mesh with textures. This is my mesh loadin class:
#define INVALID_OGL_VALUE 0xFFFFFFFF
#define INVALID_MATERIAL 0xFFFFFFFF
#define SAFE_DELETE(p) if (p) { delete p; p = NULL; }
Mesh::MeshEntry::MeshEntry()
{
VB = INVALID_OGL_VALUE;
IB = INVALID_OGL_VALUE;
NumIndices = 0;
MaterialIndex = INVALID_MATERIAL;
};
Mesh::MeshEntry::~MeshEntry()
{
if (VB != INVALID_OGL_VALUE)
{
glDeleteBuffers(1, &VB);
}
if (IB != INVALID_OGL_VALUE)
{
glDeleteBuffers(1, &IB);
}
}
void Mesh::MeshEntry::Init(const std::vector<Vertex>& Vertices,
const std::vector<unsigned int>& Indices)
{
NumIndices = Indices.size();
glGenBuffers(1, &VB);
glBindBuffer(GL_ARRAY_BUFFER, VB);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * Vertices.size(), &Vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &IB);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IB);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * NumIndices, &Indices[0], GL_STATIC_DRAW);
}
Mesh::Mesh()
{
}
Mesh::~Mesh()
{
Clear();
}
void Mesh::Clear()
{
for (unsigned int i = 0 ; i < textures_cnt.size() ; i++) {
SAFE_DELETE(textures_cnt[i]);
}
}
/*Loads mesh
*#Filename - name of the .obj file
**********************************************************/
bool Mesh::LoadMesh(const std::string& Filename){
Assimp::Importer Importer;
bool rc = false;
//clear previous loaded mesh
Clear();
//read file content
const aiScene* oScene = Importer.ReadFile(Filename.c_str(), aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs );
if(oScene){
printf (" %i animations\n", oScene->mNumAnimations);
printf (" %i cameras\n", oScene->mNumCameras);
printf (" %i lights\n", oScene->mNumLights);
printf (" %i materials\n", oScene->mNumMaterials);
printf (" %i meshes\n", oScene->mNumMeshes);
printf (" %i textures\n", oScene->mNumTextures);
submeshes_cnt.resize(oScene->mNumMeshes);
textures_cnt.resize(oScene->mNumMaterials);
/*.........Initialize the meshes in the scene one by one...........*/
for (unsigned int i = 0 ; i < submeshes_cnt.size() ; i++) {
const aiMesh* paiMesh = oScene->mMeshes[i];
InitMesh(i, paiMesh);
}
// Extract the directory part from the file name
std::string::size_type SlashIndex = Filename.find_last_of("/");
std::string Dir;
if (SlashIndex == std::string::npos) {
Dir = ".";
}
else if (SlashIndex == 0) {
Dir = "/";
}
else {
Dir = Filename.substr(0, SlashIndex);
}
/*.................Initialization of meshes end....................*/
/*.............Initialize the materials.............................*/
for(unsigned int i = 0 ; i < oScene->mNumMaterials ; i++) {
const aiMaterial* pMaterial = oScene->mMaterials[i];
textures_cnt[i] = NULL;
if (pMaterial->GetTextureCount(aiTextureType_DIFFUSE) > 0) {
aiString Path;
if (pMaterial->GetTexture(aiTextureType_DIFFUSE, 0, &Path, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS) {
std::string FullPath = Dir + "/" + Path.data;
textures_cnt[i] = new Texture(GL_TEXTURE_2D, FullPath.c_str());
if (!textures_cnt[i]->Load()) {
printf("Error loading texture '%s'\n", FullPath.c_str());
delete textures_cnt[i];
textures_cnt[i] = NULL;
rc = false;
}
else {
printf("Loaded texture '%s'\n", FullPath.c_str());
}
}
}
}
/*.................Initialization of materials end....................*/
}
else {
printf("Error parsing '%s': '%s'\n", Filename.c_str(), Importer.GetErrorString());
}
return rc;
}
void Mesh::InitMesh(unsigned int Index, const aiMesh* paiMesh)
{
submeshes_cnt[Index].MaterialIndex = paiMesh->mMaterialIndex;
std::vector<Vertex> Vertices;
std::vector<unsigned int> Indices;
const aiVector3D Zero3D(0.0f, 0.0f, 0.0f);
for (unsigned int i = 0 ; i < paiMesh->mNumVertices ; i++) {
const aiVector3D* pPos = &(paiMesh->mVertices[i]);
const aiVector3D* pNormal = &(paiMesh->mNormals[i]);
const aiVector3D* pTexCoord = paiMesh->HasTextureCoords(0) ? &(paiMesh->mTextureCoords[0][i]) : &Zero3D;
Vertex v(Vector3f(pPos->x, pPos->y, pPos->z),
Vector2f(pTexCoord->x, pTexCoord->y),
Vector3f(pNormal->x, pNormal->y, pNormal->z));
Vertices.push_back(v);
}
for (unsigned int i = 0 ; i < paiMesh->mNumFaces ; i++) {
const aiFace& Face = paiMesh->mFaces[i];
assert(Face.mNumIndices == 3);
Indices.push_back(Face.mIndices[0]);
Indices.push_back(Face.mIndices[1]);
Indices.push_back(Face.mIndices[2]);
}
submeshes_cnt[Index].Init(Vertices, Indices);
}
void Mesh::Render(){
//enable VAOs for vertices, normals, textures
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
for(unsigned int i = 0 ; i < submeshes_cnt.size() ; i++){
glBindBuffer(GL_ARRAY_BUFFER, submeshes_cnt[i].VB);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)12);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)20);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, submeshes_cnt[i].IB);
const unsigned int MaterialIndex = submeshes_cnt[i].MaterialIndex;
if (MaterialIndex < textures_cnt.size() && textures_cnt[MaterialIndex]) {
textures_cnt[MaterialIndex]->Bind(GL_TEXTURE0);
}
glDrawElements(GL_TRIANGLES, submeshes_cnt[i].NumIndices, GL_UNSIGNED_INT, 0);
}
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
}
vertex shader:
#version 420
uniform mat4 camera;
uniform mat4 model;
in vec3 vert;
in vec2 vertTexCoord;
out vec2 fragTexCoord;
void main() {
// Pass the tex coord straight through to the fragment shader
fragTexCoord = vertTexCoord;
// Apply all matrix transformations to vert
gl_Position = camera * model * vec4(vert, 1);
}
fragment shader:
#version 420
uniform sampler2D tex;
in vec2 fragTexCoord;
out vec4 finalColor;
void main() {
//note: the texture function was called texture2D in older versions of GLSL
finalColor = texture(tex, fragTexCoord);
}
this is what i get:
before
but when i try to add phong lighting, when I add in attribute for normals to my vertex shader this is what I get:
after
Where is the problem?
Thank you for help.
//edit
shader loading and link
shprogram::shprogram(const std::vector<shader>& shaders) :
_object(0)
{
if(shaders.size() <= 0)
throw std::runtime_error("No shaders were provided to create the program");
//create the program object
_object = glCreateProgram();
if(_object == 0)
throw std::runtime_error("glCreateProgram failed");
//attach all the shaders
for(unsigned i = 0; i < shaders.size(); ++i)
glAttachShader(_object, shaders[i].getObject());
//link the shaders together
glLinkProgram(_object);
//detach all the shaders
for(unsigned i = 0; i < shaders.size(); ++i)
glDetachShader(_object, shaders[i].getObject());
//throw exception if linking failed
GLint status;
glGetProgramiv(_object, GL_LINK_STATUS, &status);
if (status == GL_FALSE) {
std::string msg("Program linking failure: ");
GLint infoLogLength;
glGetProgramiv(_object, GL_INFO_LOG_LENGTH, &infoLogLength);
char* strInfoLog = new char[infoLogLength + 1];
glGetProgramInfoLog(_object, infoLogLength, NULL, strInfoLog);
msg += strInfoLog;
delete[] strInfoLog;
glDeleteProgram(_object); _object = 0;
throw std::runtime_error(msg);
}
}
shprogram::~shprogram() {
//might be 0 if ctor fails by throwing exception
if(_object != 0) glDeleteProgram(_object);
}
GLuint shprogram::object() const {
return _object;
}
void shprogram::use() const {
glUseProgram(_object);
}
bool shprogram::isInUse() const {
GLint currentProgram = 0;
glGetIntegerv(GL_CURRENT_PROGRAM, &currentProgram);
return (currentProgram == (GLint)_object);
}
void shprogram::stopUsing() const {
assert(isInUse());
glUseProgram(0);
}
GLint shprogram::attrib(const GLchar* attribName) const {
if(!attribName)
throw std::runtime_error("attribName was NULL");
GLint attrib = glGetAttribLocation(_object, attribName);
if(attrib == -1)
throw std::runtime_error(std::string("Program attribute not found: ") + attribName);
return attrib;
}
GLint shprogram::uniform(const GLchar* uniformName) const {
if(!uniformName)
throw std::runtime_error("uniformName was NULL");
GLint uniform = glGetUniformLocation(_object, uniformName);
if(uniform == -1)
throw std::runtime_error(std::string("Program uniform not found: ") + uniformName);
return uniform;
}
void shprogram::setUniformMatrix2(const GLchar* name, const GLfloat* v, GLsizei count, GLboolean transpose) {
assert(isInUse());
glUniformMatrix2fv(uniform(name), count, transpose, v);
}
void shprogram::setUniformMatrix3(const GLchar* name, const GLfloat* v, GLsizei count, GLboolean transpose) {
assert(isInUse());
glUniformMatrix3fv(uniform(name), count, transpose, v);
}
void shprogram::setUniformMatrix4(const GLchar* name, const GLfloat* v, GLsizei count, GLboolean transpose) {
assert(isInUse());
glUniformMatrix4fv(uniform(name), count, transpose, v);
}
void shprogram::setUniform(const GLchar* name, const glm::mat2& m, GLboolean transpose) {
assert(isInUse());
glUniformMatrix2fv(uniform(name), 1, transpose, glm::value_ptr(m));
}
void shprogram::setUniform(const GLchar* name, const glm::mat3& m, GLboolean transpose) {
assert(isInUse());
glUniformMatrix3fv(uniform(name), 1, transpose, glm::value_ptr(m));
}
void shprogram::setUniform(const GLchar* name, const glm::mat4& m, GLboolean transpose) {
assert(isInUse());
glUniformMatrix4fv(uniform(name), 1, transpose, glm::value_ptr(m));
}
void shprogram::setUniform(const GLchar* uniformName, const glm::vec3& v) {
setUniform3v(uniformName, glm::value_ptr(v));
}
void shprogram::setUniform(const GLchar* uniformName, const glm::vec4& v) {
setUniform4v(uniformName, glm::value_ptr(v));
}
setting up uniforms
//bind shader program
gProgram->use();
//set the "camera" uniform
gProgram->setUniform("camera", gCamera.matrix());
//set the "model" uniform in the vertex shader, based on the gDegreesRotated global
gProgram->setUniform("model", glm::rotate(glm::mat4(), 150.0f ,glm::vec3(0,1,0)));
gProgram->setUniform("light.position", gLight.position);
gProgram->setUniform("light.intensities", gLight.intensities);
You neither explicitely set the attribute locations in the shader source, nor bind them before linking the shader, nor query them. The GL is free to use any valid attribute index for any active input attribute.
You just assume that 0 is position, 1 is texcoord and 2 is normal. It might work by accident for the position+texcoord case, but when you add the normal, the indices might get all mixed up. Either use layout(location=...) (see GL_ARB_explicit_attrib_location for details) in the GLSL code, or use glBindAttribLocation() to specify the mapping you want.