Directx Assimp Wrong Texture Coordinates - c++

I'm trying to load a mesh into my directx app. I can successfully load any mesh but texture coordinates are wrong on a side of mesh. (Only a side. The other side's texture is mapped correctly)
ScreenShot
Here's my code.
Model.h
#ifndef MODEL_H
#define MODEL_H
#include <vector>
#include <d3d11_1.h>
#include <DirectXMath.h>
#include <D3DX10.h>
#include <Importer.hpp>
#include <scene.h>
#include <postprocess.h>
#include "Mesh.h"
using namespace DirectX;
class CModel
{
public:
CModel();
~CModel();
bool Load(HWND hwnd, ID3D11Device* dev, ID3D11DeviceContext* devcon, std::string filename);
void Draw(ID3D11DeviceContext* devcon);
void Close();
private:
ID3D11Device *dev;
ID3D11DeviceContext *devcon;
std::vector<Mesh> meshes;
string directory;
vector<Texture> textures_loaded;
HWND hwnd;
void processNode(aiNode* node, const aiScene* scene);
Mesh processMesh(aiMesh* mesh, const aiScene* scene);
vector<Texture> loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName, const aiScene* scene);
string determineTextureType(const aiScene* scene, aiMaterial* mat);
int getTextureIndex(aiString* str);
ID3D11ShaderResourceView* getTextureFromModel(const aiScene* scene, int textureindex);
};
#endif
Model.cpp
#include "Model.h"
CModel::CModel()
{
}
CModel::~CModel()
{
}
bool CModel::Load(HWND hwnd, ID3D11Device* dev, ID3D11DeviceContext* devcon,
std::string filename)
{
Assimp::Importer importer;
const aiScene* pScene = importer.ReadFile(filename,
aiProcess_Triangulate |
aiProcess_ConvertToLeftHanded |
aiProcess_FlipUVs);
if (pScene == NULL)
return false;
this->directory = filename.substr(0, filename.find_last_of('/'));
this->dev = dev;
this->hwnd = hwnd;
processNode(pScene->mRootNode, pScene);
return true;
}
void CModel::processNode(aiNode* node, const aiScene* scene)
{
for (UINT i = 0; i < node->mNumMeshes; i++)
{
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
meshes.push_back(this->processMesh(mesh, scene));
}
for (UINT i = 0; i < node->mNumChildren; i++)
{
this->processNode(node->mChildren[i], scene);
}
}
string textype;
Mesh CModel::processMesh(aiMesh* mesh, const aiScene* scene)
{
// Data to fill
vector<VERTEX> vertices;
vector<DWORD> indices;
vector<Texture> textures;
if (mesh->mMaterialIndex >= 0)
{
aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex];
if(textype.empty()) textype = determineTextureType(scene, mat);
}
// Walk through each of the mesh's vertices
for (UINT i = 0; i < mesh->mNumVertices; i++)
{
VERTEX vertex;
vertex.X = mesh->mVertices[i].x;
vertex.Y = mesh->mVertices[i].y;
vertex.Z = mesh->mVertices[i].z;
if (mesh->mTextureCoords[0])
{
vertex.TEXX = mesh->mTextureCoords[0][i].x;
vertex.TEXY = mesh->mTextureCoords[0][i].y;
}
else
{
vertex.TEXX = 0.0f;
vertex.TEXY = 0.0f;
}
vertices.push_back(vertex);
}
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]);
}
if (mesh->mMaterialIndex >= 0)
{
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
vector<Texture> diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene);
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
//vector<Texture> specularMaps = this->loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
//textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
}
return Mesh(dev, vertices, indices, textures);
}
vector<Texture> CModel::loadMaterialTextures(aiMaterial* mat, aiTextureType
type, string typeName, const aiScene* scene)
{
vector<Texture> textures;
for (UINT i = 0; i < mat->GetTextureCount(type); i++)
{
aiString str;
mat->GetTexture(type, i, &str);
// Check if texture was loaded before and if so, continue to next iteration: skip loading a new texture
bool skip = false;
for (UINT j = 0; j < textures_loaded.size(); j++)
{
if (std::strcmp(textures_loaded[j].path.C_Str(), 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
HRESULT hr;
Texture texture;
if (textype == "embedded compressed texture")
{
int textureindex = getTextureIndex(&str);
texture.texture = getTextureFromModel(scene, textureindex);
}
else
{
string filename = string(str.C_Str());
filename = directory + '/' + filename;
hr = D3DX11CreateShaderResourceViewFromFile(dev, filename.c_str(), nullptr, nullptr, &texture.texture, nullptr);
if (FAILED(hr))
MessageBox(hwnd, "Texture couldn't be loaded", "Error!", MB_ICONERROR | MB_OK);
}
texture.type = typeName;
texture.path = str;
textures.push_back(texture);
this->textures_loaded.push_back(texture); // Store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures.
}
}
return textures;
}
void CModel::Draw(ID3D11DeviceContext* devcon)
{
for (int i = 0; i < meshes.size(); i++)
{
meshes[i].Draw(devcon);
}
}
void CModel::Close()
{
for (int i = 0; i < meshes.size(); i++)
{
meshes[i].Close();
}
dev->Release();
}
string CModel::determineTextureType(const aiScene* scene, aiMaterial* mat)
{
aiString textypeStr;
mat->GetTexture(aiTextureType_DIFFUSE, 0, &textypeStr);
string textypeteststr = textypeStr.C_Str();
if (textypeteststr == "*0" || textypeteststr == "*1" || textypeteststr == "*2" || textypeteststr == "*3" || textypeteststr == "*4" || textypeteststr == "*5")
{
if (scene->mTextures[0]->mHeight == 0)
{
return "embedded compressed texture";
}
else
{
return "embedded non-compressed texture";
}
}
if (textypeteststr.find('.') != string::npos)
{
return "textures are on disk";
}
}
int CModel::getTextureIndex(aiString* str)
{
string tistr;
tistr = str->C_Str();
tistr = tistr.substr(1);
return stoi(tistr);
}
ID3D11ShaderResourceView * CModel::getTextureFromModel(const aiScene * scene, int textureindex)
{
HRESULT hr;
ID3D11ShaderResourceView *texture;
int* size = reinterpret_cast<int*>(&scene->mTextures[textureindex]->mWidth);
hr = D3DX11CreateShaderResourceViewFromMemory(dev, reinterpret_cast<unsigned char*>(scene->mTextures[textureindex]->pcData), *size, nullptr, nullptr, &texture, nullptr);
if (FAILED(hr))
MessageBox(hwnd, "Texture couldn't be created from memory!", "Error!", MB_ICONERROR | MB_OK);
return texture;
}
Mesh.h (This is a header only class)
#ifndef MESH_H
#define MESH_H
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
using namespace std;
#include <vector>
#include <d3d11_1.h>
#include <DirectXMath.h>
#include <D3DX11.h>
#include <D3DX10.h>
using namespace DirectX;
struct VERTEX {
FLOAT X, Y, Z;
D3DXCOLOR color;
FLOAT TEXX, TEXY;
};
struct Texture {
string type;
aiString path;
ID3D11ShaderResourceView *texture;
};
class Mesh {
public:
vector<VERTEX> vertices;
vector<DWORD> indices;
vector<Texture> textures;
ID3D11Device *dev;
Mesh(ID3D11Device *dev,vector<VERTEX> vertices, vector<DWORD> indices, vector<Texture> textures)
{
this->vertices = vertices;
this->indices = indices;
this->textures = textures;
this->dev = dev;
this->setupMesh(dev);
}
void Draw(ID3D11DeviceContext *devcon)
{
UINT stride = sizeof(VERTEX);
UINT offset = 0;
devcon->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset);
devcon->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, 0);
devcon->PSSetShaderResources(0, 1, &textures[0].texture);
devcon->DrawIndexed(indices.size(), 0, 0);
}
void Close()
{
VertexBuffer->Release();
IndexBuffer->Release();
}
private:
/* Render data */
ID3D11Buffer *VertexBuffer, *IndexBuffer;
/* Functions */
// Initializes all the buffer objects/arrays
bool setupMesh(ID3D11Device *dev)
{
HRESULT hr;
D3D11_BUFFER_DESC vbd;
vbd.Usage = D3D11_USAGE_IMMUTABLE;
vbd.ByteWidth = sizeof(VERTEX) * vertices.size();
vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = 0;
vbd.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA initData;
initData.pSysMem = &vertices[0];
hr = dev->CreateBuffer(&vbd, &initData, &VertexBuffer);
if (FAILED(hr))
return false;
D3D11_BUFFER_DESC ibd;
ibd.Usage = D3D11_USAGE_IMMUTABLE;
ibd.ByteWidth = sizeof(DWORD) * indices.size();
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
ibd.CPUAccessFlags = 0;
ibd.MiscFlags = 0;
initData.pSysMem = &indices[0];
hr = dev->CreateBuffer(&ibd, &initData, &IndexBuffer);
if (FAILED(hr))
return false;
}
};
#endif
Thanks.

I solved it. If anyone else facing this issue be sure you have set a SamplerState.

Related

I am having problems with skeletal mesh loading with Assimp and DirectX

One thing is that the number of vertices in the mesh does not align with the number of vertices the bones are mapped to. The other is that I tried to hold on to the mRootnode in the header. When I call functions in the model class the node returned is not the same. I don't know how much of my code is right. I am trying to deform the mesh in the model class and not the shader.
Here is my code:
//Model.h
#pragma once
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include "Mesh.h"
#include <map>
#include <unordered_map>
#include <string>
using namespace std;
using namespace DirectX;
struct Bone {
int id = 0; // position of the bone in final upload array
std::string name = "";
XMMATRIX offset = XMMatrixIdentity();
std::vector<Bone> children = {};
};
class Model
{
public:
bool Initialize(const std::string & filePath, ID3D11Device * device, ID3D11DeviceContext * deviceContext, ConstantBuffer<CB_VS_vertexshader> & cb_vs_vertexshader, bool skel);
void Draw(const XMMATRIX & worldMatrix, const XMMATRIX & viewProjectionMatrix);
void Draw(const XMMATRIX& worldMatrix, const XMMATRIX& viewProjectionMatrix, float locx, float locz);
void boneTransform();
bool makeGrass(ID3D11Device* device, ID3D11DeviceContext* deviceContext, ConstantBuffer<CB_VS_vertexshader>& cb_vs_vertexshader);
bool makeMount(ID3D11Device* device, ID3D11DeviceContext* deviceContext, ConstantBuffer<CB_VS_vertexshader>& cb_vs_vertexshader);
bool makeWindow(ID3D11Device* device, ID3D11DeviceContext* deviceContext, ConstantBuffer<CB_VS_vertexshader>& cb_vs_vertexshader);
std::vector<Vertex> getVert(int num);
std::vector<DWORD> getIndu(int num);
float boneRots[500][4];
int numbones = 0;
string bonenames[500];
Bone skeleton;
private:
std::vector<Mesh> meshes;
XMMATRIX convertMat(aiMatrix4x4 m);
bool LoadModel(const std::string & filePath, bool hasSkel);
void ProcessNode(aiNode * node, const aiScene * scene, const XMMATRIX & parentTransformMatrix);
Mesh ProcessMesh(aiNode* node, aiMesh * mesh, const aiScene * scene, const XMMATRIX & transformMatrix);
void readNodeHierarchy(const aiNode* p_node, const aiMatrix4x4 parent_transform);
void updateMeshes();
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);
bool first;
ID3D11Device * device = nullptr;
ID3D11DeviceContext * deviceContext = nullptr;
ConstantBuffer<CB_VS_vertexshader> * cb_vs_vertexshader = nullptr;
std::string directory = "";
bool hasSkeleton;
aiMatrix4x4 m_global_inverse_transform;
std::vector<Mesh> transformed;
std::map<std::string, unsigned int> m_bone_mapping;
std::vector<BoneMatrix> m_bone_matrices;
std::vector<XMMATRIX> glmTransforms;
unsigned int m_num_bones = 0;
std::vector<MeshInfo> m_mesh_infos;
int mesh_index = 0;
std::vector<MeshBones> forMesh;
const aiScene* rootscene;
const aiNode * rootnode;
std::vector<unsigned int> texnum;
//std::unordered_map<std::string, std::pair<int, XMMATRIX>> boneInfo = {};
};
//Model.cpp
#include "Model.h"
#include <random>
unsigned int seed(165981);
mt19937 gen(seed);
uniform_real_distribution<double> dist(0, 1);
bool Model::Initialize(const std::string & filePath, ID3D11Device * device, ID3D11DeviceContext * deviceContext, ConstantBuffer<CB_VS_vertexshader>& cb_vs_vertexshader, bool skel)
{
this->device = device;
this->deviceContext = deviceContext;
this->cb_vs_vertexshader = &cb_vs_vertexshader;
try
{
if (!this->LoadModel(filePath, skel))
return false;
}
catch (COMException & exception)
{
ErrorLogger::Log(exception);
return false;
}
return true;
}
void Model::Draw(const XMMATRIX & worldMatrix, const XMMATRIX & viewProjectionMatrix)
{
this->deviceContext->VSSetConstantBuffers(0, 1, this->cb_vs_vertexshader->GetAddressOf());
if (hasSkeleton) {
this->cb_vs_vertexshader->data.mat = viewProjectionMatrix; //Calculate World-View-Projection Matrix
this->cb_vs_vertexshader->data.mat = XMMatrixTranspose(this->cb_vs_vertexshader->data.mat);
this->cb_vs_vertexshader->ApplyChanges();
for (int i = 0; i < transformed.size(); i++) transformed[i].Draw();
}else{
for (int i = 0; i < meshes.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();
meshes[i].Draw();
}
}
}
void Model::Draw(const XMMATRIX& worldMatrix, const XMMATRIX& viewProjectionMatrix, float locx, float locz) {
if (hasSkeleton) {
int non = 0;
}
this->deviceContext->VSSetConstantBuffers(0, 1, this->cb_vs_vertexshader->GetAddressOf());
char ord[] = {0, 0, 0};
float val[] = { 0, 0, 0 };
char last = 0;
for (char i = 0; i < 3; i++) {
float relx = meshes.at(i).locx - locx;
float relz = meshes.at(i).locz - locz;
float dist = sqrt(relx * relx + relz * relz);
for (char j = 0; j < 3; j++) {
if (dist > val[j]) {
last = j;
break;
}
}
if (last < 2) {
for (char j = 1; j >= last; j--) {
ord[j + 1] = ord[j];
val[j + 1] = val[j];
}
}
ord[last] = i;
val[last] = dist;
}
for (int i = 0; i < 3; i++)
{
int cho = (int)ord[i];
//Update Constant buffer with WVP Matrix
this->cb_vs_vertexshader->data.mat = meshes[cho].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();
meshes[cho].Draw();
}
}
std::vector<Vertex> Model::getVert(int num) {
std::vector<Vertex> ret;
if (num < meshes.size()) ret = meshes.at(num).getVerts();
return ret;
}
std::vector<DWORD> Model::getIndu(int num) {
std::vector<DWORD> ret;
if (num < meshes.size()) ret = meshes.at(num).getIndus();
return ret;
}
bool Model::LoadModel(const std::string & filePath, bool hasSkel)
{
first = true;
hasSkeleton = hasSkel;
this->directory = StringHelper::GetDirectoryFromPath(filePath);
Assimp::Importer importer;
const aiScene* pScene = importer.ReadFile(filePath,
aiProcess_Triangulate |
aiProcess_ConvertToLeftHanded | aiProcess_OptimizeMeshes);
if (pScene == nullptr)
return false;
rootscene = pScene;
rootnode = pScene->mRootNode;
m_global_inverse_transform = pScene->mRootNode->mTransformation;
m_global_inverse_transform.Inverse();
this->ProcessNode(pScene->mRootNode, pScene, DirectX::XMMatrixIdentity());
return true;
}
void Model::ProcessNode(aiNode * node, const aiScene * scene, const XMMATRIX & parentTransformMatrix)
{
XMMATRIX nodeTransformMatrix = XMMatrixTranspose(XMMATRIX(&node->mTransformation.a1)) * parentTransformMatrix;
for (UINT i = 0; i < node->mNumMeshes; i++)
{
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
Mesh mdup = this->ProcessMesh(node, mesh, scene, nodeTransformMatrix);
meshes.push_back(mdup);
if (hasSkeleton) transformed.push_back(mdup);
}
//int num = node->mNumChildren;
for (UINT i = 0; i < node->mNumChildren; i++)
{
this->ProcessNode(node->mChildren[i], scene, nodeTransformMatrix);
}
}
Mesh Model::ProcessMesh(aiNode* node, aiMesh* mesh, const aiScene* scene, const XMMATRIX& transformMatrix)
{
// Data to fill
std::vector<Vertex> vertices;
std::vector<DWORD> indices;
std::vector<VertexBoneData> bones_id_weights;
VertexBoneData emp;
//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);
bones_id_weights.push_back(emp);
}
//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]);
}
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());
if (hasSkeleton) {
//std::unordered_map<std::string, std::pair<int, XMMATRIX>> boneInfo = {};
std::vector<unsigned int> boneCounts;
boneCounts.resize(vertices.size(), 0);
int nBoneCount = mesh->mNumBones;
for (unsigned int i = 0; i < mesh->mNumBones; i++)
{
unsigned int bone_index = 0;
std::string bone_name(mesh->mBones[i]->mName.data);
if (m_bone_mapping.find(bone_name) == m_bone_mapping.end())
{
bonenames[numbones] = bone_name;
bone_index = m_num_bones;
m_num_bones++;
BoneMatrix bi;
m_bone_matrices.push_back(bi);
m_bone_matrices[bone_index].offset_matrix = mesh->mBones[i]->mOffsetMatrix;
m_bone_mapping[bone_name] = bone_index;
for (int j = 0; j < 4; j++) {
boneRots[numbones][j] = 0;
}
XMMATRIX pusher1;
glmTransforms.push_back(pusher1);
numbones++;
}
else
{
bone_index = m_bone_mapping[bone_name];
}
for (unsigned int j = 0; j < mesh->mBones[i]->mNumWeights; j++)
{
unsigned int vertex_id = mesh->mBones[i]->mWeights[j].mVertexId;
float weight = mesh->mBones[i]->mWeights[j].mWeight;
if (vertex_id >= bones_id_weights.size()) {
int non = 0;
}
bones_id_weights[vertex_id].ids.push_back(bone_index);
bones_id_weights[vertex_id].weights.push_back(weight);
}
}
MeshBones tmp;
tmp.boneInfl = bones_id_weights;
tmp.mesh = mesh_index;
forMesh.push_back(tmp);
mesh_index++;
}
return Mesh(this->device, this->deviceContext, vertices, indices, textures, transformMatrix);
}
TextureStorageType Model::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> Model::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 Model::GetTextureIndex(aiString * pStr)
{
assert(pStr->length >= 2);
return atoi(&pStr->C_Str()[1]);
}
void Model::readNodeHierarchy(const aiNode* p_node, const aiMatrix4x4 parent_transform)
{
std::string aname = p_node->mName.data;
aiMatrix4x4 global_transform;
std::string node_name(p_node->mName.data);
aiMatrix4x4 node_transform = p_node->mTransformation;
int sizes = 0;
for (int i = 0; i < meshes.size(); i++) sizes += meshes.at(i).getSize();
if (m_bone_mapping.find(node_name) != m_bone_mapping.end())
{
int bi = m_bone_mapping[node_name];
//aiVector3D scaling_vector = node_anim->mScalingKeys[2].mValue;
aiVector3D scaling_vector = aiVector3D(1, 1, 1);
aiMatrix4x4 scaling_matr;
aiMatrix4x4::Scaling(scaling_vector, scaling_matr);
//rotation
//aiQuaternion rotate_quat = node_anim->mRotationKeys[2].mValue;
aiQuaternion rotate_quat = aiQuaternion(boneRots[bi][0], boneRots[bi][1], boneRots[bi][2], boneRots[bi][3]);;
aiMatrix4x4 rotate_matr = aiMatrix4x4(rotate_quat.GetMatrix());
//translation
//aiVector3D translate_vector = node_anim->mPositionKeys[2].mValue;
aiVector3D translate_vector = aiVector3D(0, 0, 0);
aiMatrix4x4 translate_matr;
aiMatrix4x4::Translation(translate_vector, translate_matr);
node_transform = translate_matr * rotate_matr * scaling_matr;
aiMatrix4x4 global_transform = parent_transform * node_transform;
unsigned int bone_ind1 = m_bone_mapping[node_name];
m_bone_matrices[bone_ind1].final_world_transform = m_global_inverse_transform * global_transform * m_bone_matrices[bone_ind1].offset_matrix;
glmTransforms[bone_ind1] = XMMATRIX(&m_bone_matrices[bone_ind1].final_world_transform.a1);
//XMMATRIX(&pScene->mRootNode->mTransformation.a1)
}
int num = p_node->mNumChildren;
if (num > -1) {
for (unsigned int i = 0; i < p_node->mNumChildren; i++)
{
readNodeHierarchy(p_node->mChildren[i], global_transform);
}
}
}
void Model::boneTransform()
{
std::vector<aiMatrix4x4> transforms;
aiMatrix4x4 identity_matrix;
readNodeHierarchy(rootnode, identity_matrix);
glmTransforms.resize(m_num_bones);
for (unsigned int i = 0; i < m_num_bones; i++)
{
glmTransforms[i] = convertMat(m_bone_matrices[i].final_world_transform);
}
updateMeshes();
}
void Model::updateMeshes() {
for (int i = 0; i < forMesh.size(); i++) {
int curm = forMesh.at(i).mesh;
if (forMesh.at(i).boneInfl.size() != meshes.at(1).getSize()) {
int var1 = forMesh.at(i).boneInfl.size();
int var2 = meshes.at(1).getSize();
int non = 0;
}
for (int j = 0; j < forMesh.at(i).boneInfl.size();j++) {
XMFLOAT3 opos = meshes.at(curm).getVertex(j);
XMMATRIX bend = XMMatrixSet(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (forMesh.at(curm).boneInfl.at(j).ids.size() > 0) {
for (int k = 0; k < forMesh.at(curm).boneInfl.at(j).ids.size(); k++) {
int matnum = forMesh.at(curm).boneInfl.at(j).ids.at(k);
float matwei = forMesh.at(curm).boneInfl.at(j).weights.at(k);
bend += glmTransforms.at(matnum) * matwei;
}
XMVECTOR invec = XMLoadFloat3(&opos);
XMVECTOR vec = XMVector3Transform(invec, bend);
XMFLOAT3 otpos;
XMStoreFloat3(&otpos, vec);
transformed.at(curm).setVertex(otpos, j);
}else{
}
}
}
}
bool Model::makeGrass(ID3D11Device* device, ID3D11DeviceContext* deviceContext, ConstantBuffer<CB_VS_vertexshader>& cb_vs_vertexshader) {
if (!Initialize("Data\\Objects\\MyStuff\\grassblade.obj", device, deviceContext, cb_vs_vertexshader, false)) {
return false;
}
std::vector<Vertex> grassVerts;
std::vector<DWORD> grassIndu;
grassVerts = getVert(0);
grassIndu = getIndu(0);
std::vector<Vertex> outVerts;
std::vector<DWORD> outIndu;
int blanum = 0;
for (float x = -120; x < 120; x += .6) {
for (float z = -120; z < 120; z += .6) {
if (!(x > -25 && x < 25 && z > -25 && z < 25)) {
XMFLOAT3 grasPos(x, 0, z);
float col = dist(gen);
XMFLOAT3 grasScale(.5, .5, .5);
float myAngle = dist(gen) * 360;
float revAngle = dist(gen) * 90 - 45;
XMMATRIX WVP;
XMMATRIX translation, rotationX, rotationY, rotationZ, scale;
translation = XMMatrixTranslation(grasPos.x, 0, grasPos.z);
rotationX = XMMatrixRotationX(revAngle * 0.01745329251994329576923690768489);
rotationY = XMMatrixRotationY(myAngle * 0.01745329251994329576923690768489);
scale = XMMatrixScaling(50, 50, 50);
WVP = rotationX * rotationY * translation * scale;
int vertsiz = grassVerts.size();
for (int i = 0; i < vertsiz; i++) {
XMFLOAT3 inpos = grassVerts.at(i).pos;
XMVECTOR invec = XMLoadFloat3(&inpos);
XMVECTOR vec = XMVector3Transform(invec, WVP);
XMFLOAT3 otpos;
Vertex tmp;
XMStoreFloat3(&otpos, vec);
tmp.pos = otpos;
tmp.texCoord.x = col;
tmp.texCoord.y = 0;
outVerts.push_back(tmp);
}
int indsiz = grassIndu.size();
for (int i = 0; i < indsiz; i++) {
int strt = blanum * indsiz;
DWORD theind = strt + grassIndu.at(i);
outIndu.push_back(theind);
}
blanum++;
}
}
}
hasSkeleton = true;
vector<Texture> materialTextures;
materialTextures.push_back(Texture(this->device, Colors::UnhandledTextureColor, aiTextureType::aiTextureType_DIFFUSE));
transformed.push_back(Mesh(this->device, this->deviceContext, outVerts, outIndu, materialTextures, XMMatrixIdentity()));
return true;
}
bool Model::makeMount(ID3D11Device* device, ID3D11DeviceContext* deviceContext, ConstantBuffer<CB_VS_vertexshader>& cb_vs_vertexshader) {
if (!Initialize("Data\\Objects\\MyStuff\\mountains1.fbx", device, deviceContext, cb_vs_vertexshader, false)) {
return false;
}
meshes.at(0).clearTextures();
meshes.at(0).ismore = true;
meshes.at(0).loadTexture(device, "Data/Textures2/variation.png");
meshes.at(0).loadTexture(device, "Data/Textures2/cliff-rockface1_albedo.png");
meshes.at(0).loadTexture(device, "Data/Textures/seamless_grass.jpg");
return true;
}
bool Model::makeWindow(ID3D11Device* device, ID3D11DeviceContext* deviceContext, ConstantBuffer<CB_VS_vertexshader>& cb_vs_vertexshader) {
if (!Initialize("Data\\Objects\\MyStuff\\window.fbx", device, deviceContext, cb_vs_vertexshader, false)) {
return false;
}
for (int i = 0; i < 3; i++) {
meshes.at(i).clearTextures();
meshes.at(i).ismore = true;
meshes.at(i).loadTexture(device, "Data/Textures2/liquid_pattern.jpg");
meshes.at(i).loadTexture(device, "Data/Textures2/liquid_alpha.png");
}
return true;
}
XMMATRIX Model::convertMat(aiMatrix4x4 m) {
return XMMATRIX
(m.a1, m.a2, m.a3, m.a4,
m.b1, m.b2, m.b3, m.b4,
m.c1, m.c2, m.c3, m.c4,
m.d1, m.d2, m.d3, m.d4);
}
//Mesh.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"
struct BoneMatrix
{
aiMatrix4x4 offset_matrix;
aiMatrix4x4 final_world_transform;
};
struct VertexBoneData
{
std::vector<unsigned int> ids;
std::vector<float> weights;
};
struct MeshBones {
unsigned int mesh;
std::vector<VertexBoneData> boneInfl;
};
struct MeshInfo {
MeshInfo()
{ // accumulate all vertices from many scene mesh in one vector
base_index = 0; // offset in our one mesh after adding vertices from next scene->mesh[i]
}
unsigned int base_index; // base_index == base_vertex
};
class Mesh
{
public:
Mesh(ID3D11Device * device, ID3D11DeviceContext * deviceContext, std::vector<Vertex> & vertices, std::vector<DWORD> & indices, std::vector<Texture> & textures, const DirectX::XMMATRIX & transformMatrix);
Mesh(const Mesh & mesh);
void Draw();
void loadTexture(ID3D11Device* device, std::string path);
void clearTextures();
const DirectX::XMMATRIX & GetTransformMatrix();
std::vector<Vertex> getVerts();
std::vector<DWORD> getIndus();
DirectX::XMFLOAT3 getVertex(unsigned int num);
void setVertex(DirectX::XMFLOAT3 vert, unsigned int num);
int getSize();
void reinit(ID3D11Device* device);
bool getpos = false;
bool ismore = false;
float locx = 0;
float locz = 0;
bool xdif = false;
private:
std::vector<Vertex> meshVerts;
std::vector<DWORD> meshIndu;
VertexBuffer<Vertex> vertexbuffer;
IndexBuffer indexbuffer;
ID3D11DeviceContext * deviceContext;
std::vector<Texture> textures;
DirectX::XMMATRIX transformMatrix;
};
//Mesh.cpp
#include "Mesh.h"
Mesh::Mesh(ID3D11Device * device, ID3D11DeviceContext * deviceContext, std::vector<Vertex>& vertices, std::vector<DWORD>& indices, std::vector<Texture> & textures, const DirectX::XMMATRIX & transformMatrix)
{
meshVerts = vertices;
meshIndu = indices;
this->deviceContext = deviceContext;
this->textures = textures;
this->transformMatrix = transformMatrix;
HRESULT hr = this->vertexbuffer.Initialize(device, vertices.data(), vertices.size());
COM_ERROR_IF_FAILED(hr, "Failed to initialize vertex buffer for mesh.");
hr = this->indexbuffer.Initialize(device, indices.data(), indices.size());
COM_ERROR_IF_FAILED(hr, "Failed to initialize index buffer for mesh.");
int vcnt = vertices.size();
float kep = vertices.at(1).pos.x;
for (int i = 0; i < vcnt; i++) {
locx += vertices.at(i).pos.x;
locz += vertices.at(i).pos.z;
if (vertices.at(i).pos.x != kep) xdif = true;
}
locx /= (float)vcnt;
locz /= (float)vcnt;
}
Mesh::Mesh(const Mesh & mesh)
{
this->deviceContext = mesh.deviceContext;
this->indexbuffer = mesh.indexbuffer;
this->vertexbuffer = mesh.vertexbuffer;
this->textures = mesh.textures;
this->transformMatrix = mesh.transformMatrix;
this->meshVerts = mesh.meshVerts;
this->meshIndu = mesh.meshIndu;
this->getpos = mesh.getpos;
this->locx = mesh.locx;
this->locz = mesh.locz;
this->xdif = mesh.xdif;
}
void Mesh::Draw()
{
UINT offset = 0;
if (ismore) {
UINT tcnt = 0;
for (int i = 0; i < textures.size(); i++)
{
if (textures[i].GetType() == aiTextureType::aiTextureType_DIFFUSE)
{
this->deviceContext->PSSetShaderResources(tcnt, 1, textures[i].GetTextureResourceViewAddress());
tcnt++;
}
}
}else {
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 & Mesh::GetTransformMatrix()
{
return this->transformMatrix;
}
std::vector<Vertex> Mesh::getVerts() {
return meshVerts;
}
std::vector<DWORD> Mesh::getIndus() {
return meshIndu;
}
DirectX::XMFLOAT3 Mesh::getVertex(unsigned int num) {
return meshVerts.at(num).pos;
}
void Mesh::setVertex(DirectX::XMFLOAT3 vert, unsigned int num) {
meshVerts.at(num).pos = vert;
}
void Mesh::reinit(ID3D11Device* device) {
vertexbuffer.Initialize(device, &meshVerts[0], meshVerts.size());
}
void Mesh::loadTexture(ID3D11Device* device, std::string path) {
textures.push_back(Texture(device, path, aiTextureType_DIFFUSE));
}
void Mesh::clearTextures() {
textures.clear();
}
int Mesh::getSize() {
return meshVerts.size();
}

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

How can I use multiple shader in my renderer?

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?

Trying to render a 3d triagle Crushes the Nvidia Driver! WHY? [C++ && DirectX11 SDK]

Here is the Triangle.cpp code:
#include "Triangle.h"
Triangle::Triangle()
{
_vertexBuffer = NULL;
_indexBuffer = NULL;
_vertexShader = NULL;
_pixelShader = NULL;
_inputLayout = NULL;
_stride = sizeof(Vertex);
_offset = 0;
}
Triangle::~Triangle()
{
if (_vertexBuffer)
{
_vertexBuffer->Release();
_vertexBuffer = NULL;
}
if (_indexBuffer)
{
_indexBuffer->Release();
_indexBuffer = NULL;
}
if (_vertexShader)
{
_vertexShader->Release();
_vertexShader = NULL;
}
if (_pixelShader)
{
_pixelShader->Release();
_pixelShader = NULL;
}
if (_inputLayout)
{
_inputLayout->Release();
_inputLayout = NULL;
}
}
const bool Triangle::Initialize(DirectX * graphics)
{
_graphics = graphics;
InitTriangleData();
if (!InitializeVertexAndIndexBuffers(graphics->GetDevice()))
return false;
if (!InitializeShadersAndinputLayout(graphics->GetDevice()))
return false;
return true;
}
void Triangle::Render()
{
_graphics->GetDeviceContext()->IASetVertexBuffers(0, 1, &_vertexBuffer, &_stride, &_offset);
_graphics->GetDeviceContext()->IASetIndexBuffer(_indexBuffer, DXGI_FORMAT_D32_FLOAT, 0);
_graphics->GetDeviceContext()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
_graphics->GetDeviceContext()->PSSetShader(_pixelShader, 0, 1);
_graphics->GetDeviceContext()->VSSetShader(_vertexShader, 0, 1);
_graphics->GetDeviceContext()->DrawIndexed(3, 0, 0);
_graphics->GetDeviceContext()->PSSetShader(0, 0, 0);
_graphics->GetDeviceContext()->VSSetShader(0, 0, 0);
}
void Triangle::InitTriangleData()
{
_vertices = new Vertex[3];
_indices = new unsigned long[3];
float halfX = 50;
float halfY = 50;
_vertices[0].position = D3DXVECTOR3(0.0f, halfY, 0.0f);
_vertices[0].uv = D3DXVECTOR2(0.0f, 0.0f);
_vertices[1].position = D3DXVECTOR3(halfX, -halfY, 0.0f);
_vertices[1].uv = D3DXVECTOR2(0.0f, 0.0f);
_vertices[2].position = D3DXVECTOR3(-halfX, -halfY, 0.0f);
_vertices[2].uv = D3DXVECTOR2(0.0f, 0.0f);
}
const bool Triangle::InitializeVertexAndIndexBuffers(ID3D11Device * device)
{
HRESULT result;
D3D11_BUFFER_DESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof bufferDesc);
D3D11_SUBRESOURCE_DATA bufferData;
ZeroMemory(&bufferData, sizeof bufferData);
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDesc.ByteWidth = _stride * 3;
bufferDesc.StructureByteStride = 0;
bufferDesc.MiscFlags = 0;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferData.pSysMem = _vertices;
result = device->CreateBuffer(&bufferDesc, &bufferData, &_vertexBuffer);
if (FAILED(result))
return false;
ZeroMemory(&bufferData, sizeof bufferData);
ZeroMemory(&bufferDesc, sizeof bufferDesc);
bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
bufferDesc.ByteWidth = sizeof(unsigned long) *3;
bufferDesc.StructureByteStride = 0;
bufferDesc.MiscFlags = 0;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferData.pSysMem =_indices;
result = device->CreateBuffer(&bufferDesc, &bufferData, &_indexBuffer);
if (FAILED(result))
return false;
delete[] _vertices;
_vertices = 0;
delete[] _indices;
_indices = 0;
return true;
}
const bool Triangle::InitializeShadersAndinputLayout(ID3D11Device * device)
{
HRESULT result;
ID3D10Blob *data;
ID3D10Blob* error;
std::string name = ".//Resources//Shaders//BasicTextureShader//color.ps";
result = D3DX11CompileFromFileA(name.c_str(), NULL, NULL, "ColorPixelShader", "ps_5_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, NULL, &data, &error, NULL);
if (FAILED(result)) {
if (error)
{
PrintOutMessage(error);
error->Release();
error = NULL;
}
return false;
}
result = device->CreatePixelShader(data->GetBufferPointer(), data->GetBufferSize(), NULL, &_pixelShader);
if (FAILED(result)) {
return false;
}
data->Release();
data = NULL;
name.clear();
name = ".//Resources//Shaders//BasicTextureShader//color.vs";
result = D3DX11CompileFromFileA(name.c_str(), NULL, NULL, "ColorVertexShader", "vs_5_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, NULL, &data, &error, NULL);
if (FAILED(result)) {
if (error)
{
PrintOutMessage(error);
error->Release();
error = NULL;
}
return false;
}
result = device->CreateVertexShader(data->GetBufferPointer(), data->GetBufferSize(), NULL, &_vertexShader);
if (FAILED(result))
return false;
D3D11_INPUT_ELEMENT_DESC elements[2];
unsigned int elementsCount = 2;
elements[0].AlignedByteOffset = 0;
elements[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
elements[0].InputSlot = 0;
elements[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
elements[0].InstanceDataStepRate = 0;
elements[0].SemanticIndex = 0;
elements[0].SemanticName = "POSITION";
elements[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
elements[1].Format = DXGI_FORMAT_R32G32_FLOAT;
elements[1].InputSlot = 0;
elements[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
elements[1].InstanceDataStepRate = 0;
elements[1].SemanticIndex = 0;
elements[1].SemanticName = "TEXCOORD";
result = device->CreateInputLayout(elements, elementsCount, data->GetBufferPointer(), data->GetBufferSize(), &_inputLayout);
if (FAILED(result))
return false;
data->Release();
data = NULL;
return true;
}
void Triangle::PrintOutMessage(ID3D10Blob * error)
{
if (!error)
return;
char * message = new char[error->GetBufferSize()];
message = (char*)error->GetBufferPointer();
std::fstream file;
file.open("ShaderErrorReport.txt", std::fstream::in | std::fstream::out | std::fstream::trunc);
if (!file.is_open())
return;
for (size_t i = 0; i < error->GetBufferSize(); i++)
{
file << message[i];
}
file.close();
}
And the Triangle.h code:
#ifndef TRIANGLE_H
#define TRIANGLE_H
#include "Engine\DirectX.h"
#include <D3DX10math.h>
#include <string>
#include <fstream>
class Triangle
{
private:
struct ConstantBuffer {
D3DXMATRIX world;
D3DXMATRIX view;
D3DXMATRIX proj;
};
struct Vertex
{
D3DXVECTOR3 position;
D3DXVECTOR2 uv;
};
public:
Triangle();
~Triangle();
const bool Initialize(DirectX* graphics);
void Render();
private:
void InitTriangleData();
const bool InitializeVertexAndIndexBuffers(ID3D11Device* device);
const bool InitializeShadersAndinputLayout(ID3D11Device* device);
void PrintOutMessage(ID3D10Blob * error);
private:
Vertex* _vertices;
unsigned long * _indices;
unsigned int _vertexCount = 3;
unsigned int indexCount = 3;
unsigned int _stride;
unsigned int _offset;
ID3D11Buffer* _vertexBuffer, *_indexBuffer, *_constantBuffer;
ID3D11InputLayout *_inputLayout;
ID3D11PixelShader* _pixelShader;
ID3D11VertexShader* _vertexShader;
DirectX* _graphics;
};
#endif
I have a Nvidia GTX 760 gpu and when i run this it the Graphics driver crushes and recovers...and my window goes white.[the 'clear' color is black]
The API ID3D11DeviceContext::PSSetShader and ID3D11DeviceContext::VSSetShader second and third arguments are use for dynamic linkage, in your case they should be nullptr and 0. By telling the device 0,1, you claim one class instance but give a nil pointer for it. The device reject your invalid shader binding, and when you attempt to render, the gpu hang because it does not have a proper shader to run.
In your code, replace
_graphics->GetDeviceContext()->PSSetShader(_pixelShader, 0, 1);
_graphics->GetDeviceContext()->VSSetShader(_vertexShader, 0, 1);
by
_graphics->GetDeviceContext()->PSSetShader(_pixelShader, nullptr, 0);
_graphics->GetDeviceContext()->VSSetShader(_vertexShader, nullptr, 0);

glCreateShader fails and return 0

I'm having a problem with glCreateShaders. It always returns 0. I'm using Glew with SDL and whenever I run the program, it says:
0(1) : error C0000: syntax error, unexpected '}' at token "}"
Shader Shaders/colorShading.vert failed to compile!
main.cpp:
#include <iostream>
#include "MainGame.h"
int main(int argc, char** argv)
{
MainGame maingame;
maingame.run();
return 0;
}
MainGame.h:
//Core -> initializing glew, sdl etc...
//Just ignore the sprite class
#pragma once
#include <SDL/SDL.h>
#include <GL/glew.h>
#include <iostream>
#include <string>
#include "Errors.h"
#include "GLSLProgram.h"
enum class GameState {PLAY, EXIT};
#include "Sprite.h"
class MainGame
{
public:
MainGame(void);
~MainGame(void);
void run();
private:
void initSystems();
void initShaders();
void gameLoop();
void processInput();
void drawGame();
SDL_Window* _window;
int _screenWidth;
int _screenHeight;
GameState _gameState;
Sprite _sprite;
GLSLProgram _colorProgram;
};
MainGame.cpp:
#include "MainGame.h"
MainGame::MainGame(void)
{
_window = nullptr;
_screenWidth = 1024;
_screenHeight = 700;
_gameState = GameState::PLAY;
}
MainGame::~MainGame(void)
{
}
void MainGame::run()
{
initSystems();
_sprite.init(-1.0f, -1.0f, 1.0f, 1.0f);
gameLoop();
}
void MainGame::initSystems()
{
//Initialize SDL
SDL_Init(SDL_INIT_EVERYTHING);
_window = SDL_CreateWindow("Game Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _screenWidth, _screenHeight, SDL_WINDOW_OPENGL);
if (_window == nullptr)
{
fatalError("SDL Window could not be created!");
}
SDL_GLContext glContext = SDL_GL_CreateContext(_window);
if (glContext == nullptr)
fatalError("SDL_GL context could not be created!");
GLenum error = glewInit();
if (error != GLEW_OK)
fatalError("Could not initialize glew!");
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
initShaders();
}
void MainGame::initShaders()
{
_colorProgram.compileShaders("Shaders/colorShading.vert", "Shaders/colorShading.frag");
_colorProgram.addAttribute("vertexPosition");
_colorProgram.linkShaders();
}
void MainGame::gameLoop()
{
while (_gameState != GameState::EXIT)
{
processInput();
drawGame();
}
}
void MainGame::processInput()
{
SDL_Event evnt;
while (SDL_PollEvent(&evnt))
{
switch (evnt.type)
{
case SDL_QUIT:
_gameState = GameState::EXIT;
break;
case SDL_MOUSEMOTION:
std::cout << "New Coords: " << evnt.motion.x << " " << evnt.motion.y << std::endl;
break;
}
}
}
void MainGame::drawGame()
{
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
_colorProgram.use();
_sprite.draw();
_colorProgram.unUse();
SDL_GL_SwapWindow(_window);
}
GLSLProgram.h:
//Used for
#pragma once
#include <string>
#include <GL/glew.h>
//#include <SDL/SDL.h>
#include "Errors.h"
class GLSLProgram
{
public:
GLSLProgram();
~GLSLProgram();
void compileShaders(const std::string& vertextShaderFilePath, const std::string& fragmentShaderFilePath);
void linkShaders();
void addAttribute(const std::string&);
void use();
void unUse();
private:
int _numAttributes;
void _compileShader(const std::string&, GLuint);
GLuint _programID;
GLuint _vertexShaderID;
GLuint _fragmentShaderID;
};
GLSLProgram.cpp:
//Used for compiling shaders
#include "GLSLProgram.h"
#include <fstream>
#include <vector>
GLSLProgram::GLSLProgram() : _numAttributes(0), _programID(0), _vertexShaderID(0), _fragmentShaderID(0)
{
}
GLSLProgram::~GLSLProgram()
{
}
void GLSLProgram::compileShaders(const std::string& vertexShaderFilePath, const std::string& fragmentShaderFilePath)
{
_vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
if (_vertexShaderID == 0)
{
fatalError("Vertex shader failed to be created!");
SDL_Quit();
}
_fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
if (_fragmentShaderID == 0)
{
fatalError("Fragment shader failed to be created!");
SDL_Quit();
}
_compileShader(vertexShaderFilePath, _vertexShaderID);
_compileShader(fragmentShaderFilePath, _fragmentShaderID);
}
void GLSLProgram::addAttribute(const std::string& attributeName)
{
glBindAttribLocation(_programID, _numAttributes++, attributeName.c_str());
}
void GLSLProgram::use()
{
glUseProgram(_programID);
for (int x = 0; x < _numAttributes; x++)
{
glEnableVertexAttribArray(x);
}
}
void GLSLProgram::unUse()
{
glUseProgram(0);
for (int x = 0; x < _numAttributes; x++)
{
glDisableVertexAttribArray(x);
}
}
void GLSLProgram::linkShaders()
{
//Vertex and fragment shaders are successfully compiled.
//Now time to link them together into a program.
//Get a program object.
_programID = glCreateProgram();
//Attach our shaders to our program
glAttachShader(_programID, _vertexShaderID);
glAttachShader(_programID, _fragmentShaderID);
//Link our program
glLinkProgram(_programID);
//Note the different functions here: glGetProgram* instead of glGetShader*.
GLint isLinked = 0;
glGetProgramiv(_programID, GL_LINK_STATUS, (int *)&isLinked);
if (isLinked == GL_FALSE)
{
GLint maxLength = 0;
glGetProgramiv(_programID, GL_INFO_LOG_LENGTH, &maxLength);
//The maxLength includes the NULL character
std::vector<char> infoLog(maxLength);
glGetProgramInfoLog(_programID, maxLength, &maxLength, &infoLog[0]);
//We don't need the program anymore.
glDeleteProgram(_programID);
//Don't leak shaders either.
glDeleteShader(_vertexShaderID);
glDeleteShader(_fragmentShaderID);
printf("%s\n", &(infoLog[0]));
fatalError("Shaders failed to link!");
}
//Always detach shaders after a successful link.
glDetachShader(_programID, _vertexShaderID);
glDetachShader(_programID, _fragmentShaderID);
glDeleteProgram(_programID);
glDeleteShader(_vertexShaderID);
glDeleteShader(_fragmentShaderID);
}
void GLSLProgram::_compileShader(const std::string &filePath, GLuint id)
{
std::ifstream vertexFile(filePath);
if (vertexFile.fail())
{
perror(filePath.c_str());
fatalError("Failed to open " + filePath);
}
std::string fileContents;
std::string line;
while (std::getline(vertexFile, line));
{
fileContents += line + "\n";
}
vertexFile.close();
const char *contentsPtr = fileContents.c_str();
glShaderSource(id, 1, &contentsPtr, nullptr);
glCompileShader(id);
GLint isCompiled = 0;
glGetShaderiv(id, GL_COMPILE_STATUS, &isCompiled);
if (isCompiled == GL_FALSE)
{
GLint maxLength = 0;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &maxLength);
//The maxLength includes the NULL character
std::vector<char> errorLog(maxLength);
glGetShaderInfoLog(id, maxLength, &maxLength, &errorLog[0]);
//Provide the infolog in whatever manor you deem best.
//Exit with failure.
glDeleteShader(id); //Don't leak the shader.
printf("%s\n", &(errorLog[0]));
fatalError("Shader" + filePath + "failed to compile!");
}
}
vertex shader:
#version 130
//The vertex shader operates on each vertex
//input data from the VBO. Each vertex is 2 floats
in vec2 vertexPosition;
void main()
{
//Set the x,y position on the screen
gl_Position.xy = vertexPosition;
//the z position is zero since we are in 2D
gl_Position.z = 0.0;
//Indicate that the coordinates are normalized
gl_Position.w = 1.0;
}
and fragment shader:
#version 130
//The fragment shader operates on each pixel in a given polygon
//This is the 3 component float vector that gets outputted to the screen
//for each pixel.
out vec3 color;
void main() {
//Just hardcode the color to red
color = vec3(1.0, 0.0, 1.0);
}
I don't have any idea why it is happening. :(
PS: I'm beginner with glew so please don't answer with some advance stuff:D
Edit 1:
02/11/2014 (11/02/2014 for Americans)
I downloaded the source code from the tutorial I was using and it is working. So there's something with my code. I will edit the post when I find the problem.
Remove semicolon in file GLSLProgram.cpp at line:
while (std::getline(vertexFile, line));
You go through the file and then just add to the empty string fileContents the last line of your shader code, that is '}'.