OpenGL + Uniform Variables not reaching shaders + splines - c++

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

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

GLFW Mouse drift

I am currently developing a test project for OpenGL to discover its possibilities.
I am experiencing a weird bug with GLFW 4.0 apparently called "mouse drift" (from different github issues). It means that even though my mouse is not moving, the glfw input callback will still be called with small x and y values (generally 1 or -1).
I provided my code here : https://github.com/Lygaen/testgl (not ads or promoting, just giving the link to the full project to help reproduce). I am using a basic GLFW, GLAD and GLM framework.
My goal is to calculate the delta position of the mouse, to have correct camera movement.
Thank you for any help that you could provide !
Here is the code that calculates input :
window.h
#ifndef __WINDOW_H__
#define __WINDOW_H__
#include <string>
#include <glad/gl.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <vector>
class Window
{
private:
GLFWwindow *window;
bool correctlyLoaded;
static void resizeCallback(GLFWwindow *, int, int);
public:
Window(const std::string &, int, int);
~Window();
const bool hasCorrectlyLoaded();
const bool shouldClose();
const void pollEvents();
const void exitNextFrame();
};
class Input
{
private:
static char *keyStates;
static bool *mouseStates;
static glm::dvec2 pos;
static glm::dvec2 delta;
static std::vector<int> pressed;
static void keyCallback(GLFWwindow *, int, int, int, int);
static void mouseCallback(GLFWwindow *, double, double);
static void mouseButtonCallback(GLFWwindow *, int, int, int);
public:
static const bool isPressed(int);
static const bool isDown(int);
static const bool isReleased(int);
static const glm::dvec2 getMousePosition();
static const glm::dvec2 getMouseDelta();
static const bool isMouseButtonDown(int);
static const void setCallbacks(GLFWwindow *);
static const void loopClear();
static const void terminate();
};
#endif // __WINDOW_H__
window.cpp
#include "window.h"
#include <spdlog/spdlog.h>
#include <algorithm>
Window::Window(const std::string &title, int width, int height)
{
correctlyLoaded = false;
if (!glfwInit())
{
spdlog::default_logger()->critical("Could not load GLFW");
return;
}
spdlog::default_logger()->info("Loaded GLFW {}", glfwGetVersionString());
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
if (!window)
{
spdlog::default_logger()->critical("Failed to create GLFW window !");
return;
}
glfwMakeContextCurrent(window);
if (!gladLoadGL(glfwGetProcAddress))
{
spdlog::default_logger()->critical("Failed to load OpenGL !");
return;
}
spdlog::default_logger()->info("Loaded OpenGL {}", glfwGetVersionString());
glViewport(0, 0, width, height);
glEnable(GL_MULTISAMPLE);
glfwSetFramebufferSizeCallback(window, Window::resizeCallback);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
Input::setCallbacks(window);
correctlyLoaded = true;
}
Window::~Window()
{
glfwTerminate();
}
void Window::resizeCallback(GLFWwindow *, int width, int height)
{
glViewport(0, 0, width, height);
}
const bool Window::hasCorrectlyLoaded()
{
return correctlyLoaded;
}
const bool Window::shouldClose()
{
return glfwWindowShouldClose(window);
}
const void Window::pollEvents()
{
Input::loopClear();
glfwSwapBuffers(window);
glfwPollEvents();
}
const void Window::exitNextFrame()
{
glfwSetWindowShouldClose(window, true);
}
char *Input::keyStates;
bool *Input::mouseStates;
glm::tvec2<double> Input::pos;
glm::tvec2<double> Input::delta;
std::vector<int> Input::pressed;
void Input::keyCallback(GLFWwindow *, int key, int /*scancode*/, int action, int /*mods*/)
{
if (key < 0 || key > GLFW_KEY_LAST)
return;
keyStates[key] = action;
if (action == GLFW_PRESS)
{
pressed.push_back(key);
}
}
void Input::mouseCallback(GLFWwindow *window, double nXPos, double nYPos)
{
glm::dvec2 newPos = {nXPos, nYPos};
delta = newPos - pos;
pos = newPos;
glfwSetCursorPos(window, 0, 0);
}
void Input::mouseButtonCallback(GLFWwindow *window, int button, int action, int /*mods*/)
{
if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST)
return;
mouseStates[button] = action;
}
const bool Input::isPressed(int key)
{
return std::count(pressed.begin(), pressed.end(), key);
}
const bool Input::isDown(int key)
{
return keyStates[key] != GLFW_RELEASE;
}
const bool Input::isReleased(int key)
{
return keyStates[key] == GLFW_RELEASE;
}
const glm::dvec2 Input::getMousePosition()
{
return pos;
}
const glm::dvec2 Input::getMouseDelta()
{
return delta;
}
const bool Input::isMouseButtonDown(int mouseButton)
{
return mouseStates[mouseButton] == GLFW_PRESS;
}
const void Input::setCallbacks(GLFWwindow *window)
{
keyStates = new char[GLFW_KEY_LAST];
mouseStates = new bool[GLFW_MOUSE_BUTTON_LAST];
glfwSetKeyCallback(window, Input::keyCallback);
glfwSetCursorPosCallback(window, Input::mouseCallback);
glfwSetMouseButtonCallback(window, Input::mouseButtonCallback);
}
const void Input::loopClear()
{
pressed.clear();
}
const void Input::terminate()
{
delete[] keyStates;
delete[] mouseStates;
}
main.cpp
#include <iostream>
#include "gui/window.h"
#include "gui/gl/shader.h"
#include <spdlog/spdlog.h>
#include <spdlog/fmt/bin_to_hex.h>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/scalar_multiplication.hpp>
glm::mat4 fpsView(glm::vec3 cam, float pitch, float yaw)
{
float cosPitch = cos(pitch);
float sinPitch = sin(pitch);
float cosYaw = cos(yaw);
float sinYaw = sin(yaw);
glm::vec3 xaxis = {cosYaw, 0, -sinYaw};
glm::vec3 yaxis = {sinYaw * sinPitch, cosPitch, cosYaw * sinPitch};
glm::vec3 zaxis = {sinYaw * cosPitch, -sinPitch, cosPitch * cosYaw};
// Create a 4x4 view matrix from the right, up, forward and eye position vectors
glm::mat4 viewMatrix = {
glm::vec4(xaxis.x, yaxis.x, zaxis.x, 0),
glm::vec4(xaxis.y, yaxis.y, zaxis.y, 0),
glm::vec4(xaxis.z, yaxis.z, zaxis.z, 0),
glm::vec4(-glm::dot(xaxis, cam), -glm::dot(yaxis, cam), -glm::dot(zaxis, cam), 1)};
return viewMatrix;
}
int main(int, char **)
{
#ifndef NDEBUG
spdlog::set_level(spdlog::level::trace);
#endif
Window window("Test GL", 800, 600);
if (!window.hasCorrectlyLoaded())
{
return 1;
}
float vertices[] = {
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
};
unsigned int indices[] = {
// note that we start from 0!
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
Shader shader;
unsigned int VAO;
GL(glGenVertexArrays(1, &VAO));
GL(glBindVertexArray(VAO));
unsigned int VBO;
GL(glGenBuffers(1, &VBO));
GL(glBindBuffer(GL_ARRAY_BUFFER, VBO));
GL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));
unsigned int EBO;
GL(glGenBuffers(1, &EBO));
GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO));
GL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW));
GL(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (void *)0));
GL(glEnableVertexAttribArray(0));
glm::mat4 Projection = glm::perspective(glm::radians(90.0f), (float)800 / (float)600, 0.1f, 100.0f);
glm::vec3 cam{4, 3, 3};
glm::vec2 dir{0, 0};
glm::mat4 Model = glm::mat4(1.0f);
while (!window.shouldClose())
{
GL(glClearColor(0.2f, 0.3f, 0.3f, 1.0f));
GL(glClear(GL_COLOR_BUFFER_BIT));
glm::mat4 View = fpsView(cam, dir.y, dir.x);
glm::mat4 mvp = Projection * View * Model;
shader.setUniform("MVP", &mvp);
shader.bind();
GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO));
GL(glBindVertexArray(VAO));
GL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0));
GL(glBindVertexArray(0));
window.pollEvents();
if (Input::isPressed(GLFW_KEY_ESCAPE))
{
window.exitNextFrame();
}
if (Input::isPressed(GLFW_KEY_F6))
{
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
else if (Input::isReleased(GLFW_KEY_F6))
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
glm::dvec2 d = Input::getMouseDelta();
dir += d * 0.001;
}
spdlog::default_logger()->info("Quitting !");
}

Static Function using static variable error (illegal reference)

Ive been working in glfw c++ and want to get input from the mouse wheel by using the glfwSetScrollCallback() and I put it in a window class that I created because it requires a glfw window. I created a scroll_callback function that adjusts the fov for the camera that I initialize in a camera class. The glfwSetScrollCallback() uses that static void of my scroll_callback function in my camera class. However, I cant seem how to initialize a the fov variable in my camera.h and use it in the static void in my camera.cpp. I tried changing it to a static public variable because I need to call it in my main class but it didnt work. Any thoughts thank you!!!
camera.h
#pragma once
#include <GL\glew.h>
#include <glm\glm.hpp>
#include <glm\gtc\matrix_transform.hpp>
#include <GLFW\glfw3.h>
class Camera
{
public:
Camera();
Camera(glm::vec3 startPosition, glm::vec3 startUp, GLfloat startYaw, GLfloat startPitch, GLfloat startMoveSpeed, GLfloat startTurnSpeed);
void keyControl(bool* keys, GLfloat deltaTime);
void mouseControl(GLfloat xChange, GLfloat yChange);
static float fov;
glm::mat4 calculateViewMatrix();
~Camera();
static void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
private:
glm::vec3 position;
glm::vec3 front;
glm::vec3 up;
glm::vec3 right;
glm::vec3 worldUp;
GLfloat yaw;
GLfloat pitch;
GLfloat moveSpeed;
GLfloat turnSpeed;
void update();
};
Camera.cpp
#include "Camera.h"
#include <iostream>
Camera::Camera() {}
Camera::Camera(glm::vec3 startPosition, glm::vec3 startUp, GLfloat startYaw, GLfloat startPitch, GLfloat startMoveSpeed, GLfloat startTurnSpeed)
{
position = startPosition;
worldUp = startUp;
yaw = startYaw;
pitch = startPitch;
front = glm::vec3(0.0f, 0.0f, -1.0f);
moveSpeed = startMoveSpeed;
turnSpeed = startTurnSpeed;
update();
}
void Camera::keyControl(bool* keys, GLfloat deltaTime)
{
GLfloat velocity = moveSpeed * deltaTime;
if (keys[GLFW_KEY_W] || keys[GLFW_KEY_UP])
{
position += front * velocity;
}
if (keys[GLFW_KEY_S] || keys[GLFW_KEY_DOWN])
{
position -= front * velocity;
}
if (keys[GLFW_KEY_A] || keys[GLFW_KEY_LEFT])
{
position -= right * velocity;
}
if (keys[GLFW_KEY_D] || keys[GLFW_KEY_RIGHT])
{
position += right * velocity;
}
}
void Camera::mouseControl(GLfloat xChange, GLfloat yChange)
{
xChange *= turnSpeed;
yChange *= turnSpeed;
yaw += xChange;
pitch += yChange;
if (pitch > 89.0f)
{
pitch = 89.0f;
}
if (pitch < -89.0f)
{
pitch = -89.0f;
}
update();
}
void Camera::scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
if (fov > 1.0f && fov < 45.0f)
fov -= yoffset;
else if (fov <= 1.0f)
fov = 1.0f;
else if (fov >= 45.0f)
fov = 45.0f;
}
glm::mat4 Camera::calculateViewMatrix()
{
return glm::lookAt(position, position + front, up);
}
void Camera::update()
{
front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
front.y = sin(glm::radians(pitch));
front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
front = glm::normalize(front);
right = glm::normalize(glm::cross(front, worldUp));
up = glm::normalize(glm::cross(right, front));
}
Camera::~Camera()
{
}
window.cpp
#include "Window.h"
#include "Camera.h"
#include <iostream>
Window::Window()
{
width = 800;
height = 800;
for (size_t i = 0; i < 1024; i++)
{
keys[i] = 0;
}
}
Window::Window(GLint windowWidth, GLint windowHeight)
{
width = windowWidth;
height = windowHeight;
for (size_t i = 0; i < 1024; i++)
{
keys[i] = 0;
}
}
int Window::Initialise()
{
if (!glfwInit())
{
printf("Error Initialising GLFW");
glfwTerminate();
return 1;
}
// Setup GLFW Windows Properties
// OpenGL version
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// Core Profile
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Allow forward compatiblity
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
// Create the window
mainWindow = glfwCreateWindow(width, height, "Test Window", NULL, NULL);
if (!mainWindow)
{
printf("Error creating GLFW window!");
glfwTerminate();
return 1;
}
// Get buffer size information
glfwGetFramebufferSize(mainWindow, &bufferWidth, &bufferHeight);
// Set the current context
glfwMakeContextCurrent(mainWindow);
// Handle Key + Mouse Input
createCallbacks();
glfwSetScrollCallback(mainWindow, Camera::scroll_callback);
glfwSetInputMode(mainWindow, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Allow modern extension access
glewExperimental = GL_TRUE;
GLenum error = glewInit();
if (error != GLEW_OK)
{
printf("Error: %s", glewGetErrorString(error));
glfwDestroyWindow(mainWindow);
glfwTerminate();
return 1;
}
glEnable(GL_DEPTH_TEST);
// Create Viewport
glViewport(0, 0, bufferWidth, bufferHeight);
glfwSetWindowUserPointer(mainWindow, this);
}
void Window::createCallbacks()
{
glfwSetKeyCallback(mainWindow, handleKeys);
glfwSetCursorPosCallback(mainWindow, handleMouse);
}
GLfloat Window::getXChange()
{
GLfloat theChange = xChange;
xChange = 0.0f;
return theChange;
}
GLfloat Window::getYChange()
{
GLfloat theChange = yChange;
yChange = 0.0f;
return theChange;
}
void Window::handleKeys(GLFWwindow* window, int key, int code, int action, int mode)
{
Window* theWindow = static_cast<Window*>(glfwGetWindowUserPointer(window));
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
{
glfwSetWindowShouldClose(window, GL_TRUE);
}
if (key >= 0 && key < 1024)
{
if (action == GLFW_PRESS)
{
theWindow->keys[key] = true;
}
else if (action == GLFW_RELEASE)
{
theWindow->keys[key] = false;
}
}
}
void Window::handleMouse(GLFWwindow* window, double xPos, double yPos)
{
Window* theWindow = static_cast<Window*>(glfwGetWindowUserPointer(window));
if (theWindow->mouseFirstMoved)
{
theWindow->lastX = xPos;
theWindow->lastY = yPos;
theWindow->mouseFirstMoved = false;
}
theWindow->xChange = xPos - theWindow->lastX;
theWindow->yChange = theWindow->lastY - yPos;
theWindow->lastX = xPos;
theWindow->lastY = yPos;
}
Window::~Window()
{
glfwDestroyWindow(mainWindow);
glfwTerminate();
}

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.

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?